open_sockets = []
listening_socket = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
listening_socket.bind( ("", 1234) )
listening_socket.listen(5)
while True:
rlist, wlist, xlist = select.select( [listening_socket] + open_sockets, [], [] )
for i in rlist:
if i is listening_socket:
new_socket, addr = listening_socket.accept()
open_sockets.append(new_socket)
else:
data = i.recv(1024)
if data == "":
i.close()
open_sockets.remove(i)
print "Connection closed"
else:
i.send(data)
print repr(data)
现在我知道这是一个简单的服务器代码,可以处理几个客户端 - 我唯一不理解的是这两行:
data = i.recv(1024)
if data == "":
据我所知,当客户端已经接受它时,将转到另一个选项,该选项检查缓冲区中是否存在某些内容。我不明白为什么,当缓冲区中没有任何内容时,它继续并且不检查该行:
if data == "":
但是当客户端按下相当于""
的enter时,它会断开连接
为什么没有按任何内容时它与""
不一样?
答案 0 :(得分:7)
首先是select
来电。此功能监视套接字并等待值得注意的事情发生。对于第一个列表中的套接字,“值得注意”表示套接字具有可供读取的数据。
rlist, wlist, xlist = select.select( [listening_socket] + open_sockets, [], [] )
代码现在遍历套接字列表,数据已准备好进行读取,并根据正在处理的套接字类型进行操作。
for i in rlist:
if i is listening_socket:
面向连接(“监听”)套接字用于接受新连接。由于它在rlist
,我们知道它有一些东西供我们“阅读”。在侦听套接字的上下文中,这意味着已收到新连接。所以我们接受连接,并将新套接字保存在open_sockets
。
new_socket, addr = listening_socket.accept()
open_sockets.append(new_socket)
如果套接字不是listening_socket
,那么它是一个(或曾经)连接到远程客户端的套接字。再次,因为它在rlist
,我们知道它有一些东西供我们“阅读”。在连接套接字的上下文中,这意味着数据实际上可以读取,或者套接字已经关闭。
因此,我们致电recv
以获取任何可用数据,
else:
data = i.recv(1024)
看看我们是否真的读过任何东西。如果没有可用的数据,则必须已关闭连接,因此我们关闭套接字对象并将其从open_sockets
中删除。
if data == "":
i.close()
open_sockets.remove(i)
print "Connection closed"
如果我们确实收到了数据,我们只需将其写回客户端并将其打印在屏幕上。
else:
i.send(data)
print repr(data)
对select
的第一次呼叫将等到收到连接。您可以通过将代码更新为
print "About to call select"
rlist, wlist, xlist = select.select( [listening_socket] + open_sockets, [], [] )
print "Returned from select"
第一次通话后,rlist
将包含listening_socket
。我们知道这一点,因为open_sockets
是空的,并且被称为select
的内容在读取“read”之前不会返回。因此,我们接受新连接并将其添加到open_sockets
。
再次调用select
时,有三种可能的事件。首先,listening_socket
可能已收到另一个连接。在这种情况下,它像以前一样处理:我们接受连接并将其添加到open_sockets
。
其次,新连接可能已收到数据。由于select
将rlist
包含在i.recv
中,因此我们知道有数据可以从套接字“读取”(意味着数据已准备好进行读取,或者套接字已经关闭)。 select
将返回新数据。
第三,新连接可能已经关闭。由于rlist
将i.recv
包含在select
中,因此我们知道有数据可以从套接字中读取(与上面的含义相同)。但rlist
将返回“”,因为套接字没有任何新数据。所以我们知道套接字已经关闭,并相应地进行清理。
如果没有从客户端发送数据(并且连接仍处于打开状态),则i.recv
将不会将其包含在{{1}}中。因此循环不会处理它,并且不会在该特定套接字上调用{{1}}。
答案 1 :(得分:3)
当套接字响应时发送""
时,通常意味着套接字已关闭(或关闭?)。如果我在这里错了,有人会纠正我。如果没有该声明,如果远程服务器突然停止响应,它可能会陷入无限循环。
答案 2 :(得分:0)
i
(顺便说一下,套接字的一个不幸的名字)不会出现在rlist
中,除非有东西可以阅读,即i.recv(1024)
将返回某些东西或连接已完成,即i.recv(1024)
返回b""
。
.recv()
返回b""
后,您将无法从此套接字中收到任何内容。
“客户(人)只按进入”的解释取决于客户(软件)。它与服务器无关,例如,客户端可以缓冲输入字符串直到遇到换行或发生超时,或者它可以在从用户收到它后立即发送每个字节等。
答案 3 :(得分:-1)
[root@pa ]# grep "banner_timeout = " /opt/panel-migrator/thirdparties/python/lib/python2.7/site-packages/paramiko/transport.py
self.banner_timeout = 60 # how long (seconds) to wait for the SSH banner