我发现有关GCDAsyncSocket的didReadData回调不直观的一点是,除非你发出另一个readData,否则它不会再次调用。为什么这样设计?期望库的用户启动另一个读取调用以获得回调是正确的还是设计缺陷?
e.g。
- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket {
...
// initiate the first read
self.socket = newSocket;
[self.socket readDataWithTimeout:-1 tag:0];
}
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
// do what you need with the data...
// read again, or didReadData won't get called!
[self.socket readDataWithTimeout:-1 tag:0];
}
答案 0 :(得分:6)
为什么这样设计?
只要您只使用 readDataWithTimeout:tag:,只要有一些新数据到达就调用委托方法,这似乎更直观。
但 readDataWithTimeout:tag:不是使用GCDAsyncSocket读取数据的唯一方法。还有例如 readDataToLength:withTimeout:tag:和 readDataToData:withTimeout:tag:
这两种方法都会在传入数据的特定点调用委托,您可能希望在处理过程中的不同位置调用不同的代理。
例如,如果您正在处理一种流格式,其中有一个CRLF分隔的标头,后跟一个长度在标头中提供的可变长度主体,那么您可能希望在 readDataToData:withTimeout:tag的调用之间切换:读取你知道的分隔符的标题,然后 readDataToLength:withTimeout:tag:来读取你从标题中提取的长度的主体。
答案 1 :(得分:1)
这是正确的;您应该在委托方法中继续读取循环。
答案 2 :(得分:0)
扩展Simon Jenkins所说的话:
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
// This method is executed on the socketQueue (not the main thread)
switch (tag) {
case CHECK_STAUTS:
[sock readDataToData:[GCDAsyncSocket ZeroData] withTimeout:READ_TIMEOUT tag:CHECK_STAUTS];
break;
default:
break;
}
}
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
// This method is executed on the socketQueue (not the main thread)
dispatch_async(dispatch_get_main_queue(), ^{
@autoreleasepool {
if (tag == CHECK_STAUTS) {
//TODO: parse the msg to find the length.
NSString *msg = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
[serverSocket readDataToLength:LENGTH_BODY withTimeout:-1 tag:CHECK_STAUTS_BODY];
} else if (tag == CHECK_STAUTS_BODY) {
//TODO: parse the msg to the body content
NSString *msg = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
}
}
});
// Echo message back to client
//[sock writeData:data withTimeout:-1 tag:ECHO_MSG];
}