Python ソケット プログラミングの完全ガイド

推奨事項: NSDT シーン エディターを使用して 3D アプリケーション シーンを迅速に構築する

 

デバイスを接続して情報を交換することが Web の本質です。ソケットは、ローカルまたはグローバル ネットワーク上のデバイス間、および同じコンピュータ上の異なるプロセス間でメッセージを転送するために使用される基本的な概念であるため、効果的なネットワーク通信に不可欠な部分です。これらは、送受信されるトラフィックをきめ細かく制御できる低レベルのインターフェイスを提供します。

この低レベルの性質により、ソケット通信上に構築されたレガシー プロトコルに存在する可能性がある特定のユースケース向けに、非常にパフォーマンスの高い通信チャネル (またはカスタム プロトコル) を作成することが可能になります。

このため、ソケットは、インスタント メッセージ交換に依存したり、大量のデータを処理したりするリアルタイムのクライアント/サーバー アプリケーションで非常に役立ちます。

この記事では、ソケット プログラミングの基本を説明し、Python を使用してソケット ベースのクライアント アプリケーションとサーバー アプリケーションを作成するためのステップバイステップ ガイドを提供します。それでは早速、本題に入りましょう!

ネットワークの基本

ネットワークはあらゆる種類の通信と情報共有をサポートします。

これは、2 つ以上のデバイスを接続して情報を交換できるようにするプロセスです。このように相互接続されたデバイスの集合体をネットワークと呼びます。

物理世界では多くのネットワークを観察できます。航空会社、送電線のネットワーク、高速道路で相互接続された都市などがその良い例です。

同様に、情報技術の世界には多くのネットワークがあります。その中で最も有名でよく知られているのは、無数のデバイスを接続するネットワークのグローバル ネットワークであるインターネットであり、おそらくこの記事を読んでいるあなたも現在使用しているネットワークです。

ネットワークタイプ

インターネットは、サイズやその他の属性が異なるさらに多くのネットワークで構成されています。たとえば、ローカル エリア ネットワーク (LAN) は通常、互いに近くにあるコンピュータをリンクします。企業やその他の機関 (銀行、大学など) のマシン、さらにはルーターに接続された家庭用デバイスも、このようなネットワークを構成します。

また、スマートフォンを Bluetooth 経由でラップトップに接続する PAN (パーソナル エリア ネットワーク)、都市全体のデバイスを相互接続する MAN (メトロポリタン エリア ネットワーク)、WAN (ワイド エリア ネットワーク) など、大小さまざまなネットワークの種類があります。 、国全体または世界全体をカバーできます。はい、最大の WAN ネットワークはインターネットそのものです。

言うまでもなく、コンピュータ ネットワークは多くの要素で構成され、非常に複雑になる可能性があります。最も基本的かつ重要なプリミティブの 1 つは通信プロトコルです。

ネットワーク通信プロトコルの種類

通信プロトコルは、情報がどのように、どのような形式で送受信されるかに関するルールを指定します。これらのプロトコルは、ネットワーク通信に関係するさまざまなタスクを管理するために階層に組み立てられます。

言い換えれば、一部のプロトコルはハードウェアがパケットを受信、送信、またはルーティングする方法を扱いますが、他のプロトコルはより高レベルであり、たとえばアプリケーションレベルの通信などに関係します。

一般的に使用され、よく知られているネットワーク通信プロトコルには次のようなものがあります。

無線ネットワーク

リンク層プロトコルの例。これは、ハードウェアに非常に近く、ワイヤレス環境で 1 つのデバイスから別のデバイスにデータを物理的に送信する役割を果たします。

IP(インターネットプロトコル)

IP は、主にパケットのルーティングと IP アドレス指定を担当するネットワーク層プロトコルです。

TCP (伝送制御プロトコル)

全二重通信を提供し、データの整合性と配信を保証する、信頼性の高い接続指向のプロトコル。これは、接続の管理、エラーの検出、情報の流れの制御に使用されるトランスポート層プロトコルです。

UDP (ユーザー データグラム プロトコル)

TCP と同じプロトコル スイートに属するプロトコル。主な違いは、UDP はよりシンプルで高速ですが信頼性の低いコネクションレス プロトコルであり、配信チェックをまったく実行せず、「ファイア アンド フォーゲット」パラダイムに従っていることです。TCP と同様に、UPD もトランスポート層にあります。

HTTP (ハイパーテキスト転送プロトコル)

アプリケーション層プロトコルであり、インターネット上のブラウザからサーバーへの通信、特に Web サイトのサービスに最も一般的に使用されるプロトコルです。言うまでもなく、今読んでいる記事も HTTP 経由で提供されます。HTTP プロトコルは TCP 上に構築され、メタデータや Cookie を送信するためのヘッダー、さまざまな HTTP メソッド (GET、POST、DELETE、UPDATE) など、Web アプリケーションに関連する情報を管理および送信します。

MQTT (メッセージ キュー テレメトリ トランスポート)

アプリケーション レベルのプロトコルの別の例は、処理能力とバッテリー寿命が限られており、信頼性の低いネットワーク条件 (採掘現場のガス センサーや家庭のスマート電球など) で動作するデバイス向けです。MQTT は、IoT (モノのインターネット) で使用される標準メッセージング プロトコルです。軽量で使いやすく、信頼性を高める再送信メカニズムを内蔵して設計されています。Python でこのプロトコルを使用することに興味がある場合は、Paho MQTTクライアントの詳細な概要を提供するこの Python MQTT ガイドを読むことができます  。

重要な観察は、上記のプロトコルはすべて内部でソケットを使用しますが、その上に独自のロジックとデータ処理を追加していることです。これは、ソケットが最新のデバイスにおけるネットワーク通信の低レベル インターフェイスであるという事実によるものであり、これについては次のセクションで説明します。

主要な概念と用語

