一、前言
- Socket
- Socket 是对 TCP/IP 协议的封装,其中IP协议对应为网络层,TCP 协议对应为传输层,而我们常用的HTTP协议,是位于应用层,在七层模型中HTTP协议是基于 TCP/IP 的,我们想要使用 TCP/IP 协议,则要通过 Socket
- Socket 编程用途(其他待补充)
- Socket 和 Http(来源网络)
- socket 一般用于比较即时的通信和实时性较高的情况,比如推送,聊天,保持心跳长连接等,http 一般用于实时性要求不那么高的情况,比如信息反馈,图片上传,获取新闻信息等。
二、类似《你猜我画》简易效果说明
三、服务端部分代码
/*!
@method 开启服务
@abstract 开启服务器 TCP 连接服务
*/
- (void)startServer {
self.serverSocket = [[GCDAsyncSocket alloc]initWithDelegate:self
delegateQueue:dispatch_get_main_queue()];
NSError *error = nil;
[self.serverSocket acceptOnPort:5555
error:&error];
if (error) {
NSLog(@"服务开启失败");
} else {
NSLog(@"服务开启成功");
}
}
#pragma mark - GCDAsyncSocketDelegate
/*!
@method 收到socket端连接回调
@abstract 服务器收到socket端连接回调
*/
- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket {
[self.clientSocketArray addObject:newSocket];
[newSocket readDataWithTimeout:-1
tag:self.clientSocketArray.count];
}
/*!
@method 收到socket端数据的回调
@abstract 服务器收到socket端数据的回调
*/
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
// 直接进行转发数据
for (GCDAsyncSocket *clientSocket in self.clientSocketArray) {
if (sock != clientSocket) {
[clientSocket writeData:data
withTimeout:-1
tag:0];
}
}
[sock readDataWithTimeout:-1
tag:0];
}
四、移动端部分代码
- 基于 GCDAsyncSocket 的接受数据代理方法及发送数据方法
- 图片数据的发送
// 回调 发送图片
__weak typeof(self) weakSelf = self;
bgImgView.block = ^(UIImage *img) {
weakSelf.drawView.drawImg = img;
// image
NSData *imgData = UIImageJPEGRepresentation(weakSelf.drawView.drawImg, 0.2);
NSMutableData *dat = [NSMutableData data];
[dat appendData:imgData];
// 拼接二进制数据流的结束符
NSData *endData = [@"$" dataUsingEncoding:NSUTF8StringEncoding];
[dat appendData:endData];
// 发送数据
[weakSelf.clientSocket writeData:dat
withTimeout:-1
tag:111111];
};
- 图片二进制数据的传输是基于流的,一段一段的,避免断包缺包等问题,需要拼接结束符,图片数据结束
- 图片数据的接受接受
// 拼接数据 转成图片
[self.socketReadData appendData:data];
NSData *endData = [data subdataWithRange:NSMakeRange(data.length -1, 1)];
NSString *end= [[NSString alloc] initWithData:endData
encoding:NSUTF8StringEncoding];
if ([end isEqualToString:@"$"]) {
UIImage *tmpImg = [UIImage imageWithData:self.socketReadData];
self.drawView.drawImg = tmpImg;
[self.drawView setNeedsDisplay];
[self.clientSocket readDataWithTimeout:-1
tag:111111];
// 拼完图片 恢复默认
self.socketReadData = nil;
}
- 画布笔画数据的传输
- 因为传输的是二进制数据,所以采取将贝塞尔曲线转换成 CGPoint 坐标数组,再加上线宽和线的颜色,最后组成一个字典,转换为二进制进行传输
- 考虑到坐标点在不同屏幕上需要适配,因此需要把当前手机端的屏幕高宽一起传输
/*!
@method 发送路径
@abstract 通过socket 发送路径信息
*/
- (void)sendPath {
// path 坐标点及 转换
NSArray *points = [(UIBezierPath *)self.dataModel.path points];
NSMutableArray *tmp = [NSMutableArray array];
for (id value in points) {
CGPoint point = [value CGPointValue];
NSDictiona