如何让socket.recv(500)不停止while循环

1 投票
4 回答
2804 浏览
提问于 2025-04-15 20:25

我做了一个IRC机器人,它用一个一直循环的方式来接收说的话。
为了接收信息,我用的是recv(500),但是如果没有信息可以接收,这个方法会让循环停下来,而我希望循环即使没有信息也能继续运行。
我需要一个临时的计时器来让它继续运行。

示例代码:

/A lot of stuff/
timer=0
while 1:
    timer=timer+1
    line=s.recv(500) #If there is nothing to receive, the loop and thus the timer stop.
/A lot of stuff/

所以我需要找到一种方法来防止循环停下来,或者我需要一个更好的计时器。

4 个回答

1

这样设计网络应用程序的方法其实并不好。我建议你看看twisted这个库,它是一个网络库,里面有很棒的IRC协议实现,可以用来制作客户端(比如你的机器人),在twisted.words.protocols.irc里。

http://www.habnabit.org/twistedex.html是一个用twisted写的非常简单的IRC机器人示例。用很少的代码,你就能访问到一个完整、正确、高效、能自动重连的IRC实现。

如果你还是想从底层的socket开始自己写,我还是建议你先学习一下像twisted这样的网络库,了解如何有效地实现网络应用。你现在的做法可能效果没有你想象的那么好。

1

如果你想用低级的Python来实现这个功能,可以考虑使用 ready_sockets = select.select([s.fileno()], [], [], 0.1) 这段代码。这段代码会检查套接字 s 是否可以读取。如果你的套接字的文件编号没有出现在 ready_sockets 中,那就说明没有数据可以读取。

要小心,如果你在一个循环中反复调用select,而这个循环又不让出CPU时间,千万不要把超时时间设置为“0”。这样会让CPU一直忙碌,使用率达到100%。我给了0.1秒的超时作为例子;在这种情况下,你的计时变量会以十分之一秒为单位进行计数。

这里有个例子:

timer=0    
sockets_to_check = [s.fileno()]

while 1:
    ready_sockets = select.select(sockets_to_check, [], sockets_to_check, 0.1)
    if (len(ready_sockets[2]) > 0):
        # Handle socket error or closed connection here -- our socket appeared
        # in the 'exceptional sockets' return value so something has happened to 
        # it.
    elif (len(ready_sockets[0]) > 0):
        line = s.recv(500)
    else:
        timer=timer+1  # Note that timer is not incremented if the select did not
                       # incur a full 0.1 second delay.  Although we may have just
                       # waited for 0.09999 seconds without accounting for that.  If
                       # your timer must be perfect, you will need to implement it
                       # differently.  If it is used only for time-out testing, this 
                       # is fine.

注意,上面的代码是利用了你的输入列表中只有一个套接字的这个事实。如果你想用这种方法处理多个套接字(select.select是支持的),那么 len(ready_sockets[x]) > 0 这个测试就不能告诉你具体是哪个套接字准备好读取或者出现了异常。

2

你可以在套接字上设置一个超时时间,这样如果没有数据可以发送,调用就会迅速返回(会有一个合适的异常,所以你需要在这段代码周围加上try/except来处理这个异常)。实际上,设置0.1秒的超时时间在大多数情况下比非阻塞套接字效果更好。

撰写回答