UDPのクライアントを作ってみる
それでは、簡単なUDPのクライアントを作ってみましょう。 どういうものにするかは、2段階で行ってみます。
単純に送って受ける、echoのようなシステム。
JSON形式のデータを送信し、簡単な処理を送り返してもらうシステム。
注釈
JSON版はもう少しお待ちください、後半で行う予定です。
まずは単純なものから行ってみましょう。
UDP echoクライアント
UDPでのechoクライアントを記述して、基本的なネットワークの操作コードを確認していきましょう。
ファイル名はecho-client.py
とします。
1#!/usr/bin/env python3
2import socket
3
4def main():
5 # UDPソケットを作る
6 with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
7 # 今回は、自分自身(localhost)のポート10000を接続先とします(10000/udp)
8 server_address = ('localhost', 10000)
9
10 message = b'Hello, World!' # 送信したいデータ列(バイト列に変換しておく)
11 print(f'送信内容: {message}')
12 sock.sendto(message, server_address)
13
14 # Receive response
15 print('応答待ち')
16 data, server = sock.recvfrom(4096)
17 print(f'受信しました: {data}')
18
19 print('終了します')
20
21if __name__ == '__main__':
22 main()
いろいろしている感じもありますが、実はネットワークに関してはたいしたことはしていません。 少し読み込んでいきましょう。
ソケットの利用
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
ネットワークの通信では、ソケット(socket)という概念を使用します。 言葉として聞くであろうソケットであり、言い換えればケーブルのようなものです。 ただ、ソケットでは『皮』と『中身』を決めてあげる必要があります。
皮: ソケットをケーブルと見立てたときの皮であり、どのような材質で相手までひっぱるかになります。
シンボル
AF_INET
(socket.AF_INET
)は、IPv4のインターネットプロトコルを使用することを意味します。今回は使いませんが、IPv6もちろん可能で、
AF_INET6
(socket.AF_INET6
)を使うこともできます。
中身: ソケット(ケーブル)の中身の材質みたいなものです、具体的にはTCPを使うかUDPを使うかということになります。
シンボル
SOCK_DGRAM
(socket.SOCK_DGRAM
)は、UDPを使用することを意味します。TCPを使う場合は、
SOCK_STREAM
(socket.SOCK_STREAM
)を使います。
注釈
DGRAMはデータグラムのことです。データグラムという『データのかたまり』を使った通信のことをUDPと呼びます。
TCPはストリーム通信という仕組みを用いて行うため、指定が socket.SOCK_STREAM
となっています。
データの送信
データグラムの通信では、過去に学んだように『投げつける』感覚です。そのため、ソケットを作ったとしても明確な接続は行いません。すごく楽ですね。
message = b'Hello, World!' # 送信したいデータ列(バイト列に変換しておく)
print(f'送信内容: {message}')
sock.sendto(message, server_address)
見ての通りで、生成したソケット(sock
)を用いてのsendto()
です。
送りたいデータと送り先をしているだけとなっています。相手との接続確認とかありません。
データの受信
さて、ソケットによる送信を行ったとき、ソケットの両端はトランスポート(UDP)であるため、ポートによる端点の識別が機能しています。
送り先: コード内で指定したポート番号(今回は10000)
送り元: 特に指定していないので『OSのお任せ』で設定(調べない限りわからない)
この情報は、UDPのヘッダにより相手(接続先)に送られているため、受信側はその情報を基に『必要があれば』返信します。 この操作も『事前の接続なしに』送られてくるため、すぐに受け取れるように待機する必要があります。
print('応答待ち')
data, server = sock.recvfrom(4096)
print(f'受信しました: {data}')
ソケットのrecvfrom()
を使うことで、受信待機を行います。
引数は受信データの最大サイズとなります。
戻り値は2つ(タプルで受け取っている)です。
受信データ(
data
で受け取っている)サーバー側のアドレス情報(
server
で受け取っている)
このアドレス情報は、受信したデータの送り元(すなわちサーバー)の情報となります。 今回は単純に表示しているだけですが、この情報を適宜操作してアプリケーションが利用することとなります。
まとめ
UDPのクライアント側は非常にシンプルな操作となっています。 この部分がUDPの特徴となっています。 続いて、サーバー部分を見てみましょう。