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
对象的副本发送到子进程。但是,您的对象包含无法序列化的套接字对象。使用 threading
和 Thread
对象代替 Process
,您就不会 运行 遇到这个问题。这是因为线程 运行 在同一个进程中。
下面是完整的工作版本。我做了一些改动:
- 按照@Dunes 的建议,我使用了线程而不是进程。
- 我将
client.py
和 server.py
合并为一个带有 "role" 参数的 app.py
。 (这只是为了避免大量重复代码。)
- 我在主线程中处理了
KeyboardException
s,因此您可以按 Ctrl+C 退出。
- 我在行中删除了“>”前缀,因为它会导致输出混乱。 (当你在其他应用程序中输入内容时,你会得到类似“> > hello”的输出。)
- 我把
server.py
里的c2
拿出来了。我不确定这样做的目的是什么,也不知道这是否会奏效。 (好像你是 connect
ing 而不是 bind
ing?)
- 我修改了 "receiver" 的拼写,因为它让我很困扰。 :-)
- 我将
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())
我正在尝试创建一个非常简单的聊天。使用 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
对象的副本发送到子进程。但是,您的对象包含无法序列化的套接字对象。使用 threading
和 Thread
对象代替 Process
,您就不会 运行 遇到这个问题。这是因为线程 运行 在同一个进程中。
下面是完整的工作版本。我做了一些改动:
- 按照@Dunes 的建议,我使用了线程而不是进程。
- 我将
client.py
和server.py
合并为一个带有 "role" 参数的app.py
。 (这只是为了避免大量重复代码。) - 我在主线程中处理了
KeyboardException
s,因此您可以按 Ctrl+C 退出。 - 我在行中删除了“>”前缀,因为它会导致输出混乱。 (当你在其他应用程序中输入内容时,你会得到类似“> > hello”的输出。)
- 我把
server.py
里的c2
拿出来了。我不确定这样做的目的是什么,也不知道这是否会奏效。 (好像你是connect
ing 而不是bind
ing?) - 我修改了 "receiver" 的拼写,因为它让我很困扰。 :-)
- 我将
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())