Python套接字: Server waits for nothing when asked to 'recv' and then 'sendall'

标签 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循环,什么也不等待。在第一次迭代中已接收到全部数据,在第二次迭代中没有接收到任何内容,因为客户端已移至接收部分。

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

谢谢。

最佳答案

socket.recv 的文档谈论能够传递到 unix 文档中描述的 recv 函数的附加标志。所以转向documentation ,我发现以下消息:

If no messages are available at the socket, the receive calls wait for a message to arrive, unless the socket is nonblocking (see fcntl(2)), in which case the value -1 is returned

因此,我们再次被引导到另一个页面。 fcntl 的文档说

Performs one of the operations described below on the open file descriptor

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

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

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

Python 很棒。我刚刚发现 Python 的一些库也可以实现异步套接字。有asyncore , asynchat它们均已被弃用,取而代之的是 asyncio如果您正在使用的 Python 版本中提供该功能。

抱歉扔了这么多。我对套接字不太了解。我在 Paramiko 库中使用过一次,仅此而已。但看起来有很多实现它们的方法。

关于Python套接字: Server waits for nothing when asked to 'recv' and then 'sendall' ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46625163/

相关文章:

python - Python 的 zipfile 模块的更快替代品?

javascript - 将 Javascript 数组传递给 Flask

python - pylint 不喜欢 pkg_resources.resource_filename

python - 使用基于类的 View 管理 Flask 中可选的动态 URL 段

java - 相当于套接字连接的 SerialPortEvent

python - 如何从多维张量中提取值而不丢失后向信息 - PyTorch

android - 适用于 Android 的基于应用程序的防火墙

Python套接字编程: Upload files from Client to Server

java - python 从套接字接收

C++:Windows 套接字错误 10013