Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Pickle-eoferor:从套接字接收时输入不足_Python_Sockets_Pickle - Fatal编程技术网

Python Pickle-eoferor:从套接字接收时输入不足

Python Pickle-eoferor:从套接字接收时输入不足,python,sockets,pickle,Python,Sockets,Pickle,我正在运行一个非常简单的python(3.x)客户机-服务器程序(都在我的PC上),用于一个学校项目(不适用于真实世界),它只是来回发送消息(如查看客户、添加客户、删除客户等…real basic) 有时数据可能是多条记录,我将它们存储为命名的整数(这很有意义),然后使用Pickle进行传输 例如,在客户机上,我执行以下操作: s.send(message.encode('utf-8')) pickledResponse = s.recv(4096); response = pickle.loa

我正在运行一个非常简单的python(3.x)客户机-服务器程序(都在我的PC上),用于一个学校项目(不适用于真实世界),它只是来回发送消息(如查看客户、添加客户、删除客户等…real basic)

有时数据可能是多条记录,我将它们存储为命名的整数(这很有意义),然后使用Pickle进行传输

例如,在客户机上,我执行以下操作:

s.send(message.encode('utf-8'))
pickledResponse = s.recv(4096);
response = pickle.loads(pickledResponse)
现在,我经常会遇到以下错误:

response = pickle.loads(pickledResponse)
EOFError: Ran out of input
我担心这与我的套接字(TCP)传输有关,也许我没有及时获取pickle.loads的所有数据-有意义吗?如果不是的话,我真的不明白为什么会发生如此不一致的事情

然而,即使我是对的,我也不知道如何(快速)修复它,我正在考虑扔掉泡菜,只使用字符串(但这难道不能承受同样的命运吗)?有人有什么建议吗

实际上,我的信息是非常基本的——通常只是一个命令和一些小数据,比如“1=John”,这意味着命令(1)是FIND命令,然后是“John”,它返回John的记录(姓名、年龄等)(作为namedTuple,但老实说,这不是强制性的)


任何建议或帮助都将不胜感激,寻找快速解决方案…

您的代码的问题是,当在TCP套接字上使用时,
recv(4096)
,可能会返回与您预期不同的数据量,因为它们在数据包边界处被切片

简单的解决方案是在每条消息前面加上长度前缀;因为我喜欢

