python で tcp 接続(server/client)でメッセージ送受信する

python で tcp 接続(server/client)でメッセージ送受信する

2024/01/16 00:00:00
Program
Python

前提 #

作成手順 #

python 3.11.6 環境構築 #

# 作業エリア pystream 作成
$ mkdir pystream
$ cd pystream
$ pyenv local 3.11.6
$ python -V
3.11.6
$ python -m venv venv
$ source venv/Scripts/activate
# yaml ファイル制御用パッケージ
$ pip install pyyaml
...
[notice] A new release of pip is available: 23.2.1 -> 23.3.2  # <--- 新しいpipがあるといってる
[notice] To update, run: python.exe -m pip install --upgrade pip
# pip 更新
$ python.exe -m pip install --upgrade pip
# exe 化用パッケージ
$ pip install pyinstaller
$ pip freeze > requirements.txt

# エディタで静的解析が必要な場合(poetry使わないと開発用パッケージが混ざるので注意)
$ pip install jedi flake8 importmagic autopep8 yapf black

tcp server 作成 #

サーバ情報(ip,port)を外部ファイル(yaml)に記載して、その内容でtcp server を起動するサンプル
動作内容は以下の通り。

  • クライアントから接続があるまで無限待ち
  • クライアント接続後、メッセージ受信待ち
  • メッセージ受信後、メッセージ内容をクライアントにオウム返し

$ emacs server.py

 1import socket
 2import argparse
 3import traceback
 4import yaml
 5
 6
 7def main(config):
 8    server_ip = str(config['ip'])
 9    server_port = int(config['port'])
10    listen_num = 5
11    buffer_size = 4096
12    # 1.ソケットオブジェクトの作成
13    tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
14    # 2.作成したソケットオブジェクトにIPアドレスとポートを紐づける
15    tcp_server.bind((server_ip, server_port))
16    # 3.作成したオブジェクトを接続可能状態にする
17    tcp_server.listen(listen_num)
18    print("server {}:{}".format(server_ip, server_port))
19    # 4.ループして接続を待ち続ける
20    while True:
21        # 5.クライアントと接続する
22        client, address = tcp_server.accept()
23        print("[*] Connected!! [ Source : {}]".format(address))
24        # 6.データを受信する
25        data = client.recv(buffer_size)
26        print("[*] Received Data : {}".format(data.decode()))
27        # 7.クライアントへデータを返す
28        message = "ACK!! [{}]".format(data.decode())
29        client.send(message.encode())
30        # 8.接続を終了させる
31        client.close()
32
33
34def read_config(args):
35    config_file = 'server.yaml'
36    if args.config:
37        config_file = args.config
38    with open(config_file, 'r') as yml:
39        config = yaml.safe_load(yml)
40    return config
41
42
43if __name__ == '__main__':
44    try:
45        # 入力引数設定
46        parser = argparse.ArgumentParser(description='tcp server')
47        parser.add_argument('-c', '--config')  # option: config ファイル指定
48        args = parser.parse_args()  # 入力引数取得
49        config = read_config(args)
50        main(config)
51    except Exception:  # # main() で発生する異常はすべてキャッチする
52        t = traceback.format_exc()
53        print("ERROR: {}".format(t))

サーバのIPアドレスとポート番号をyamlファイルに記載
とりあえず、127.0.0.1:9901(ローカルホスト)にしておく

$ emacs server.yaml

1ip: "127.0.0.1"
2port: 9901

tcp client 作成 #

指定したip,portにメッセージを送信するサンプル
内容は以下の通り

  • 入力引数にip,port,messageを指定
  • 入力引数に従いtcp client作成しmessageを送信
  • 送信完了後、受信待ちをする
  • 受信すると、送信したmessageと同じ内容が返される

$ emacs client.py

 1import socket
 2import argparse
 3import traceback
 4
 5
 6def main(args):
 7    target_ip = str(args.ip)  # "127.0.0.1"
 8    target_port = int(args.port)  # 8080
 9    buffer_size = 4096
10    # 1.ソケットオブジェクトの作成
11    tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
12    # 2.サーバに接続
13    tcp_client.connect((target_ip, target_port))
14    # 3.サーバにデータを送信
15    tcp_client.send(str(args.message).encode())
16    # 4.サーバからのレスポンスを受信
17    response = tcp_client.recv(buffer_size)
18    print("[*]Received a response : {}".format(response.decode()))
19
20
21if __name__ == '__main__':
22    try:
23        # 入力引数設定
24        parser = argparse.ArgumentParser(description='tcp client')
25        parser.add_argument('ip', help='ip')
26        parser.add_argument('port', help='port')
27        parser.add_argument('message', help='message')
28        args = parser.parse_args()  # 入力引数取得
29        main(args)
30    except Exception:  # # main() で発生する異常はすべてキャッチする
31        t = traceback.format_exc()
32        print("ERROR: {}".format(t))

exe化 バッチ 作成&実行 #

以下をバッチを実行すると dist ディレクトリにexeファイルが作成される

$ emacs server-build.bat

1pyinstaller server.py --onefile

$ emacs client-build.bat

1pyinstaller client.py --onefile

$ emacs build.bat

1call server-build.bat
2call client-build.bat

exe 化する
distディレクトリにそれぞれ、server.exe, client.exe が生成される

$ ./build.bat

実行手順 #

exe を利用する場合 #

server 起動

server.yaml は自分の設定に置き換えておく必要がある。localhostのままでもいいがserver,clientは同じ端末で実施する必要がある
※ server.exeをダブルクリックで起動しても server.exe 直下の server.yaml を読み込んで実行するようになっている

# server.yaml を適宜記載しておくこと
$ cd pystream
$ cd dist
# パターン1:暗黙で同じ階層のserver.yamlを読み込んで起動
$ ./server.exe
# パターン2:-c 省略オプションで指定したserver.yamlを読み込んで起動
$ ./server.exe -c server.yaml
# パターン3:--config オプションで指定したserver.yamlを読み込んで起動
$ ./server.exe --config server.yaml

client 起動

server.yaml の内容のip,portを指定してメッセージ送信する

$ cd pystream
$ cd dist
$ ./client.exe 127.0.0.1 9901 test

python を利用する場合 #

準備

# for git-bash
$ cd pystream
$ python -m venv venv
$ source venv/Scripts/activate
$ pip install -r requirements.txt

server 起動

$ python server.py
$ python server.py -c server.yaml

client 起動

server.yaml の内容のip,portを指定してメッセージ送信する

$ python client.py 127.0.0.1 9901 test

参考URL #