一番簡単なWebSocketをやりとりするJavaサーバープログラム 4

1 > 2 > 3 > 4 > 5 > (ページと結果)

次のファイルは今回一番大きなサイズになったSessionにつけておくManager部です。

さっそくプログラム
package com.ttProject.webSocket.manager;
 
import java.security.NoSuchAlgorithmException;
 
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
 
import com.ttProject.webSocket.library.MD5;
import com.ttProject.webSocket.model.data.ConnectData;
 
/**
 * それぞれのセッションのデータを管理するマネージャー
 */
public class SessionManager {
	private ConnectData cdata;
	/**
	 * コンストラクタ
	 */
	public SessionManager(IoSession session) {
		cdata = new ConnectData(session);
	}
	/**
	 * HandShakeの準備
	 * @param buffer 入力バッファ
	 */
	private void handShake(IoBuffer buffer) {
		// コネクションが確立していないので、はじめの接続をやってやる。
		byte[] b = new byte[buffer.capacity()];
		String data;
		int i = 0;
		for(byte bi:buffer.array()) {
			if(bi == 0x0D || bi == 0x0A) {
				if(b.length != 0) {
					data = (new String(b)).trim();
					if(data.contains("GET ")) {
						String[] ary = data.split("GET ");
						ary = ary[1].split(" HTTP/1.1");
						cdata.setPath(ary[0]);
					}
					else if(data.contains("Sec-WebSocket-Key1")) {
						cdata.setKey1(data);
					}
					else if(data.contains("Sec-WebSocket-Key2")) {
						cdata.setKey2(data);
					}
					else if(data.contains("Host")) {
						String[] ary = data.split("Host: ");
						cdata.setHost(ary[1]);
					}
					else if(data.contains("Origin")) {
						String[] ary = data.split("Origin: ");
						cdata.setOrigin(ary[1]);
					}
					if(data.length() > 4) {
						System.out.println(data);
					}
				}
				i = 0;
				b = new byte[buffer.capacity()];
			}
			else {
				b[i] = bi;
				i ++;
			}
		}
		// 最終業に最後のバイトデータがはいっているはず。
		doHandShake(b);
	}
	/**
	 * HandShakeを実行し、クライアントに応答を返す。
	 * @param key3
	 */
	private void doHandShake(byte[] key3) {
		if(key3 == null) {
			System.out.println("最終byteが不正");
			return;
		}
		String key1 = cdata.getKey1();
		String key2 = cdata.getKey2();
		if(key1 == null || key2 == null) {
			System.out.println("キーデータが足りない");
			return;
		}
		// handShakeの実動作を実行する。
		byte[] b = new byte[16];
		// key1とkey2のデータを変換
		int buf1 = getKeyInteger(key1);
		int buf2 = getKeyInteger(key2);
		// md5化
		byte[] result;
		try {
			b[0] = (byte)((buf1 & 0xFF000000) >> 24);
			b[1] = (byte)((buf1 & 0x00FF0000) >> 16);
			b[2] = (byte)((buf1 & 0x0000FF00) >> 8);
			b[3] = (byte)((buf1 & 0x000000FF));
			b[4] = (byte)((buf2 & 0xFF000000) >> 24);
			b[5] = (byte)((buf2 & 0x00FF0000) >> 16);
			b[6] = (byte)((buf2 & 0x0000FF00) >> 8);
			b[7] = (byte)((buf2 & 0x000000FF));
			b[8]  = key3[0];
			b[9]  = key3[1];
			b[10] = key3[2];
			b[11] = key3[3];
			b[12] = key3[4];
			b[13] = key3[5];
			b[14] = key3[6];
			b[15] = key3[7];
			result = MD5.crypt(b);
		}
		catch(NoSuchAlgorithmException e) {
			e.printStackTrace();
			return;
		}
		catch(ArrayIndexOutOfBoundsException e) {
			e.printStackTrace();
			return;
		}
		// 送信元にデータをおくっておく。
		// 応答を返す。
		IoBuffer buf = IoBuffer.allocate(2048);
		byte[] bb = {0x0D, 0x0A};
		buf.put("HTTP/1.1 101 WebSocket Protocol Handshake".getBytes());
		buf.put(bb);
		buf.put("Upgrade: WebSocket".getBytes());
		buf.put(bb);
		buf.put(("Sec-WebSocket-Origin: " + cdata.getOrigin()).getBytes());
		buf.put(bb);
		buf.put(("Sec-WebSocket-Location: " + cdata.getHost()).getBytes());
		buf.put(bb);
		buf.put("Sec-WebSocket-Protocol: sample".getBytes());
		buf.put(bb);
		buf.put(bb);
		buf.put(result);
		buf.flip();
		cdata.getSession().write(buf);
		cdata.setConnected();
		System.out.println("HandShakeの動作完了");
	}
	/**
	 * keyから生成される整数値を計算する。
	 * @param key 入力キー文字列
	 * @return 生成された数値
	 */
	private Integer getKeyInteger(String key) {
		StringBuffer numList = new StringBuffer();
		int spaceCount = 0;
		for(int i=20;i < key.length(); i++) {
			char c = key.charAt(i);
			if(c >= 0x30 && c < 0x3A) {
				// 数字の項なので文字列に加える。
				numList.append(c);
			}
			else if(c == ' ') {
				spaceCount ++;
			}
		}
		return (int)(new Long(numList.toString()) / spaceCount);
	}
	/**
	 * サーバーがうけとったメッセージを処理する。
	 * @param buffer 受け取ったバイナリメッセージ
	 */
	public void setMessage(IoBuffer buffer) {
		if(!cdata.isConnected()) {
			handShake(buffer);
		}
		else {
			// すでにコネクション確立済みなので、その処理を実施する。
			// とりあえずそのままエコーする。
			cdata.getSession().write(buffer);
		}
	}
}
 

やっていることは、
1:メッセージを受け取る(setMessage)
2:HandShakeが完了していない場合はhandShakeへ
完了している場合はSessionにエコーしてやって、送り元に同じメッセージを応答するとしてあります。
3:HandShake動作は(handShake:メッセージ分解)→(doHandshake:応答メッセージの作成)2つの部分に分けておきました。

なお、WebSocketのhandShakeの失敗条件には、
Originの応答が不一致
Hostの応答が不一致
MD5データの不一致
の3点を確認しました。

1 > 2 > 3 > 4 > 5 > (ページと結果)

タグ:

+ タグ編集
  • タグ:

このサイトはreCAPTCHAによって保護されており、Googleの プライバシーポリシー利用規約 が適用されます。

最終更新:2011年02月11日 21:22
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。