Python通过套接字发送不完整数据

1 投票
2 回答
2254 浏览
提问于 2025-04-15 23:22

我有一个套接字服务器的脚本,

import SocketServer
import shelve
import zlib

    class MyTCPHandler(SocketServer.BaseRequestHandler):
        def handle(self):
            self.words = shelve.open('/home/tipu/Dropbox/dev/workspace/search/words.db', 'r');
            self.tweets = shelve.open('/home/tipu/Dropbox/dev/workspace/search/tweets.db', 'r');

            param = self.request.recv(1024).strip()
            try:
                result = str(self.words[param])
            except KeyError:
                result = "set()"
            self.request.send(str(result))

    if __name__ == "__main__":
        HOST, PORT = "localhost", 50007
        SocketServer.TCPServer.allow_reuse_address  = True
        server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
        server.serve_forever()

还有一个接收器,

from django.http import HttpResponse
from django.template import Context, loader
import shelve
import zlib
import socket


def index(req, param = ''):
    HOST = 'localhost'    
    PORT = 50007              
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((HOST, PORT))
    s.send(param)
    data = zlib.decompress(s.recv(131072))
    s.close()
    print 'Received', repr(data)
    t = loader.get_template('index.html') 
    c = Context({ 'foo' : data })
    return HttpResponse(t.render(c))

我正在向接收器发送一些几百千字节的字符串,但我只收到了一部分。有没有办法解决这个问题,让整个字符串都能发送过去呢?

补充说明:我想发送的字符串实际上有418437个字符。我的想法是,我想发送一个集合的字符串表示,使用str(set)来实现,这样我就可以用eval重新组装这个集合。有没有办法让我让套接字发送完整的数据,或者压缩到足够小,以便套接字可以一次性发送?我试过使用zlib,但压缩后的数据也没有完全发送,因为我经常收到头部错误。根据我找到的信息,这个错误是因为压缩字符串不完整。

2 个回答

0

使用pickle模块可以把对象转成一种可以通过网络传输的格式,然后在另一端再把它加载回来。就像这样:

    pkl_dict= pickle.dumps(THE_SET)
    mysocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    mysocket.connect((HOST, PORT))

    mysocket.send(pkl_dict)

    mysocket.close()
6

socket.recv(N) 这个函数并不能保证你会收到正好 N 个字节的数据。N 只是你一次最多能接收的字节数,实际上你可能收到的字节数会少于 N。为了提高效率,最好把 N 设置成4096的整数倍,文档里也有提到这一点。

你需要不断地“接收”数据,也就是循环接收,直到你收到了所有想要的字节。而且看起来你的协议并没有传达这个重要的信息:你必须明确告诉接收方你想要的字节数,可以通过在数据前面加上长度信息,或者在数据末尾加上一个结束符来实现。否则,接收方是无法从数据流中自动获取这个信息的。

发送数据也是类似的,不过在这种情况下你可以使用socket.sendall,这个函数会帮你处理好循环发送的过程。

撰写回答