もちろん、ネットワーク環境では他にも多くの重要な概念や用語が使用されます。このチュートリアルの残りの部分で発生する可能性のある最も顕著な問題のいくつかの概要を次に示します。

  • パケット: コンピュータ ネットワークにおけるデータ送信の標準単位 (口語的には「メッセージ」という用語と比較します)。
  • エンドポイント: パケットが到着する宛先。
  • IP アドレス: ネットワーク上のデバイスを一意に識別する数値識別子IP アドレスの例は次のとおりです: 192.168.0.0
  • ポート: デバイス上で実行されているプロセスを一意に識別し、特定のネットワーク通信を処理する数値識別子。たとえば、HTTP 経由で Web サイトにサービスを提供します。IP アドレスはデバイスを識別し、ポートはアプリケーションを識別します (各アプリケーションはプロセスであるか、プロセスで構成されます)。ポートのよく知られた例としては、HTTP トラフィックを管理するためにサーバー アプリケーションによって一般的に使用されるポート 80 と、HTTPS (Secure HTTP) に使用されるポート 443 があります。
  • ゲートウェイ: あるネットワークから別のネットワークへのアクセス ポイントとして機能する特別なネットワーク ノード (デバイス)。これらのネットワークは異なるプロトコルを使用することもあるため、ゲートウェイで何らかのプロトコル変換を実行する必要がある場合があります。ゲートウェイの例としては、ホーム ローカル ネットワークをインターネットに接続するルーターが挙げられます。

ソケットを理解する

ソケットとは何ですか?

ソケットは、同じマシンまたは異なるマシン上にある異なるプロセス間で通信するためのインターフェイス (ゲート) です。後者の場合は、Web ソケットについて説明します。

Web ソケットは接続管理を抽象化します。これらは接続ハンドラーと考えることができます。特に Unix システムでは、ソケットは同じ書き込み操作と読み取り操作をサポートする単なるファイルですが、すべてのデータをネットワーク上に送信します。

ソケットがリスニング状態または接続状態にある場合、ソケットは常に、ホスト (コンピューター/デバイス) とプロセスを識別する IP アドレスとポート番号の組み合わせにバインドされます。

ソケット接続の仕組み

ソケットは受信接続をリッスンしたり、送信接続自体を実行したりできます。接続が確立されると、リスニング ソケット (サーバー ソケット) が接続側の IP とポートにさらにバインドされます。

あるいは、新しいソケットを作成して、リスナーとリクエスターの IP アドレスとポート番号のペアにバインドします。このようにして、異なるコンピュータ上にある 2 つの接続されたソケットは相互に認識し、他の接続をリッスンし続けている間、リッスンしているソケットをブロックすることなく、データ転送用の 1 つの接続を共有できます。

接続ソケット (クライアント ソケット) の場合、接続の開始時にデバイスの IP アドレスとランダムなアクセス可能なポート番号に暗黙的にバインドされます。次に、接続が確立されたら、リッスン ソケットとほぼ同じ方法で、新しいソケットを作成せずに、他の通信側の IP とポートにバインドします。

ネットワークコンテキストにおけるソケット

このチュートリアルでは、ソケットの実装ではなく、ネットワークのコンテキストにおけるソケットの意味に焦点を当てます。

ソケットは接続エンドポイント (トラフィックの宛先) であると言えます。ソケットは、一方ではホストの IP アドレスとソケットが作成されたアプリケーションのポート番号に関連付けられ、他方ではもう 1 つは、コンピュータ上で実行されているアプリケーションの IP アドレスであり、ポートに関連付けられています。

ソケットプログラミング

ソケット プログラミングについて話すとき、ソケット オブジェクトをインスタンス化し、コード内でそれらの操作 (リッスン、接続、受信、送信など) を実行します。この場合のソケットは、ネットワーク接続とトラフィックを処理するための特別なメソッドを使用してプログラム内で作成する特別なオブジェクトにすぎません。

これらのメソッドは舞台裏でオペレーティング システム カーネル、より具体的には、ネットワーク操作を管理するカーネルの特別な部分であるネットワーク スタックを呼び出します。

ソケットとクライアントサーバー通信

ここで、ソケットはクライアントとサーバーの通信のコンテキストでよく登場することにも言及することが重要です。

考え方は単純です。ソケットは接続に関するものであり、接続ハンドラーです。Web では、データを送受信したいときは常に、(ソケットと呼ばれるインターフェイスを介して) 接続を開始します。

ここで、あなたまたは接続しようとしている相手はサーバーとして機能し、もう一方はクライアントとして機能します。サーバーがクライアントにデータを提供するとき、クライアントは積極的にサーバーに接続し、サーバーにデータを要求します。サーバーは、待機ソケットを通じて新しい接続を待機し、新しい接続を確立し、クライアントの要求を取得し、要求されたデータを応答でクライアントに通信します。

一方、クライアントは、接続先のサーバーの IP アドレスとポートを使用してソケットを作成し、接続を開始し、サーバーに要求を送信し、応答としてデータを受け取ります。クライアントとサーバーのソケット間のこのシームレスな情報交換は、あらゆる種類のネットワーク アプリケーションのバックボーンを形成します。

ネットワークプロトコルの基礎としてのソケット

ソケットがバックボーンを形成するという事実は、さまざまなプロトコルがその上に構築され、使用されることも意味します。非常に一般的なのは、簡単に説明した UDP と TCP です。これらのトランスポート プロトコルのいずれかを使用するソケットは、UDP または TCP ソケットと呼ばれます。

産業用コンピュータソケット

Web ソケット以外にも、他の種類があります。たとえば、IPC (プロセス間通信) ソケットです。IPC ソケットは同じコンピュータ上のプロセス間でデータを転送するために使用されますが、ネットワーク ソケットはネットワーク上で同じことを行うことができます。

IPC ソケットの利点は、データを送信するためのパケットの構築とルートの解析にかかるオーバーヘッドの多くを回避できることです。IPC ソケットを介した通信は、IPC の送信側と受信側のコンテキストでローカル プロセスが行われるため、一般に待ち時間が短くなります。

