ZMQError:在循环中使用套接字时已经使用的地址

时间:2017-08-22 09:49:42

标签: python sockets zeromq networkx pyzmq

我试图在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_pcli_p是在node函数中调用的服务器和客户端函数的对象,即在ser_p和{{for row in csv_dict中调用cli_pfor c_node, data in max_wg_ngs中进一步调用1}}。我也在这里使用 Networkx Python库(仅使用来自Book5.csv的连接概率值来查找客户端中的2个最近邻居)。
有谁知道我可能会出错?为什么它显示地址已经在使用,即使套接字在每次迭代时都关闭了? 非常感谢提前:)(使用Ubuntu 14.04 32位VM)

1 个答案:

答案 0 :(得分:0)

StackOverflow同意使用基于MCVE的问题:

您是否介意达到该级别并完成 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告诉你,这不是必要的 - 明确处理这些情况并保持控制是专业的,所以没有例外,没有任何借口。