我试图在Python中使用 Zero MQ “模拟在分布式环境中的6个节点之间传递消息”,特别是使用 REQ 的经典客户端/服务器架构和 REP 。我的想法是,在这些节点之间使用 TCP / IP 连接时,在第一次迭代中,node-1必须是服务器而客户端是其他节点。在下一个节点中,node-2将是服务器,其余的(包括node-1)应该是客户端,依此类推。在每次迭代时,服务器都会告知它已经建立了自己,并且客户端向发送确认的服务器发送请求。一旦收到 ACK ,客户端就会将“消息”发送到服务器(当然这被视为输出),然后我们将进入下一次迭代。 />
现在的问题是我面临众所周知的ZMQError: Address already in use
我不确定它是否是由于套接字绑定造成的。我在客户端和服务器功能中添加了socket.close()
和context.term()
,但是徒劳无功
当我以某种方式尝试运行代码时,VM进入死锁状态,除非我执行硬重启,否则我无法恢复。这是我的代码片段 -
@staticmethod
def server(node_id):
context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind("tcp://*:%s" % port_s)
print "Running server node %s on port: %s and value of server = __temp__" % (node_id, port_s)
message = socket.recv()
print "Received request : %s from c_node %s and value (temp): __value__" % (message, c_node)
socket.send("Acknowledged - from %s" % port_s)
time.sleep(1)
socket.close()
context.term()
@staticmethod
def client(c_node):
context = zmq.Context()
# print "Server node __num__ with port %s" % port_s
socket = context.socket(zmq.REQ)
#for port in ports:
socket.connect ("tcp://localhost:%s" % port_c)
#for request in range(20):
print "c_node %s Sending request to server node __num__" % c_node
socket.send ("Hello")
message = socket.recv()
print "Received ack from server %s and message %s" % (node_id, message)
time.sleep (1)
socket.close()
context.term()
def node(self, node_id):
#global node_id
# global key
# ser_p = Process(target=self.server, args=(node_id,))
print 'Memory content of node %d\n' % node_id
for key in nodes_memory[node_id]:
print 'Neighbor={%s}, Temp={%s}\n' % (key, nodes_memory[node_id][key])
#return key
global c_node
#key1 = key
# cli_p = Process(target=self.client, args=(c_node,))
with open("Book5.csv","r+b") as input:
has_header = csv.Sniffer().has_header(input.read(1024))
input.seek(0) # rewind
incsv = csv.reader(input)
if has_header:
next(incsv) # skip header
csv_dict = csv.DictReader(input, skipinitialspace=True, delimiter=",")
node_id = 0
for row in csv_dict:
for i in row:
#print(row[i])
if type(row[i]) is str:
g.add_edge(node_id, int(i), conn_prob=(float(row[i])))
max_wg_ngs = sorted(g[node_id].items(), key=lambda e: e[1]["conn_prob"], reverse=True)[:2]
#maxim = max_wg_ngs.values.tolist()
#sarr = [str(a) for a in max_wg_ngs]
print "\nNeighbours of Node %d are:" % node_id
#print(max_wg_ngs)
ser_p = multiprocessing.Process(target=self.server, args=(node_id,))
ser_p.start()
for c_node, data in max_wg_ngs:
for key in nodes_memory[node_id]: #print ''.join(str(item))[1:-1]
#if type(key1) == node_id:
cli_p = multiprocessing.Process(target=self.client, args=(c_node,))
cli_p.start()
print('Node {a} with Connection Rate = {w}'.format(a=c_node, w=data['conn_prob']))
print('Temperature of Node {a} = {b}'.format(a=c_node, b=nodes_memory[node_id][key]))
node_id += 1
pos=nx.spring_layout(g, scale=100.)
nx.draw_networkx_nodes(g, pos)
nx.draw_networkx_edges(g,pos)
nx.draw_networkx_labels(g,pos)
#plt.axis('off')
#plt.show()
“消息”是“温度”(文件未在代码段中显示,但目前不需要),供参考Book5.csv
的值为 -
0,1,2,3,4,5
0,0.257905291,0.775104118,0.239086843,0.002313744,0.416936603
0.346100279,0,0.438892758,0.598885794,0.002263231,0.406685237
0.753358102,0.222349243,0,0.407830809,0.001714776,0.507573592
0.185342928,0.571302688,0.51784403,0,0.003231018,0.295197533
0,0,0,0,0,0
0.478164621,0.418192795,0.646810223,0.410746629,0.002414973,0
ser_p
和cli_p
是在node
函数中调用的服务器和客户端函数的对象,即在ser_p
和{{for row in csv_dict
中调用cli_p
在for c_node, data in max_wg_ngs
中进一步调用1}}。我也在这里使用 Networkx Python库(仅使用来自Book5.csv
的连接概率值来查找客户端中的2个最近邻居)。
有谁知道我可能会出错?为什么它显示地址已经在使用,即使套接字在每次迭代时都关闭了?
非常感谢提前:)(使用Ubuntu 14.04 32位VM)
答案 0 :(得分:0)
您是否介意达到该级别并完成 MCVE缺失的部分 - 既不是 port_c
,也不是 port_s
在词汇上是正确的(从未定义,在其他地方)。
如果此处提供的代码适用于文件,请始终准备好此文件的最低版本,以确保MCVE代码能够像您期望的那样使用该文件。语句如:" 文件未显示在代码段中,但目前不需要"与StackOverflow MCVE规则不兼容。
如果多个进程尝试通过 .bind()
将 port_s
放到同一个端口#set上,他们只会(并且必须)发生冲突ZMQError: Address already in use
属于例外。首先重新启动O / S,然后预先扫描已使用的IP:port#
- s,然后设置非冲突的服务器端.bind()
(可能仍有挂起的.context()
非-terminated .socket()
实例(通常来自手动原型设计或来自未处理的例外),保留IP:port#
而不释放它。因此,重启+端口扫描是先行者。
使用任何确定性的,主要是非冲突的服务器-2 <transport-class://address:port>
映射(.bind()
- 使用通配符,锁定所有IP地址,有点危险习惯)&amp;你的代码将顺利运作。
始终使用 <socket>.setsockopt( zmq.LINGER, 0 )
以防止无限死锁。
始终使用try: {...} except: {...} finally: {...}
正式表达式,以避免任何未处理的异常孤立于您控件之外的任何.context()
实例,也许没有优雅的.term() - ination和release(即使是新的API告诉你,这不是必要的 - 明确处理这些情况并保持控制是专业的,所以没有例外,没有任何借口。