GCDAsyncSocket didReadData 只被调用一次
GCDAsyncSocket didReadData only gets called once
我正在尝试设置一个 Java 服务器,使用 GCDAsyncSocket 与 iPhone 客户端通信。出于某种原因,我在 iPhone 上的客户端代码没有读回所有数据。
我第一次看到 didReadData 被调用,但再也没有调用过。理想情况下,我需要模仿 HTTP 协议的功能,它发送 header 然后发送有效负载。有效负载的大小将在 header 中。但这没有用,所以我进一步简化了我的代码,希望能找到问题所在。下面是代码,下面是输出。
客户:
- (BOOL) sendString:(NSString *) string
{
[asyncSocket writeData:[string dataUsingEncoding:NSUTF8StringEncoding]
withTimeout:-1 tag:TAG_PAYLOAD];
[asyncSocket readDataToLength:1 withTimeout:(-1) tag:TAG_HEADER];
}
- (void) socket:(GCDAsyncSocket *) sock didReadData:(NSData *)data
withTag:(long)tag
{
NSString *str = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
NSLog(@"Read data %@ with tag: %ld", str, tag);
if(tag == TAG_HEADER)
{
//TODO - parse the header, get the fields
[sock readDataToLength:3 withTimeout:-1 tag:TAG_PAYLOAD];
//[sock readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1
tag:TAG_PAYLOAD];
}
else
{
NSLog(@"Payload... %@", str);
NSLog(@"Tag: %ld", tag);
}
}
Java 服务器:
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
String clientCommand = in.readLine();
System.out.println("Client Says :" + clientCommand);
out.println("Andrew\r\nAUSTIN\r\n");
out.flush();
然而,在客户端,我唯一返回的是A。确切的输出是:
读取标签为:10
的数据A
我的问题是:
- 为什么 didReadData 方法再也没有被调用过?客户端上应该有更多 "Andrew\r\nAustin" recv'd。但它只是挂起。 readDataToData 和 readDataToLength 似乎都无法获得完整的字符串。
- 我注意到 GCDAsyncSocket.h 中定义的 CRLF 不是 \r\n 而是十六进制值。这有关系吗?这就是为什么我尝试了 readDataToLength 方法但仍然失败的原因。但我想知道这是否重要cross-platform。
谢谢。
好的 - 所以我在拔掉剩下的那根头发后就明白了。
发生的事情是我在视图之外的单独 class 中有上面的客户端代码。实际上,我遇到的所有示例都在视图中处理了 GCDAsyncSocket 内容。它在那里工作得很好!我真的不想这样做,因为在每个视图上我都需要 send/read 数据并且不想重复我的工作。通过在这个名为 SocketComm 的助手 class 的 dealloc 方法中放置一个 NSLog() 行,我能够看到它在触发之前被释放。所以我需要改变我打电话给我的助手的方式 class。我在 viewController.h 文件中将 SocketComm* sockComm 声明为强 属性 并在 viewDidLoad() 方法中分配它。这意味着它始终在范围内。当然,这意味着我需要手动释放它并做一些其他的内务处理工作。
就内存管理而言,我仍然不确定这是否是处理这种情况的最佳方法。因为现在我必须在每个 viewDidLoad 方法上分配它。看起来它应该比这更简单,但我们到了。而且我仍然不知道为什么它从来没有第一次读取数据(我唯一的猜测是 GCDAsyncSocket 库或 iphone 软件在生成它的父进程被释放并决定终止它时检测到死线程- 但这只是一个猜测,因为我刚刚开始 objective-c)。
这也可以解释为什么它有时会起作用,有时却不起作用。它似乎处于比赛状态。不确定我最初发布的上述代码是否准确地导致了竞争条件,但我尝试的一些事情会起作用,然后下一次失败。不过,它从来没有比第一次读得更多,而且只有大约一半的时间会读到那个。有时它甚至不会通过套接字发送数据!
总而言之(以及其他前来寻找答案的人):
- 经常检查你的内存管理。我不得不在 SocketComm 助手 class 的 dealloc() 中放置一个 NSLog 以完全了解发生了什么,一旦我这样做,我就知道罪魁祸首是什么。
- 如果有时有效有时无效的奇怪结果,请检查您的内存管理。对我来说,有时它会进行第一次阅读,有时则不会。这让我相信线程正在终止。
- 如果我找到更好的方法,我会回来更新这个答案。
- 内存管理。再说一遍:内存管理。
我正在尝试设置一个 Java 服务器,使用 GCDAsyncSocket 与 iPhone 客户端通信。出于某种原因,我在 iPhone 上的客户端代码没有读回所有数据。
我第一次看到 didReadData 被调用,但再也没有调用过。理想情况下,我需要模仿 HTTP 协议的功能,它发送 header 然后发送有效负载。有效负载的大小将在 header 中。但这没有用,所以我进一步简化了我的代码,希望能找到问题所在。下面是代码,下面是输出。
客户:
- (BOOL) sendString:(NSString *) string
{
[asyncSocket writeData:[string dataUsingEncoding:NSUTF8StringEncoding]
withTimeout:-1 tag:TAG_PAYLOAD];
[asyncSocket readDataToLength:1 withTimeout:(-1) tag:TAG_HEADER];
}
- (void) socket:(GCDAsyncSocket *) sock didReadData:(NSData *)data
withTag:(long)tag
{
NSString *str = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
NSLog(@"Read data %@ with tag: %ld", str, tag);
if(tag == TAG_HEADER)
{
//TODO - parse the header, get the fields
[sock readDataToLength:3 withTimeout:-1 tag:TAG_PAYLOAD];
//[sock readDataToData:[GCDAsyncSocket CRLFData] withTimeout:-1
tag:TAG_PAYLOAD];
}
else
{
NSLog(@"Payload... %@", str);
NSLog(@"Tag: %ld", tag);
}
}
Java 服务器:
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
String clientCommand = in.readLine();
System.out.println("Client Says :" + clientCommand);
out.println("Andrew\r\nAUSTIN\r\n");
out.flush();
然而,在客户端,我唯一返回的是A。确切的输出是: 读取标签为:10
的数据A我的问题是:
- 为什么 didReadData 方法再也没有被调用过?客户端上应该有更多 "Andrew\r\nAustin" recv'd。但它只是挂起。 readDataToData 和 readDataToLength 似乎都无法获得完整的字符串。
- 我注意到 GCDAsyncSocket.h 中定义的 CRLF 不是 \r\n 而是十六进制值。这有关系吗?这就是为什么我尝试了 readDataToLength 方法但仍然失败的原因。但我想知道这是否重要cross-platform。
谢谢。
好的 - 所以我在拔掉剩下的那根头发后就明白了。
发生的事情是我在视图之外的单独 class 中有上面的客户端代码。实际上,我遇到的所有示例都在视图中处理了 GCDAsyncSocket 内容。它在那里工作得很好!我真的不想这样做,因为在每个视图上我都需要 send/read 数据并且不想重复我的工作。通过在这个名为 SocketComm 的助手 class 的 dealloc 方法中放置一个 NSLog() 行,我能够看到它在触发之前被释放。所以我需要改变我打电话给我的助手的方式 class。我在 viewController.h 文件中将 SocketComm* sockComm 声明为强 属性 并在 viewDidLoad() 方法中分配它。这意味着它始终在范围内。当然,这意味着我需要手动释放它并做一些其他的内务处理工作。
就内存管理而言,我仍然不确定这是否是处理这种情况的最佳方法。因为现在我必须在每个 viewDidLoad 方法上分配它。看起来它应该比这更简单,但我们到了。而且我仍然不知道为什么它从来没有第一次读取数据(我唯一的猜测是 GCDAsyncSocket 库或 iphone 软件在生成它的父进程被释放并决定终止它时检测到死线程- 但这只是一个猜测,因为我刚刚开始 objective-c)。
这也可以解释为什么它有时会起作用,有时却不起作用。它似乎处于比赛状态。不确定我最初发布的上述代码是否准确地导致了竞争条件,但我尝试的一些事情会起作用,然后下一次失败。不过,它从来没有比第一次读得更多,而且只有大约一半的时间会读到那个。有时它甚至不会通过套接字发送数据!
总而言之(以及其他前来寻找答案的人):
- 经常检查你的内存管理。我不得不在 SocketComm 助手 class 的 dealloc() 中放置一个 NSLog 以完全了解发生了什么,一旦我这样做,我就知道罪魁祸首是什么。
- 如果有时有效有时无效的奇怪结果,请检查您的内存管理。对我来说,有时它会进行第一次阅读,有时则不会。这让我相信线程正在终止。
- 如果我找到更好的方法,我会回来更新这个答案。
- 内存管理。再说一遍:内存管理。