Python中的recv()

时间:2012-12-07 22:20:20

标签: python sockets

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时,它会断开连接

为什么没有按任何内容时它与""不一样?

4 个答案:

答案 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

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

第三,新连接可能已经关闭。由于rlisti.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