Unix ソケット

IPC ソケットの良い例は Unix ソケットです。Unix ソケットは、Unix のすべてのものと同様、ファイル システム上の単なるファイルです。これらは IP アドレスとポートではなく、ファイル システム上のファイル パスによって識別されます。

IPC ソケットとしての Web ソケット

サーバーと受信側の両方がローカルホスト上にある (つまり、IP アドレスが 127.0.0.1 である) 場合は、プロセス間通信に Web ソケットを使用することもできることに注意してください。

もちろん、一方では、ネットワーク スタックによるデータの処理に関連するオーバーヘッドにより追加の待ち時間が追加されますが、他方では、Web ソケットが存在し、Web ソケットが存在するため、基盤となる OS について心配する必要がなくなります。特定のオペレーティング システムまたはオペレーティング システム ファミリに固有の IPC ソケットではなく、すべてのシステムで動作します。

Pythonソケットライブラリ

Python でのソケット プログラミングの場合、公式の組み込み Python ソケット ライブラリを使用します。このライブラリは、ソケットを作成、管理、使用するための関数、定数、クラスで構成されています。このライブラリの一般的な機能には次のようなものがあります。

  • socket() : 新しいソケットを作成します。
  • bind() : ソケットを特定のアドレスとポートに関連付けます。
  • listen() : ソケット上の着信接続のリスニングを開始します。
  • accept() : クライアントからの接続を受け入れ、通信用の新しいソケットを返します。
  • connect() : リモートサーバーとの接続を確立します。
  • send() : ソケットを通じてデータを送信します。
  • recv() : ソケットからデータを受信します。
  • close() : ソケット接続を閉じます。

Python ソケットの例

Python で書かれた実践的な例でソケット プログラミングについて学びましょう。ここでの目標は、2 つのアプリケーションを接続し、相互に通信できるようにすることです。Python ソケット ライブラリを使用して、ネットワーク経由でクライアントと通信し、情報を交換するサーバー ソケット アプリケーションを作成します。

注意事項と制限事項

ただし、この例は教育目的で簡略化されており、アプリケーションは実際のネットワーク経由で通信するのではなく、ローカルで実行されることに注意してください。クライアントをサーバーに接続するためにループバック ローカルホスト アドレスを使用します。

これは、クライアントとサーバーが同じコンピューター上で実行され、クライアントは、サーバーを表す別のプロセスであっても、実行されている同じコンピューターへの接続を開始することを意味します。

別のコンピュータで実行する

あるいは、2 つの異なるデバイスにアプリを配置し、両方を同じ Wi-Fi ルーターに接続して、ローカル エリア ネットワークを形成することもできます。あるデバイス上で実行されているクライアントは、別のコンピュータ上で実行されているサーバーに接続できます。

ただし、この場合、ルーターによってデバイスに割り当てられた IP アドレスを把握し、ローカルホスト (127.0.0.1) ループバック IP アドレスの代わりにそれらを使用する必要があります (IP アドレスを確認するには、Unix のターミナル コマンドを使用します)。システムや - Windows の場合など)。アプリケーションの IP アドレスを取得したら、コード内で IP アドレスを変更しても、サンプルは引き続き機能します。ifconfigipconfig

とにかく、例から始めましょう。もちろん、最新の状態に保ちたい場合は、Python をインストールする必要があります。

Pythonでソケットサーバーを作成する

まず、クライアントとメッセージを交換するソケット サーバー (後で説明するように、TCP ソケットで動作するため、具体的には Python TCP サーバー) を作成します。用語を明確にするために、技術的にはどのサーバーもソケット サーバーですが、ソケットはネットワーク接続を開始するために常にバックグラウンドで使用されるため、この例では明らかにソケット プログラミングが使用されているため、「ソケット サーバー」という表現を使用します。

したがって、以下の手順に従ってください。

いくつかのボイラープレートを使用して Python ファイルを作成する

  • という名前のファイルを作成しますserver.py
  • Python スクリプトでモジュールをインポートします。socket

  • という名前の関数を追加します。そこにコードの大部分を追加します。関数にコードを追加するときは、適切にインデントすることを忘れないでください。run_server

ソケットオブジェクトをインスタンス化する

次に、関数を使用してソケット オブジェクトを作成します。run_serversocket.socket()

最初の引数 () は、IPv4 の IP アドレス ファミリを指定します (他のオプションには、IPv6 ファミリと Unix ソケットが含まれます)。socket.AF_INETAF_INET6AF_UNIX

2 番目のパラメータ (TCP ソケットを使用していることを示します。socket.SOCK_STREAM)

TCP の場合、オペレーティング システムは、連続したデータ送信、エラー検出と再送信、およびフロー制御を通じて信頼性の高い接続を作成します。これらすべての詳細を実装することについて考える必要はありません。

UDP ソケットを指定するオプションもあります: 。これにより、UDP のすべての機能を内部で実装するソケットが作成されます。socket.SOCK_DGRAM

さらに下位に進み、ソケットで使用される TCP/IP ネットワーク層プロトコルの上に独自のトランスポート層プロトコルを構築する場合は、2 番目のパラメーターとして value を使用できます。この場合、OS は上位レベルのプロトコル機能を処理しないため、必要に応じてすべてのヘッダー、接続確認、再送信機能を自分で実装する必要があります。他の値についてもドキュメントで読むことができますsocket.RAW_SOCKET

サーバーソケットをIPアドレスとポートにバインドする

ホスト名またはサーバー IP とポートを定義して、サーバーに到達可能な場所と受信接続をリッスンする場所を示します。この例では、サーバーはローカル コンピューターでリッスンしています。これは、(localhost とも呼ばれる) に設定された変数によって定義されます。server_ip127.0.0.1

この変数は、オペレーティング システムがサーバー アプリケーションを識別するポート番号である に設定されます (システム プロセスで使用されるポートとの競合を避けるために、ポート番号には 1023 より大きい値を使用することをお勧めします)。port8000

