GCDAsyncSocket - 无法接收数据 - AsyncSocket正常工作

7

我使用GCDAsyncSocket让iPhone客户端连接到一个运行在Windows服务器上的.Net服务器。连接很好,数据也能够成功发送。

然后,我告诉客户端在发送完数据后直接进入接收状态......

[sock readDataToData:[GCDAsyncSocket LFData] withTimeout:15 tag:1]; 

我还设置了接收以下内容:

- (void)onSocket:(GCDAsyncSocket *)sock didReadData:(NSData *)data 
withTag:(long)tag 

并且:

   - (NSTimeInterval)socket:(GCDAsyncSocket *)sock shouldTimeoutReadWithTag:(long)tag 

如果我等待超时,将调用超时方法。
如果我从服务器发送数据,则不会调用超时,因此我假设客户端已经看到了某些内容,但在客户端没有任何指示。
我还添加了:
- (void)socket:(GCDAsyncSocket *)sock didReadPartialDataOfLength: (NSUInteger)partialLength tag:(long)tag 

希望我能看到部分数据包,但是这并没有被触发。如上所述,如果我从服务器发送一些数据到客户端,超时就不会触发。然而,我认为如果它没有收到终止字符,它也应该超时。我还尝试了使用长度为3的读取,但没有任何区别。GCDAsyncSocket 是问题所在,AsyncSocket 看起来工作正常。也许初始化有问题?dispatch_queue_t mainQueue = dispatch_get_main_queue(); asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:mainQueue]。您有什么想法是我做错了什么吗?我在 Google 代码上发布了一个帖子,但没有任何活动,所以不确定是否会得到答案。最理想的情况是,如果有人有一个接收工作的示例代码,那就太棒了!谢谢!
6个回答

10
Maybe there was something wrong with the spelling. (So this happened to me and I was searching for hours until I've seen the small difference)
GCDAsyncSocket 将所有委托回调重命名为 socket,以匹配苹果的命名风格。
在您上面提到的示例中。
- (void)onSocket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag 

重命名为

- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag 

这应该解决那个问题。

在我的代码中,我还遇到了另一个问题。确保调用GCDAsyncSocket的对象在您连接时仍然存在。GCDAsyncSocket的委托是对您对象的弱引用。因为它是异步的,所以当套接字响应时,委托可能变为零(自动释放,或者实例是在已经离开的方法中创建的)。结果似乎没有被调用,但启动套接字的类已经从内存中释放。特别是如果您与GCDAsyncSocket一起使用ARC,就会发生这种情况。

希望这有所帮助。


那个关于弱引用的信息帮了我很大的忙。我自己可能永远都找不到。谢谢。 - Darren
千言万语表达不尽的感激!这一直是我进展的绊脚石。 - VaporwareWolf
GCDAsyncSockets的委托是一个弱引用,让我很迷惑!对于那些仍在苦苦挣扎的人,正如@JackPearse所说,didAccept方法中的newSocket如果离开该方法将被ARC(垃圾回收器)清理。您必须将其分配给类的成员变量,以确保ARC不会清理您的newSocket。 - AndaluZ
挽救了一条生命。!!! - Ashish Ramani

3

你确定你的服务器发送的数据是以换行符(LineFeed)而不是回车换行符(CRLF)结尾吗?或者,你从服务器返回的数据根本没有以任何字符结尾?readDataToData会一直等待,直到在接收到的数据中找到终止字符。

以下是我用来连接的代码。我已经删除了我认为不必要的部分-希望我没有删除任何重要内容。

初始化套接字

asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];

连接

[asyncSocket connectToAddress:addr error:&err]

在连接时

- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port {
    connected = YES;

发送(无超时)
[asyncSocket writeData:dataData withTimeout:-1 tag:0];

请求读取数据

[asyncSocket readDataToData:[GCDAsyncSocket CRLFData] withTimeout:30.0 tag:0];

数据已经传输完成(我只是发送字符串)

- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
    NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

是的,它肯定发送正确。我尝试使用telnet连接服务器,一切正常。我还切换了.h和.m文件,使用没有GDC的旧版本,也可以工作。 - Mark Worsnop
我不确定还有什么其他建议。我唯一遇到的问题是在iOS5上通过蓝牙连接,但这仍然受NDA保护,所以我不能谈论它。 - Nick Bull
这段代码对我来说是有效的... 我只需要确保我发送的所有字符串都附加了 \r\n。 - T1000
@T1000 如果需要的话,您可以通过在readDataToData方法中将CRLFData更改为LFData或CRData来更改它。 - Nick Bull
我的问题是我没有明确告诉它读取数据。添加 [sock readDataWithTimeout:-1 tag:0] 就解决了问题。 - user376845
显示剩余2条评论

3

我曾经遇到同样的问题,准备放弃。我的问题是服务器端的。在我的代理方法 onSocket:didAcceptNewSocket: 中,我调用了错误的套接字进行读取操作。这个问题通过修改得以解决。

-(void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket
{
    NSLog(@"Connection Socket connected to ipad at %@",[newSocket connectedHost]);
    _ipadSocket = newSocket;
    [_ipadSocket setDelegate:self];

    //***This code was the faulty line. I was calling listen on sock not newSocket
    [_ipadSocket readDataToData:[AsyncSocket CRLFData] withTimeout:10 tag:0];
}

是的,我也卡在这个问题上了。不过从AsyncSocket的“RUNLOOP”示例中并不清楚这个语法是否正确。例如,似乎newSocket委托被继承了。但还是感谢你指明方向! - MoFlo
谢谢,我也是在Sock上调用了readData而不是“newSocket”。 - Moaz Saeed

1

在 didConnectToHost 结尾处加入:

[sock readDataWithTimeout:-1 tag:0];

- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
    //Your Code

    [sock readDataWithTimeout:-1 tag:0];
}

如果在2021年有人遇到同样的问题,这个方法可能仍然适用于你,对我来说肯定起作用了。 - n3dx

1

我认为问题出在你发送的内容上。 如果文件中包含换行符LF,读取将在读取到LF时结束。 在发送文件之前应该进行base64编码,或者读取指定大小的数据。


0

我已经开发了几乎相同的代码,服务器端是iOS,客户端是VB.NET。从VB.NET发送一个147KB的文件使用socket.sendfile方法,而在iOS中使用AsyncSocket:

- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag;
{

        [sock readDataToData:[AsyncSocket CRData] withTimeout:-1 tag:0]; 

        [dataFile appendData:data];
}

我在连接和发送/接收方面没有任何问题,但我的唯一问题是如果使用CRData分隔符,则接收到的是152 kb,而如果使用LFData分隔符,则接收到的是143 kb。

答案是如何在vb net中添加分隔符来发送文件?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接