2016-03-18 13 views
1

Pythonでは、私はnon-blockingに設定したソケットにsocket.connect()を使用したいと思います。これを実行しようとすると、メソッドは常にBlockingIOErrorをスローします。エラー(後述)を無視すると、プログラムは期待通りに実行されます。接続後にソケットを非ブロッキングに設定すると、エラーは発生しません。 select.select()を使用してソケットが読み書き可能であることを確認すると、エラーが発生します。非ブロックソケットとの接続()

testserver.py

import socket 
import select 

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
sock.setblocking(0) 

host = socket.gethostname() 
port = 1234 

sock.bind((host, port)) 
sock.listen(5) 

while True: 
    select.select([sock], [], []) 
    con, addr = sock.accept() 
    message = con.recv(1024).decode('UTF-8') 
    print(message) 

testclient.py

import socket 
import select 

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
sock.setblocking(0) 

host = socket.gethostname() 
port = 1234 

try: 
    sock.connect((host, port)) 
except BlockingIOError as e: 
    print("BlockingIOError") 

msg = "--> From the client\n" 

select.select([], [sock], []) 
if sock.send(bytes(msg, 'UTF-8')) == len(msg): 
    print("sent ", repr(msg), " successfully.") 

sock.close() 

端末1

$ python testserver.py 
--> From the client 

端末2

$ python testclient.py 
BlockingIOError 
sent '--> From the client\n' successfully. 

このコードは、最初の接続にBlockingIOError()を除いて正常に動作します。エラーのドキュメントは次のようになります。Raised when an operation would block on an object (e.g. socket) set for non-blocking operation.

ノンブロッキングに設定されたソケットに正しく接続するにはどうしたらいいですか?私はconnect()non-blockingを作ることができますか?または、エラーを無視するのが適切ですか?ここ

+0

このリンクはあなたに役立つかもしれません: http://stackoverflow.com/questions/1205863/how-can-i-get-non-blocking-socket-connects – akash12300

+0

@ Akash1993ええ、以前私はその質問を見ました。それを私の簡単な例に関連付けるのは苦労しました。私はasyncioを避けたいです。それは過度のようだ。それは、ブロックするべきではないときにブロックを接続するためにエラーがスローされることを明確にしています(blockingioerrorドキュメントとともに)。問題は、 'connect()non-blocking'を作る方法があるということです。 – MikeJava

答えて

0

トリックは、あなたが再びsock.connectを呼び出す必要が選択が、その後初めて、を完了したときにということです。 connectから正常な戻り状況を受け取るまで、ソケットは接続されていません。

print("first select completed") 
sock.connect((host, port)) 

EDIT:
フォロー

はただ、これらの二行select完了の最初の呼び出しを追加します。私はsock.connectへの追加の呼び出しが必要であると述べたのは誤りでした。ただし、独自のコードパスで接続エラーを処理する場合は、元の非ブロッキング呼び出しであるconnectが成功したかどうかを確認することをお勧めします。

Cコードでこれを達成するための従来の方法は、ここで説明されていますAsync connect and disconnect with epoll (Linux)

これはgetsockoptを呼び出す必要とします。これはPythonでも行うことができますが、sock.getsockoptから返された結果はbytesオブジェクトです。そして、それが失敗を表している場合は、それを整数のerrno値に変換し、それを文字列にマップする必要があります(または例外や、問題を外部に伝えるために必要なもの)。 sock.connectを呼び出すと、もう一度errnoの値が適切な例外にマップされます。

解決策2: あなたは、単に接続が完了した後にまでsock.setblocking(0)を呼び出す延期することができます。

+1

私が投稿したコードは、それが想定していたやり方で動作し、私はこのことをより明確にするために質問を編集しました。問題は、最初の接続でスローするBlockingIOErrorであり、接続の成功ではありません。私が投稿した端末の出力を調べると、もっと明確になるでしょう。 – MikeJava

+0

解決策2は絶対に正しいです!私は実際に私の質問でそれを言及した。ソケットが非ブロッキングに設定された後に、これを行う方法があるかどうか疑問に思っています。 – MikeJava

+0

私はこれに従っていません。ノン・ブロッキング・ビヘイビアを求めた後、ブロック・ビヘイビアを得る方法はありますか? 'sock.setblocking(0)'を呼ばないと、デフォルトの動作はブロックされます。 –

関連する問題