2017-08-25 48 views
0

我一直在寻找和处理这个问题一个星期。我有客户端代码导致select()返回一个实际上从外部原因关闭的套接字,抛出一个错误9 BAD FILE DESCRIPTOR,但是我测试了不同python文件中的代码,并且无法将其报错。我曾尝试过一百万件事。继承自服务器的代码片段:Python随机关闭套接字似乎

注意:这将适用于几次迭代,然后突然中止,它在message_queue中出错,因为由于文件描述符中断而导致的关键错误即使是消息/没有消息具有密钥为那个插座提供。

#Create the socket to communicate with uWSGI applications 
server_address = ('localhost', 10001) 
server = create_server_socket(server_address) 
#Sockets which we expect to read on from select() 
input_sockets = [server] 
#Sockets which we expect to write to from select() 
output_sockets = [] 
#Message buffer dicitonary for outgoing messages 
message_queue = {} 
#Now wait for connections endlessly 
while input_sockets: 
    print >> sys.stderr, "Waiting for the next event..." 
    readable, writable, exceptional = select.select(input_sockets, output_sockets, input_sockets) 
    #Handle input_sockets 
    for s in readable: 
     #Server socket is available for reading now 
     if s is server: 
      #Create a connection and address object when incoming request is recieved 
      connection, client_addr = s.accept() 
      print >> sys.stderr, "Connection recieved from %s!" % (client_addr,) 
      #Set client connection to non blocking as well 
      connection.setblocking(0) 
      #Add this socket to input sockets as it will read for client data 
      input_sockets.append(connection) 
      #Give connection a queue for sending messages to it 
      message_queue[connection] = Queue.Queue() 
     #A client has sent data so we can handle its request 
     else: 
      #Pull data from the client 
      data = "" 
      try: 
       while True: 
        message = s.recv(1024) 
        if not message: 
         break 
        data += message 
      except Exception as e: 
       print str(e) 
      if data: 
       #Readable client socket has data 
       print >> sys.stderr, 'Recieved "%s" from %s' % (data, s.getpeername()) 
       message_queue[s].put(data) 

       #Add output channel now to send message 
       if s not in output_sockets: 
        output_sockets.append(s) 
      #There is no data to be read, socket must be closed 
      else: 
       print >> sys.stderr, 'Closing', client_addr,'after recieving no data.' 
       #Stop listening for input on the socket 
       if s in output_sockets: 
        output_sockets.remove(s) 
       input_sockets.remove(s) 
       #Close the connection 
       s.close() 
       del message_queue[s] 
    #Handle writable connections  
    for s in writable: 
     if s: 
      try: 
       next_message = message_queue[s].get_nowait() 
      except: 
       print >> sys.stderr, 'No data to send for', s.getpeername() 
       output_sockets.remove(s) 
      else: 
       try: 
        print >> sys.stderr, 'Sending "%s" to %s' % (next_message, s.getpeername()) 
        s.sendall(next_message) 
       except: 
        print >> sys.stderr, 'No data to send for', s.getpeername() 
        output_sockets.remove(s) 
       #s.sendall('EOF:[email protected]#$:EOF') 
    #Now handle any exceptions 
    for s in exceptional: 
     print >> sys.stderr, 'Handling exception on ', s.getpeername() 
     input_sockets.remove(s) 
     if s in output_sockets: 
      output_sockets.remove(s) 
     s.close() 
     #Remove any messages 
     del message_queue[s] 

客户端:

messages = [ 'This is the message. ', 
     'It will be sent ', 
     'in parts.', 
     ] 
server_address = ('localhost', 10001) 

# Create a TCP/IP socket 
socks = [ socket.socket(socket.AF_INET, socket.SOCK_STREAM), 
      socket.socket(socket.AF_INET, socket.SOCK_STREAM), 
      ] 

# Connect the socket to the port where the server is listening 
print >>sys.stderr, 'connecting to %s port %s' % server_address 
for s in socks: 
    s.connect(server_address) 
for message in messages: 

    # Send messages on both sockets 
    for s in socks: 
     print >>sys.stderr, '%s: sending "%s"' % (s.getsockname(), message) 
     s.send(message) 

    # Read responses on both sockets 
    for s in socks: 
     data = s.recv(1024) 
     print >>sys.stderr, '%s: received "%s"' % (s.getsockname(), data) 
     if not data: 
      print >>sys.stderr, 'closing socket', s.getsockname() 
      s.close() 

注:此客户端仅仅是测试,并开始传递消息。

+0

这是很多代码。究竟哪一行你会得到错误? –

+0

在服务器下可写,我从队列中得到一个关键错误,因为FD坏了,而不是用作密钥的同一个套接字。然后,如果我捕捉所有错误并继续原来罪魁祸首其实是ERRNO 9的位置:对于s的写: 如果s: 尝试: next_message = message_queue [S] .get_nowait() 除外: 打印>> SYS。标准错误, '没有要发送的数据为',s.getpeername() output_sockets.remove(S) –

+0

选择不应该返回一个BADF是否正确? –

回答

1

当套接字以可读和可写方式返回时,代码中存在争用,并且由于读返回0字节而关闭套接字。在这种情况下,你从input_socketsoutput_socketsmessage_queue卸下插槽,但关闭socket仍处于writable,因此它会尝试写它选择环路的同一迭代内。

我不知道如果是这样的比赛,你会看到,因为你既没有显示调试输出不是你说,你绊倒这个EBADF。要跟踪类似的问题下来,我建议你在哪里关闭套接字,并在那里你尝试处理一个插座,因为它是读写,让你真正找到了比赛的确切地点有更多的调试信息,以增加自己的代码在看的时候调试输出。

+0

生病试试这个早上,因为这是有道理的,生病看是否removong插座在读从两个可写可读AMD拆除和给予好评 –

+0

我认为加上一个writable.remove(S)将解决这个问题! –

+0

非常感谢你为我的朋友敏捷+100 –