Python & Raspberry Pi 開発ブログ ☆彡

PythonとRaspberry Piの基本的な使い方をわかりやすく解説。初心者、入門者必見!!

Python Socket通信の仕方:サーバー側

今回はRaspberry Piでソケット通信を行う方法を紹介したいと思います。ネットワークが繋がっていれば、ソケット通信でデータのやり取り等ができてとても便利です。ネットワークは難しいから手が出ないという方もいると思いますが、汎用的に使えますので、覚えてしまうと便利です。 また、下記のクライアント側のブログと合わせて読んでください。

www.raspberrypirulo.net

サンプルコードの内容

ソケット通信はクライアント ⇔ サーバー間でデータをやり取りする仕組みになっています。下記のサンプルコードは以下のように動作します。
・クライアントから文字を入力
・入力した文字列をサーバーに送信
・サーバーがデータを受け取る
・受け取ったデータをそのままクライアントに送信

構成

・サーバー:Raspberry Pi IPアドレス 192.168.1.10  ポート:12345
・クライアント:Raspberry Pi IPアドレス 192.168.1.15 ポート:12345

サーバー側のサンプルコード

それではコードの説明をしてきます。

socket.socket(socket.AF_INET, socket.SOCK_STREAM)
⇒ socketモジュールをインスタンス化

server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) ⇒ プログラムを終了 -> 再起動をすぐに行うと"ソケットが既に使用されています"というエラーが発生する場合がある。この問題を解消する。

server_socket.bind( (self.host, self.port) )
⇒ IPアドレスとポートを設定

server_socket.listen(CLIENTNUM)
⇒ クライアントの接続台数を設定、接続待ち

client_socket, address = server_socket.accept()
⇒ クライアントからの接続要求受け入れ。接続が確立されると戻り値として、client_socket:接続を通じてデータの送受信を行うための 新しい ソケットオブジェクトと、address :接続先でソケットにbindしているアドレスを返します。

下記コードにもコメントで説明を加えていますので、参考にしてください。

import socket
import threading
from datetime import datetime

HOST_IP = "192.168.0.10" # サーバーのIPアドレス
PORT = 12345 # 使用するポート
CLIENTNUM = 3 # クライアントの接続上限数
DATESIZE = 1024 # 受信データバイト数

class SocketServer():
    def __init__(self, host, port):
        self.host = host
        self.port = port

    def run_server(self):
        # サーバー起動
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server_socket:
            server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            server_socket.bind((self.host, self.port))
            server_socket.listen(CLIENTNUM)
            print('[{}] run server'.format(datetime.now().strftime('%Y-%m-%d %H:%M:%S')))
            
            while True:
                client_socket, address = server_socket.accept() # クライアントからの接続要求受け入れ
                print('[{0}] connect client -> address : {1}'.format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), address) )
                client_socket.settimeout(60)
                t = threading.Thread(target = self.conn_client, args = (client_socket,address)) 
                t.setDaemon(True)
                t.start() # クライアントごとにThread起動 send/recvのやり取りをする

    def conn_client(self, client_socket, address):
        
        with client_socket:
            while True:
                rcv_data = client_socket.recv(DATESIZE) # クライアントからデータ受信
                if rcv_data:
                    print('[{0}] recv date : {1}'.format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), rcv_data.decode('utf-8')) )
                    client_socket.send(rcv_data) # データ受信したデータをそのままクライアントへ送信
                else:
                    break

        print('[{0}] disconnect client -> address : {1}'.format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), address) )

if __name__ == "__main__":
    SocketServer(HOST_IP, PORT).run_server()

以上でサーバー側の説明は終了です。

ラズパイ ソフトウェアに戻る
ラズパイ ハードウェアに戻る
トップページに戻る