【Python】socket通信で複数データ(リストや辞書)を送信・受信する方法

時計 2021.01.18 / 時計

【Python】socket通信で複数データ(リストや辞書)を送信・受信する方法

本記事ではPythonにおけるsocket通信でリスト辞書データを送信・受信する方法について解説しています。

サーバー(Webアプリケーション)にデータを送信する方法は様々ありますが、本記事ではsocket通信を使用します。

socket通信を通して単一データをサーバに送信する方法はインターネット上にたくさんありますが、複数データ(リストや辞書)を送信する方法はなかなか見つかりません。

どのようにsocket通信で複数データを送信するのか見ていきましょう。

リストや辞書データを送信する必要が発生した経緯

アプリ開発

私はあるときパソコンの情報(ホスト名、IPアドレス、バージョンなど)をリアルタイムでサーバーに送信することで、パソコン情報をサーバーで一括管理しようと考えました。

今までパソコンの資産管理にはエクセルを使用していました。

それをサーバー(Webアプリケーション)で管理できるようにして、かつバージョン情報から定期的にバージョンアップをしているかも確認する考えでした。

プログラムはPythonで作成し、サーバーへの情報送信はSocket通信を使用します。

Socket通信については以下記事をご参照ください。

パソコン情報を送信するクライアントはWindows10、受信するサーバーもWindows10のパソコンで構築します。

リストや辞書データを送信したい

ここで一つ問題が発生しました。

複数のパソコン情報を送信する際、単にsocket通信だけでは一つずつしかデータを送信できないと思いました。

またsocket通信でデータを送信する際はデータをバイトオブジェクト(バイト型)で送信する必要があります。

複数のパソコン情報をリストや辞書にまとめてバイト型でサーバーに送信するにはどうしたらよいのか。

その答えはpickleモジュールを使うことでした。

pickleモジュール

pickleモジュールとは

pickleモジュールはオブジェクトを直列化(バイト列に変換すること)や非直列化(変換されたバイト列を元に戻すこと)するために使用されるモジュールです。

IT用語の確認

バイト列とは、バイト型を列に並べたデータ群です

pickleモジュールを使用してオブジェクトをバイト列に変換し、ファイルに保存することが多いです。

また複数のオブジェクトを1つにまとめることにも使用されます。

pickleモジュールでバイト列に変換できるオブジェクトはリスト型や辞書型も可能です。

pickleモジュールは標準モジュールのためpipでインストールする必要はありません。
プログラムで使用する際はインポートしてください。

import pickle

dumps()メソッド

オブジェクトをバイト列に変換するにはpickleモジュールのdumps()メソッドを使用します。

pickle.dumps(object)

dumps()の引数objectには、バイト列に変換したいオブジェクトを指定します。

loads()メソッド

変換されたバイト列をPythonオブジェクトに復元するにはloads()メソッドを使用します。

pickle.loads(bytes)

loads()メソッドの引数bytesにはバイト列を指定します。

socket通信でリストや辞書データを送信・受信するサンプルプログラム

Server

# server.py
import socket
import pickle

ip_address = '127.0.0.1'
port = 7010
buffer_size = 2048

with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
    # IP Adress とPortの指定と割り当て
    s.bind((ip_address, port))

    # クライアントからのデータ送信を待機
    while True:
        # 受信したデータとアドレスを代入
        data, addr = s.recvfrom(buffer_size)
	# 受信したバイト型を復元する
        data = pickle.loads(data)
        print('data : {}, addr: {}'.format(data, addr))

Client

# client.py
import socket
import platform
import pickle
import os
import subprocess

ip_address = '127.0.0.1'
port = 7010
buffer_size = 2048

with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
    # OSバージョン情報
    os_info = platform.system() + platform.release()
    # ホスト名
    host_name = socket.gethostname()
    # IPアドレス
    ip = socket.gethostbyname(socket.gethostname())
    # UserName
    user_name = os.getlogin()
    # version
    ver = subprocess.run(['ver'], check=True, shell=True, stdout=subprocess.PIPE).stdout.decode()

    data = {"os_info":os_info, "host_name":host_name, "ip":ip, "user_name":user_name, "ver":ver}

    data = pickle.dumps(data)
    s.sendto(data, (ip_address, port))

サンプルプログラムの解説

サンプルプログラムは以下の流れで起動します。

  1. サーバー側(server.py)プログラムを起動して待機状態にする
  2. クライアント側(client.py)プログラムを起動してデータ送信を行う

プログラムを起動するとサーバー側では以下のような表示がされます。

data : {'os_info': 'Windows10', 'host_name': 'OFFICE54', 'ip': '192.168.0.54', 'user_name': 'OFFICE54', 'ver': '\r\nMicrosoft Windows [Version 10.0.19042.685]\r\n'}, addr: ('127.0.0.1', 49235)

サンプルプログラムはUDPでSocket通信を行っています。

クライアント側はパソコン情報を辞書に格納します。
その辞書をpickleモジュールのdumps()メソッドを使用して、バイト型に変換してサーバーへ送信しています。

サーバー側は受信したバイト型データをpickleモジュールのloads()メソッドで復元しています。