WebSocket
RFC6455で定義されている通信規格.Webにソケット通信を導入する.
日本語訳してくれたサイト,助かる.RFC 6455, The WebSocket Protocol
まずHTTPでサーバとクライアント間のコネクションを確立し,Websocketプロトコルにアップグレードして双方向にデータをやり取りする.
下位層にはTCPを使うことが多い.
送受信は文字列の他にも,バイナリもやり取り可能.メッセージの型を送信時に一緒に指定すれば良いか?
ブラウザからマイコンのシリアルデータのリアルタイム垂れ流しとかやりたい.
サンプルソフトとstm32で通信を試す
クライアント(stm32)
stm32はNucleo-F767ZIを利用.ファームウェアはArduinoのSimpleWebSocketを使った.これでひとまず動かしてからArduinoのライブラリの中潜ってstm32のドライバ内部の実装見ていきたい.
define.h
の設定を変更する必要がある.Nuclo-F767ZIはRJ45コネクタが実装されており,Ethernetが使える.このため,
USE_BUILTIN_ETHERNET
をtrue
に変えておく.デフォルトだとfalse
Nucleo-F767ZI自身のIPアドレスを設定する.ここは接続するネットワーク次第.192.168.0.200
に割り当てておいた.
SimpleWebSocket.ino
もいくつか設定を変更する必要がある.
WebsocketサーバIPアドレスの変更
Websocketのエコーサーバであるecho.websocket.org
の部分を変更する.
今回は自宅ネットワーク内部のPCにNode.jsでWebsocketのサーバを立ててそこにアクセスさせたい.なのでWebsocketサーバを走らせるPCのIPアドレス入力する.サーバを走らせるPCには192.1688.0.100
を割り当てていたので,このアドレスに上書きする.
ポート番号の変更
あまり理解ができていないがあわせないと通信できない.今回走らせるWebsocketのサンプルが5001
を使っていたのであわせておく.
//char serverAddress[] = "echo.websocket.org"; // server address char serverAddress[] = "192.168.0.100"; // server address 自宅のネットワーク内に接続されているマシンのIPアドレス //int port = 80; int port = 5001;
静的IPを割り当てる.
define.h
で設定したIPをNucleo-F767ZIに割り当てるには呼び出すコンストラクタをヘンコする必要がある.186行目くらいに記載されている,呼び出すコンストラクタを切り替えればいいだけ.
// Use Static IP Ethernet.begin(mac[index], ip); // define.hで設定したIPを静的に割り当て //Ethernet.begin(mac[index]); // DHCPサーバに自動割当してもらう <- 標準だとこっちになってる.
サーバ+クライアント
サーバはNode.js,クライアントはhtmlで実装.
5分で動かせるwebsocketのサンプル3つの実装例を写経しておく.
Node.jsの初期設定
mkdir server cd server npm init -y npm i ws --save touch index.js
Node.jsでのサーバ側実装,ファイル名はindex.js
var server = require('ws').Server; var s = new server({port:5001}); s.on('connection',function(ws){ ws.on('message',function(message){ console.log("Received: "+message); s.clients.forEach(function(client){ client.send(message+' : '+new Date()); }); }); ws.on('close',function(){ console.log('I lost a client'); }); });
htmlでのクライアント側の実装.ファイル名はindex.html
stm32の場合と同様にサーバを走らせるPC(ここでは同じPCなので別に変えなくてもいいけど)である192.168.0.100
に変更しておく.
127.0.0.1
はlocalhost
のことなのでデフォルトのサンプルはブラウザのアドレスにlocalhost
と入力すればいい.
しかし外部のマシンからアクセスするにはIPを教える必要がある.深く考えずにサーバが実行されるマシンのIPでいい.
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <input type="button" id="sample" value="送信"> <script> //var sock = new WebSocket('ws://127.0.0.1:5001'); localhost なので同じPCでの動作なら書き換えなくても問題ない. var sock = new WebSocket('ws://192.168.0.100:5001'); // 実行するPCのIPアドレス.なので別PCからindex.htmlファイルを開いて動かしたいときはこっちにすると動く. // 接続 sock.addEventListener('open',function(e){ console.log('Socket 接続成功'); }); // サーバーからデータを受け取る sock.addEventListener('message',function(e){ console.log(e.data); }); document.addEventListener('DOMContentLoaded',function(e){ // サーバーにデータを送る document.getElementById('sample').addEventListener('click',function(e){ sock.send('hello'); }); }); </script> </body> </html>
PwerShellとかでinde.jsを起動し,htmlファイルをブラウザでアクセスする.F12で開発者モードを開くと受信したメッセージが表示されている.
node index.js
Nucleo-F767ZIのWebsocketサンプルも,通信が確立されると送受信を繰り返す様になっているのでそのやり取りがindex.htmlにも,サーバを走らせたPowershellの画面にも表示される.
参考文献
WebSocket の導入: ウェブにソケットを実装する
WebSocketについて調べてみた。
WebSocketプロトコル
WebSocket / WebRTCの技術紹介
WebSocket のはなし
Windows 8 と WebSocket プロトコル
C言語での実装
libwebsockets
Arduinoライブラリ
μWebSockets
Node.jsのサンプル
Socket.IOで始めるWebSocket超入門
WebSocket を使ったサンプルプログラムを作りました
大抵のWebsocketのサンプルは同じマシンにサーバとクライアント立てて,localhostにアクセスするものばかりだった.別マシンからアクセスする場合にアドレスをどう指定するのか不明だったけど,サーバの走っているマシンのIPで問題なかった.
How do I connect to a server in LAN from a different computer? I'm using socket.io and nodejs