こんにちは、今回はWebSocketについて記載をして行きたいと思います。
簡単な説明をいたしましたの上で、下記の素晴らしい方の実装を真似て、クライアントから数字をストリングのバイトで送信してもらって、それをサーバーで受け取り計算をして返すという構造を実装して見ました。
全く何かの役に立つものではございませんが、自分の知識を一旦整理したいのでこちらに書きます。
そもそもWebSocketとは?
双方向通信を行うことができるプロトコルのことです。
WebSocket は HTTP 上の相乗りプロトコルで、確立済みの HTTP/HTTPS 回線上で任意長・任意フォーマットデータの双方向通信を実現するものです。
WebSocketの登場以前は下記のようなLong PollingというシステムやCometという概念に従ってプログラムを作成したりしながらなんとか無駄を内包しながらも擬似的な双方向性を保っていたのです。
画像参照:https://www.fullstackpython.com/websockets.html
上記二つの説明については、下記の記事が読みやすいと思いますので、そちらを参照ください。
https://qiita.com/otmb/items/138f12c8832f78b2534d
https://codezine.jp/article/detail/7075
そして、今回の記事のメインとなるwebsocketについては、下記の画像にあるような構造となります。
画像参照:https://www.fullstackpython.com/websockets.html
他の方のブログを参照している中で賛否両論あるなと感じました。
肯定的な意見は多く見つかると思うのですが、例えば、こちらの方はこの技術を奇形であるが、当然の流れで生まれた産物であると述べています。
http://www.silex.jp/blog/wireless/2016/10/websocket.html
また、こちらの方のwebsocketの使用例の記述は大変分りやすかったです。
https://qiita.com/south37/items/6f92d4268fe676347160
例えばFacebookのチャットアプリみたいに多数のクライアントが一つのページにアクセスしてて誰かがメッセージを投稿するとそれをその他のユーザーに通知したい場合があって、そういった時に双方向通信の必要性が出てくる。
利点
一旦確立したHTTP/LTSの通信基盤の上で持続的にコネクトをするものであるので、都度ヘッダーなどを送信する必要がないのです、また、Firewallや他のルーター等はこの接続に関してはHTTPでの接続の延長線上と認識をするので、パケットの送信等に際しての障害もなくなります。つまり、大変無駄がなくなります。
実装 in Python
# client.py
from websocket import create_connection
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter('%(module)s - %(asctime)s - %(levelname)s - %(message)s'))
logger.addHandler(handler)
ws = create_connection("ws://127.0.0.1:12345")
logger.info("Open")
send = "11 23"
logger.info("Sending '{}'...".format(send))
ws.send(send)
logger.info("sent")
logger.info("Receiving...")
result = ws.recv()
logger.info("Received '{}".format(result))
ws.close()
logger.info("Close")
# server.py
import logging
from websocket_server import WebsocketServer
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter('%(module)s - %(asctime)s - %(levelname)s - %(message)s'))
logger.addHandler(handler)
def new_client(client, server):
logger.info('New Client {}:{} has joined'.format(client['address'][0], client['address'][1]))
def client_left(client, server):
logger.info('New Client {}:{} has left'.format(client['address'][0], client['address'][1]))
def message_received(client, server, message):
logger.info('Message "{}" has been received from {}:{}'.format(message, client['address'][0], client['address'][1]))
result = message_processing(message)
server.send_message(client, str(result))
logger.info('Message "{}" has been received from {}:{}'.format(result, client['address'][0], client['address'][1]))
def message_processing(message):
content = message.split(' ')
return int(content[0]) + int(content[1])
if __name__ == '__main__':
server = WebsocketServer(port=12345, host='127.0.0.1', loglevel=logging.INFO)
server.set_fn_new_client(new_client)
server.set_fn_client_left(client_left)
server.set_fn_message_received(message_received)
server.run_forever()
まだまだ実際のHTTPのHeaderの中身などを見れていないので認識が甘い部分は多いかと思いますが、ご拝読いただけましたこと、ありがとうございます!
こちらの記事を僕ももっと勉強したいと思います!
https://msdn.microsoft.com/ja-jp/magazine/jj863133.aspx
https://triple-underscore.github.io/RFC6455-ja.html