Python通过套接字发送不完整数据
我有一个套接字服务器的脚本,
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,这个函数会帮你处理好循环发送的过程。