Python ソケット受け入れタイムアウト

Mohd Mohtashim Nawaz 2023年6月21日
  1. ソケットの受け入れ、拒否、およびタイムアウト
  2. Python でのソケット メソッドとその使用法
  3. Python でのソケット受け入れタイムアウトの例
  4. Python でソケットごとにデフォルトのタイムアウトを設定する
  5. まとめ
Python ソケット受け入れタイムアウト

ソケットは、ネットワーク通信の基本的な構成要素です。 2つのネットワーク エンティティがデータを転送する必要がある場合は常に、ソケットが開かれます。

これらのソケットは、セッション中は接続されたままです。 しかし、Python でソケットを操作しているときに、相手側がまだソケット接続を受け入れている間、長時間待たされることがあります。

この記事では、Python のソケットの timeout 機能について説明します。これは、socket accept を無限に待つという問題を軽減するために必要です。

ソケットの受け入れ、拒否、およびタイムアウト

Python スクリプトを使用してサーバーへの接続を確立しようとするたびに、ソケット接続を開く必要があります。 このソケット接続は、クライアントとサーバーの間でデータを転送するためのトンネルとして機能します。

ソケットを開くプロセスには、3つのシナリオがあります。

  1. Socket Accept: ソケットが正常に開かれ、サーバーとクライアントがデータを送受信するために接続されると、これを socket accept と呼びます。 このシナリオは、ソケットを開く最終目標です。

  2. Socket reject: ソケットを開いたが、いくつかの異なるパラメーターを渡した、パラメーターを渡すのを忘れた、またはソケットを開くプロセスが正しく行われなかったとします。 あなたは拒否されるでしょう。 データを送受信するための接続を確立できなかったことを意味します。

  3. Socket Accept timeout: これは重要なシナリオですが、見過ごされがちです。 ソケットを開こうとしても、反対側から応答がない場合があります。

    このため、あなたは永遠に待たされます。 永遠に待つのではなく、現在のリクエストを閉じて別のリクエストを試したいので、これは望ましくない状況です。

    timeout オプションを使用すると、要求が相手に受け入れられるまでの最大待機時間を設定できます。 制限時間を超えると、エラーが発生します。

Python でのソケット メソッドとその使用法

Python には、ソケット接続を使用するためにインポートする必要がある socket という名前の組み込みライブラリがあります。 socket ライブラリの重要なメソッドをいくつか見てみましょう。

  1. accept(): 名前が示すように、accept() メソッドは、別の当事者からの受信ソケット要求を受け入れます。 このメソッドは、接続されたエンティティ間でデータを転送するために使用できるソケット接続を返します。

  2. bind(): このメソッドは、ソケット接続をアドレスにバインドまたはアタッチします。 ソケットを操作する場合は、このメソッドを呼び出す必要があります。

    bind() メソッドは、ソケットをバインドする IP アドレスとポートのタプルを受け入れます。

  3. listen(): これは、サーバーがソケットを受け入れて接続間でデータを転送できるようにするサーバー側のメソッドです。

  4. connect(): このメソッドはアドレスを引数として受け取ります。 次に、そのアドレスでリモート ソケットを接続します。

  5. settimeout(): このメソッドは、TimeoutError を発生させる前に待機する秒数としてゼロ以外の数値を受け入れます。 この方法は、無限の待機時間の問題を軽減するために重要です。

  6. setdefaulttimeout(): 複数のソケット接続を使用していて、各接続に同じタイムアウト制限を設定したい場合、これは目的に合った方法です。 引数として秒数を受け取り、それを待機タイムアウト制限としてすべての新しいソケット接続に適用します。

Python でのソケット受け入れタイムアウトの例

Python のコードを使用して、ソケット受け入れタイムアウトの例を見てみましょう。 この例では、サーバー用とクライアント用の 2つの Python スクリプトを作成する必要があります。

以下で説明するように、3つの異なるシナリオが表示されます。

  1. 最初のシナリオは、タイムアウト制限が設定されていない場合です。 この場合、クライアントは待機し続けます。

    オペレーティング システムによっては、しばらくするとリクエストが自動的に拒否される場合があります。

  2. 2 番目のシナリオでは、settimeout() メソッドを使用してタイムアウト制限を設定します。 この場合、設定された制限の後に TimeoutError が返されます。

  3. 3 番目のケースでは、setdefaulttimeout() メソッドを使用してタイムアウト制限を設定します。

上記の 3つのケースのコードを 1つずつ見てみましょう。

タイムアウト制限が設定されていない場合の Python でのソケット受け入れタイムアウト

サーバー側スクリプト:

import socket

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind(("", 1717))

クライアント側スクリプト:

import socket

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect(("127.0.0.1", 1717))

サーバー側には listen() メソッドはありません。 したがって、サーバーは応答せず、クライアントは待機しています。

タイムアウトが設定されている場合の Python でのソケット受け入れタイムアウト

この場合、タイムアウト時間が経過すると、クライアントが操作を中止し、TimeoutError を発生させることがわかります。

サーバ側:

import socket

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind(("", 1717))

クライアント側:

import socket

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.settimeout(3)
    s.connect(("127.0.0.1", 1717))

この場合、Python ソケット TimeoutError が発生します。 プラットフォームによってソケットの動作が異なる場合があることに注意してください。

Linux マシンでは、ソケットは、サーバー側でソケットを受け入れないまで、ConnectionRefusedError: [Errno 111] 接続が拒否されました エラーをスローします。

Python でソケットごとにデフォルトのタイムアウトを設定する

このメソッドは、すべての新しいソケットに対して同じデフォルト タイムアウトを設定します。 このように、各ソケットのタイムアウトを個別に設定することで、時間と手間を節約できます。

サーバ側:

import socket

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind(("", 1717))

クライアント側:

import socket

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    socket.setdefaulttimeout(3)
    s.connect(("127.0.0.1", 1717))

setdefaulttimeout() の場合、すべてのスレッドのタイムアウトを設定するため、オブジェクトの代わりにソケット クラスを直接使用する必要があることに注意してください。

まとめ

ソケット タイムアウトは、Python でのソケット プログラミングの重要な側面です。 タイムアウトを処理しないと、クライアントがソケットを永久に待機したままになる可能性があります。

または、環境の実装によっては、エラーが発生する場合があります。

関連記事 - Python Socket