前に定義した IP アドレスとポートにソケットをバインドして、接続を受信できるようにソケットを準備します。

着信接続をリッスンする

この関数を使用して、サーバー ソケットにリスニング状態を設定し、受信クライアント接続を受信できるようにします。listen

この関数は、キューに入れられた未承認の接続の最大数を指定する引数を呼び出しに受け入れます。この例では、このパラメータの値を使用します。これは、1 つのクライアントだけがサーバーと対話できることを意味します。サーバーが別のクライアントを使用している間に実行されるクライアントの接続試行は拒否されます。backlog0

たとえば、より大きい値を指定すると、クライアントでメソッドを呼び出す前にキューに入れることができるクライアントの数がオペレーティング システムに通知されます。01accept

一度呼び出されると、クライアントはキューから削除され、この制限に対してカウントされなくなります。これは、コードをさらに見てみるとより明確になるかもしれませんが、このパラメーターが本質的に行うことは次のように言えます。リスニング サーバーが接続リクエストを受信すると、このクライアントをキューに追加し、リクエストを受け入れ続けます。サーバーが最初のクライアントで内部呼び出しを行う前に 2 番目のクライアントから接続要求を受信した場合、十分なスペースがある限り、2 番目のクライアントを同じキューにプッシュします。このキューのサイズは、backlog パラメーターによって制御されます。サーバーが最初のクライアントを受け入れると、そのクライアントはキューから削除され、サーバーはそのクライアントとの通信を開始します。2 番目のクライアントはキューに残り、サーバーが解放されて接続を受け入れるのを待ちます。acceptaccept

backlog パラメータが省略された場合、システムのデフォルトに設定されます (Unix では、通常、このデフォルトはファイルで確認できます)。/proc/sys/net/core/somaxconn

着信接続を受け入れる

次に、受信クライアント接続を待って受け入れます。このメソッドは、クライアントが接続するまで実行スレッドを停止します。次に、アドレスがクライアント IP アドレスとポートのタプルであるタプル ペアを返します。これは、クライアントとの接続を共有し、クライアントとの通信に使用できる新しいソケット オブジェクトです。accept(conn, address)conn

acceptリスニング ソケット (この例で呼び出されている) をクライアントのアドレスにバインドする代わりに、クライアントと通信するための新しいソケットを作成し、それを通信に使用します。これは、リスニング ソケットは他のクライアントからのさらなる接続をリッスンする必要があるためです。そうでない場合はブロックされます。 。もちろん、この場合は 1 つのクライアントのみを処理し、その間は他のすべての接続を拒否しますが、マルチスレッド サーバーの例に入ると、これはより意味のあるものになります。server

コミュニケーションループを作る

クライアントとの接続が確立されると (メソッドの呼び出し後)、通信の無限ループが開始されます。このループでは、オブジェクトのメソッドの呼び出しを実行します。このメソッドは、クライアントから指定されたバイト数 (この場合は 1024) を受け取ります。acceptrecvclient_socket

1024 バイトはペイロード サイズの一般的な規則にすぎません。これは <> のべき乗であり、おそらく他の値よりも最適化に適しているためです。この値は自由に変更できます。

クライアントから変数で受け取ったデータは生のバイナリ形式であるため、この関数を使用してバイトのシーケンスから文字列に変換します。requestdecode

次に、メッセージを受信した場合に通信ループを抜け出す if ステートメントがあります。これは、サーバーがリクエスト内の文字列を受信すると、クライアントに確認応答を送り返し、クライアントとの接続を終了することを意味します。それ以外の場合は、受信したメッセージをコンソールに出力します。私たちの場合、確認はクライアントに文字列を送信するだけです。”close””close””closed”

if ステートメントの文字列に対して使用するメソッドは、文字列を単に小文字に変換するだけであることに注意してください。このようにすると、文字列が最初に大文字で書かれたか小文字で書かれたかは関係なくなります。lowerrequestclose

応答をクライアントに送り返す

次に、クライアントに対するサーバーの通常の応答 (つまり、クライアントが接続を閉じたくない場合) を処理する必要があります。while ループの直後に、応答文字列 (この場合) をバイトに変換してクライアントに送信する次の行を追加します。このようにして、サーバーはクライアントからメッセージを受信するたびに、応答として文字列を送信します。print(f"Received: {request}")”accepted””close””accepted”

リソースを解放する

無限 while ループから抜け出すと、クライアントとの通信が完了するため、システム リソースを解放するメソッドを使用してクライアント ソケットを閉じます。同じ方法を使用してサーバー ソケットも閉じます。これにより、サーバーが効果的にシャットダウンされます。もちろん、現実の世界では、サーバーが 1 つのクライアントと通信した後にシャットダウンするのではなく、他のクライアントをリッスンし続けたい場合もありますが、心配する必要はありません。別の例については、以下で説明します。close

ここで、無限 while ループの後に次の行を追加します。

注:ファイルの最後で関数を呼び出すことを忘れないでください。次のコード行を使用するだけです。run_serverserver.py

完全なサーバーソケットコードの例

完全なソースコードは次のとおりです。server.py

インポートソケット

def run_server():
# ソケットオブジェクトを作成します

server_ip = "127.0.0.1"
port = 8000

# bind the socket to a specific address and port
server.bind((server_ip, port))
# listen for incoming connections
server.listen(0)
print(f"Listening on {server_ip}:{port}")

# accept incoming connections
client_socket, client_address = server.accept()
print(f"Accepted connection from {client_address[0]}:{client_address[1]}")

# receive data from the client
while True:
    request = client_socket.recv(1024)
    request = request.decode("utf-8") # convert bytes to string
    
    # if we receive "close" from the client, then we break
    # out of the loop and close the conneciton
    if request.lower() == "close":
        # send response to the client which acknowledges that the
        # connection should be closed and break out of the loop
        client_socket.send("closed".encode("utf-8"))
        break

    print(f"Received: {request}")

    response = "accepted".encode("utf-8") # convert string to bytes
    # convert and send accept response to the client
    client_socket.send(response)

