TypeError:context必须指定"在zmq unpickling

时间:2016-08-20 17:09:47

标签: python multithreading sockets chat pyzmq

我正在尝试创建一个非常简单的聊天。使用PyZMQ库。由于套接字不是线程安全的,我使用两个套接字并在每个套接字上运行一个线程。一个检查传入消息,一个检查发送消息。

但我的程序正在给我,错误信息:

    Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\Python27\lib\multiprocessing\forking.py", line 381, in main
    self = load(from_parent)
  File "C:\Python27\lib\pickle.py", line 1384, in load
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\Python27\lib\multiprocessing\forking.py", line 381, in main
    self = load(from_parent)
  File "C:\Python27\lib\pickle.py", line 1384, in load
    return Unpickler(file).load()
  File "C:\Python27\lib\pickle.py", line 864, in load
    return Unpickler(file).load()
  File "C:\Python27\lib\pickle.py", line 864, in load
    dispatch[key](self)
  File "C:\Python27\lib\pickle.py", line 1089, in load_newobj
    dispatch[key](self)
  File "C:\Python27\lib\pickle.py", line 1089, in load_newobj
    obj = cls.__new__(cls, *args)
  File "zmq\backend\cython\socket.pyx", line 279, in zmq.backend.cython.socket.Socket.__cinit__ (zmq\backend\cython\socket.c:3456)
TypeError: context must be specified
    obj = cls.__new__(cls, *args)
  File "zmq\backend\cython\socket.pyx", line 279, in zmq.backend.cython.socket.Socket.__cinit__ (zmq\backend\cython\socket.c:3456)
TypeError: context must be specified

我无法弄清楚为什么我会得到它们,或者如何解决它。

这也是我的逻辑错误吗?:

  

我们启动创建套接字并将其绑定到端口的服务器。然后它监听消息/连接的套接字。然后我们创建另一个套接字并将其绑定到同一个端口。我们创建一个新线程,使我们等待在第一个套接字上收到消息然后发送到第二个套接字。   然后我们有一个连接到第一个套接字的客户端。我们为它创建一个新线程,以便它可以在另一个套接字上侦听传入的消息,因此它可以使用第一个线程通过第一个套接字发送消息。

server.py

from communication import Communication
from multiprocessing import Process
import zmq
import random
import sys
import time

if __name__ == '__main__':

    if len(sys.argv) > 1:
        port = sys.argv[1]
    else:
        port = "5556"

    c = Communication(port)
    c.bind()
    recieverP = Process(target=c.reciever)
    recieverP.start()
    print("first process")

    c2 = Communication(port)
    c2.connect()
    senderP = Process(target=c2.sender)
    senderP.start()
    print("second process")

client.py

from communication import Communication
from multiprocessing import Process
import zmq
import random
import sys
import time

if __name__ == '__main__':

    if len(sys.argv) > 1:
        port = sys.argv[1]
    else:
        port = "5556"

    c = Communication(port)
    c.connect()


    recieverP = Process(target=c.reciever, args=())
    senderP = Process(target=c.sender,args=())
    recieverP.start()
    senderP.start()

communications.py

import zmq

class Communication:
    def __init__(self, port):
        context = zmq.Context.instance()
        self.port = port
        self.socket = context.socket(zmq.PAIR)

    def connect(self):
        self.socket.connect("tcp://localhost:%s" % self.port)

    def bind(self):
        self.socket.bind("tcp://*:%s" % self.port)

    def sender(self):
        while True:
            msg = raw_input("> ")
            self.socket.send(msg)

    def reciever(self):
        while True:
            msg = self.socket.recv()
            print("> " + msg)

2 个答案:

答案 0 :(得分:1)

这些是进程而不是线程。出现此问题是因为在后台Python必须将Communication对象的副本发送到子进程。但是,您的对象包含无法序列化的套接字对象。使用threadingThread对象代替Process,您将不会遇到此问题。这是因为线程在同一进程中运行。

答案 1 :(得分:1)

以下完全正常工作的版本。我做了一些改动:

  1. 我使用线程代替进程,如@Dunes所建议。
  2. 我将client.pyserver.py合并为一个带有“角色”参数的app.py。 (这只是为了避免大量重复的代码。)
  3. 我在主线程中处理了KeyboardException,因此您可以按Ctrl + C退出。
  4. 我在行上删除了“&gt;”前缀,因为它导致输出混乱。 (当您在其他应用中输入内容时,您会得到类似“&gt;&gt; hello”的输出。)
  5. 我拿出了c2中的server.py。我不确定那是什么目的,我不知道这是否有用。 (好像你是connect而不是bind ing?)
  6. 我到处修正了“接收器”的拼写,因为它困扰着我。 : - )
  7. 我将port改为int而不是str,因为它是。{ : - )
  8. app.py:

    import argparse
    from threading import Thread
    import time
    
    from communication import Communication
    
    if __name__ == '__main__':
        parser = argparse.ArgumentParser()
        parser.add_argument("role", help="either 'client' or 'server'", choices=['client', 'server'])
        parser.add_argument("--port", "-p", type=int, help="port number", default=5556)
        args = parser.parse_args()
    
        c = Communication(args.port)
        if args.role == 'client':
            c.connect()
        else:
            c.bind()
    
        receiverP = Thread(target=c.receiver)
        senderP = Thread(target=c.sender)
        receiverP.daemon = True
        senderP.daemon = True
        try:
            receiverP.start()
            senderP.start()
            while True:
                time.sleep(100)
        except (KeyboardInterrupt, SystemExit):
            pass
    

    communication.py:

    import zmq
    
    class Communication:
        def __init__(self, port):
            self.port = port
            context = zmq.Context.instance()
            self.socket = context.socket(zmq.PAIR)
    
        def connect(self):
            self.socket.connect("tcp://localhost:%d" % self.port)
    
        def bind(self):
            self.socket.bind("tcp://*:%d" % self.port)
    
        def sender(self):
            while True:
                self.socket.send(raw_input())
    
        def receiver(self):
            while True:
                print(self.socket.recv())