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(セット)を使用してセットの文字列表現を送信しようとしているので、evalを使用してセットを再組み立てることができます。ソケットが完全なデータを送信するか、ソケットが一度に送信できるように十分に圧縮するためのソケットを取得する方法はありますか? Zlibを使用しようとしましたが、圧縮データは完全には送信されません。なぜなら、私が見つけることができたものから、圧縮された文字列が不完全だったために、ヘッダーエラーを繰り返し取得するからです。
解決
socket.recv(n) 正確なnバイトが受信されることを保証しません:むしろ、nはただ 最大 1つのガルプで受信できるバイト数(および効率のために、ドキュメントが示唆するように、理想的には4096のわずかな倍数である必要があります)。
あなたが望むすべてのバイトが得られるまで「受信し続ける」(ループと蓄積)する必要があります(そして、あなたのプロトコルはその重要な価値を通信しないようです:あなた 意思 プレフィックスの長さまたは送信の終了時にターミネーターのいずれかで明示的にする必要がありますが、ストリームソケットから暗黙的に抽出できる方法はありません。
同様に送信用ですが、その場合は使用できます Socket.sendall これはあなたに代わって必要なループを行います。
他のヒント
ピックルモジュールを使用して、オブジェクトをソケットにシリアル化し、反対側にロードします。何かのようなもの:
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()