首页 > 解决方案 > Python socket Select 模块显示它已收到读取请求,但它只收到一个。为什么?

问题描述

我正在创建一个程序,客户端在其中输入包含图像的文件的名称。然后将其转换为 numpy 数组,腌制并发送到服务器。服务器使用 PIL ImageDraw 在所述图像上绘制一个红色 X,然后将其发送回客户端。我注意到 select 函数出于某种原因将套接字两次添加到读取列表中。我知道这一点,因为客户端取回了图像,并且我在发送过程结束时添加了一个打印功能,它触发了一次,但随后更早的打印语句再次发生,并返回错误。这是服务器输出:

b'56925          '
sent
b''
Traceback (most recent call last):
  File "server.py", line 31, in <module>
    msglengthi = int(msglength)
ValueError: invalid literal for int() with base 10: ''

这是服务器代码:

import socket
import pickle
from PIL import ImageDraw
from PIL import Image
import select
import numpy

IP = socket.gethostbyname(socket.gethostname())
PORT = 4321
HEADERSIZE = 15

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((IP, PORT))
s.listen(5)
socketlist = [s]
readqueue = []


while True:
    readqueue, write, exception  = select.select(socketlist, [], [])
    for socket in readqueue:
        if socket == s:
            clientsocket, clientaddress = s.accept()
            socketlist.append(clientsocket)
            print(f"Connection received from {clientaddress}")
            clientsocket.send(bytes("Welcome to the server", "utf-8"))
        else:
            msglen = socket.recv(HEADERSIZE)
            msglength = msglen.decode("utf-8")
            print(msglen)
            msglengthi = int(msglength)
            fullmsg = []
            x=0
            while x<=msglengthi:
                msgu = socket.recv(3000)
                fullmsg.append(msgu)
                x+=3000
            fullmsg = b"".join(fullmsg)
            msg = pickle.loads(fullmsg)
            img = Image.fromarray(msg)
            draw = ImageDraw.Draw(img)
            width, height = img.size
            draw.line((0, 0, width, height), fill="red", width=20)
            draw.line((width, 0, 0, height), fill="red", width=20)
            payload = pickle.dumps(numpy.array(img))
            paylen = len(payload)
            socket.send(bytes(f"{paylen:<{HEADERSIZE}}", "utf-8")+payload)
            print("sent")

最后是客户端代码:

import socket
import pickle
from PIL import Image
import numpy


PORT = 4321
IP = socket.gethostbyname(socket.gethostname())
HEADERSIZE = 15

cs = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
cs.connect((IP, PORT))
welcomemsg = cs.recv(21)
welcomemsg = welcomemsg.decode("utf-8")
print(welcomemsg)

img = input("Enter image file: ")
imgo = Image.open(img)
imga = numpy.array(imgo)
imgdump = pickle.dumps(imga)
msglen = len(imgdump)
print(msglen)
cs.send(bytes(f"{msglen:<{HEADERSIZE}}", "utf-8")+imgdump)
msglen = cs.recv(HEADERSIZE)
msglen = msglen.decode("utf-8").strip()
msglen = int(msglen)
x=0
fullmsg=[]
while x<=msglen:
    msg = cs.recv(3000)
    fullmsg.append(msg)
    x+=3000
fullmsg = b"".join(fullmsg)
img = pickle.loads(fullmsg)
img = Image.fromarray(img)
img.show()

谢谢!

标签: pythonsocketsselectpython-sockets

解决方案


我注意到 select 函数出于某种原因将套接字两次添加到读取列表中。

它没有。select只要有关于可以使用 检索的套接字的信息,就会返回该套接字是可读的recv。当您处理recv返回实际数据的情况时,您不会处理当对等方关闭连接时recv返回空缓冲区(即)的情况。''换句话说:问题不在于select您对如何selectrecv工作的假设。


推荐阅读