我有一个包含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
整个类在Singleton中设计,并由主线程创建。 该程序在开始时运行良好。数据可以正常发送和接收。
但是,大约一小时后,该程序在运行到“ response = self.cs.recvfrom(1024)”这一行时收到“无法在套接字上选择”错误。
我已经搜索了几天,但是仍然不知道为什么以及如何触发此错误。
我的python版本是2.7.13,请帮助我了解如何处理此问题。
答案 0 :(得分:0)
CPython源代码(用C编写,因此称为名称)表明,消息是由称为select_error
的函数产生的。这样调用recvfrom
(sock_recvfrom_guts
):
...
if (!IS_SELECTABLE(s)) {
select_error();
return -1;
}
...
因此,仅当宏IS_SELECTABLE
返回错误值时才触发该错误消息。宏在这里定义:
#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()
的值。那应该告诉您在触发错误时的文件描述符值。