TypeError: context must be specified" in zmq unpickling

TypeError: context must be specified" in zmq unpickling

我正在尝试创建一个非常简单的聊天。使用 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

我不知道为什么会收到它们,或者如何解决。

还有我的逻辑错了吗?:

We start the server which creates a socket and binds it to a port. Then It listens to that sockets for messages/connections. Then we create another socket and binds it to the same port. We create a new thread that makes it so that we wait for messages to be recieved on the first socket to then be sent to the second one. Then we have a client who connects to the first socket. We create a new thread for it so it can listen on the other socket for incoming messages, and thus it can use the first thread to send messages through the first socket.

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)

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

下面是完整的工作版本。我做了一些改动:

  1. 按照@Dunes 的建议,我使用了线程而不是进程。
  2. 我将 client.pyserver.py 合并为一个带有 "role" 参数的 app.py。 (这只是为了避免大量重复代码。)
  3. 我在主线程中处理了 KeyboardExceptions,因此您可以按 Ctrl+C 退出。
  4. 我在行中删除了“>”前缀,因为它会导致输出混乱。 (当你在其他应用程序中输入内容时,你会得到类似“> > hello”的输出。)
  5. 我把server.py里的c2拿出来了。我不确定这样做的目的是什么,也不知道这是否会奏效。 (好像你是 connecting 而不是 binding?)
  6. 我修改了 "receiver" 的拼写,因为它让我很困扰。 :-)
  7. 我将 port 设为 int 而不是 str,因为它确实如此。 :-)

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())