问题及处理
在使用 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…