TCPサーバーを実装したソケット通信【STM32Nucleo】

マイコンをイーサネット対応にしてpingが通った状態でネットワークに参加しただけでは何の意味もありませんが、上位のトランスポート層にTCPやUDPといったプロトコルを搭載することによってサーバーとクライアント間で通信ができるようになります。

ソケット通信は前回解説したOSI参照モデルのトランスポート層に属するTCPプロトコルにしたがった通信手段です。W5500コントローラを搭載したマイコンでTCPソケット通信を実現するためには内蔵したTCP/IPプロトコルスタックをレジスタで操作します。操作自体はメーカーがドライバを提供しているので容易に行われます。

TCPサーバーを構築してソケット通信の実装が整えば、任意のタイミングでシリアル通信のようなデータのやりとりができるようになります。

TCPソケット通信とは

めかのとろ

インターネット情報には無数の解説記事が存在するためにここでは詳細の解説は割愛しますが、簡潔にまとめますとソケット通信はサーバーとクライアントが互いに確認しながら通信を行うTCPプロトコルに基づいた方式です。互いにやりとりすることからハンドシェイク方式とも呼ばれます。

めかのとろ

ソケット通信は電話による会話に似ていて会話の出入り口である受話器、耳、口に相当するものをソケットと呼びます。相手が応答して初めて会話(通信)が成立し、途中で相手やこちらで切断すると会話も終了します。また、相手が接続中(受話器を上げたままの状態)のときは、こちらからの接続要求に応答しません。

めかのとろ

トランスポート層に属するプロトコルには他にUDPがありますが、これはサーバーがクライアントに確認せずに一方的に情報を与える方式です。動画などのストリーミングで内容に多少の不備があっても問題がない多量の情報を送るのに適しています。

めかのとろ

下図はソケット通信で標準的なバークレーソケット(BSD unixに実装されたネットワーク用API)に基づいた通信のフローチャートです。サーバー、クライアントともにあらかじめソケットを作成しておき、クライアント側から必要時に接続要求をだして、サーバーが応答して通信を確立します。一度確立すると、どちら側から切断しないかぎり、任意のタイミングで送受信できるのがソケット通信の特徴です。

TCPソケット通信

TCPサーバーの実装

めかのとろ

ドライバsoket.cでは標準インターフェースのBSDソケットに準じた関数をまとめていますがここではドライバ内に定義された関数の一部のみを使用したソケット通信のサンプルを紹介しています。

めかのとろ

サンプルプログラムではTCPサーバーをサンプリングタイム5msで実行する専用タスクprvTask_Tcpに構成しています。

めかのとろ

ドライバのソケット標準関数を使用して一般的なTCPサーバーを作成することもできますが、ここではサンプリングタイム毎にモニターしたソケット状態に応じた処理ドライバのレジスタ操作関数を使って実行します。

ソケットレジスタブロックの設定

TCPサーバータスクサンプル

 ① ソケット状態のモニター 

state = getSn_SR(SN);

めかのとろ

ソケットの状態は主に
SOCK_CLOSED」ソケット閉鎖
SOCK_LISTEN」ソケット待機
SOCK_ESTABLISHED」ソケット確立
SOCK_CLOSING」ソケット閉鎖中
の4種類があり、これらの状態をソケット番号SNに応じてgetSn_SR(SN)関数でソケットのレジスタ値を読み込みます。

② ソケット生成 

srcSocket = socket(SN,Sn_MR_TCP, PORT, SF_IO_NONBLOCK);

めかのとろ

プログラム起動直後のソケットは「SOCK_CLOSED」ですのでまずソケットをsocket()関数で生成します。

めかのとろ

関数の第1引数はソケット番号SNで、SNは自作関数をまとめたヘッダファイルnet_conf.hで1に定義しています。

めかのとろ

第2引数はプロトコルは設定でTCPプロトコルを指定しています。第3引数はPORT番号を指定し、第4引数ではnon-blockを指定し、ノンブロッキングソケットとしています。

③ STABE_LISTENに遷移 

LISTEN(SN);

めかのとろ

ソケットが作成されるとlisten(SN)関数を実行し、SOCK_LISTEN状態に遷移してクライアントからの接続待ち状態で待機します。

めかのとろ

ソケットの状態がSOCK_LISTENの待機時にクライアントのターミナルからIPアドレスおよびポートを指定して接続の要求をし、接続が確立するとSOCK_ESTABLISHEDになります。接続が確立しクライアントのターミナルにサーバーのIPアドレスが表示されると任意のタイミングで送受信ができるようになります。

