イントロダクション

この例では、Oracle Java を使用して WebSocket API サーバーを作成する方法を示します。

他のサーバーサイドの言語を使用して WebSocket サーバーを作成することもできますが、この例では Oracle Java を使用してサンプルコードを簡略化しています。

このサーバーは RFC 6455 に準拠しているため、Chrome バージョン 16、Firefox 11、IE 10 以降の接続のみを処理します。

ファーストステップ

WebSocket は TCP (伝送制御プロトコル) 接続を介して通信します。 Java の ServerSocket クラスは java.net パッケージにあります。

ServerSocket

コンストラクタ:

ServerSocket(int port)

ServerSocket クラスをインスタンス化すると、port 引数で指定したポート番号にバインドされます。

私たちが学んだことを実装する方法は次のとおりです。

import java.net.ServerSocket;
import java.net.Socket;

public class Server{
    public static void main(String[] args){
        ServerSocket server = new ServerSocket(80);

        System.out.println("Server has started on 127.0.0.1:80.\r\nWaiting for a connection...");

        Socket client = server.accept();

        System.out.println("A client connected.");
    }
}

Socket

メソッド:

OutputStream

メソッド:

write(byte[] b, int off, int len)

指定された byte 配列からオフセット off で始まる len バイトをこの出力ストリームに書き込みます。

InputStream

メソッド:

read(byte[] b, int off, int len)

最大 len バイトのデータを入力ストリームからバイト配列に読み込みます。

私たちの例を拡張してみましょう。

Socket client = server.accept();

System.out.println("A client connected.");

InputStream in = client.getInputStream();

OutputStream out = client.getOutputStream();

new Scanner(in, "UTF-8").useDelimiter("\\r\\n\\r\\n").next();

ハンドシェイキング

クライアントがサーバーに接続すると、単純な HTTP リクエストから WebSocket への接続をアップグレードするための GET リクエストが送信されます。 これはハンドシェイキングと呼ばれます。

import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

//translate bytes of request to string
String data = new Scanner(in,"UTF-8").useDelimiter("\\r\\n\\r\\n").next();

Matcher get = Pattern.compile("^GET").matcher(data);

if (get.find()) {
    
} else {

}

このようにしなければならない理由を理解するよりも、レスポンスを作成する方が簡単です。

次のことをやらなければなりません

  1. 先頭と末尾の空白なしで Sec-WebSocket-Key リクエストヘッダーの値を取得します
  2. "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" とリンクします
  3. SHA-1 と Base64 のコードを計算します
  4. Sec-WebSocket-Accept レスポンスヘッダーの値を HTTP レスポンスの一部として書き戻します。
if (get.find()) {
    Matcher match = Pattern.compile("Sec-WebSocket-Key: (.*)").matcher(data);
    match.find();
    byte[] response = ("HTTP/1.1 101 Switching Protocols\r\n"
            + "Connection: Upgrade\r\n"
            + "Upgrade: websocket\r\n"
            + "Sec-WebSocket-Accept: "
            + DatatypeConverter
            .printBase64Binary(
                    MessageDigest
                    .getInstance("SHA-1")
                    .digest((match.group(1) + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
                            .getBytes("UTF-8")))
            + "\r\n\r\n")
            .getBytes("UTF-8");

    out.write(response, 0, response.length);
}

メッセージのデコード

ハンドシェイクが成功した後、クライアントはサーバーにメッセージを送信できますが、これはエンコードされています。

"abcdef" を送信すると、次のバイトが得られます。

129 134 167 225 225 210 198 131 130 182 194 135

- 129:

FIN (これは全体のメッセージですか?) RSV1 RSV2 RSV3 Opcode
1 0 0 0 0x1=0001

FIN: あなたはメッセージをフレームで送ることができますが、今は物事を単純に保ちます。
Opcode 0x1 は、これがテキストであることを意味します。オペコードの完全なリストです

- 134:

2番目のバイトから 128 を引いた値が 0〜125 の場合、これはメッセージの長さです。126 の場合は、次の 2 バイト (16 ビット符号なし整数)、127 の場合、次の 8 バイト (64 ビット符号なし整数、最上位ビットは 0 でなければならない) が長さです。

最初のビットは常に1なので、128を取ることができます。

- 167、225、225、および 210 はデコードするキーのバイトです。それは毎回変わります。

- 残りの符号化されたバイトはメッセージです。

アルゴリズムのデコード

デコードされたバイト = エンコードされたバイト XOR (エンコードされたバイトの位置 BITWISE および 0x3) バイト目のキー

Java の例です

byte[] decoded = new byte[6];
byte[] encoded = new byte[] {198, 131, 130, 182, 194, 135};
byte[] key = byte[4] {167, 225, 225, 210};

for (int i = 0; i < encoded.length; i++) {
    decoded[i] = (byte)(encoded[i] ^ key[i & 0x3]);
}

関連

 

ドキュメントのタグと貢献者

このページの貢献者: silverskyvicto
最終更新者: silverskyvicto,