Python でのソケットプログラミング:初心者ガイド
通常、プログラムを作成するときは、他のプログラムやコンピューターと通信する必要はありません。
ただし、サーバークライアントアーキテクチャを使用してメッセンジャーや他のアプリケーションを作成するには、他のコンピューターと通信する必要がある場合があります。このようなアプリケーションを作成するには、Python でソケットプログラミングを使用できます。
この記事では、Python でのソケットプログラミングの基本について説明します。また、TCP および UDP プロトコルを使用したソケットプログラミングを使用して、単純なメッセンジャーアプリケーションを個別に実装します。
Python のソケットとは
2つのアプリケーションまたはプロセスが相互作用する場合、それらは指定された通信チャネルを使用します。ソケットは、そのような通信チャネルのエンドポイントまたはエントリポイントです。
ソケットを使用して、2つのプロセス間、プロセス内、または異なるマシン上のプロセス間で通信チャネルを確立できます。TCP ソケット、UDP ソケット、UNIX ドメインソケットなど、さまざまな種類のソケットがあります。
Python でソケットプログラミングを実装する方法
Python は、ソケットプログラミングを実装するための socket
モジュールを提供します。socket
モジュールは標準の Python ライブラリの一部であり、Python でソケットを作成できるすべての関数とメソッドを提供します。
マシンに socket
モジュールを明示的にダウンロードする必要はありません。次のように、import ステートメントを使用してプログラムに直接インポートできます。
import socket
ソケットプログラミングを実装するには、ソケットを使用して通信する 2つのプロセスを作成する必要があります。
プログラムの 1つはサーバーとして機能し、もう 1つはクライアントとして機能します。サーバーとクライアントの両方が異なる機能を持っています。したがって、サーバープロセスとクライアントプロセスを作成するときにさまざまな機能を使用します。
サーバーとクライアントプロセスを 1つずつ作成する方法について説明します。
Python のソケットプログラミングでサーバーを作成する方法
サーバーを作成するには、最初にソケットを作成します。このために、socket()
メソッドを使用します。
ソケットの作成:socket()
メソッド
socket()
メソッドの構文は次のとおりです。
socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, fileno=None)
ここ、
- パラメータ
family
は、ソケットが属するアドレスファミリを表します。デフォルトでは、これはAF_INET
であり、インターネットプロトコルバージョン 4(IPv4)アドレスでソケットを作成します。UNIX アドレスにはAF_UNIX
、インターネットプロトコルバージョン 6(IPv6)アドレスにはAF_INET6
などの他のアドレスファミリを使用できます。 - パラメータ
type
はソケットタイプを示します。デフォルトでは、値SOCK_STREAM
があり、ソケットがコネクション型 TCP プロトコルに従うことを示します。SOCK_DGRAM
を使用して、UDP プロトコルに従うデータグラムソケットを作成できます。 - パラメータ
proto
はプロトコル番号を示し、通常は 0 です。パラメータファミリでアドレスファミリAF_CAN
を使用する場合、プロトコル番号はCAN_RAW, CAN_BCM, CAN_ISOTP, CAN_J1939
のいずれかである必要があります。 - パラメータ
fileno
にはデフォルト値None
が含まれています。fileno
でファイル記述子を指定すると、パラメーターfamily
、type
、およびproto
の値がファイル記述子から自動的に検出されます。
ソケットを作成したら、bind()
メソッドを使用してソケットをアドレスとポート番号にバインドします。
ソケットをアドレスにバインドする:bind()
メソッド
socket()
関数を使用して、作成したソケットオブジェクトで bind()
メソッドが呼び出されます。
ソケットがバインドされるアドレスを含むタプルを取ります。アドレスの形式は、選択したアドレスファミリによって異なる場合があります。アドレスファミリ AF_INET
でソケットを作成します。したがって、アドレスにはホスト名
とポート番号
が含まれます。
bind()
メソッドの構文は次のとおりです。
bind((hostname, port))
ホスト名
を明示的に指定できます。ローカルマシン上にサーバーを作成する場合は、ホスト名を localhost
または 127.0.0.1
として指定できます。これは、ローカルホストアドレスのデフォルト値です。
または、gethostname()
メソッドを使用してホスト名を取得することもできます。パラメータ port
には、1024
より大きく 65535
より小さい任意のポート番号を使用できます。
ソケットをアドレスにバインドした後、サーバーはクライアントの接続要求をリッスンします。このために、listen()
メソッドを使用します。
接続をリッスンする:listen()
メソッド
listen()
メソッドの構文は次のとおりです。
listen(backlog)
ここで、パラメータ backlog
は、新しい接続を拒否する前にシステムが許可する、受け入れられない接続の最大数を示します。
listen()
メソッドを実行すると、サーバーは接続を受け入れる準備が整います。
接続要求を受け入れる:accept()
メソッド
サーバーは常に無限ループで実行され、クライアントからの接続を受け入れるためのクライアント要求をリッスンします。クライアント要求が見つかると、サーバーは accept()
メソッドを使用して要求を受け入れます。
accept()
メソッドはタプル (client, address)
を返します。ここで、client
は、メッセージの送受信に使用する新しいソケットオブジェクトを表します。アドレス
は、クライアントソケットがバインドされる場所です。
クライアントとの通信:send()
および recv()
メソッド
接続を受け入れた後、サーバーはクライアントと通信できます。
send()
メソッドを使用して、クライアントにメッセージを送信します。send()
メソッドは、accept()
メソッドによって返される client
オブジェクトで呼び出されます。
recv()
メソッドを使用してメッセージを受信します。recv()
メソッドは、client
オブジェクトで呼び出されると、接続から読み取ることができる最大バイト数を表す数値を受け入れます。実行後、接続から読み取ったデータを返します。
すべての操作が完了したら、接続を閉じる必要があります。このために、accept()
メソッドによって返される client
オブジェクトで close()
メソッドを呼び出します。
サーバーの作成に必要なすべての方法について説明したので、サーバープロセスを作成しましょう。
import socket
mySocket = socket.socket(
family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, fileno=None
)
print("Socket created.")
hostname = "localhost"
portno = 9999
mySocket.bind((hostname, portno))
print("Socket bound to address {} and port number {}".format(hostname, portno))
mySocket.listen(5)
print("Listening for client.")
while True:
client, client_addr = mySocket.accept()
print("Connection established with client at address {}".format(client_addr))
msg = client.recv(1024).decode()
print("Message received from the client:")
print(msg)
print("Sending acknowledgment to the client.")
msg_out = "Message received: {}. Thank you.".format(msg).encode()
client.send(msg_out)
print("Terminating the connection.")
client.close()
break
サーバーを作成したので、サーバーと通信するクライアントプロセスを作成しましょう。
ソケットプログラミングでクライアントを作成する方法
クライアントを作成するには、サーバーの作成時に行ったように、最初に socket()
メソッドを使用してソケットを作成する必要があります。クライアントソケット用に定義されたプロトコルは、サーバーソケットと同じである必要があることに注意してください。そうしないと、プログラムは期待どおりに機能しません。
ソケットを作成したら、それをサーバーに接続する必要があります。このために、connect()
メソッドを使用します。
サーバーに接続する:connect()
メソッド
connect()
メソッドの構文は次のとおりです。
connect((host, port))
ここで、パラメータ host
はサーバーのアドレスを示します。パラメータ port
は、サーバーソケットが作成されるポート番号を示します。サーバーの作成時に bind()
メソッドに指定したホストおよびポートパラメーターへの入力と同じ値を指定する必要があります。
サーバーとの通信
サーバーに接続した後、send()
および recv()
メソッドを使用してサーバーと通信できます。最後に、close()
メソッドを使用してクライアント側から接続を閉じるのに役立ちます。
以下は、クライアントプロセスを作成するために使用するクライアントプログラムです。
import socket
mySocket = socket.socket(
family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0, fileno=None
)
print("Socket created.")
hostname = "localhost"
portno = 9999
mySocket.connect((hostname, portno))
print("Connection established with the server.")
msg = "Hi I am a TCP client created by Aditya."
print("Sending msg to the server:", msg)
mySocket.send(msg.encode())
msg_in = mySocket.recv(1024).decode()
print("Acknowledgment received from the server:")
print(msg_in)
print("Terminating the Connection.")
mySocket.close()
サーバーとクライアントを作成したら、プログラムを実行してみましょう。クライアントプログラムとサーバープログラムの両方を同時に実行して、両方のプロセスが同時に稼働し、相互に通信できるようにする必要があることに注意してください。
サーバープログラムを含むターミナルの出力は次のようになります。
Socket created.
Socket bound to address localhost and port number 9999
Listening for client.
Connection established with client at address ('127.0.0.1', 37958)
Message received from the client:
Hi I am a TCP client created by Aditya.
Sending acknowledgment to the client.
Terminating the connection.
クライアントプログラムを含むターミナルの出力は次のようになります。
Socket created.
Connection established with the server.
Sending msg to the server: Hi I am a TCP client created by Aditya.
Acknowledgment received from the server:
Message received: Hi I am a TCP client created by Aditya.. Thank you.
Terminating the Connection.
Python での UDP プロトコルを使用したソケットプログラミング
前のセクションでは、接続で TCP プロトコルに従うソケットを作成しました。TCP プロトコルでは、クライアントとサーバー間の接続は通信全体を通じて維持されます。
ただし、リソースの制約により、クライアントとサーバー間の安定した接続を維持できない状況が多くあります。したがって、安定した接続を必要としない通信プロトコルが必要です。このために、UDP プロトコルを使用します。
Python で UDP プロトコルを使用してサーバーを作成する方法
UDP プロトコルとの接続を作成するには、サーバーを実装する際に次の手順に従う必要があります。
socket()
メソッドを使用してサーバーソケットを作成するときに、type パラメーターの入力にSOCK_DGRAM
を指定します。bind()
メソッドを使用して、ソケットをアドレスとポート番号にバインドします。- クライアントとの接続を確立する必要がないため、接続を確立するために
listen()
およびaccept()
メソッドを使用しません。クライアントとの直接のコミュニケーションを開始できます。 - UDP プロトコルでメッセージを受信するには、
recvfrom()
メソッドを使用します。入力引数として読み取るバイト数を取り、データとデータの受信元のアドレスを含むタプルを返します。 - UDP プロトコルでメッセージを送信するには、
sendto()
メソッドを使用します。sendto()
メソッドは、最初の入力引数としてデータを受け取り、データの送信先となるソケットのアドレスとしてホスト名とポート番号を含むタプルを取ります。 - 通信後、
close()
メソッドを使用してソケットを閉じる必要があります。
次の Python プログラムを使用して、UDP プロトコルと通信するサーバープロセスを実装できます。
import socket
mySocket = socket.socket(
family=socket.AF_INET, type=socket.SOCK_DGRAM, proto=0, fileno=None
)
print("Socket created.")
hostname = "localhost"
portno = 9999
mySocket.bind((hostname, portno))
print("Socket bound to address {} and port number {}".format(hostname, portno))
while True:
msg, client_addr = mySocket.recvfrom(1024)
print("Message received from the client:")
print(msg.decode())
print("Sending acknowledgment to the client.")
msg_out = "Message received: {}. Thank you.".format(msg).encode()
mySocket.sendto(msg_out, client_addr)
mySocket.close()
break
Python で UDP プロトコルを使用してクライアントを作成する方法
UDP プロトコルに従うクライアントプロセスを作成するには、socket()
メソッドを使用してサーバーソケットを作成するときに、type パラメーターへの入力で SOCK_DGRAM
を指定してソケットを作成する必要があります。接続を作成する必要がないため、ここでは connect()
メソッドを使用する必要はありません。
ソケットを作成した後、sendto()
および recvfrom()
メソッドを使用してサーバーとの通信を直接開始できます。サーバーと通信した後、close()
メソッドを使用してソケットを閉じることを忘れないでください。
次の Python プログラムを使用して、UDP プロトコルと通信するクライアントプロセスを実装できます。
import socket
mySocket = socket.socket(
family=socket.AF_INET, type=socket.SOCK_DGRAM, proto=0, fileno=None
)
print("Socket created.")
while True:
msg = "Hi I am a UDP client created by Aditya."
print("Sending msg to the server:", msg)
mySocket.sendto(msg.encode(), ("localhost", 9999))
msg_in = mySocket.recv(1024).decode()
print("Acknowledgment received from the server:")
print(msg_in)
print("Terminating the Connection.")
mySocket.close()
break
繰り返しになりますが、出力を観察するには、クライアントプログラムとサーバープログラムの両方を同時に実行して、両方のプロセスが同時に稼働し、相互に通信できるようにする必要があります。
サーバープログラムを含むターミナルの出力は次のようになります。
Socket created.
Socket bound to address localhost and port number 9999
Message received from the client:
Hi I am a UDP client created by Aditya.
Sending acknowledgment to the client.
クライアントプログラムを含むターミナルの出力は次のようになります。
Socket created.
Sending msg to the server: Hi I am a UDP client created by Aditya.
Acknowledgment received from the server:
Message received: b'Hi I am a UDP client created by Aditya.'. Thank you.
Terminating the Connection.
まとめ
この記事では、Python でのソケットプログラミングについて説明しました。また、Python でのソケットプログラミングの基本を学ぶために、TCP プロトコルと UDP プロトコルを使用してクライアントプログラムとサーバープログラムを別々に実装しました。
TCP はコネクション型であるため、信頼性の高いプロトコルです。TCP プロトコルを使用している間、メッセージがサーバーからクライアントに、またはその逆に到達することが保証されます。UDP では、メッセージが目的の宛先に配信されることは保証されていません。
一方、UDP プロトコルは高速で実装が簡単ですが、TCP プロトコルは低速です。また、TCP プロトコルはブロードキャストに使用できませんが、UDP プロトコルはブロードキャストに使用できます。
利用可能なリソースとニーズに応じて、ソケットを使用してクライアント/サーバー通信を実装するための任意のプロトコルを選択できます。
Aditya Raj is a highly skilled technical professional with a background in IT and business, holding an Integrated B.Tech (IT) and MBA (IT) from the Indian Institute of Information Technology Allahabad. With a solid foundation in data analytics, programming languages (C, Java, Python), and software environments, Aditya has excelled in various roles. He has significant experience as a Technical Content Writer for Python on multiple platforms and has interned in data analytics at Apollo Clinics. His projects demonstrate a keen interest in cutting-edge technology and problem-solving, showcasing his proficiency in areas like data mining and software development. Aditya's achievements include securing a top position in a project demonstration competition and gaining certifications in Python, SQL, and digital marketing fundamentals.
GitHub