liguofeng29’s blog

個人勉強用ブログだっす。

WebSocket概要

WebSocketは、javascriptを通してサーバと接続を行い継続的に通信(ソケット通信)を行えようにするための仕組みである。

WebSocketのメソッド

  • send() : データ送信
  • close() : 通信切断

WebSocketのリスナー

  • onopen : 接続確立時
  • onerror : エラー時
  • onclose : 切断時
  • onmessage : データ受信時

WebSocketのステータス

  • CONNECTING(0)
  • OPEN(1)
  • CLOSING(2)
  • CLOSED(3)

・サンプルコード

クライアント側

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title> WebSocketサンプル </title>
</head>

<body>
    <script type="text/javascript">
        // WebSocket生成
        var webSocket = new WebSocket("ws://127.0.0.1:30000");
        // 接続リスナー
        webSocket.onopen = function() {
                alert("サーバ接続成功");
                // 发送消息
                webSocket.send("クライアントからの送信データ");
            }
            // データ受信リスナー
        webSocket.onmessage = function(event) {
            alert("受信データ:" + event.data);
        }
    </script>
</body>

</html>

サーバ側

import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.MessageDigest;
import java.util.Base64;
import java.util.Base64.Encoder;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SimpleServer {
    public SimpleServer() throws Exception {
        // サーバソケット
        ServerSocket ss = new ServerSocket(30000);
        // 受け入れ待ち
        Socket socket = ss.accept();
        // 入力ストリーム
        InputStream in = socket.getInputStream();
        // 出力ストリーム
        OutputStream out = socket.getOutputStream();
        // バッファサイズ
        byte[] buff = new byte[1024];

        int count = -1;
        String req = "";
        // ここでクライアントに接続を確立
        count = in.read(buff);
        // データ取得
        req = new String(buff, 0, count);
        System.out.println("リクエスト" + req);
        // WebSocketのキー取得
        String secKey = getSecWebSocketKey(req);
        System.out.println("secKey = " + secKey);
        // ヘッダー
        String response = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: "
                + "websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "
                + getSecWebSocketAccept(secKey) + "\r\n\r\n";
        System.out.println("secAccept = " + getSecWebSocketAccept(secKey));
        out.write(response.getBytes());
        // 再度データ読み取り
        count = in.read(buff);
        System.out.println("受信データバイト数" + count);
        /*
        * WebSocketプロトコール 3~6は隠しコード 7バイト目からがデータ 3~6で後ろのデータを処理
        */
        for (int i = 0; i < count - 6; i++) {
            buff[i + 6] = (byte) (buff[i % 4 + 2] ^ buff[i + 6]);
        }
        System.out.println("受信データ" + new String(buff, 6, count - 6, "UTF-8"));
        // 送信する際に、2バイトは必ず受信と同じである必要がある
        byte[] pushHead = new byte[2];
        pushHead[0] = buff[0];
        String pushMsg = "Welcom to WebSocket";
        // 第2バイトは長さを記録
        pushHead[1] = (byte) pushMsg.getBytes("UTF-8").length;
        // 2バイト送信
        out.write(pushHead);
        // 有効データ送信
        out.write(pushMsg.getBytes("UTF-8"));
        // socket終了
        socket.close();
        // serverクローズ
        ss.close();
    }

    /**
    * WebSocketのキー取得
    *
    * @param req
    * @return
    */
    private String getSecWebSocketKey(String req) {
        Pattern p = Pattern.compile("^(Sec-WebSocket-Key:).+",
                Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
        Matcher m = p.matcher(req);
        if (m.find()) {
            // Sec-WebSocket-Key取得
            String foundstring = m.group();
            return foundstring.split(":")[1].trim();
        } else {
            return null;
        }
    }

    /**
    * WebSocketのSecKeyからSecAccept計算
    *
    * @param key
    * @return
    * @throws Exception
    */
    private String getSecWebSocketAccept(String key) throws Exception {
        String guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
        key += guid;
        MessageDigest md = MessageDigest.getInstance("SHA-1");
        md.update(key.getBytes("UTF-8"), 0, key.length());
        byte[] sha1Hash = md.digest();
        Encoder encoder = Base64.getEncoder();

        return new String(encoder.encode(sha1Hash), "UTF-8");
    }

    public static void main(String[] args) throws Exception {
        new SimpleServer();
    }
}

サーバ起動後に、htmlを開く。

f:id:liguofeng29:20160218214330g:plain