Python ソケット通信 (TCP/UDP) 実装ガイド:サーバー・クライアントの作り方

この記事は約6分で読めます。

LinuxやWindowsでのプロセス間通信(exe間通信)や、機器間でのデータやり取りに欠かせないのが「ソケット通信」です。

私は業務でもデータの引き渡しによくソケット通信を利用しますが、実はPythonでも標準ライブラリを使って非常に簡単に実装できます。

この記事では、信頼性の高いTCPと、高速なUDPの両方について、そのまま使えるサンプルコード付きで解説します。

もっと深く制御したい方へ

TCP/UDPといった標準的なプロトコルではなく、EthernetヘッダやIPヘッダから自分で構築して「Rawパケット」を送信したい場合は、以下の記事を参考にしてください。

WindowsでScapyを使ってEthernet rawパケットを送信する方法【Python】

1. TCPとUDP、どちらを使うべき?

実装の前に、まずはTCPとUDPの違いを整理しておきましょう。

特徴TCP (SOCK_STREAM)UDP (SOCK_DGRAM)
信頼性高い(再送制御あり)低い(送りっぱなし)
速度普通(接続手順が必要)高速
主な用途ファイル転送、HTTP、確実なデータ送受信リアルタイム動画、センサーデータ送信

基本的には「データの欠落が許されないならTCP」、「速度やリアルタイム性が最優先ならUDP」と使い分けます。

2. TCP通信のサンプルコード

まずは、接続を確立してから通信を行うTCPの例です。

Server側 (tcp_server.py)

import socket

def create_tcp_server(ip, port):
    # SOCK_STREAMを指定してTCPソケットを作成
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind((ip, port))
    server.listen(1)
    return server

if __name__ == '__main__':
    IP_ADDR = '127.0.0.1'
    PORT = 12345
    
    server = create_tcp_server(IP_ADDR, PORT)
    print(f"TCP Server待機中... ({IP_ADDR}:{PORT})")

    # クライアントからの接続待ち
    (con, client) = server.accept()
    print("クライアント接続成功:", client)

    try:
        # データの送信 (bytearray型)
        x = bytearray([1, 2, 3, 4])
        con.send(x)

        # データの受信
        while True:
            data = con.recv(1024)
            if not data:
                break
            print("受信データ(HEX):", data.hex())
            break
    finally:
        con.close()
        server.close()
        print("Server終了")

Client側 (tcp_client.py)

import socket

def create_tcp_client(ip, port):
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect((ip, port))
    return client

if __name__ == '__main__':
    IP_ADDR = '127.0.0.1'
    PORT = 12345

    con = create_tcp_client(IP_ADDR, PORT)
    print("Serverに接続しました")

    # 受信
    data = con.recv(1024)
    print("受信データ(HEX):", data.hex())

    # 送信
    x = bytearray([5, 6, 7, 8])
    con.send(x)

    con.close()
    print("Client終了")

3. UDP通信のサンプルコード

次に、接続不要でいきなりデータを送受信するUDPの例です。

Server側 (udp_server.py)

import socket

def start_udp_server(ip, port):
    # SOCK_DGRAMを指定してUDPソケットを作成
    server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    server.bind((ip, port))
    return server

if __name__ == '__main__':
    IP_ADDR = '127.0.0.1'
    PORT = 12345
    
    server = start_udp_server(IP_ADDR, PORT)
    print(f"UDP Server待機中... ({IP_ADDR}:{PORT})")

    while True:
        # recvfromでデータと送信元アドレスを取得
        data, addr = server.recvfrom(1024)
        print(f"受信元: {addr}, データ: {data.hex()}")

        # 受信した相手に返信
        response = bytearray([0xAA, 0xBB])
        server.sendto(response, addr)
        break

    server.close()

Client側 (udp_client.py)

import socket

if __name__ == '__main__':
    IP_ADDR = '127.0.0.1'
    PORT = 12345

    client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # 送信先を指定してデータを投げる (connect不要)
    msg = bytearray([0xCC, 0xDD])
    client.sendto(msg, (IP_ADDR, PORT))

    # 返信待ち
    data, server_addr = client.recvfrom(1024)
    print(f"Serverからの返信: {data.hex()}")

    client.close()

4. プログラムの解説

ソケットの生成

どちらの通信も socket.socket() で作成しますが、第2引数が異なります。

  • TCP: socket.SOCK_STREAM
  • UDP: socket.SOCK_DGRAM

送受信の関数の違い

  • TCPの場合:一度 connectaccept で接続が確立されると、相手が固定されるため send() / recv() を使います。
  • UDPの場合:接続という概念がないため、送信のたびに宛先を指定する sendto() を使い、受信時は recvfrom() で送り主の情報も一緒に受け取ります。

UDP使用時の注意点

UDPはデータロストが発生しても検出できません。もしUDPで信頼性を確保したい場合は、アプリケーション層(自分で書くプログラム側)で「届いたら返事を出す」「返事がなければ再送する」といった仕組みを実装する必要があります。

そのため、特別な理由がなければ、まずはTCPから検討することをおすすめします。

まとめ

Pythonのソケット通信は、標準ライブラリだけで完結し、Windows/Linux問わず同じ書き方で動作します。

  • 確実な通信ならTCP
  • 速度重視ならUDP
  • パケットを1から作りたいならRawパケット(Scapy等)

これらを使い分けることで、デバイス制御や自作アプリ間の連携がより柔軟に行えるようになります。ぜひ皆さんの開発に役立ててください!

コメント

タイトルとURLをコピーしました