# close connection socket with the client
client_socket.close()
print("Connection to client closed")
# close server socket
server.close()

run_server()

この基本的な例を複雑にしないために、エラー処理を省略していることに注意してください。もちろん、try-excel ブロッ​​クを追加して、句内のソケットが常に閉じられるようにする必要があります。続きを読むと、より高度な例が表示されます。finally

Python でクライアント ソケットを作成する

サーバーをセットアップしたら、次のステップは、サーバーに接続してリクエストを送信するクライアントをセットアップすることです。それでは、次の手順から始めましょう。

いくつかのボイラープレートを使用して Python ファイルを作成する

  • という名前のファイルを作成しますclient.py
  • ソケット ライブラリをインポートします。

インポートソケット

  • すべてのコードを配置する関数を定義します。run_client

def run_client():
# ここにコードが入ります

ソケットオブジェクトをインスタンス化する

次に、この関数を使用して、クライアントとサーバーの接続点として機能する TCP ソケット オブジェクトを作成します。socket.socket()

// ソケット オブジェクトを作成
client =ソケット.socket(socket.AF_INET,ソケット.SOCK_STREAM)

サーバーソケットに接続する

サーバーに接続できるように、サーバーの IP アドレスとポートを指定します。これらのアドレスとポートは、前に設定した IP アドレスとポートと一致する必要があります。server.py

server_ip = "127.0.0.1"  # replace with the server's IP address
server_port = 8000  # replace with the server's port number

クライアント ソケット オブジェクトのメソッドを使用して、サーバーとの接続を確立します。クライアント ソケットを IP アドレスまたはポートにバインドしていないことに注意してください。これはクライアントにとっては正常です。空いているポートが自動的に選択され、システムのネットワーク インターフェイス (この場合) からサーバーへの最適なルートを提供する IP アドレスが選択され、クライアントはソケットに設定されます。これらのインターフェイスにバインドされます。connectconnect127.0.0.1

# establish connection with server
client.connect((server_ip, server_port))

コミュニケーションループを作る

接続が確立されると、無限通信ループが開始され、複数のメッセージがサーバーに送信されます。Python の組み込み関数を使用してユーザーから入力を受け取り、それをバイトにエンコードし、最大 1024 バイトにトリミングします。その後、 を使用します。inputclient.send

while True:
# メッセージを入力してサーバーに送信します
msg = input("Enter message: ")
client.send(msg.encode("utf-8")[:1024])

サーバーの応答を処理する

サーバーはクライアントからメッセージを受信すると、それに応答します。次に、クライアント コードで、サーバーの応答を受信したいとします。このため、このメソッドを使用して通信ループ内で最大 1024 バイトを読み取ります。次に、バイトの応答を文字列に変換します。この場合、ループから抜け出します。これにより、後で説明するように、クライアントの接続が終了します。それ以外の場合は、サーバーの応答をコンソールに出力します。recvdecode”closed”

   # receive message from the server
    response = client.recv(1024)
    response = response.decode("utf-8")

    # if server sent us "closed" in the payload, we break out of the loop and close our socket
    if response.lower() == "closed":
        break

    print(f"Received: {response}")

リソースを解放する

最後に、while ループの後で、このメソッドを使用してクライアント ソケット接続を閉じます。これにより、リソースが適切に解放され、接続が終了します (つまり、メッセージを受信して​​ while ループから抜け出すとき)。close“closed”

// クライアントソケット(サーバーへの接続)を閉じる
client.close()
print("サーバーへの接続が閉じられました")

: また、次のように、ファイルの最後で上記で実装した関数を呼び出すことを忘れないでください。run_client

run_client()

完全なクライアント ソケット コードの例

完全なコードは次のとおりです。client.py

インポートソケット

def run_client():
# ソケットオブジェクトを作成
client =ソケット.socket(socket.AF_INET,ソケット.SOCK_STREAM)

server_ip = "127.0.0.1"  # replace with the server's IP address
server_port = 8000  # replace with the server's port number
# establish connection with server
client.connect((server_ip, server_port))

while True:
    # input message and send it to the server
    msg = input("Enter message: ")
    client.send(msg.encode("utf-8")[:1024])

    # receive message from the server
    response = client.recv(1024)
    response = response.decode("utf-8")

    # if server sent us "closed" in the payload, we break out of the loop and close our socket
    if response.lower() == "closed":
        break

    print(f"Received: {response}")

# close client socket (connection to the server)
client.close()
print("Connection to server closed")

run_client()

クライアントとサーバーをテストする

上で書いたサーバーとクライアントの実装をテストするには、次のようにします。

  • 2 つのターミナル ウィンドウを同時に開きます。
  • ターミナル ウィンドウで、ファイルが存在するディレクトリに移動し、次のコマンドを実行してサーバーを起動します。server.py

python server.py

これにより、サーバー ソケットがポート 127 上のローカルホスト アドレス (0.0.1.8000) にバインドされ、受信接続の待機が開始されます。

  • 別のターミナルで、ファイルが存在するディレクトリに移動し、次のコマンドを実行してクライアントを起動します。client.py

python client.py

これにより、ユーザーに入力を求めるプロンプトが表示されます。次に、メッセージを入力して Enter キーを押します。これにより、入力がサーバーに送信され、そのターミナル ウィンドウに表示されます。サーバーはクライアントに応答を送信し、クライアントは再度入力を求めます。これは、文字列をサーバーに送信するまで続きます。”close”

複数のクライアントの使用 - マルチスレッド

前の例では、サーバーが単一のクライアントからのリクエストにどのように応答するかを見てきましたが、実際の多くの状況では、多くのクライアントが同時に単一のサーバーに接続する必要がある場合があります。ここでマルチスレッドが登場します。マルチスレッドは、複数の関数の実行など、複数のタスクを同時に (同時に) 処理する必要がある場合に使用されます。