④ データ送受信 

len=recv(SN, (uint8_t*)rcvbuffer, sizeof(rcvbuffer));

めかのとろ

データ受信にはrecv関数を使用します。第1引数はソケット番号、第2引数は受信バッファのポインタ、第3引数はデータ長を指定します。データを受信するとデータ長を返します

send(SN, (uint8_t*)sendbuffer, sizeof(sendvbuffer));

めかのとろ

データ送信にはsend関数を使用します。第1引数はソケット番号、第2引数は送信バッファのポインタ、第3引数はデータ長を指定します。

めかのとろ

通信用バッファメモリである送信TXおよび受信RXバッファはそれぞれ16Kバイトのブロックで構成されています。

⑤ ソケット制御関数

setSn_CR(SN,Sn_CR_CLOSE);

めかのとろ

setSn_CR関数はsocket.c内に定義されている関数でソケットを制御するものです。第1引数はソケット番号、第2引数はソケットの状態を指定します。Sn_CR_CLOSEを指定するとソケットを閉鎖(close)します。

めかのとろ

その他ソケットの”OPEN", ”LISTEN", "CONNECT", "DISCON", "SEND", "SEND_MAC", "SEND_KEEP", "RECV"等があります。詳細はドライバのソケット定義ファイルsocket.cを確認してください。

TCPサーバーの動作フロー
めかのとろ

TCPサーバーのソケット状態遷移をまとめると上図のようになります。W5500ではソケット状態は他にもありますが、とりあえず主な4つの状態をコントロールしておけば機能します。

ソケット通信のイメージ

めかのとろ

ソケット通信の状態を電話による会話に例えると下図のようなイメージなります。この通信状態を想定しながら実際にソケット通信を実施して動作を確認してみます。

ソケット通信における接続イメージ

実際のソケット通信

めかのとろ

クライアントではターミナルソフトを使用します。ここでもTera Termを使用しています。これに限らず慣れたツールを使用してください。

めかのとろ

起動後、TCPソケット通信ですのでサーバーに登録したIPアドレスおよびポート番号を入力し"OK"を押します。

① 接続要求 

めかのとろ

画面左上にサーバーのIPアドレスが表示されると設定ポートが開いてクライアントとサーバーが接続したことになります。

② ソケット接続確立中 

めかのとろ

TCPサーバーに対してコマンドを与えて通信できるかを確認します。通信テスト用の応答メッセージを返す処理ソケットの閉鎖(close)および接続切断(disconnect)するコマンドをまとめたファイルを作成して実行しています。

コマンド処理(通信テスト用)
めかのとろ

まず文字列"ABC"を入力します。受信バッファに格納された文字列が"ABC"で一致すると”Matched‼"と応答します。応答はsend関数を使用しています。

めかのとろ

文字列"abc"を入力すると"ABC"と一致しませんので”Error"と応答します。

めかのとろ

ソケットが接続確立しているところで新たに別の接続を試みます。

めかのとろ

すでにポートが開いているために接続が拒否されました。電話では相手の受話器が上がっていて話し中の状態です。

③ ソケットclose 

めかのとろ

ソケットを閉じるためにコマンド"scls"を入力すると"socket close"メーセージを返してCRレジスタにSn_CR_CLOSEを送信してからソケットを閉鎖(close)します。結果、未接続となります。

④ 接続要求+ソケット接続確立 

めかのとろ

また新たに接続を試みると今度はソケットが閉じているため再びポートが開き接続できます。

めかのとろ

最後に接続自体を遮断するため、コマンド"srst"を入力します。CRレジスタにSn_CR_DISCONを送信し、切断処理(disconnect)を実行します。

⑤ 接続切断 

めかのとろ

画面左上が未接続となり接続が遮断されたことが確認できます。

めかのとろ

以上、テスト用コマンドを入力してソケット通信の様子を確認しました。実際のソケット通信ではプログラミング次第でコマンドをさらに多様化してコマンドにより様々な処理を実施させることになります。

めかのとろ

TCPソケット通信はサーバーとクライアント間でリアルタイムでデータをやりとりできることが特徴ですので組み込み機器にTCPサーバーを搭載しておけばIoTとしてリアルタイムでインターネットを介してデータのリモート管理ができるようになります。