【问题标题】:Disable Nagle's algorithm for NSOutputStream禁用 NSOutputStream 的 Nagle 算法
【发布时间】:2014-07-11 16:48:30
【问题描述】:

我正在使用MPCF 创建多人游戏。您使用 iPhone 在 iPad 上控制宇宙飞船。

我在随机时间和间隔遇到各种延迟和延迟以及缓冲/暂停,现在已经登陆 Apples Technical Q&A NW26 论文,该论文谈论禁用 Nagle 算法。我尝试了一下,但我的程序不断崩溃,我不明白为什么。 CFWriteStreamCopyProperty 似乎总是返回 NULL。

- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode
{
    switch (eventCode) {
        case NSStreamEventOpenCompleted:

            // Trying to get a handle to the native socket
            CFSocketNativeHandle rawsock;

            // This always return NULL
            CFDataRef socketData = CFWriteStreamCopyProperty((__bridge CFWriteStreamRef)(stream), kCFStreamPropertySocketNativeHandle); 

            // And this row always crash (coz of socketData being NULL i guess)
            CFDataGetBytes(socketData, CFRangeMake(0, sizeof(CFSocketNativeHandle)), (UInt8 *)&rawsock); 
            CFRelease(socketData);

            // Code example from Apple that need a handle to the native socket, that I am trying to get above
            int err; 
            static const int kOne = 1;  
            err = setsockopt(rawsock, IPPROTO_TCP, TCP_NODELAY, &kOne, sizeof(kOne)); 
            if (err < 0) {     
                err = errno; 
            }

            break;

        default:
            break;
    }
}

感谢任何帮助。

【问题讨论】:

  • 您找到解决方案了吗?我也在尝试减少延迟,并且不使用 `sendData:toPeers:withMode:error:` 和MCSessionSendDataUnreliable,这样我就可以避免处理数据包丢失......
  • 不,抱歉。切换到蓝牙 LE。
  • 太糟糕了...感谢您的回复。

标签: ios objective-c network-programming nsstream multipeer-connectivity


【解决方案1】:

您假设streamNSOutputStream,但也可以传递NSInputStream。 所以它在那条线上崩溃了。

这是一个可以处理这两种情况并修复崩溃的示例代码:

- (void)disableNaglesAlgorithmForStream:(NSStream *)stream {

    CFDataRef socketData;

    // Get socket data
    if ([stream isKindOfClass:[NSOutputStream class]]) {
        socketData = CFWriteStreamCopyProperty((__bridge CFWriteStreamRef)((NSOutputStream *)stream), kCFStreamPropertySocketNativeHandle);
    } else if ([stream isKindOfClass:[NSInputStream class]]) {
        socketData = CFReadStreamCopyProperty((__bridge CFReadStreamRef)((NSInputStream *)stream), kCFStreamPropertySocketNativeHandle);
    }

    // get a handle to the native socket
    CFSocketNativeHandle rawsock;

    CFDataGetBytes(socketData, CFRangeMake(0, sizeof(CFSocketNativeHandle)), (UInt8 *)&rawsock);
    CFRelease(socketData);

    // Disable Nagle's algorythm

    // Debug info
    BOOL isInput = [stream isKindOfClass:[NSInputStream class]];
    NSString * streamType = isInput ? @"INPUT" : @"OUTPUT";

    int err;
    static const int kOne = 1;
    err = setsockopt(rawsock, IPPROTO_TCP, TCP_NODELAY, &kOne, sizeof(kOne));
    if (err < 0) {
        err = errno;
        NSLog(@"Could Not Disable Nagle for %@ stream", streamType);
    } else {
        NSLog(@"Nagle Is Disabled for %@ stream", streamType);
    }
}

这应该在case NSStreamEventOpenCompleted:中调用

对于任何想知道为什么复制粘贴时无法编译的人:

#import <arpa/inet.h>       // for IPPROTO_TCP
#include <netinet/tcp.h>    // for TCP_NODELAY

但是,它对周期性延迟问题没有帮助。 我仍在寻找防止这种情况发生的方法。

我录制了一个演示该问题的简单视频,我相信您也遇到了同样的问题: https://www.dropbox.com/s/omdqkbckph4b1y2/Multipeer%20Connectivity.mov?dl=0

编辑:我能够找到解决周期性延迟问题的方法。导致问题的是MCNearbyServiceAdvertiser。 您需要停止为对等点做广告以消除滞后: 连接成功后立即在您的MCNearbyServiceAdvertiser 实例上调用stopAdvertisingPeer 方法。

MCNearbyServiceAdvertiser *nearbyServiceAdvertiser;

- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state {

    switch (state) {

        case MCSessionStateConnected: {
            dispatch_async(dispatch_get_main_queue(), ^{
                [self.nearbyServiceAdvertiser stopAdvertisingPeer];
            });
        ...
    }
    ...
}

但延迟只会在 30 秒后关闭。不知道怎么让它马上消失。

【讨论】:

  • 很好的答案,我在我的应用程序中遇到了类似的问题,我每秒发送许多小数据包。偶然发现了这个答案,它似乎解决了我的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-02-08
  • 1970-01-01
  • 2013-07-24
  • 2012-03-29
  • 1970-01-01
  • 2020-07-10
  • 2019-10-07
相关资源
最近更新 更多