Python套接字:当被要求“回复”时,服务器不会等待任何内容。然后' sendall'

时间:2017-10-07 21:11:56

标签: python sockets

我正在尝试使用python套接字试图更好地理解整个概念,但我遇到了一个问题。我有一个简单的服务器和一个客户端,客户端将一个列表发送到服务器,然后等待服务器发送一个字符串,表明该过程已完成。

这是客户端文件:

import socket
import json


host = '192.168.1.102'
port = 14314


def request():

    print 'Connecting'
    clientsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    clientsocket.connect((host, port))

    print 'Sending request'
    clientsocket.sendall(json.dumps([1, 2, 3, 4, 5, 6, 7, 8, 9]))

    print 'Receiving data'
    data = clientsocket.recv(512)
    print 'Received: {}'.format(data)


request()

这是服务器文件:

import socket
import json


host = '192.168.1.102'
port = 14314


def run():

    print 'Binding socket'
    serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    serversocket.bind((host, port))

    print 'Waiting for client'
    serversocket.listen(1)
    clientsocket, addr = serversocket.accept()

    print 'Receiving data'
    raw_data = ''
    while True:
        tmp = clientsocket.recv(1024)
        if not tmp:
            break
        raw_data += tmp
    data = json.loads(raw_data)
    print 'Received: {}'.format(data)

    print 'Sending data'
    clientsocket.sendall('done')


run()

问题在于,当客户端完成发送列表时,服务器卡在recv循环中,等待什么都没有。整个数据已经在第一次迭代中被接收,在第二次迭代中没有任何东西被接收,因为客户端已经移动到接收部分。

奇怪的是,如果我从客户端注释掉接收部分并从服务器注释发送部分,则该过程成功完成。那么,我做错了什么?为什么这不起作用?

感谢。

1 个答案:

答案 0 :(得分:1)

socket.recv的文档讨论了能够传递到unix文档中描述的recv函数的其他标志。所以转向documentation,我发现了以下信息:

  

如果套接字上没有可用消息,则接收呼叫等待   要到达的消息,除非套接字是非阻塞的(参见fcntl(2)),   在这种情况下返回值-1

所以再一次,我们被引导到另一页。 fcntl的文档说

  

在打开的文件上执行下面描述的操作之一   描述符

因此,通常socket.recv函数是阻塞的(它将无限期地等待新数据),除非我们使用文件描述符。我们怎么做?好吧有一个socket.makefile函数,它给我们一个附加到套接字的文件描述符。凉。这个SO question给出了一个示例,说明如何使用文件描述符读取和写入套接字。

如果我们不想使用文件描述符,该怎么办?进一步阅读recv函数的unix文档,我看到我可以使用MSG_DONTWAIT标志。这在Windows中不起作用,但我确实发现我们可以使用socket.setbocking(False)永久地将套接字更改为非阻塞模式。然后,您需要忽略任何“无法立即完成非阻塞套接字操作”错误。这些是正常的和非致命的(this page的错误#10035提到它是非致命的)。

另一种可能的实现是多线程程序,您可以为套接字实现接收和发送线程。这可能会给您带来最佳性能,但设置起来需要做很多工作。

Python太棒了。我刚刚发现一些Python也有异步套接字的库。 asyncoreasynchat如果在您使用的Python版本中可用,则已弃用asyncio

很抱歉在那里扔了那么多。我不太了解套接字。我在Paramiko库中使用过一次,就是这样。但看起来有很多方法可以实现它们。