7.1 ソケットって何?
もっと深く掘り下げよう。最初はrequest
を使うことを学びましたよね、次にhttp.client
を使って、そしてプロキシを考えた。次はどうする?次はこれらすべてのライブラリのフードの下にのぞいてみるぞ…
ソケットはネットワーク内のポイントで、データが送信されたり受信されたりする。ソケットを、同じまたは別のマシンで動作する2つのプログラム間の双方向通信チャネルの終端ポイントとして考えることができる。
ソケットは様々なネットワークプロトコルをサポートしていますが、最もよく使われるのは次の2つです:
-
TCP
(Transmission Control Protocol): 接続を確立し、データの整合性および正しい順序を保証する信頼性の高いプロトコル。 -
UDP
(User Datagram Protocol): 接続指向でないプロトコルで、データの配信を保証しないが、特定のタイプのアプリケーションにはより速く効果的。
ソケットを識別するためには、IPアドレス(ネットワーク内のデバイスを識別)とポート(デバイス上の特定のアプリケーションまたはサービスを識別)が使用されます。
重要!
IPアドレスとポートは、ネットワーク内のプログラムを一意に識別します。これは家の住所と部屋番号のようなものです。家の住所(IPアドレス)はネットワーク上のあなたのコンピュータの住所で、ポートはプログラムがメッセージを受け取り・送信するために使用する部屋番号です。
IPアドレスとポートが何であるかについては、ネットワークの仕組みに関するレクチャーでより詳しく知ることができます。
ソケットを使うプログラムの主な手順は以下の通りです:
- ソケットの作成:プログラムはプロトコルのタイプ(TCPまたはUDP)を指定してソケットを作成する。
- アドレスにバインド:ソケットはIPアドレスとポート番号にバインドされ、接続やデータの送信/受信に利用可能になる。
- リスニングと接続の確立(TCPの場合):
- リスニング:サーバー側のソケットはリスニングモードに入り、受信接続を待つ。
- 接続の確立:クライアントがサーバーに接続を開始し、サーバーはそれを受け入れ、新しいソケットを作ってクライアントとやり取りする。
- データの交換:クライアントとサーバー間でデータを送受信します。TCPの場合、データは信頼性をもって順序正しく送受信される。
- 接続の終了:データ交換が終了した後、接続を閉じます。
ソケットを使うことの利点は:
- 柔軟性:ソケットを使うとアプリケーションは場所やプラットフォームに関係なくデータをやり取りできる。
- パフォーマンス:特にUDPを使う場合、ソケットはデータ転送を高速かつ効率的に行える。
- 信頼性(TCPの場合):TCPプロトコルはデータの信頼性ある転送を保証し、整合性チェックやパケットの再送も行う。
7.2 ソケットサーバーの作成
Pythonでのソケットの操作は、低レベルのネットワークプログラミングのためのインターフェイスを提供する組み込みのモジュール socket
を使用して行います。
ソケットを使ってsocketサーバー
を作成できます。これは、クライアントからのリクエストを受け取り、それに答えるアプリケーション/オブジェクトです。また、socketクライアント
も作成できます。これはsocketサーバー
にリクエストを送り、その返信を受け取るアプリケーション/オブジェクトです。
socketサーバー
を作成するには、次の3つの手順を行います:
- ソケットサーバーオブジェクトを作成する。
- それを任意のIPとポートにバインド(
bind
)する。 - 受信メッセージをリスニング(
listen
)するモードにする。
このコードはおおよそこんな感じです:
import socket
# ソケットの作成
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# ソケットをアドレスとポートにバインド
server_socket.bind(('localhost', 12345))
# 受信接続をリスニング
server_socket.listen(5)
print("サーバーは接続を待っています...")
ここでsocket.AF_INET
はIPv4を使っていることを示し、socket.SOCK_STREAM
はTCPを使っていることを意味します。これらの設定はネットワークアプリケーションを作成する際に最も一般的です。
受信メッセージが来たら、次の4つの手順を行う必要があります:
- クライアントとの
(accept)
接続を確立する。 - クライアントからのリクエスト(データ)を
(receive)
受信する。 - クライアントに応答のデータを
(send)
送信する。 - 接続を
(close)
終了する。
このコードはおおよそこんな感じです:
# 新しい接続の受付
client_socket, client_address = server_socket.accept()
print(f"接続が確立されました: {client_address}")
# クライアントからのデータ受信
data = client_socket.recv(1024)
print(f"受信: {data.decode('utf-8')}")
# クライアントへデータ送信
client_socket.sendall(b'Hello, client!')
# クライアントとの接続を終了
client_socket.close()
sendall()
メソッドはsend()
の代わりに使われます。なぜなら、send()
はバッファがいっぱいになるとデータの一部しか送信できないことがあるからです。
recv(1024)
の1024は、一度に受信できる最大バイト数を示します。これは、一度に処理されるデータの量を制御するのに役立ちます。
最後の例のコードは通常無限ループ内で実行されます。サーバーはリクエストを処理し、新しいリクエストを待ち、次にそれを処理し、これは絶えず続きます。
それを実行してみたい場合や完全な例を見たい場合は、以下にそれを示します:
import socket
# ソケットの作成
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# ソケットをアドレスとポートにバインド
server_socket.bind(('localhost', 12345))
# 受信接続をリスニング
server_socket.listen(5)
print("サーバーは接続を待っています...")
while True:
# 新しい接続の受付
client_socket, client_address = server_socket.accept()
print(f"接続が確立されました: {client_address}")
# クライアントからのデータ受信
data = client_socket.recv(1024)
print(f"受信: {data.decode('utf-8')}")
# クライアントへデータ送信
client_socket.sendall(b'Hello, client!')
# クライアントとの接続を終了
client_socket.close()
7.3 ソケットクライアントの作成
ソケットサーバーを作成しましたので、次はサーバーにデータを要求し、応答を受け取るソケットクライアントを作成しましょう。
これには、次の5つの手順が必要です:
socket-クライアント
オブジェクトを作成する。socket-サーバー
のIPアドレスとポートに(connect)
接続を確立する。- サーバーにメッセージを
(send)
送信する。 - サーバーからデータを
(receive)
受け取る。 - 接続を
(close)
終了する。
実際のところ、思っているより簡単です。このコードはこうなります:
import socket
# ソケットの作成
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# サーバーへの接続を確立
client_socket.connect(('localhost', 12345))
# サーバーにデータを送信
client_socket.sendall(b'Hello, server!')
# サーバーからデータを受信
data = client_socket.recv(1024)
print(f"サーバーから受信: {data.decode('utf-8')}")
# ソケットを終了
client_socket.close()
socket-サーバー
がその側に起動していないか、接続が切れた場合は、socket.error
タイプの例外が発生します。例外処理を忘れずに行ってください。
今日はソケットについての作業はここまでです。
ネットワークに関する作業をしていると、ホスト、ポート、IPアドレス、接続の確立、リクエストのリスニングなどが何度も出てくることでしょう。それらがどのように深く動いているかを理解することは、あなたの人生を大いに楽にし、分散している知識を一つの絵として結びつける助けとなります。
GO TO FULL VERSION