您的位置:首页 > 理论基础 > 计算机网络

iOS 使用第三方库CocoaAsyncSocket进行Tcp通讯

2016-06-22 02:11 591 查看
iPhone的标准推荐CFNetwork C库编程。但是编程比较烦躁。在其它OS往往用类来封装的对Socket函数的处理。比如MFC的CAsysncSocket.在iphone也有类似于开源项目.cocoa AsyncSocket库, 官方网站: http://code.google.com/p/cocoaasyncsocket/ 它用来简化CFnetwork的调用.。

但是由于中国的长城防火墙,谷歌网站无法访问。因此,这里我是从github上下的 https://github.com/robbiehanson/CocoaAsyncSocket

AsyncSocket分为2个版本(个人理解如下)

(1)GCD版。Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。 简单的说就是基于多线程。

(2)RunLoop版。就是单线程以阻塞处理事件而形成一个消息循环,执行完毕后并不退出。

目录结构如下



AsyncSocket包括TCP和UDP,通过实现委托AsyncSocketDelegate进行交互。

调用此API时需先引入CFNetWork.framework。(网上有的说需要加入该框架,但是为在 iOS9 XCode7beta 中不添加亦可正常运行)

如果是实现GCD版本,则需要将GCD文件夹中的4个文件加入项目



这里只实现GCD版本的Tcp,Udp类似,实现代码如下

1、Main.storyboard



2、ConnectionDef

//
//  ConnectDef.h
//  AsyncSocketDemo
//
//  Created by 555chy on 6/22/16.
//  Copyright © 2016 555chy. All rights reserved.
//

#ifndef ConnectDef_h
#define ConnectDef_h

#define DEF_STR_ENCODING    NSUTF8StringEncoding
//连接超时时间为60秒
#define CONNECT_TIMEOUT     60
#define READ_TIMEOUT        -1
//发送数据超时时间为60秒
#define WRITE_TIMEOUT       60

#define SERVER_QUEUE        "tcpServerQueue"
#define CLIENT_QUEUE        "tcpClientQueue"

#define SERVER_ADDRESS      @"127.0.0.1"
#define SERVER_PORT         12345

#endif /* ConnectDef_h */


2、TcpServer.h

//
//  TcpServer.h
//  AsyncSocketDemo
//
//  Created by 555chy on 6/21/16.
//  Copyright © 2016 555chy. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "GCDAsyncSocket.h"
#import "ConnectionDef.h"

@interface TcpServer : NSObject  <GCDAsyncSocketDelegate> {
GCDAsyncSocket *serverSocket;
NSMutableArray *clientArray;
long readTag;
long writeTag;
}

-(long)getReadTag;
-(long)getWriteTag;
-(void)createTcpSocket:(const char *)queueName acceptOnPort:(uint16_t)port;
-(void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket;
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag;
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag;
-(void)socket:(GCDAsyncSocket *)sock writeString:(NSString *)str withTag:(long)tag;
-(void)broadcastStr:(NSString *)str;
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err;

@end


3、TcpServer.m

//
//  TcpServer.m
//  AsyncSocketDemo
//
//  Created by 555chy on 6/21/16.
//  Copyright © 2016 555chy. All rights reserved.
//

#import "TcpServer.h"

@implementation TcpServer

-(long)getReadTag {
return readTag++;
}

-(long)getWriteTag {
return writeTag++;
}

-(void)createTcpSocket:(const char *)queueName acceptOnPort:(uint16_t)port {
clientArray = [NSMutableArray array];
dispatch_queue_t dispatchQueue = dispatch_queue_create(queueName, NULL);
serverSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatchQueue];
[serverSocket acceptOnPort:port error:nil];
readTag = 0;
writeTag = 0;
}

-(void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket {
NSString* ip = [newSocket connectedHost];
uint16_t port = [newSocket connectedPort];
NSLog(@"server didAcceptNewSocket [%@:%d]", ip, port);
[clientArray addObject:newSocket];
//一直等待readSocket的消息(tag是一个标记类似于tcp数据包中的序列号)
[newSocket readDataWithTimeout:READ_TIMEOUT tag:[self getReadTag]];
}

-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
NSString *ip = [sock connectedHost];
uint16_t port = [sock connectedPort];
NSString *str = [[NSString alloc] initWithData:data encoding:DEF_STR_ENCODING];
NSLog(@"server didReadData [%@:%d] %@", ip, port, str);
//再次接收数据,因为这个方法只接收一次
[sock readDataWithTimeout:READ_TIMEOUT tag:[self getReadTag]];
}

-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
NSString *ip = [sock connectedHost];
uint16_t port = [sock connectedPort];
NSLog(@"server didWriteDataWithTag [%@:%d]", ip, port);
}

