7
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 == "":

但是当客户端只是按下回车相当于""它断开连接

为什么当什么都没有被按下时它不一样""

4

4 回答 4

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它是空的,并且 as calledselect不会返回,直到某些内容被读取为“读取”。所以我们接受新的连接并将其添加到open_sockets.

select再次调用时,有三个可能的事件。首先,listening_socket可能已经收到另一个连接。在这种情况下,它像以前一样处理:我们接受连接并将其添加到open_sockets.

其次,新连接可能已经接收到数据。由于select包含在 中rlist,我们知道有数据准备好从套接字“读取”(意味着数据已准备好读取,或者套接字已关闭)。i.recv将返回新数据。

第三,新的连接可能已经关闭。由于select包含在 中rlist,我们知道有数据准备好从套接字读取(与上面的含义相同)。但i.recv将返回 "" 因为套接字没有任何新数据。所以我们知道套接字已经关闭,并进行相应的清理。

如果客户端没有发送数据(并且连接仍然打开),则不select会将其包含在rlist. 所以循环不会处理它,i.recv也不会在那个特定的套接字上被调用。

于 2012-12-07T22:45:51.523 回答
3

当套接字发送""响应时,这通常意味着套接字已关闭(或关闭?)。如果我在这里错了,请有人纠正我。如果没有该语句,如果远程服务器突然停止响应,它可能会陷入无限循环。

于 2012-12-07T22:43:32.580 回答
0

i(顺便说一句,一个不幸的套接字名称)不会出现在 中,rlist除非有一些东西要读取,即i.recv(1024)返回一些东西或连接完成,即i.recv(1024)返回b""

一旦.recv()返回b"",您将不会从这个套接字收到任何东西。

“客户端(人类)只需按下回车键”的解释取决于客户端(软件)。它与服务器无关,例如,客户端可以缓冲输入字符串,直到遇到换行符或发生超时,或者它可以在从用户接收到每个字节后立即发送,等等。

于 2012-12-08T01:06:17.137 回答
-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
于 2017-07-28T09:58:56.507 回答