iOS NSStream TCP服务器客户端无法通信。

7
我遇到了一个关于使用Bonjour在Objective C中开发TCP服务器/客户端的问题。
在服务器端,我正确地打开流并使用handleEvent函数发送和接收数据。但我不知道发送和接收数据的正确方式。我阅读了这篇优秀的文章:Correct way to send data through a socket with NSOutputStream,所以我使用了一个分组队列系统来发送数据:
    switch(eventCode) {

    case NSStreamEventOpenCompleted: {
        NSLog(@"Complete");

    } break;

    case NSStreamEventHasSpaceAvailable: {
        if (stream == _outputStream)
            [self _sendData];
    } break;

...

- (void)_sendData {
flag_canSendDirectly = NO;
NSData *data = [_dataWriteQueue lastObject];
if (data == nil) {
    flag_canSendDirectly = YES;
    return;
}
uint8_t *readBytes = (uint8_t *)[data bytes];
readBytes += currentDataOffset;
NSUInteger dataLength = [data length];
NSUInteger lengthOfDataToWrite = (dataLength - currentDataOffset >= 1024) ? 1024 : (dataLength - currentDataOffset);
NSInteger bytesWritten = [_outputStream write:readBytes maxLength:lengthOfDataToWrite];
currentDataOffset += bytesWritten;
if (bytesWritten > 0) {
    self.currentDataOffset += bytesWritten;
    if (self.currentDataOffset == dataLength) {
        [self.dataWriteQueue removeLastObject];
        self.currentDataOffset = 0;
    }
}

所以基本上我只是将我的数据分成许多数据包发送。但是我不知道如何在客户端重新构造数据。我认为我没有正确理解NSStreamEventHasBytesAvailable事件。因为我发送了许多数据包,但是客户端上的此事件只调用一次。当我从缓冲区重构数据时,数据似乎已经损坏了。如果有人能澄清所有这些问题,我将非常感激,因为文档在这一点上并不是很清楚(或者可能我错过了什么..)。

        case NSStreamEventHasBytesAvailable: {
        if (stream == _inputStream)
        {
            //read data
            uint8_t buffer[1024];
            int len;
            while ([_inputStream hasBytesAvailable])
            {
                len = [_inputStream read:buffer maxLength:sizeof(buffer)];
                if (len > 0)
                {
                    NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSUTF8StringEncoding];
                    //NSData *theData = [[NSData alloc] initWithBytes:buffer length:len];
                    UnitySendMessage("AppleBonjour_UnityNetworkManager(Clone)", "OnLocalClientReceiveMessageFromServer", [output cStringUsingEncoding:NSUTF8StringEncoding]);
                }
            }
        }

你尝试过一个简单的测试吗?发送一个短字符串。当你这样做时,你的变量“output”得到了什么?顺便说一下,每次发送都不必有单个字节的调用可用,如果它们及时到达并且一个读取将获取它们所有,它们将被组合在一起。请尝试此测试并告诉我们你得到了什么。 - john elemans
哦,我忘记了一件事情;你可以使用像telnet这样的简单tcp程序来测试接收器。只需连接到您的端口并输入一些文本即可。如果接收器代码正在运行,则应直接获得您的文本。 - john elemans
好的,一个简单的字符串已经可以工作了。所以如果我发送的字符串比缓冲区大,我只需要在每次调用NSStreamEventHasBytesAvailable时重新构建它。但是当字符串完全发送后,我如何得到通知呢? - thegrandwaazoo
你不能这样做。流就是流,你必须在流本身中编码消息的结束标记。当接收器处理传入的字节时,它必须寻找“消息结束标记”。根据发送方和接收方可能会忙碌的情况,你必须准备好处理一个块,其中可能包含消息的结束标记以及更多的字节,即下一条消息的开始。 - john elemans
1个回答

3

看起来你在同一个目的上使用了两个变量 currentDataOffset -- 一个实例变量和一个属性。如果你确实需要这两个,那么你也应该将 currentDataOffset 设置为 0。但我认为代码片段应该像这样:

readBytes += currentDataOffset;
NSUInteger dataLength = [data length];
NSUInteger lengthOfDataToWrite = MIN(dataLength - currentDataOffset, 1024);
NSInteger bytesWritten = [_outputStream write:readBytes maxLength:lengthOfDataToWrite];
if (bytesWritten > 0) {
    currentDataOffset += bytesWritten;
    if (currentDataOffset == dataLength) {
        [self.dataWriteQueue removeLastObject];
        currentDataOffset = 0;
    }
}

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