如何在ZMQ套接字启动/退出时清空缓冲区?(防止服务器连接死亡客户端)
我在用Python做ZMQ通信,使用的是REQ/REP类型的套接字。现在有多个客户端想要连接到一个服务器上。为了防止客户端一直等待,我在客户端的脚本里加了超时设置。
问题是,当服务器没有运行时,如果一个客户端试图连接,它的信息会被放到一个队列里。理想情况下,这个队列根本不应该存在。等到脚本开始运行后,如果有新的客户端连接,服务器会先处理之前客户端的数据。这种情况是不应该发生的。
当服务器启动时,它会认为之前有一个客户端连接过,因为这个客户端试图连接但没有成功(因为服务器当时是关着的)。
在下面的代码中,当客户端第一次尝试连接时,它会收到ERR 03: Server down
的错误提示,这个是正确的,接着会出现Error disconnecting
的错误。当服务器启动后,我会收到ERR 02: Server Busy
的错误提示,针对第一个连接的客户端。这种情况也不应该发生。现在服务器已经运行,客户端应该能够顺利连接上去。
服务器代码:
import zmq
def server_fn():
context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind("tcp://192.168.1.14:5555")
one=1
while one == 1:
message = socket.recv()
#start process if valid new connection
if message == 'hello':
socket.send(message) #ACK
#keep session alive until application ends it.
while one == 1:
message = socket.recv()
print("Received request: ", message)
#exit connection
if message == 'bye':
socket.send(message)
break
#don't allow any client to connect if already busy
if message == 'hello':
socket.send ('ERR 00')
continue
#do all data communication here
else:
socket.send('ERR 01: Connection Error')
return
server_fn()
客户端代码:
import zmq
class client:
def clientInit(self):
hello='hello'
#zmq connection
self.context = zmq.Context()
print("Connecting to hello world server...")
self.socket = self.context.socket(zmq.REQ)
self.socket.connect("tcp://192.168.1.14:5555")
#RCVTIMEO to prevent forever block
self.socket.setsockopt(zmq.RCVTIMEO, 5000)
#SNDTIME0 is needed since script may not up up yet
self.socket.setsockopt(zmq.SNDTIMEO, 5000)
try:
self.socket.send(hello)
except:
print "Sending hello failed."
try:
echo = self.socket.recv()
if hello == echo:
#connection established.
commStatus = 'SUCCESS'
elif echo == 'ERR 00':
#connection busy
commStatus = "ERR 00. Server busy."
else:
#connection failed
commStatus="ERR 02"
except:
commStatus = "ERR 03. Server down."
return commStatus
def clientQuit(self):
try:
self.socket.send('bye')
self.socket.recv()
except:
print "Error disconnecting."
cObj = client()
commStatus=cObj.clientInit()
print commStatus
cObj.clientQuit()
PS - 我觉得解决这个问题可能和正确使用socket.bind和socket.connect有关。
1 个回答
6
我来回答我自己的问题-
问题在于,第一个客户端发送的消息在服务器启动时就会被接受,不管这个客户端的状态如何。
为了防止这种情况发生,需要做两件事。最重要的是使用 socket.close() 来关闭客户端的连接。其次,可以将 LINGER 参数设置为一个较小的值或零。这样在关闭 socket 后,超时值过后就会清空缓冲区。
class client:
def clientInit(self):
...
self.socket.setsockopt(zmq.LINGER, 100)
...
def clientQuit(self):
try:
self.socket.send('bye')
self.socket.recv()
except:
print "Error disconnecting."
self.socket.close()