GCDAynscSocket简单使用-客户端
这是一篇介绍GCDAynscSocket客户端简单使用的文章(服务端后续添加)
背景:在这篇文章之前我对socket的了解仅限于知道有TCP、UDP两种方式,使用抓包工具时甚至看不懂抓包数据(惭愧...),所以本文介绍内容深度有限,主要介绍了一些简单用法。
在这篇文章中主要介绍:
1、使用GCDAynscSocket创建连接、发送数据、接收数据、断开连接;
2、发生数据粘包的处理。
------------------------------------------------------------------------------------
1、创建连接
GCDAynscSocket的初始化般使用两种方式:
// aDelegate是设置的委托对象,而dq是委托所在的线程,sq是socket所在的线程。其中dp不能为空,sq可以为空
- (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq;
- (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq;
/**
* @brief 连接到服务器
*/
- (void)socketConnectHost
{
self.socket = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:delegateQueue];
NSError *error = nil;
[self.socket connectToHost:self.socketHost onPort:self.socketPort withTimeout:3 error:&error];
[self.socket readDataWithTimeout:30 tag:100];
}
连接是否成功都是在委托方法中查看的
// 连接成功的委托方法
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
NSLog(@"连接成功了...");
}
// 连接失败或中途断开连接的委托方法
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{
NSLog(@"连接失败... 断开连接了...");
}
2、发送数据
发送数据比较简单,调用[self.socket writeData:data withTimeout:-1 tag:1]即可
/**
* @brief 写入字符串数据
* @param sendStr 要写入的字符串
*/
- (void)writeAndSendData:(NSString *)sendStr
{
NSData *data = [sendStr dataUsingEncoding: NSUTF8StringEncoding];
[self.socket writeData:data withTimeout:-1 tag:1];
}
3、接收数据
// 在委托方法中接收数据
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
// 对得到的data值进行解析
[self parseSocket:sock withData:data withTag:tag];
}
在此处有一个疑问:
在接收数据之前,是否必须执行[self.socket readDataWithTimeout:-1 tag:100]??最初开始使用时,是必须添加的否则接收不到数据,但是现在工程中没有执行这句代码,为什么可以一直接收数据呢?
4、断开连接
断开连接直接调用方法[self.socket disconnect]即可,可以在委托方法查看是否断开
/**
* @brief 切断socket
*/
-(void)cutOffSocket
{
[self.socket disconnect];
}
5、数据粘包处理
通常在tcp中都要处理数据粘包。我使用的是给数据添加包头的方式,这也是网上比较推荐的一种方式。
思路:定义好包头协议后,在数据发送端每次发送数据之前都添加一个包头(因为是每次发送都添加,所以我认为只要能够满足解包需求包头要尽可能短)。接收端根据包头信息对接收到的数据进行拆包。
一个简单的包头数据: 有5个字节包含两项内容开始:字符$和数据包长度msgLen。
char startStr = '$';
uint32_t msgLen;
msgLen = (uint32_t)(str.length + 5);
在接收端接收到数据后,根据包头信息,找到开始字符$,然后读出包的长度,即可正确拆包。
在整个过程中要注意:如果发送端对数据进行了编码,那么接收端要进行相应的解码,否则会造成乱码,拆包失败。
总结:
在整个使用学习过程中,网络知识一窍不通,又无人指导,感觉举步维艰,还好最终实现了!回头看看前面自己绕的弯路觉得很可笑,纠结的问题更是...
且学且努力!