LoginSignup
0
0

More than 1 year has passed since last update.

便利ページ:WebSocketをサクッと触れるページを作ってみた

Last updated at Posted at 2021-05-05

便利ページ:Javascriptでちょっとした便利な機能を作ってみた のシリーズです。

今回は、WebSocketをサクッと呼び出せるページを作ります。
最近のほとんどのブラウザには、WebSocket APIが実装されているため、それを使います。

もろもろは、GitHubに上げてあります。

Webページはこちらからも見ることができます。ユーティリティタブでWebSocketを選択してください。

また、今回からついで、ベースとしていたフレームワークをBootstrap 3.4.1からBootstrap 5に変更し、便利ページ内の各ページをVueのコンポーネントで構成するようにしました。
こうすることで、ページもメンテナンスしやすく、追加しやすくなりました。
もし、Bootstrap3.4.1との比較を見たい場合は以下を参照してください。

 Bootstrap 3からBootstrap 5に移行してみた

画面はこんな感じです。

image.png

PWAにもしているので、アプリとして登録してあげてください。
Chromeを立ち上げなくても、いつでも便利ページを呼び出せますので。WindowsでもAndroidでもOKです。

ソースコード

といっても、大したことはやっていないので、ソースコード(Vueコンポーネント)を示しておきます。

js/comp/comp_websocket.js
const log_separator = "\n----------\n";

export default {
  mixins: [mixins_bootstrap],
  template: `
<div>
  <h2 class="modal-header">WebSocket</h2>
  <label class="title">url</label>
  <input type="text" class="form-control" v-model="ws_url" placeholder="wss://192.168.1.1:443/ws">
  <div class="row">
    <label class="col-auto title">protocols</label>
    <span class="col-auto">
      <input type="text" class="form-control" v-model="ws_protocols">
    </span>
  </div>
  <button class="btn btn-secondary" v-on:click="ws_open" v-if="!ws_socket">Open</button>
  <button class="btn btn-secondary" v-on:click="ws_close" v-else>Close</button>
  <br>
  status: {{ws_status_message}}
  <br><br>
  <div class="row">
    <label class="col-auto title">message</label>
    <span class="col-auto">
      <select class="form-select" v-model="ws_send_type">
        <option value="text">text</option>
        <option value="binary">binary</option>
      </select>
    </span>
  </div>
  <input type="text" class="form-control" v-model="ws_send_message">
  <button class="btn btn-secondary" v-on:click="ws_send" v-bind:disabled="!ws_socket">送信</button>
  <br><br>
  <textarea class="form-control col" id="ws_textarea" rows="10">{{ws_console_message}}</textarea>
  <button class="btn btn-secondary" v-on:click="console_clear">クリア</button>
</div>`,
  data: function () {
    return {
      ws_socket: null,
      ws_url: "",
      ws_protocols: "",
      ws_console_message: "",
      ws_send_type: "text",
      ws_send_message: "",
      ws_status_message: "closed",
    }
  },
  methods: {
    /* WebSocket */
    ws_open: function(){
      this.ws_close();

      try{
        this.ws_socket = new WebSocket(this.ws_url);
        this.ws_socket.binaryType = "arraybuffer";
        this.ws_socket.onopen = (event) => {
//          console.log("websocket opened", event);
          this.console_log(this.make_console_state_message(event));
          var date_string = new Date().toLocaleString('ja-JP', { "hour12": false, "year": "numeric", "month": "2-digit", "day": "2-digit", "hour": "2-digit", "minute": "2-digit", "second": "2-digit" });
          this.ws_status_message = "opened from " + date_string;
        };
        this.ws_socket.onclose = (event) =>{
//          console.log("websocket closed", event);
          this.console_log(this.make_console_close_message(event));
          this.ws_socket = null;
          this.ws_status_message = "closed";
        };
        this.ws_socket.onerror = (event) =>{
//          console.log("websocket error", event);
          this.console_log(this.make_console_state_message(event));
        };
        this.ws_socket.onmessage = (event) => {
//          console.log("websocket message", event);
          if (typeof (event.data) == "string" || event.data instanceof String ){
            this.console_log(this.make_console_input_message(event));
          }else{
            this.console_log(this.make_console_input_message(event));
          }
        };
      }catch(error){
        alert(error);
      }
    },
    ws_close: function(){
      if (this.ws_socket)
        this.ws_socket.close();
    },
    ws_send: function(){
      if( this.ws_send_type == "text" ){
        this.ws_socket.send(this.ws_send_message);
        this.console_log(this.make_console_output_message("text", this.ws_send_message));
      }else{
        var data = hexStr2byteAry(this.ws_send_message);
        var array = new Uint8Array(data);
        this.ws_socket.send(array);
        this.console_log(this.make_console_output_message("binary", array));
      }
    },
    console_clear: function () {
      this.ws_console_message = "";
    },
    make_console_output_message: function (type, data) {
      var date_string = new Date().toLocaleString('ja-JP', { "hour12": false, "year": "numeric", "month": "2-digit", "day": "2-digit", "hour": "2-digit", "minute": "2-digit", "second": "2-digit" });
      var message;
      if (typeof (data) == "string" || data instanceof String) {
        message = data;
      } else {
//        message = new Uint8Array(data).toString();
        message = byteAry2hexStr(data);
      }
      return "[SEND] message " + type + " " + date_string + "\n" + message;
    },
    make_console_state_message: function (event) {
      var date_string = new Date().toLocaleString('ja-JP', { "hour12": false, "year": "numeric", "month": "2-digit", "day": "2-digit", "hour": "2-digit", "minute": "2-digit", "second": "2-digit" });
      return "[STATE] " + event.type + " " + date_string;
    },
    make_console_close_message: function (event) {
      var date_string = new Date().toLocaleString('ja-JP', { "hour12": false, "year": "numeric", "month": "2-digit", "day": "2-digit", "hour": "2-digit", "minute": "2-digit", "second": "2-digit" });
      return "[STATE] " + event.type + " code=" + event.code + " " + date_string;
    },
    make_console_input_message: function(event){
      var date_string = new Date().toLocaleString('ja-JP', { "hour12": false, "year": "numeric", "month": "2-digit", "day": "2-digit", "hour": "2-digit", "minute": "2-digit", "second": "2-digit" });
      var message;
      var type;
      if (typeof (event.data) == "string" || event.data instanceof String) {
        message = event.data;
        type = "text";
      } else {
//        message = new Uint8Array(event.data).toString();
        message = byteAry2hexStr(event.data);
        type = "binary";
      }

      return "[RECV] " + event.type + " " + type + " " + date_string + "\n" + message;
    },
    console_log: function(message){
      this.ws_console_message = message + log_separator + this.ws_console_message;
    }
  },
  mounted: function(){
    var elem_in = document.querySelector("#ws_textarea");
    elem_in.style.height = 10;
  }
};