このアイデアは、プロセッサによって処理できる独立した命令のセットであるスレッドを生成することです。スレッドは実際にはプロセス自体内に存在し、多くのリソースを自分自身に割り当てる必要がないため、プロセスよりもはるかに軽量です。

Python でのマルチスレッドの制限

Python のマルチスレッドには制限があることに注意してください。標準の Python 実装 (CPython) では、実際にはスレッドを並列実行できません。グローバル インタープリター ロック (GIL) により、一度に実行できるスレッドは 1 つだけです。ただし、これは別のトピックなので説明しません。この例では、限られた CPython スレッドを使用し、これを理解するだけで十分です。ただし、実際のシナリオでは、Python を使用する場合は、非同期プログラミングを検討する必要があります。これについてはまた別のトピックになるため、今は説明しません。通常、この記事で特に関心のある低レベルのソケット操作の一部が抽象化されています。

マルチスレッドサーバーの例

以下の例を見て、サーバーにマルチスレッドを追加して多数のクライアントを処理する方法を見てみましょう。今回は、try-excel-finally ブロックを使用した基本的なエラー処理も追加することに注意してください。開始するには、次の手順に従います。

スレッド生成サーバー関数を作成する

Python ファイルで、 および モジュールをインポートして、ソケットとスレッドの両方を使用できるようにします。

上の例のように、サーバー ソケットを作成し、バインドして受信接続をリッスンする関数を定義します。次に、無限の while ループが呼び出されます。これにより、常に新しい接続がリッスンされます。受信接続を取得して戻った後、コンストラクターを使用してスレッドを作成します。このスレッドは、後で定義する関数を実行し、それをパラメータ (接続されたクライアントの IP アドレスとポートを含むタプル) として渡します。スレッドを作成したら、それを呼び出して実行を開始します。run_serveracceptacceptthreading.Threadhandle_clientclient_socketaddraddrstart

呼び出しがブロックされていることに注意してください。そのため、while ループの最初の反復では、行に到達すると停止し、他には何もせずにクライアントが接続するのを待ちます。クライアントが接続すると、メソッドは戻り、実行を継続します。そのクライアントを処理するスレッドを生成し、次の反復に進み、別のクライアントの接続を待つ呼び出しで再び停止します。acceptacceptacceptaccept

関数の最後には、予期せぬ事態が発生した場合に備えてサーバーソケットが常に閉じられるようにするためのエラー処理が含まれています。

def run_server():
server_ip = "127.0.0.1" # サーバーのホスト名または IP アドレス
port = 8000 # サーバーのポート番号
# ソケット オブジェクトを作成
try:
server =ソケット.socket(socket.AF_INET,ソケット.SOCK_STREAM)
# ソケットをバインドしますホストとポートに
接続
ます

    while True:
        # accept a client connection
        client_socket, addr = server.accept()
        print(f"Accepted connection from {addr[0]}:{addr[1]}")
        # start a new thread to handle the client
        thread = threading.Thread(target=handle_client, args=(client_socket, addr,))
        thread.start()
except Exception as e:
    print(f"Error: {e}")
finally:
    server.close()

この例のサーバーは、予期しないエラーが発生した場合にのみ停止することに注意してください。それ以外の場合、クライアントは無制限にリッスンすることになるため、停止したい場合はターミナルを強制終了する必要があります。

別のスレッドで実行するクライアント ハンドラー関数を作成する

さて、関数の上に、 という別の関数を定義します。この関数は、クライアント接続ごとに個別のスレッドで実行される関数になります。クライアントのソケット オブジェクトとタプルを引数として受け取ります。run_serverhandle_clientaddr

この関数では、シングルスレッドの例と同じことといくつかのエラー処理を実行します。つまり、 を使用するループを開始します。recv

次に、シャットダウン メッセージを受信したかどうかを確認します。その場合、文字列で応答し、ループを中断して接続を閉じます。それ以外の場合は、クライアントのリクエスト文字列をコンソールに出力し、次のループ反復に進んで次のクライアントのメッセージを受信します。”closed”

この関数の最後には、予期せぬ状況に対するいくつかのエラー処理 (句) と使用法があります。何があっても、この句は常に実行され、クライアント ソケットが常に適切に解放されることが保証されます。

def handle_client(client_socket, addr):
try:
while True:
# クライアントメッセージを受信して​​出力します
request = client_socket.recv(1024).decode("utf-8")
if request. lower() == "close":
client_socket. send("closed".encode("utf-8"))
Break
print(f"Received: {request}")
# accept 応答を変換してクライアントに送信します
response = "accepted"
client_socket.send(response.encode(") utf-8"))
e としての例外を除く:
print(f"クライアント処理時のエラー: {e}")
最後に:
client_socket.close()
print(f"クライアントへの接続 ({addr[0]}:{addr[ 1]}) 閉店しました")

復帰すると、それを実行していたスレッドも自動的に解放されます。handle_client

: ファイルの最後にある関数を呼び出すことを忘れないでください。run_server

完全なマルチスレッド サーバー コードの例

次に、完全なマルチスレッド サーバー コードをまとめてみましょう。

インポートソケット
インポートスレッド

def handle_client(client_socket, addr):
try:
while True:
# クライアントメッセージを受信して​​出力します
request = client_socket.recv(1024).decode("utf-8")
if request. lower() == "close":
client_socket. send("closed".encode("utf-8"))
Break
print(f"Received: {request}")
# accept 応答を変換してクライアントに送信します
response = "accepted"
client_socket.send(response.encode(") utf-8"))
e としての例外を除く:
print(f"クライアント処理時のエラー: {e}")
最後に:
client_socket.close()
print(f"クライアントへの接続 ({addr[0]}:{addr[ 1]}) 閉店しました")

