Python取消勾选堆栈下溢

Python取消勾选堆栈下溢,python,debugging,pickle,stackunderflow,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

我一直在开发一个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())
客户端类

# 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())
服务器类

# 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

这个问题可能是什么?

当pickle意外结束时,可能会发生取消pickle堆栈下溢

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

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

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

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

  • 也许更简单的方法是按照消息发送的前四个字节的长度开始所有消息。接收器总是从流中读取四个字节开始,将其解码为整数,然后从流中读取那么多字节,这是一条完整的消息

  • 或者,如果发送方和接收方都使用Python,则可以重新构造程序以使用多处理队列


    我想说,使用HTTP库作为传输协议可能是最简单的,因为它可以处理所有这些细节,为您分块消息,并且可以跨多台机器和技术使用。

    看起来您遇到了一个糟糕的难题。为什么要使用recv(12).strip()
    ?我也使用了pickle,但没有
    strip()
    ,但没有区别。我用
    send(1024)
    recv(1024)
    发送数据,但是发送了错误的数据,因为读取了1024字节而不是一行。也许我应该把它改成
    readline
    或者别的什么?整数就是最大值吗?还是需要精确?因为一开始我用send(1024)和recv(1024)发送数据,但发送的数据错误,因为读取的是1024字节而不是一行。@Barto:传递给read()的整数是read()返回的最大字节数,read()返回的字节数可能比请求的少,但永远不会多。感谢您的解释。一有机会,我就去试试!您还应该知道,使用TCP套接字,来自单个
    send()
    的数据可以跨多个
    recv()
    调用显示。100字节的
    send()
    可能出现在前25个字节的
    recv()
    中,然后是剩余75个字节的
    recv()
    (或者,可以想象,100个
    recv()
    每个字节!)。如果必须使用TCP,那么长度前缀肯定是一种方法。