Edited at

pythonでsocket通信を勉強しよう

More than 1 year has passed since last update.

学習履歴


■はじめに

python で掲示板アプリを作成したいと思って情報を集めている。

作り方の予想は大方ついたが、掲示板に投稿した際、画面上に投稿内容を

リアルタイム表示する方法が現状不明だ。

socket 通信を使えばレスポンシブルなやり取りができそうだったので、

勉強してみようと思う。


■Socket 通信


Socket とは

Socket は、サーバとクライアントを結ぶ仮想的な接続を実現する。

img.png

サーバとクライアントがお互い関係を持っているので、片方のソケットが書き込んだデータは、

もう片方のソケットから取り出すことができる。


アドレスファミリ

アドレスファミリは、ソケットが利用できるアドレス体系を示すものだ。

アドレスファミリ
意味

AF_INET
IPv4 によるソケット

AF_INET6
IPv6 によるソケット

AF_UNIX
ローカルなプロセス間通信用のソケット

AF_INET
デバイスレベルのパケットインターフェース


ソケットタイプ

ソケットタイプは、ソケットの性質を表す。

ソケットタイプ
意味

SOCK_STREAM
順序性と信頼性があり、双方向の接続されたバイトストリーム(byte stream)を提供する(TCP)

SOCK_DGRAM
データグラム(接続、信頼性なし、固定最大長メッセージ)をサポートする(UDP)

このソケットタイプとアドレスファミリの組み合わせて、通信方式を決定する。

例えば、AF_INETとSOCK_STREAM であれば IPv4+TCP による通信が行われ、AF_INET と SOCK_DGRAM であれば IPv4+UDP による通信が行える。


TCP/IP での Socket

TCP/IP を使った Socket 通信から見てみよう。

まずは、socket サーバを作成する


server.py

# socket サーバを作成


import socket

# AF = IPv4 という意味
# TCP/IP の場合は、SOCK_STREAM を使う
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
# IPアドレスとポートを指定
s.bind(('127.0.0.1', 50007))
# 1 接続
s.listen(1)
# connection するまで待つ
while True:
# 誰かがアクセスしてきたら、コネクションとアドレスを入れる
conn, addr = s.accept()
with conn:
while True:
# データを受け取る
data = conn.recv(1024)
if not data:
break
print('data : {}, addr: {}'.format(data, addr))
# クライアントにデータを返す(b -> byte でないといけない)
conn.sendall(b'Received: ' + data)


続いて、クライアントを作成する


client.py

# クライアントを作成


import socket

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
# サーバを指定
s.connect(('127.0.0.1', 50007))
# サーバにメッセージを送る
s.sendall(b'hello')
# ネットワークのバッファサイズは1024。サーバからの文字列を取得する
data = s.recv(1024)
#
print(repr(data))


処理の流れを図にするとこうなる。

これは、python に限った話ではなく、socket 通信の規格上、このような流れになるらしい。

img.png

筆者は、Windows 環境なので、コマンドプロンプトから server.py 及び

client.py の順で python を起動してみる。

〇server.py の実行

img.png

ソケットサーバの立ち上げに成功したら、クライアントを実行してみよう。

〇client.py の実行

img.png

画像では、既に表示されてしまっているが、client.py で送信したデータの

結果を server.py がちゃんと受け取っていることが確認できた。


UDP/IP での Socket

TCP/IP がうまくいったので、今度は、UDP/IP でやってみよう。

といっても TCP/IP の簡略版だ。


server.py

import socket

with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.bind(('127.0.0.1', 50007))
while True:
data, addr = s.recvfrom(1024)
print("data: {}, addr: {}".format(data, addr))



client.py

import socket

with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.sendto(b'Hello UDP', ('127.0.0.1', 50007))


これだけだ。

あとは、TCP/IP のときと同じように、コマンドプロンプト上で、server.py ->

client.py の順に python ファイルを実行してみよう。

〇server.py の実行

img.png


webserver を立ててみる

最後に、webserver を立ててみよう。


webserver.py

import http.server

import socketserver

with socketserver.TCPServer(('127.0.0.1', 8000), http.server.SimpleHTTPRequestHandler) as httpd:
httpd.serve_forever()


上記を実行後、ブラウザにアクセスすると webserver.py を置いた

ディレクトリ情報が確認できる。

img.png

webserver.py が確認できる。

PHPMyAdmin みたいだ。


■まとめ

クライアントのレスポンスに対して、サーバがレスポンスをリアルアイムに

返答してくれている。

掲示板の実装に使えそうに思えるので、頑張ってみようと思う。


■参考

ソケットプログラミング HOWTO