-(void)socket:(GCDAsyncSocket *)sock writeString:(NSString *)str withTag:(long)tag {
NSData *data = [str dataUsingEncoding:DEF_STR_ENCODING];
[sock writeData:data withTimeout:WRITE_TIMEOUT tag:[self getWriteTag]];
}

-(void)broadcastStr:(NSString *)str {
for(GCDAsyncSocket *sock in clientArray) {
[self socket:sock writeString:str withTag:[self getWriteTag]];
}
}

-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {
NSString *ip = [sock connectedHost];
uint16_t port = [sock connectedPort];
NSLog(@"server socketDidDisconnect [%@:%d]", ip, port);
[clientArray removeObject:sock];
}

@end


4、TcpClient.h

//
//  TcpClient.h
//  AsyncSocketDemo
//
//  Created by 555chy on 6/21/16.
//  Copyright © 2016 555chy. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "GCDAsyncSocket.h"
#import "ConnectionDef.h"

@interface TcpClient : NSObject<GCDAsyncSocketDelegate> {
GCDAsyncSocket *clientSocket;
long readTag;
long writeTag;
}

-(long)getReadTag;
-(long)getWriteTag;
-(void)createTcpSocket:(const char *)queueName connectToHost:(NSString *) host onPort:(uint16_t)port;
-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port;
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag;
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag;
-(void)writeString:(NSString *)str withTag:(long)tag;
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err;

@end


5、TcpClient.m

//
//  TcpClient.m
//  AsyncSocketDemo
//
//  Created by 555chy on 6/21/16.
//  Copyright © 2016 555chy. All rights reserved.
//

#import "TcpClient.h"

@implementation TcpClient

-(long)getReadTag {
return readTag++;
}

-(long)getWriteTag {
return writeTag++;
}

-(void)createTcpSocket:(const char *)queueName connectToHost:(NSString *) host onPort:(uint16_t)port {
dispatch_queue_t dispatchQueue = dispatch_queue_create(queueName, NULL);
clientSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatchQueue];
[clientSocket connectToHost:host onPort:port withTimeout:CONNECT_TIMEOUT  error:nil];
}

-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port {
NSLog(@"client didConnectToHost [%@:%d]", host, port);
[sock readDataWithTimeout:READ_TIMEOUT tag:[self getReadTag]];
}

-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
NSString *ip = [sock connectedHost];
uint16_t port = [sock connectedPort];
NSString *str = [[NSString alloc] initWithData:data encoding:DEF_STR_ENCODING];
NSLog(@"client didReadData [%@:%d] %@", ip, port, str);
}

-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
NSString *ip = [sock connectedHost];
uint16_t port = [sock connectedPort];
NSLog(@"client didWriteDataWithTag [%@:%d]", ip, port);

}

-(void)writeString:(NSString *)str withTag:(long)tag {
NSData *data = [str dataUsingEncoding:DEF_STR_ENCODING];
[clientSocket writeData:data withTimeout:WRITE_TIMEOUT tag:[self getWriteTag]];
}

-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {
NSString *ip = [sock connectedHost];
uint16_t port = [sock connectedPort];
NSLog(@"client socketDidDisconnect [%@:%d]", ip, port);
//可以在这边实现断线重连机制
}

@end


7、ViewController.h

//
//  ViewController.h
//  AsyncSocketDemo
//
//  Created by 555chy on 6/21/16.
//  Copyright © 2016 555chy. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "TcpServer.h"
#import "TcpClient.h"
#import "ConnectionDef.h"

@interface ViewController : UIViewController

@property (nonatomic, retain) TcpServer *tcpServer;
@property (nonatomic, retain) TcpClient *tcpClient;

@property (weak, nonatomic) IBOutlet UITextField *serverSendTextField;
@property (strong, nonatomic) IBOutlet UIView *serverSendButton;
@property (weak, nonatomic) IBOutlet UITextField *clientSendTextField;
@property (weak, nonatomic) IBOutlet UIButton *clientSendButton;
- (IBAction)serverSendButtonClick:(id)sender;
- (IBAction)clientSendButtonClick:(id)sender;

@end


8、ViewController.m

//
//  ViewController.m
//  AsyncSocketDemo
//
//  Created by 555chy on 6/21/16.
//  Copyright © 2016 555chy. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

_tcpServer = [[TcpServer alloc] init];
_tcpClient = [[TcpClient alloc] init];
[_tcpServer createTcpSocket:SERVER_QUEUE acceptOnPort:SERVER_PORT];
[_tcpClient createTcpSocket:CLIENT_QUEUE connectToHost:SERVER_ADDRESS onPort:SERVER_PORT];
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

- (IBAction)serverSendButtonClick:(id)sender {
[_tcpServer broadcastStr:_serverSendTextField.text];
}

- (IBAction)clientSendButtonClick:(id)sender {
[_tcpClient writeString:_clientSendTextField.text withTag:[_tcpClient getWriteTag]];
}

@end

实际效果图如下

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: