python-2.7 - python套接字错误:无法在套接字上选择
问题描述
我有一个包含 UDP 套接字的 python 类。套接字初始代码如下:
self.cs = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.cs.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.cs.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
self.cs.bind(('', 0))
我还定义了属于该类的函数并调用套接字来发送/接收数据。函数中的代码如下:
with self.lock:
while True:
try:
self.cs.sendto(packet, (self.host, 80))
self.cs.settimeout(10)
response = self.cs.recvfrom(1024)
break
整个类是单例设计的,由主线程创建。该程序在开始时运行良好。可以正常发送和接收数据。
但是,过了一会儿,大约 1 小时后,程序在运行到“response = self.cs.recvfrom(1024)”行时出现“无法在套接字上选择”的错误。
我已经用谷歌搜索了几天,但仍然不知道为什么以及如何触发此错误。
我的 python 版本是 2.7.13,请帮助我了解如何处理这个问题。
解决方案
CPython 源代码(用 C 语言编写,因此得名)显示消息是由名为select_error
. 像这样调用recvfrom
( sock_recvfrom_guts
) :
...
if (!IS_SELECTABLE(s)) {
select_error();
return -1;
}
...
IS_SELECTABLE
因此,仅当宏返回 false 值时才会触发该错误消息。宏在这里定义:
#ifdef HAVE_POLL
/* Instead of select(), we'll use poll() since poll() works on any fd. */
#define IS_SELECTABLE(s) 1
/* Can we call select() with this socket without a buffer overrun? */
#else
/* If there's no timeout left, we don't have to call select, so it's a safe,
* little white lie. */
#define IS_SELECTABLE(s) (_PyIsSelectable_fd((s)->sock_fd) || (s)->sock_timeout <= 0.0)
#endif
由此我们可以推断出您的系统没有该poll
功能(或者至少在构建 CPython 时没有检测到/配置它);否则,IS_SELECTABLE
永远不会失败。调用是那里唯一的_PyIsSelectable_fd
考虑因素(因为我们知道你sock_timeout
的设置为 10),它被定义为:
/* A routine to check if a file descriptor can be select()-ed. */
#ifdef HAVE_SELECT
#define _PyIsSelectable_fd(FD) (((FD) >= 0) && ((FD) < FD_SETSIZE))
#else
#define _PyIsSelectable_fd(FD) (1)
#endif /* HAVE_SELECT */
这向我表明,要么套接字在途中某处关闭(这导致fd
设置为-1
),要么被检查的套接字的文件描述符大于或等于FD_SETSIZE
. 是特定于平台的,但它是系统调用FD_SETSIZE
处理的固定长度文件描述符位数组中可以使用的最大文件描述符。select
在我的 linux 平台上,它设置为 1024。可能是你无意中一遍又一遍地创建套接字,最终你有这么多打开的文件描述符,新的套接字得到了上面的文件描述符FD_SETSIZE
?
为了确切了解发生了什么,我将捕获您看到错误消息的异常并打印出self.cs.fileno()
. 这应该告诉您触发错误时的文件描述符值。
推荐阅读
- windows - EC2 快照会备份没有卷的实例吗?
- php - 在 PHP 中读取包含非英文字符的文件时出现问题
- fail2ban - 无法将 sendmail“超出连接速率限制”与 fail2ban 匹配
- java - 同一类的多个外键
- angular-openlayers - 我无法使用 Angular OpenLayers 和 WMTS 服务加载地图
- octave - 如何让 Octave GUI 在编辑器和控制台中正确加载/读取 .m 文件?
- postgresql - 如果我的 VPN 开启,我的 Phoenix 项目突然无法连接到 postgres - 如何修复?
- c# - 接口和抽象类在 C# 8.0 的上下文中有什么区别
- javascript - 跨多个子域的 OneSignal 推送通知
- java - 理解 Java 中的 getSystemResource()