Python unpickling堆下溢

boo*_*ans 6 python debugging pickle stackunderflow

我一直在研究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]
Run Code Online (Sandbox Code Playgroud)

客户类

# this is the client.sendMessage() function
def sendMessage(self, message):
    self.s.sendall(pickle.dumps(message))
Run Code Online (Sandbox Code Playgroud)

服务器类

# 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())
Run Code Online (Sandbox Code Playgroud)

这一切都很好,除了随机的时刻,当我改变暂停播放时,我不断收到此错误:

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
Run Code Online (Sandbox Code Playgroud)

这个问题可能是什么?

Lie*_*yan 6

unpickling stack underflow 当泡菜意外结束时会发生.

在这里self.request.recv(12),您最多只接收12个字节,您的pickle对象必须长于12个字节,因此它会被切断.

我不建议直接处理TCP套接字,除非您非常非常熟悉网络,并且您需要非常高的性能.我建议使用HTTP来包装你的消息并使用HTTP库.

如果你必须直接处理TCP,你将有两个选择:

  1. 您可以同意客户端和服务器之间的终结符字符串,例如'\ 0'(null)字符; 并且您的消息将使用此终止符字符串分隔.终结符字符串绝不能出现在消息体内(或者您必须找到一种方法来转义正文中的终结符字符串); 您还需要缓冲数据包,以便在读取大小小于或大于对象时接收整个消息,并将消息拆分到终结器字符串上.请注意,您还需要处理如果快速连续发送多个小消息的情况,接收器可能会在一个消息中接收多个消息.recv().

  2. 也许更容易的是按照它发送的前四个字节的长度启动所有消息.接收器将始终从流中读取四个字节,将其解码为整数,并从流中读取多个字节,这是一个完整的消息.

或者,如果发送方和接收方都在Python中,您可以重新构建程序以使用多处理队列.

我会说使用HTTP库,因为你的传输协议可能是最简单的,因为它将处理所有这些细节,为你分块消息,以及可用于多种机器和技术.