Основная проблема c в том, что вам нужен способ разметки сообщений в потоке байтов TCP. Это быстро усложняется. Маринованные потоки знают свой размер, и если все, что вы планируете делать, это передавать маринованные продукты туда и обратно, вы можете использовать это знание. Предполагая, что вы придерживаетесь блокировки ввода-вывода, на стороне отправки это легко, просто выберите и отправьте, но используйте s.sendall()
, чтобы убедиться, что это действительно работает. send()
может отправить меньше, чем вы просите, и вы должны проверить его возврат и продолжить отправку. sendall сделает это за вас.
Принимающая сторона более сложна. pickle.loads
требует, чтобы вы сначала загрузили байтовую строку (и как узнать, сколько она длится?), И не сообщает вам, сколько потока она потребляет. pickle.Unpickler
делает то, что вы хотите, но использует файловый объект, а не сокет. Если вы продолжаете блокировать сокеты, вы можете использовать socket.makefile()
для создания файлового объекта для сокета и использовать его с unpickler.
Вот рабочий пример
import sys
import socket
import pickle
PORT = 8722
def client():
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.connect(('localhost', PORT))
f = s.makefile(mode='wb')
pickle.dump(["list 1", 1,2,3], f)
pickle.dump(["list 2", 4, 5, 6], f)
pickle.dump(["list 3", 7, 8, 9], f)
f.close()
s.close()
def server():
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('localhost', PORT))
s.listen(1)
conn, addr = s.accept()
f = conn.makefile(mode='rb')
unpkl = pickle.Unpickler(f)
try:
while True:
obj = unpkl.load()
print(obj)
except EOFError:
print('done')
try:
if sys.argv[1] == "client":
client()
elif sys.argv[1] == "server":
server()
else:
raise IndexError()
except IndexError:
print("test.py client|server")
exit(1)
Альтернативно, вы можете реализовать какой-нибудь метод разграничения каждого буфера рассола. Возможно, небольшой заголовок, записанный через struct
, содержит размер. Затем это двухэтапный процесс: прочитайте заголовок, затем используйте этот размер для чтения данных. Вы даже можете активизировать его и использовать другой метод, например HTTP rp c или zeromq, et c ...