Help us understand the problem. What is going on with this article?

pythonでsocket通信を勉強しよう

学習履歴

■はじめに

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

作り方の予想は大方ついたが、掲示板に投稿した際、画面上に投稿内容を
リアルタイム表示する方法が現状不明だ。

socket 通信を使えばレスポンシブルなやり取りができそうだったので、
勉強してみようと思う。

■参考

この記事は、現役シリコンバレーエンジニアが教えるPython 3 入門 + 応用 +アメリカのシリコンバレー流コードスタイルを参考にしています(すごく、おすすめです!)

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

■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 みたいだ。

■まとめ

クライアントのレスポンスに対して、サーバがレスポンスをリアルアイムに
返答してくれている。

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

__init__
PythonとGo言語が一番好きです。どちらも仕事で使っています!
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away