def run_server():
server_ip = "127.0.0.1" # サーバーのホスト名または IP アドレス
port = 8000 # サーバーのポート番号
# ソケット オブジェクトを作成
try:
server =ソケット.socket(socket.AF_INET,ソケット.SOCK_STREAM)
# ソケットをバインドしますホストとポートに
接続
ます

    while True:
        # accept a client connection
        client_socket, addr = server.accept()
        print(f"Accepted connection from {addr[0]}:{addr[1]}")
        # start a new thread to handle the client
        thread = threading.Thread(target=handle_client, args=(client_socket, addr,))
        thread.start()
except Exception as e:
    print(f"Error: {e}")
finally:
    server.close()

run_server()

: 実際のコードでは、マルチスレッド サーバーを扱うときに競合状態やデータの不整合などの起こり得る問題を防ぐために、スレッド セーフと同期技術を考慮する必要があります。ただし、この単純な例では、これは問題ではありません。

基本的なエラー処理を含むクライアントの例

複数のクライアントを同時に処理できるサーバー実装ができたので、上記の最初の基本的な例で示したものと同じクライアント実装を使用して接続を開始することも、それを少し更新してエラー処理を追加することもできます。以下にコードを示します。これは前のクライアントの例と同じですが、try-Except ブロックが追加されています。

インポートソケット

def run_client():
# ソケットオブジェクトを作成
client =ソケット.socket(socket.AF_INET,ソケット.SOCK_STREAM)

server_ip = "127.0.0.1"  # replace with the server's IP address
server_port = 8000  # replace with the server's port number
# establish connection with server
client.connect((server_ip, server_port))

try:
    while True:
        # get input message from user and send it to the server
        msg = input("Enter message: ")
        client.send(msg.encode("utf-8")[:1024])

        # receive message from the server
        response = client.recv(1024)
        response = response.decode("utf-8")

        # if server sent us "closed" in the payload, we break out of
        # the loop and close our socket
        if response.lower() == "closed":
            break

        print(f"Received: {response}")
except Exception as e:
    print(f"Error: {e}")
finally:
    # close client socket (connection to the server)
    client.close()
    print("Connection to server closed")

run_client()

マルチスレッドの例をテストする

マルチクライアント実装をテストしている場合は、クライアント用に複数のターミナル ウィンドウを開き、サーバー用に 1 つのターミナル ウィンドウを開きます。まず でサーバーを起動します。その後、サーバーターミナルウィンドウで . を使用すると、新しいクライアントがサーバーにどのように接続するかが表示されます。これで、対応する端末にテキストを入力することで、さまざまなクライアントからメッセージの送信を続けることができ、これらのメッセージはすべて処理されて、サーバー側のコンソールに出力されます。python server.pypython client.py

データサイエンスにおけるソケットプログラミング

すべてのネットワーク アプリケーションは、オペレーティング システムによってバックグラウンドで作成されたソケットを使用しますが、特殊な使用例やパフォーマンスのために、ソケット プログラミングに大きく依存するシステムも数多くあります。しかし、データ サイエンスの文脈において、ソケット プログラミングは具体的にどのような役に立つのでしょうか? 確かに、大量のデータを迅速に送受信する必要がある場合には、重要な役割を果たします。したがって、ソケット プログラミングは主にデータ収集とリアルタイム処理、分散コンピューティング、プロセス間通信に使用されます。しかし、データ サイエンスの分野におけるいくつかの特定のアプリケーションを詳しく見てみましょう。

リアルタイムのデータ収集

ソケットは、さらなる処理、データベースや分析パイプラインへの転送などのために、さまざまなソースからリアルタイム データを収集するために広く使用されています。たとえば、ソケットを使用すると、金融システムやソーシャル メディア API からデータを即座に受信し、その後データ サイエンティストが処理することができます。

分散コンピューティング

データ サイエンティストはソケット接続を使用して、大規模なデータセットの処理と計算を複数のマシンに分散できます。ソケット プログラミングは、Apache Spark やその他の分散コンピューティング フレームワークでノード間の通信によく使用されます。

モデルの展開

機械学習モデルをユーザーに提供する場合、ソケット プログラミングを使用して、その場で予測と推奨事項を提供できます。リアルタイムの意思決定を促進するために、データ サイエンティストは、大量のデータを受信し、トレーニングされたモデルで処理して予測を提供し、結果をクライアントに迅速に返す高性能のソケット ベースのサーバー アプリケーションを使用できます。

プロセス間通信 (IPC)

ソケットは IPC に使用でき、これにより、同じマシン上で実行されている異なるプロセスが相互に通信し、データを交換できるようになります。これは、データ サイエンスにおいて、複雑でリソースを大量に消費する計算を複数のプロセスに分散するのに役立ちます。実際、Python のサブ処理ライブラリは、この目的によく使用されます。これは、複数のプロセスを生成して、複数のプロセッサ コアを活用し、重い計算を実行する際のアプリケーションのパフォーマンスを向上させます。このようなプロセス間の通信は、IPC ソケットを通じて実現できます。

コラボレーションとコミュニケーション

ソケット プログラミングにより、データ サイエンティスト間のリアルタイムの通信とコラボレーションが可能になります。効果的なコラボレーションと知識の共有を促進するために、ソケットベースのチャット アプリケーションまたは共同データ分析プラットフォームが使用されます。

上記のアプリケーションの多くでは、データ サイエンティストがソケットの使用に直接関与していない可能性があることに注意してください。彼らは通常、ソケット プログラミングの低レベルの詳細をすべて抽象化したライブラリ、フレームワーク、システムを使用します。ただし、舞台裏では、これらのソリューションはすべてソケット通信に基づいており、ソケット プログラミングを利用しています。

ソケットプログラミングの課題とベストプラクティス

