Python unpickling stack underflow

Я работал над приложением python, где клиент отправляет тактовый сигнал на сервер, а сервер отвечает звуковым сигналом.
У меня есть две кнопки: одна для запуска часов и одна для приостановки трека.

Основной Класс

# function I call when I hit the play button
def play(self):
    start_song = [250]
    global IS_FIRST_PLAY
    if IS_FIRST_PLAY:
        IS_FIRST_PLAY = False
        self.startClock()
    if IS_CONNECTED:
        client.sendMessage(start_song)

# here I start the clock and send a constant clock signal to the client
def startClock(self):
    clock = midi.startClock()
    for i in clock:
        if IS_CONNECTED:
            client.sendMessage(i)
    midi.playing = True

# here I pause the track
def pause(self):
    stop_song = [252]
    if IS_CONNECTED:
        client.sendMessage(stop_song)
    midi.sendMidiMessage(stop_song)
    midi.playing = False
    midi.mtClock = [0, 0, 0, 0]

клиентский класс

# this is the client.sendMessage() function
def sendMessage(self, message):
    self.s.sendall(pickle.dumps(message))

сервер класс

# this is the class that handles the incoming clock signal for the server
class MyTCPHandler(socketserver.BaseRequestHandler):

    def handle(self):
        global IS_FIRST_PLAY, IS_PLAYING      
        thread1 = threading.Thread(target=self.sendAudio)
        thread1.start()
        while True:
            # here throws python an error
            self.data = pickle.loads(self.request.recv(12).strip())

все работает нормально, за исключением случайного момента, когда я изменить паузу играть, я продолжаю получать эту ошибку:

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/socketserver.py", line 306, in _handle_request_noblock
    self.process_request(request, client_address)
  File "/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/socketserver.py", line 332, in process_request
    self.finish_request(request, client_address)
  File "/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/socketserver.py", line 345, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/socketserver.py", line 666, in __init__
    self.handle()
  File "/Users/cedricgeerinckx/Dropbox/Redux/OSX/Server.py", line 85, in handle
    self.data = pickle.loads(self.request.recv(12).strip())
_pickle.UnpicklingError: unpickling stack underflow

что это может быть за проблема?

1 ответов


unpickling stack underflow может произойти, когда рассол заканчивается неожиданно.

здесь self.request.recv(12), вы получаете только 12 байтов max, ваш маринованный объект должен быть длиннее 12 байтов, и поэтому он отрезается.

Я бы не рекомендовал обрабатывать сокеты TCP напрямую, если вы не очень хорошо знакомы с сетью, и вам нужна очень высокая производительность. Я бы предложил использовать HTTP для упаковки ваших сообщений и использовать библиотеку HTTP.

Если вам нужно иметь дело с TCP напрямую, хотя, у вас будет два варианта:

  1. вы можете договориться о строке Терминатора между вашим клиентом и сервером, скажем, символ "\0 " (null); и ваши сообщения будут разделены этой строкой Терминатора. Строка Терминатора никогда не должна возникать внутри тела сообщения (или вам придется найти способ избежать строки Терминатора в теле); вам также нужно будет буферизировать пакеты, чтобы вы могли получить все сообщение, если ваш размер чтения меньше или больше чем ваши объекты и разделить сообщения на строку Терминатора. Обратите внимание, что вам также нужно справиться с ситуацией, когда если несколько небольших сообщений отправляются в быстрой последовательности, получатель может получить несколько сообщений в одном .recv().

  2. возможно, проще запустить все сообщения по его длине в качестве первых четырех байтов, которые он отправляет. Приемник всегда будет начинать с чтения четырех байтов из потока, декодировать это в целое число и читать, что много байтов из поток, это одно полное сообщение.

кроме того, вы можете повторно выбрать программу для использования многопроцессорной очереди, если отправитель и получатель находятся в Python.

Я бы сказал, что использование библиотеки HTTP в качестве вашего транспортного протокола, вероятно, будет проще, поскольку он будет обрабатывать все эти данные для фрагментации сообщений для вас, а также использоваться на нескольких машинах и технологиях.