我在我的应用程序中出现了一个似乎不可重现的失败。 我有一个TCP套接字连接失败,应用程序试图重新连接它。 在connect()尝试重新连接的第二个调用中,我得到了errno == EADDRNOTAVAIL的连接()的手册页所表示的错误结果意味着:“指定的地址不是从本地计算机可用。
看着连接()的调用,第二个参数看起来是错误所指的地址,但据我所知,这个参数是远程主机的TCP套接字地址,所以我对这个人感到困惑页面引用本地机器。 这个地址到远程TCP套接字主机是不是从我的本地机器可用? 如果是这样,为什么呢? 它必须成功调用连接()第一次在连接失败之前,它试图重新连接,并得到这个错误。 connect()的参数两次都是一样的。
这个错误是否是一个短暂的错误,如果我尝试再次调用connect可能会消失,如果我等了很久? 如果不是,我应该如何尝试从这个故障中恢复?
检查这个链接
http://www.toptip.ca/2010/02/linux-eaddrnotavail-address-not.html
编辑 :是的,我的意思是增加更多,但不得不在那里切断,因为紧急情况
尝试重新连接之前是否关闭了套接字? 关闭会告诉系统socketpair(ip / port)现在是空闲的。
这里是额外的项目,看看:
链接有一个类似于你的错误(答案接近底部)
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4294599
看来你的套接字基本上停留在TCP内部状态之一,并且增加延迟重新连接可能会解决你的问题,因为他们似乎已经在这个错误报告中完成了。
这也可能发生,如果一个无效的端口,如0。
如果您不愿意更改可用临时端口的数量(如David所建议的那样),或者您需要的连接数量超出理论最大值,则还有两种方法可以减少正在使用的端口数量。 但是,它们在不同程度上违反了TCP标准,所以应该谨慎使用。
首先是打开SO_LINGER
零秒超时,迫使TCP
堆栈发送一个RST数据包并刷新连接状态。 然而有一个微妙之处:在shutdown
之前,你应该在套接字文件描述符上调用shutdown
,以便你有机会在RST
包之前发送一个FIN
包。 所以代码看起来像这样:
shutdown(fd, SHUT_RDWR); struct linger linger; linger.l_onoff = 1; linger.l_linger = 0; // todo: test for error setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &linger, sizeof(linger)); close(fd);
如果FIN
数据包被RST
数据包重新排序,服务器只应该看到一个提前连接重置。
请参阅TCP选项SO_LINGER(零) – 何时需要更多详细信息。 (实验上,你设置setsockopt
位置似乎并不重要。)
第二个是使用SO_REUSEADDR
和一个显式bind
(即使你是客户端),这将允许Linux在运行时重用临时端口,然后再等待。 请注意,您必须使用INADDR_ANY
和端口0
bind
,否则SO_REUSEADDR
不受尊重。 你的代码看起来像这样:
int opts = 1; // todo: test for error setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &opts, sizeof(int)); struct sockaddr_in listen_addr; listen_addr.sin_family = AF_INET; listen_addr.sin_port = 0; listen_addr.sin_addr.s_addr = INADDR_ANY; // todo: test for error bind(fd, (struct sockaddr *) &listen_addr, sizeof(listen_addr)); // todo: test for addr // saddr is the struct sockaddr_in you're connecting to connect(fd, (struct sockaddr *) &saddr, sizeof(saddr));
这个选项不太好,因为依照netstat -an | grep -e tcp -e udp | wc -l
你仍然可以使TCP连接的内部内核数据结构饱和 netstat -an | grep -e tcp -e udp | wc -l
netstat -an | grep -e tcp -e udp | wc -l
。 但是,在这种情况下,您将不会开始重用端口。
另一件要检查的是界面已经启动。 最近我在使用网络命名空间时感到困惑,因为它似乎创建了一个新的网络命名空间,它产生了一个完全独立的回送接口,但是并没有提出(至少在Debian版本中)。 这让我有一段时间逃脱了,因为人们通常不会把环回看成是一直停下来的。