Python
 Computer >> コンピューター >  >> プログラミング >> Python

Pythonの低レベルネットワークインターフェース(ソケット)の基礎と使い方


Pythonの標準ライブラリに含まれる「socket」モジュールは、OSが提供するソケットエンドポイントを利用して、サーバーマシンとクライアントマシンが通信するための仕組みを定義しています。socket APIには、コネクション型(接続指向)プロトコルとコネクションレス型(非接続型)プロトコルの両方に対応した関数が用意されています。

ソケットとは、双方向通信リンクの「終端(エンドポイント)」のことです。IPアドレスとポート番号によって識別され、通信を開始するには両端でソケットを適切に設定する必要があります。これにより、クライアント・サーバー環境において、着信メッセージを待ち受け、応答を送り返すことが可能になります。

socketオブジェクトの作成

socketモジュールのsocket()関数を使うと、ソケットオブジェクトを生成できます。

import socket
obj = socket.socket(family, type, protocol)

引数「family」はデフォルトでAF_INETです。その他にAF_INET6、AF_UNIX、AF_CAN、AF_RDSなどを指定できます。「type」はデフォルトでSOCK_STREAMであり、これはコネクション型プロトコル(TCP)を意味します。コネクションレス型プロトコル(UDP)を使う場合はSOCK_DGRAMを指定します。「protocol」は通常、デフォルトの0のままで問題ありません。

サーバー側のソケットオブジェクトは「サーバーソケット」、クライアント側は「クライアントソケット」と呼ばれます。ソケットオブジェクトは以下のメソッドを実装しています。

サーバー側の主要メソッド

bind()ソケットを指定したIPアドレスとポート番号に紐付けます。
listen()サーバーを起動し、クライアントからの接続要求を待ち受けるループに入ります。
accept()サーバーが接続要求を受け取ると、このメソッドがそれを受け入れ、クライアントソケットをそのアドレスとともに識別します。

典型的なサーバー側のコードは次のようになります。

import socket

ss = socket.socket()
ss.bind(('localhost', 12345))
ss.listen()
client, addr = ss.accept()
print("connection request from: " + str(addr))

同一マシン上でサーバーとクライアントを動かしてローカルテストを行う場合、IPアドレスは「127.0.0.1」(ループバックアドレス)を使用します。これはホスト名「localhost」でも識別できます。ソケットは空いている任意のポート番号で待ち受けます。なお、ネットワーク上の離れたマシン同士で通信する場合は、実際のIPアドレスを使用する必要があります。

クライアントソケットは、待ち受けているサーバーソケットのIPアドレスとポート番号に対して接続要求を送信します。

connect()

obj = socket.socket()
obj.connect((host, port))

クライアントからの接続要求がサーバーに受け入れられると、両方のソケットオブジェクトはTCPプロトコルで接続され、データの送受信ができるようになります。

send()

サーバーは、accept()で取得したクライアントソケットを使ってデータを送信します。

client.send(bytes)

クライアントソケットは、接続を確立した相手のソケットへデータを送信します。

obj.send(bytes)

sendall()

send()と似ていますが、このメソッドはすべてのデータが送信し終わるまで送信を継続します。

sendto()

このメソッドはUDPプロトコルの場合にのみ使用します。

recv()

クライアントに送られてきたデータを受信するために使います。サーバー側では、接続を受け入れたリモートソケットに対して呼び出します。

client.recv(bytes)

クライアント側では次のようにします。

obj.recv(bytes)

recvfrom()

このメソッドはUDPプロトコルの場合に使用します。

サーバー側のコード例

import socket

host = "127.0.0.1"
port = 12345

ss = socket.socket()
ss.bind((host, port))
ss.listen()

cs, addr = ss.accept()
print("Connection from: " + str(addr))

while True:
    data = cs.recv(1024).decode()
    if not data:
        break
    print("from connected user: " + str(data))
    reply = input("type message: ")
    cs.send(reply.encode())

cs.close()

クライアント側のコード例

import socket

host = '127.0.0.1'
port = 12345

obj = socket.socket()
obj.connect((host, port))

message = input("type message: ")
while message != 'q':
    obj.send(message.encode())
    data = obj.recv(1024).decode()
    print('Received from server: ' + data)
    message = input("type message: ")

obj.close()

コマンドプロンプト(ターミナル)のウィンドウを2つ開き、片方でまずサーバーのコードを実行します。その後、もう片方でクライアントのコードを実行すると、双方向のメッセージ交換が確認できます。


  1. Pythonのソケットエラー48(Address already in use)の原因と解決策

    ソケットエラー48は、プロセスがすでに使用中のポートへバインドしようとした際に発生するPythonのエラーです。エラーメッセージとしては「socket.error: [Errno 48] Address already in use」と表示されます。「socket.error: [Errno 48] Address already in use」エラーの原因調査の結果、このエラーの主な原因は以下の通りです。ポートへのプロセスのバインド: サーバー上でプロセスを作成すると、インターネットと通信するためにポートが使用されます。ポートとは、一度に一人のゲストしか受け入れられないホストのようなものです

  2. Rubyネットワークプログラミング入門!ソケットの基本とTCPサーバーの作り方

    Rubyでオリジナルのネットワーククライアントやサーバーを作りたいと思ったことはありませんか?あるいは、その仕組みを理解したいだけかもしれません。 その場合、必ず「ソケット」と向き合うことになります。 この記事では、Rubyネットワークプログラミングの基礎を学び、Rubyを使って他のサーバーやクライアントと通信を始めるための方法をご紹介します。 ソケットとは何か? ソケットとは、通信チャネルのエンドポイント(終端)のことです。クライアントとサーバーの両方が、このソケットを使って通信を行います。 その仕組みは非常にシンプルです。 接続が確立されると、ソケットにデータを書き込むことでデータが相手側