关于Websocket RFC645第13版协议的新手扫盲贴
这到底是websocket没人看好还是怎么了,个人觉得开始重点升级安全性的协议,将不会是一般般的协议简洁的html+javascript实现的websocket与java nio握手和后续通信不乱码的例子。
一般研究网络/服务器之类的一开始,都只是想要一个建立好连接,互相发送一段字符串接收成功的简洁实例而已.至于一个聊天室要怎么做,谁关心收到之后的数据你是想开个线程呢还是不打算用池呢.
没有扩展包,jetty WebsocketSevlet的,就干净的实现,给刚接触websocket的同僚一同参考。
这是javascript的websocket对象,面向对象好点
function conn(host, port) {this.websocket = new WebSocket('ws://' + host + ':' + port);console.log(this.websocket);this.websocket.onmessage = function(msg) {try {alert(msg.data);var parsed = JSON.parse(msg.data);switch (parsed.type) {case 'message':alert("message");break;case 'error':alert("error");break;default:throw new Error('Unknown message type ' + parsed.type);break;}} catch (e) {console.warn(e);alert(e);}};this.websocket.onopen = function(msg) {alert("open");}this.send = function(data){var _data = JSON.stringify(data);alert(_data);this.websocket.send(_data);}}
这是html,我叫kisme
<!DOCTYPE html><html><head><title>Kisme.</title></head><body><div id="desc"><div><input type="button" value="drawimg" /></div></div><script type="text/javascript" src="scripts/net/conn.js" charset="utf-8"></script></body></html>
服务器端代码有点多也不相关所以不黏了,这个是websocket协议的加解码工具类:
1.收到websocket发过来的信息后(直接打印出来应该是乱码),要decode,发送前要encode,代码如下
package server.io.client;import java.io.UnsupportedEncodingException;import java.nio.ByteBuffer;import java.nio.charset.Charset;public class EnDeCode{private static Charset charset = Charset.forName("utf-8");/** * charset encode ** @param str * @return */public static ByteBuffer encode(String a_str){return charset.encode(a_str);}/** * charset decode ** @param bb * @return */public static String decode(ByteBuffer a_bb){return charset.decode(a_bb).toString();}public static String WSP13Decode(byte[] data){byte _firstByte = data;byte _secondByte = data;int opcode = _firstByte & 0x0F;boolean isMasked = ((_firstByte & 128) == 128);// 实载数据长度int _payloadSize = _secondByte & 0x7F;if (!isMasked || opcode != 1){try{return new String(data, "utf-8");} catch (UnsupportedEncodingException e){// TODO Auto-generated catch blocke.printStackTrace();}} // not masked and opcode textint[] mask = new int;for (int i = 2; i < 6; i++){mask = data;}int _payloadOffset = 6;int dataLength = _payloadSize + _payloadOffset;int _payload_int_Length = dataLength - _payloadOffset;int[] _payload_int = new int;for (int i = _payloadOffset; i < dataLength; i++){int j = i - _payloadOffset;int _unmaskPL = data ^ mask;_payload_int = _unmaskPL;}byte[] _payload_byte = new byte;for (int i = 0; i < _payload_int.length; i++){byte _eachByte = (byte) (0xff & _payload_int);_payload_byte = _eachByte;// _payload_byte = (byte) (0xff & _payload_int);// _payload_byte = (byte) ((0xff00 & _payload_int) >> 8);// _payload_byte = (byte) ((0xff0000 & _payload_int) >>// 16);// _payload_byte = (byte) ((0xff000000 & _payload_int) >>// 24);}String _result = new String(_payload_byte);System.out.println("ssss:" + _result + " " + _result.length());return _result;}public static byte[] WSP13Encode(String data){// 一次最多127k,内容就只有125k,协议头2kif (data.length() > 125){data = data.substring(0, 125);}byte[] _payload_byte = null;try{_payload_byte = data.getBytes("utf-8");} catch (UnsupportedEncodingException e){// TODO Auto-generated catch blocke.printStackTrace();}// 只使用了32位int的后8位,作为head中每个字节,因为之后 % 4 了// 实载数据长度int _payload_length = _payload_byte.length;int _first4Byte = 129; // 1000 0001, fin and opcodeint _second4Byte = _payload_length + 128; // 1000 0000, mask,// 第一位是1(mask位),所以后面需要mask// key作为安全需要int _head_FirstPart_length = 2;int _mask_length = 4;int _head_length = _payload_length + _mask_length+ _head_FirstPart_length;// head's byteint[] _head = new int;// mask's byteint[] _mask = new int;_head = _first4Byte;_head = _second4Byte;int _time_ms = (int) System.currentTimeMillis();// mask是个随机数(位),用来加密for (int i = 0; i < 4; i++){_mask = _time_ms % 255;}// 把mask key放进headfor (int i = 0, j = _head_FirstPart_length; i < _mask.length; i++, j++){_head = _mask;}for (int i = 0, j = _mask_length + _head_FirstPart_length; i < _payload_length; i++, j++){_head = _payload_byte ^ _mask;}byte[] _payload_byte_protocol = new byte;for (int i = 0; i < _head_length; i++){_payload_byte_protocol = (byte) (0xff & _head);}String _result = new String(_payload_byte_protocol);System.out.println("pppp:" + _result + " " + _result.length());return _payload_byte_protocol;}}
顺便补充一下握手部分,这个简化了比以前而且网上好多,一般都是看乱码部分吧
package server.io.client;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import org.apache.commons.codec.binary.Base64;import sun.misc.BASE64Encoder;public class HandShake {private MessageDigest m_sha1 = null;public HandShake() {// TODO Auto-generated constructor stubtry {m_sha1 = MessageDigest.getInstance("SHA-1");} catch (NoSuchAlgorithmException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public String createKey(String content) {String _outBase64Key = null;String[] _each = content.split("\r\n");for (int i = 0; i < _each.length; i++) {if (_each.contains("Sec-WebSocket-Key")) {String _comekey = _each.split(": ");String _fixkey = _comekey+ "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";// 转换成bytebyte[] _outkey_byte = _fixkey.getBytes();m_sha1.update(_outkey_byte);byte[] _outShaKey = m_sha1.digest();_outBase64Key = new String(Base64.encodeBase64(_outShaKey));//BASE64Encoder base64en = new BASE64Encoder();//_outBase64Key = base64en.encode(_outShaKey);System.out.println(_outBase64Key);}}return _outBase64Key;}public byte[] createProtocal(String content){String _base64Key = createKey(content);System.out.println("_base64key:" + _base64Key);String _protocal = "";_protocal = _protocal+ "HTTP/1.1 101 Switching Protocols\r\n"+ "Upgrade: websocket\r\n"+ "Connection: Upgrade\r\n"+ "Sec-WebSocket-Accept: " + _base64Key+ "\r\n\r\n";byte[] _outProtocal = _protocal.getBytes();return _outProtocal;}}
总结:
1.第13版的send()不再是什么数据包头尾\x00 \xff了,而是用了全新的协议头,也不再是什么utf-8这么高级的编码发过来了,是二进制流(更好控制不解释)
Kisme 求各种交流
页:
[1]