私は、UDPを使用して、Pythonでスレッド化された非同期ネットワーキングの実験を行っています。
ポーリングとPythonモジュールの選択について理解したいのですが、C /C++で使用したことはありません。
それらは何のためのものですか?ちょっとした選択はわかりますが、リソースを見ているとブロックされますか?ポーリングの目的は何ですか?
私は、UDPを使用して、Pythonでスレッド化された非同期ネットワーキングの実験を行っています。
ポーリングとPythonモジュールの選択について理解したいのですが、C /C++で使用したことはありません。
それらは何のためのものですか?ちょっとした選択はわかりますが、リソースを見ているとブロックされますか?ポーリングの目的は何ですか?
さて、一度に1つの質問。
単純なソケットサーバースケルトンは次のとおりです。
s_sock = socket.socket()
s_sock.bind()
s_sock.listen()
while True:
c_sock, c_addr = s_sock.accept()
process_client_sock(c_sock, c_addr)
サーバーはループしてクライアントからの接続を受け入れ、そのプロセス関数を呼び出してクライアントソケットと通信します。ここに問題があります:process_client_sock
時間がかかるか、ループが含まれている可能性があります(これはよくあることです)。
def process_client_sock(c_sock, c_addr):
while True:
receive_or_send_data(c_sock)
この場合、サーバーはそれ以上の接続を受け入れることができません。
簡単な解決策は、マルチプロセスまたはマルチスレッドを使用し、要求を処理するための新しいスレッドを作成するだけで、メインループは新しい接続をリッスンし続けます。
s_sock = socket.socket()
s_sock.bind()
s_sock.listen()
while True:
c_sock, c_addr = s_sock.accept()
thread = Thread(target=process_client_sock, args=(c_sock, c_addr))
thread.start()
これはもちろん機能しますが、パフォーマンスを考慮すると十分ではありません。新しいプロセス/スレッドは余分なCPUとメモリを必要とするため、サーバーがアイドル状態でない場合、数千の接続が発生する可能性があります。
したがってselect
、poll
システムコールはこの問題を解決しようとします。ファイル記述子のセットをselect
指定し、fdが読み取り/書き込み/または例外が発生した場合に通知するように指示します。
はい、またはいいえは、渡したパラメーターによって異なります。
select manページにあるように、struct timeval
パラメータを取得します
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
3つのケースがあります:
timeout.tv_sec==0およびtimeout.tv_usec=0
ブロッキングなし、すぐに戻る
タイムアウト==NULL
ファイル記述子の準備ができるまで、永久にブロックします。
タイムアウトは正常です
一定の時間待機します。それでも使用可能なファイル記述子がない場合は、タイムアウトして戻ります。
簡単に言えば、ポーリングはIOを待機しているときに他の作業のためにCPUを解放します。
これは、次のような単純な事実に基づいています。
それが役に立てば幸い。
read
またはの場合recv
、1つの接続のみを待機しています。複数の接続がある場合は、複数のプロセスまたはスレッドを作成する必要があり、システムリソースが無駄になります。
select
またはpoll
またはを使用epoll
すると、1つのスレッドのみで複数の接続を監視し、それらのいずれかにデータが利用可能になったときに通知を受け取り、対応する接続でread
またはを呼び出すことができます。recv
引数に応じて、無限にブロックするか、一定時間ブロックするか、まったくブロックしない場合があります。
select()は、ソケットの3つのリストを取り込んで、3つの条件(読み取り、書き込み、エラー)をチェックし、それらの条件で実際に処理する準備ができているソケットのリスト(通常は短く、多くの場合空)を返します。
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.bind((Local_IP, Port1))
s1.listen(5)
s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s2.bind((Local_IP, Port2))
s2.listen(5)
sockets_that_might_be_ready_to_read = [s1,s2]
sockets_that_might_be_ready_to_write_to = [s1,s2]
sockets_that_might_have_errors = [s1,s2]
([ready_to_read], [ready_to_write], [has_errors]) =
select.select([sockets_that_might_be_ready_to_read],
[sockets_that_might_be_ready_to_write_to],
[sockets_that_might_have_errors], timeout)
for sock in ready_to_read:
c,a = sock.accept()
data = sock.recv(128)
...
for sock in ready_to_write:
#process writes
...
for sock in has_errors:
#process errors
したがって、タイムアウト秒待機後にソケットが接続を試行しなかった場合、リストready_to_readは空になります-その時点で、accept()とrecv()がブロックされるかどうかは関係ありません-空の場合は呼び出されませんリスト....
ソケットが読み取る準備ができている場合、データが含まれているので、それもブロックされません。