CocoaAsyncSocket实现局域网内通信
内容概要
利用CocoaAsyncSocket实现局域网内 iOS设备间的简单通讯.
结构
1 2 3
| 1,服务端,用于接受客户端连接. 2,客户端,向服务端发起连接 3,通讯协议,两端都遵守协议格式进行数据收发无误
|
代码
通讯协议
非常简略的协议只为实现简单的文字通讯功能
1 2
| 1,长度包: |内容包长度(8bit)| 2,内容爆: |消息类型(1bit)|传输内容(不定)|
|
客户端
1,创建GCDSocket
1 2 3
| self.socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)]; //设置代理 和 代理队列,代理方法将在代理队列中执行 //其实也可以为其中的socket通讯执行的队列,但是,队列须要为串行队列,保持数据成流
|
2, 开始连接
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| ///链接至指定ip -(BOOL)connectToIP:(NSString*)ip{ NSError* err; //此处端口号为服务端监听端口 [self.socket connectToHost:ip onPort:8866 error:&err]; NSLog(@"===%@===",err); return YES; }
-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port{ //开始读取操作,因为为阻塞式,会等待直至有数据返回,进行读取 [self.socket readDataToLength:8 withTimeout:-1 tag:IMDataTag_Length]; NSLog(@"===服务端接受链接==="); }
|
3,写入数据
1 2 3 4 5 6 7 8 9 10 11 12
| //发送模型 -(void)writeStr:(id<IMModelProtocol>)model{ //将要发送的模型转换为原始数据 NSData* data = [model getSendData];
//发送数据长度包,表示后续内容包的长度 [self.socket writeData:[data subdataWithRange:NSMakeRange(0, 8)] withTimeout:-1 tag:0];
//发送内容包 [self.socket writeData:[data subdataWithRange:NSMakeRange(8, data.length-8)] withTimeout:-1 tag:0]; }
|
4,读取数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| -(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{ switch (tag) { case IMDataTag_Length: //获得长度 self.currentDataLength = [self.analy getDataTotalLength:data]; //获取长度后,进行内容读取 [self.socket readDataToLength:self.currentDataLength withTimeout:-1 tag:IMDataTag_Content]; break; case IMDataTag_Content: //获得内容 { //将原始数据转换为需要的模型(我讲模型与Data转化的方法为了简介提到了外面) id<IMModelProtocol> model = [self.analy getIMDataModelWithTotalLength:self.currentDataLength andData:data]; [[NSNotificationCenter defaultCenter] postNotificationName:IMGetModelNoti object:model]; [self.socket readDataToLength:8 withTimeout:-1 tag:IMDataTag_Length]; } break; } }
|
服务端
1,创建接口监听的socket
1 2 3 4 5
| //此socket用来监听接口,是否有服务端链接 self.socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(0, 0)];
//监听 8886接口 [self.socket acceptOnPort:8866 error:nil];
|
2,接受到客户端链接请求
1 2 3 4 5 6 7 8 9 10 11 12
| //当接受到链接请求时 回调该代理方法 -(void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket{
// newSocket是对客户端链接的封装,若想保持连接,则将newSocket持有 // 对客户端的 断开,读取,写入都是对newSocket进行的 self.clientSsocket = newSocket; newSocket.delegate = self.clientDelegate; [newSocket setDelegateQueue:dispatch_get_global_queue(0, 0)]; //直接开始读取(因为为阻塞式的) [newSocket readDataToLength:8 withTimeout:-1 tag:IMDataTag_Length]; }
|
然后对newSocket的读写操作就和客户端一样了.
效果如下,一个是虚拟机,一个是真机
其他
应为NAT的存在,所以这里只实现了在局域网下的通讯,若想实现真正的想微信那样的通讯, 还需要自己再路由器下映射的端口号,实现内网穿透, 此外 还有很多细节需要实现~~ 路漫漫其修远兮~~