2017-08-25 6 views
0

私はこの問題を1週間見てきました。 select()がエラーを投げている外部の理由から実際に閉じたソケットを返すようにするクライアントコードがありますが、私は別のpythonファイルのコードをテストしてエラーにはなりません。 Iveは何百万ものことを試みました。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が悪くなり、キーと同じソケットではないため、キューからキーエラーが発生します。 sのために書き込み可能に: sの場合: 試し: NEXT_MESSAGE = message_queue [S] .get_nowait() 除い: 印刷>> SYS私はすべてのエラーをキャッチし続けるならば、それは犯人がここで実際にERRNO 9で判明しました。 stderr、 '送信するデータがありません'、s.getpeername() output_sockets.remove(s) –

+0

選択はBADFを返しません。 –

答えて

1

ソケットが読み込み可能と書き込み可能の両方で返され、読み取りが0バイト返されたためにソケットを閉じると、コードに競合が発生します。この場合、ソケットをinput_sockets,output_socketsおよびmessage_queueから削除しますが、閉じたソケットはまだwritableにあります。したがって、selectループの同じ繰り返し内でソケットを書き込もうとします。

このレースはあなたには見えませんが、デバッグ出力が表示されないので、あなたはこのEBADFを遭遇した場所を言いませんでした。同様の問題を追跡するために、ソケットをどこで閉じるか、ソケットを処理しようとする場所について、より多くのデバッグ情報をコードに追加することをお勧めします。デバッグ出力。

+0

悪いことに、これは午前中に試してみてください。読み込み時にソケットを取り外しても、書き込み可能なamdが読み込み可能でupvoteの両方から取り除かれているのを確認してください –

+0

writable.remove(s)を追加するとこれが修正されると思います! –

+0

私の友人の素早さのために100以上もありがとう –

関連する問題