function hexStr2byteAry(hexs, sep = '') {
  hexs = hexs.trim(hexs);
  if (sep == '') {
    var array = [];
    for (var i = 0; i < hexs.length / 2; i++)
      array[i] = parseInt(hexs.substr(i * 2, 2), 16);
    return array;
  } else {
    return hexs.split(sep).map((h) => {
      return parseInt(h, 16);
    });
  }
}

function byteAry2hexStr(bytes, sep = '', pref = '') {
  if (bytes instanceof ArrayBuffer)
    bytes = new Uint8Array(bytes);
  if (bytes instanceof Uint8Array)
    bytes = Array.from(bytes);

  return bytes.map((b) => {
    const s = b.toString(16);
    return pref + (b < 0x10 ? ('0' + s) : s);
  }).join(sep);
}

要は、以下でWebSocketサーバに接続して、

        this.ws_socket = new WebSocket(this.ws_url);

以下で、サーバに送信して、

        this.ws_socket.send(this.ws_send_message);

以下で、サーバから受信する。

        this.ws_socket.onmessage = (event) => {

それだけです。
何かわかんなくなったり、パラメータで微調整したい場合は、以下を参考にしてください。

接続・切断・送信・受信の動きは、テキストエリアに逐一出力していますので、時系列で終えるようにしています。

WebSocket API (WebSockets)
 https://developer.mozilla.org/ja/docs/Web/API/WebSockets_API

終わりに

HTTPSで立ち上げたWebサーバのJavascriptからHTTPのWebSocketサーバに接続するには、WebSocketサーバをHTTPS接続にする必要があります。
以下を参考に、Web Proxyサーバを立ち上げてください。

 HTTPで立ち上げたWebSocketサーバに、HTTPSで接続するためのWeb Proxyの立ち上げ

あと、こちらもご参考まで。

 MMDダンスをM5Core2のディスプレイに表示する

以上

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0