Error Domain=NSPOSIXErrorDomain Code=65 "No route to host" 报错的一个可能问题

381 阅读2分钟

问题及处理

在使用 socket 的过程中,你有可能会遇到 Error Domain=NSPOSIXErrorDomain Code=65 "No route to host" 报错 在确定 ip 或者 url 没有问题的情况后,可以尝试创新创建 socket 来处理

我的开发 局域网通信功能 以及 使用 SimplePing 的过程中,都遇到过此问题。 以前开发局域网通信时一直没找到原因,最新 app 使用 SimplePing 的过程中,遇到一个 bug, 在手机从 5g 切换到 wifi 后,会出现一下函数在调用 sendto(::::) 函数时报错,之后所有的 pingdata 都会报错,发不出去,查看错误后就是 Code=65 "No route to host",检查了参数,只有可能时 self.socket实例在网络波动时系统做了处理,导致消息发送一直失败,所以在sendPingWithData失败后, 重新创建 self.socket 后,消息发送恢复正常。

在使用 CocoaAsyncSocket 也遇到过相同问题

sendPingWithData 函数:

- (**void**)sendPingWithData:(NSData *)data {

    **int**                     err;

    NSData *                payload;

    NSData *                packet;

    ssize_t                 bytesSent;

    **id**<SimplePingDelegate>  strongDelegate;

    

    // data may be nil

    NSParameterAssert(**self**.hostAddress != **nil**);     // gotta wait for -simplePing:didStartWithAddress:

    

    // Construct the ping packet.

    

    payload = data;

    **if** (payload == **nil**) {

        payload = [[NSString stringWithFormat:@"%28zd bottles of beer on the wall", (ssize_t) 99 - (size_t) (**self**.nextSequenceNumber % 100) ] dataUsingEncoding:NSASCIIStringEncoding];

        assert(payload != **nil**);

        

        // Our dummy payload is sized so that the resulting ICMP packet, including the ICMPHeader, is

        // 64-bytes, which makes it easier to recognise our packets on the wire.

        

        assert([payload length] == 56);

    }

    

    **switch** (**self**.hostAddressFamily) {

        **case** AF_INET: {

            packet = [**self** pingPacketWithType:ICMPv4TypeEchoRequest payload:payload requiresChecksum:**YES**];

        } **break**;

        **case** AF_INET6: {

            packet = [**self** pingPacketWithType:ICMPv6TypeEchoRequest payload:payload requiresChecksum:**NO**];

        } **break**;

        **default**: {

            assert(**NO**);

        } **break**;

    }

    assert(packet != **nil**);

    

    // Send the packet.

    

    **if** (**self**.hostAddress.length == 0) {

        bytesSent = -1;

        err = EBADF;

    }

    **else** **if** (**self**.socket == **NULL**) {

        bytesSent = -1;

        err = EBADF;

    } **else** {

        bytesSent = sendto(

                           CFSocketGetNative(**self**.socket),

                           packet.bytes,

                           packet.length,

                           0,

                           **self**.hostAddress.bytes,

                           (socklen_t) **self**.hostAddress.length

                           );

        err = 0;

        **if** (bytesSent < 0) {

            err = errno;

        }

    }

    

    // Handle the results of the send.

    

    strongDelegate = **self**.delegate;

    **if** ( (bytesSent > 0) && (((NSUInteger) bytesSent) == packet.length) ) {

        

        // Complete success.  Tell the client.

        

        **if** ( (strongDelegate != **nil**) && [strongDelegate respondsToSelector: **@selector**(simplePing:didSendPacket:sequenceNumber:)] ) {

            [strongDelegate simplePing:**self** didSendPacket:packet sequenceNumber:**self**.nextSequenceNumber];

        }

    } **else** {

        NSError *   error;

        

        // Some sort of failure.  Tell the client.

        

        **if** (err == 0) {

            err = ENOBUFS;          // This is not a hugely descriptor error, alas.

        }

        error = [NSError errorWithDomain:NSPOSIXErrorDomain code:err userInfo:**nil**];

        **if** ( (strongDelegate != **nil**) && [strongDelegate respondsToSelector: **@selector**(simplePing:didFailToSendPacket:sequenceNumber:error:)] ) {

            [strongDelegate simplePing:**self** didFailToSendPacket:packet sequenceNumber:**self**.nextSequenceNumber error:error];

        }

    }

    

    **self**.nextSequenceNumber += 1;

    **if** (**self**.nextSequenceNumber == 0) {

        **self**.nextSequenceNumberHasWrapped = **YES**;

    }

}

其他

关于切换网络,socket 很容易有一些问题出现,基本都是要重启 socket 在使用 SocketRocket时,我遇到过从 wifi 切换蜂窝时,报错 Domain=SRWebSocketErrorDomain Code=2133 "Invalid Sec-WebSocket-Accept response" UserInfo={NSLocalizedDescription=Invalid Sec-WebSocket-Accept response} 相关的描述可以查看此回复

一些想法

关于切换网络,系统可能是会对 socket 做一些处理的,我不清楚我的想法是否正确,但是以上我遇到了问题应该都是系统 CFSocketRef 对网络变化的高敏反应造成的

索引

SimplePing 的代码从此处可以看到 github.com/chrishulber…