import struct
packet = pickle.dumps(foo)
length = struct.pack('!I', len(packet)
packet = length + packet

import struct

buf = b''
while len(buf) < 4:
    buf += socket.recv(4 - len(buf))

length = struct.unpack('!I', buf)[0]
# now recv until at least length bytes are received,
# then slice length first bytes and decode.
和客户作为

from multiprocessing.connection import Client

client = Client(('localhost', 1234))
client.send(['hello', 'world'])

代码的问题在于,当在TCP套接字上使用时,
recv(4096)
,返回的数据量可能与您预期的不同,因为它们在数据包边界处被切片

简单的解决方案是在每条消息前面加上长度前缀;因为我喜欢

import struct
packet = pickle.dumps(foo)
length = struct.pack('!I', len(packet)
packet = length + packet

import struct

buf = b''
while len(buf) < 4:
    buf += socket.recv(4 - len(buf))

length = struct.unpack('!I', buf)[0]
# now recv until at least length bytes are received,
# then slice length first bytes and decode.
和客户作为

from multiprocessing.connection import Client

client = Client(('localhost', 1234))
client.send(['hello', 'world'])

要在服务器关闭连接端之前接收服务器发送的所有内容,请尝试以下操作:

import json
import socket
from functools import partial


def main():
    message = 'Test'

    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
        sock.connect(('127.0.0.1', 9999))

        sock.sendall(message.encode('utf-8'))
        sock.shutdown(socket.SHUT_WR)

        json_response = b''.join(iter(partial(sock.recv, 4096), b''))

    response = json.loads(json_response.decode('utf-8'))
    print(response)


if __name__ == '__main__':
    main()
我之所以使用
sendall()
,是因为
send()
recv()
有相同的“问题”:它不能保证所有内容都被发送
send()
返回实际发送的字节数,程序员必须确保与参数的长度匹配,如果不匹配,则发送其余的字节,直到所有内容都完成。发送后,连接的写入端被关闭(
shutdown()
),因此服务器知道不再有来自客户端的数据。在此之后,将接收来自服务器的所有数据,直到服务器关闭其连接端,从而导致从
recv()
调用返回空字节对象

以下是适用于客户端的
socketserver.TCPServer

import json
from socketserver import StreamRequestHandler, TCPServer


class Handler(StreamRequestHandler):

    def handle(self):
        print('Handle request...')
        message = self.rfile.read().decode('utf-8')
        print('Received message:', message)
        self.wfile.write(
            json.dumps(
                {'name': 'John', 'age': 42, 'message': message}
            ).encode('utf-8')
        )
        print('Finished request.')



def main():
    address = ('127.0.0.1', 9999)
    try:
        print('Start server at', address, '...')
        server = TCPServer(address, Handler)
        server.serve_forever()
    except KeyboardInterrupt:
        print('Stopping server...')


if __name__ == '__main__':
    main()

它从客户端读取完整的数据,并将其与其他一些固定项一起放入JSON编码的响应中。它不使用低级套接字操作,而是使用
TCPServer
提供的更方便的类似文件的对象从连接读取和写入数据。
handle()
方法完成后,
TCPServer
关闭连接。

要接收服务器发送的所有内容,直到关闭连接端,请尝试以下操作:

import json
import socket
from functools import partial


def main():
    message = 'Test'

    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
        sock.connect(('127.0.0.1', 9999))

        sock.sendall(message.encode('utf-8'))
        sock.shutdown(socket.SHUT_WR)

        json_response = b''.join(iter(partial(sock.recv, 4096), b''))

    response = json.loads(json_response.decode('utf-8'))
    print(response)


if __name__ == '__main__':
    main()
我之所以使用
sendall()
,是因为
send()
recv()
有相同的“问题”:它不能保证所有内容都被发送
send()
返回实际发送的字节数,程序员必须确保与参数的长度匹配,如果不匹配,则发送其余的字节,直到所有内容都完成。发送后,连接的写入端被关闭(
shutdown()
),因此服务器知道不再有来自客户端的数据。在此之后,将接收来自服务器的所有数据,直到服务器关闭其连接端,从而导致从
recv()
调用返回空字节对象

以下是适用于客户端的
socketserver.TCPServer

import json
from socketserver import StreamRequestHandler, TCPServer


class Handler(StreamRequestHandler):

    def handle(self):
        print('Handle request...')
        message = self.rfile.read().decode('utf-8')
        print('Received message:', message)
        self.wfile.write(
            json.dumps(
                {'name': 'John', 'age': 42, 'message': message}
            ).encode('utf-8')
        )
        print('Finished request.')



def main():
    address = ('127.0.0.1', 9999)
    try:
        print('Start server at', address, '...')
        server = TCPServer(address, Handler)
        server.serve_forever()
    except KeyboardInterrupt:
        print('Stopping server...')


if __name__ == '__main__':
    main()

它从客户端读取完整的数据,并将其与其他一些固定项一起放入JSON编码的响应中。它不使用低级套接字操作,而是使用
TCPServer
提供的更方便的类似文件的对象从连接读取和写入数据。
handle()
方法完成后,
TCPServer
将关闭连接。

如果源不受信任,并且在网络上不信任任何人,则不应使用pickle,引用文档:“警告:pickle模块不用于防止错误或恶意构造的数据。从不从未受信任或未经验证的源接收数据。“您可能会考虑不使用Socket本身的可能性(使用Socket本身意味着关心消息长度,而不是在这里做什么)。。我将提倡使用HTTP、JSON消息,在这里,所有这些都是RESTful的。@JulienPalard鉴于这是一个学校项目,“受信任”的概念并不重要,项目要求是使用套接字(TCP)进行通信——遗憾的是,我无法改变that@JulienPalard知道它是本地的(在同一台PC上)没有办法解决长度问题?如果我使用字符串而不是pickle数据会怎么样?有其他方法可以避免这个问题吗?您可以使用pickle版本1(人类可读)轻松调试,或json,您将看到哪里出了问题。关闭连接可以不必关心长度。如果源不受信任,您不应该使用pickle,并且在网络上,不要信任任何人,引用文档:“警告pickle模块不用于防止错误或恶意构造的数据。从不解除从不受信任的或不受信任的服务器接收的ICKICK数据