###### tags: `WebSocket` `javascript` `go` `Rust` # WebSocket RFC 6455, The WebSocket Protocol リアルタイム双方向通信を低コストで行うための仕組み ## WebSocketの仕組み 1. TCP通信(HTTPなど)でハンドシェイクして、サーバー側とクライアント側の接続を確立 2. そのあとは、サーバーとクライアントを接続しっぱなしにしてTCP通信 WebSocket、Socket.ioとは何か? https://qiita.com/seri1234/items/7d8f03140ddbf2ab8bc7 Mozilla WebsocketAPI https://developer.mozilla.org/ja/docs/Web/API/WebSockets_API ### レガシーな手法: ポーリング ポーリングとは、ms単位の一定周期ごとにサーバーにHTTPリクエストをしてデータを同期する仕組み。 HTTPだけでは双方向は正直つらい。 ### redisのpubsubで代用できない? redisはサーバーサイドのプログラムなので、サーバーとサーバーの通信には使える クライアントとサーバーの双方向通信にはWebSocketしかない というか、redisのサーバーを立てるくらいならWebSocketサーバーを立てるのも同じコスト 複数サーバーのWebSocketをredisのpubsubで同期するという使い方があるらしい。 ## 注意: WebSocketとSocket.ioは違う - WebSocket : 通信プロトコル。 ws:// で始まるurlで通信先を指定 - socket.io : Node.jsによるWebSocketのサーバー・クライアント実装 昔は、WebSocket実装がNodeのsocket.ioしかなく、ブラウザごとの差異を吸収するなどの特性もありsocket.io一択だった しかし、現在は WebSocket API が各ブラウザに実装されてきており、socket.ioを使う必要もない。 というか、socket.ioはサーバーとクライアントが統一されていないと使えないらしく、 socket.io-clientをGoやRustのWebSocketと組み合わせて使うことができない # クライアント側実装 ## javascript ブラウザに実装される**WebSocket API**を使う ```jsx= import React, {useState} from "react"; import _ from "lodash"; const socket = new WebSocket("ws://localhost:5000/ws") const App = () => { const [message, setMessage] = useState([]) socket.onmessage = (event)=>{ setMessage([event.data, ...message]) } return( <React.Fragment> {_.map(message, (item)=>(<p>{item}</p>))} <button onClick={()=>(socket.send("hello"))}>send</button> </React.Fragment> ) } export default App ``` - socketはコンポーネントの外側でconstで宣言 - => コンポーネントがマウントされるたびにいちいち接続し直すと面倒だから - urlのプロトコルは **ws** - wssはサーバー側が対応してなかった ## WebSocketオブジェクト - .send("string") : メッセージを送る。 - .onmessage : メッセージを受け取ったときに実行する関数を代入しておく WebSocketにおいて、送るデータのpayloadをmessageとよぶ mozilla の公式の実装を見ると、いろいろ使い方が乗ってる https://javascript.info/websocket ## npmモジュール : wscat websocketを簡単にテストできるクライアントコマンド ```bash= npm i -g wscat wscat -c ws://host:port ``` # サーバー側実装 ## Go ```rust= import React, {useState} from "react"; import _ from "lodash"; const socket = new WebSocket("ws://localhost:5000/ws") const App = () => { const [message, setMessage] = useState([]) socket.onmessage = (event)=>{ setMessage([event.data, ...message]) } return( <React.Fragment> {_.map(message, (item)=>(<p>{item}</p>))} <button onClick={()=>(socket.send("hello"))}>send</button> </React.Fragment> ) } export default App ``` 今回はGoでやった Rustでやってもいいかも ## melody Go言語における、WebSocketサーバーの実装 **gin** や **echo** といったwebframeworkと組み合わせて使う ### melody公式リポジトリ chatアプリケーションやhtmlタグの位置の同期など 使えそうなExampleがあるので確認する。 Github.com https://github.com/olahol/melody 配布がgithubではなく、gopkg.in gopkg.in/olahol/melody.v1 ## Rust ws でやりたい https://github.com/housleyjk/ws-rs やった ```rust= extern crate ws; fn main() { ws::listen("localhost:5000", |out|{ move |msg|{ println!("{}", msg); out.send(msg) } }).unwrap() } ```