ソケットは接続を管理するための低レベルの概念であるため、ソケットを使用する開発者は、堅牢で信頼性の高いアプリケーションを作成するために必要なインフラストラクチャをすべて実装する必要があります。もちろん、これには多くの課題が伴います。ただし、これらの問題を克服するために従うことができるベスト プラクティスと一般的なガイドラインがいくつかあります。ここでは、ソケット プログラミングで最もよく発生する問題と、一般的なヒントをいくつか示します。

接続管理

複数の接続を同時に処理し、複数のクライアントを管理し、同時リクエストを効率的に処理することは確かに困難であり、簡単ではありません。ボトルネックを回避するには、慎重なリソース管理と調整が必要です

ベストプラクティス

  • リストやディクショナリなどのデータ構造を使用して、アクティブな接続を追跡します。または、スケーラビリティにも役立つ接続プーリングなどの高度な技術を使用します。
  • スレッドまたは非同期プログラミング手法を使用して、複数のクライアント接続を同時に処理します。
  • 接続を適切に閉じてリソースを解放し、メモリ リークを回避します。

エラー処理

接続障害、タイムアウト、データ転送の問題などのエラーを処理することは重要です。これらのエラーを処理し、クライアントに適切なフィードバックを提供することは、特に低レベルのソケット プログラミングを行う場合には困難になることがあります。

ベストプラクティス

  • try-excel-finally ブロックを使用して、特定の種類のエラーを捕捉して処理します。
  • 有益なエラー メッセージを提供し、トラブルシューティングに役立つようにログを記録することを検討してください。

スケーラビリティとパフォーマンス

大容量のデータ ストリームやリアルタイム アプリケーションを扱う場合、最適なパフォーマンスを確保し、遅延を最小限に抑えることが重要な問題となります。

ベストプラクティス

  • コードを最適化して、不必要なデータ処理とネットワークのオーバーヘッドを最小限に抑えてパフォーマンスを向上させます。
  • バッファリング技術を実装して、大規模なデータ転送を効率的に処理します。
  • 負荷分散技術を使用してクライアント要求を複数のサーバー インスタンスに分散することを検討してください。

セキュリティと認証

ソケットベースの通信を保護し、適切な認証メカニズムを実装することは難しい場合があります。データのプライバシーを確​​保し、不正アクセスを防止し、悪意のある活動を防止するには、セキュリティ プロトコルを慎重に検討し実装する必要があります。

ベストプラクティス

  • SSL/TLS セキュリティ プロトコルを利用して、情報を暗号化することでデータ送信のセキュリティを確保します。
  • トークンベースの認証、公開キー暗号化、ユーザー名/パスワードなどの安全な認証方法を実装して、クライアントの ID を確保します。
  • 機密データ (パスワードや API キーなど) が保護および暗号化されていることを確認するか、理想的にはまったく保存しないようにしてください (必要に応じてハッシュのみ)。

ネットワークの信頼性と回復力

ネットワークの停止、帯域幅の変動、および信頼性の低い接続に対処することは、課題となる可能性があります。安定した接続を維持し、切断を適切に処理し、再接続メカニズムを実装することは、堅牢なネットワーク アプリケーションにとって重要です。

ベストプラクティス

  • キープアライブ メッセージを使用して、非アクティブな接続または切断された接続を検出します。
  • タイムアウトを実装して、無期限のブロックを回避し、タイムリーな応答処理を確保します。
  • 接続が失われた場合に接続を再確立するために、指数バックオフ再接続ロジックを実装します。

コードの保守性

最後に重要なことは、コードの保守性です。ソケット プログラミングは低レベルであるため、開発者はさらに多くのコードを作成することになります。これはすぐに保守不可能なスパゲッティ コードに変わる可能性があるため、早期に整理して構築し、コードのアーキテクチャの計画に余分な労力を費やすことが重要です。

ベストプラクティス

  • コードをクラスまたは関数に分割します。理想的には長すぎないようにします。
  • クライアントとサーバーの実装をモックして単体テストを早期に作成する
  • ソケットプログラミングが絶対に必要でない限り、接続を処理するために高レベルのライブラリを使用することを検討してください。

概要: Python でのソケット プログラミング

ソケットは、すべてのネットワーク アプリケーションに不可欠な部分です。この記事では、Python でのソケット プログラミングについて説明しました。覚えておくべき重要なポイントは次のとおりです。

  • ソケットは接続管理を抽象化するインターフェイスです。
  • ソケットにより、異なるプロセス (通常はクライアントとサーバー) 間、またはネットワーク上での通信が可能になります。
  • Python では、ソケットの操作は、 、 、 、 などのソケット オブジェクトのさまざまなメソッドを提供するライブラリを通じて行われます。socketrecvsendlistenclose
  • ソケット プログラミングには、データ収集、プロセス間通信、分散コンピューティングなど、データ サイエンスにおけるさまざまな有用な用途があります。
  • ソケット プログラミングの課題には、接続管理、データの整合性、スケーラビリティ、エラー処理、セキュリティ、コードの保守性などが含まれます。

ソケット プログラミングのスキルがあれば、開発者は効率的なリアルタイム ネットワーク アプリケーションを作成できます。概念とベスト プラクティスを習得することで、ソケット プログラミングの可能性を最大限に活用して、信頼性が高くスケーラブルなソリューションを開発できます。

ただし、ソケット プログラミングは非常に低レベルの技術であり、アプリケーション エンジニアはアプリケーション通信のあらゆる詳細を考慮する必要があるため、使用するのが困難です。

最近では、アプリケーションのパフォーマンスを実際に絞り出したり拡張したりする必要がない限り、ソケットは通常、高レベルのライブラリやフレームワークによって処理されるため、ソケットを直接使用する必要はありません。

ただし、ソケットを理解し、ソケットが内部でどのように機能するかについて洞察を得ることで、開発者やデータ サイエンティストの全体的な認識を向上させることができ、常に良いアイデアとなります。

元のリンク: Python ソケット プログラミングの完全ガイド (mvrlink.com)

おすすめ

転載: blog.csdn.net/ygtu2018/article/details/132713550