这到底是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" onclick="conn.send('123');"/>
</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[0];
byte _secondByte = data[1];
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 block
e.printStackTrace();
}
} // not masked and opcode text
int[] mask = new int[4];
for (int i = 2; i < 6; i++)
{
mask[i - 2] = data[i];
}
int _payloadOffset = 6;
int dataLength = _payloadSize + _payloadOffset;
int _payload_int_Length = dataLength - _payloadOffset;
int[] _payload_int = new int[_payload_int_Length];
for (int i = _payloadOffset; i < dataLength; i++)
{
int j = i - _payloadOffset;
int _unmaskPL = data[i] ^ mask[j % 4];
_payload_int[j] = _unmaskPL;
}
byte[] _payload_byte = new byte[_payload_int.length];
for (int i = 0; i < _payload_int.length; i++)
{
byte _eachByte = (byte) (0xff & _payload_int[i]);
_payload_byte[i] = _eachByte;
// _payload_byte[i + 0] = (byte) (0xff & _payload_int[i]);
// _payload_byte[i + 1] = (byte) ((0xff00 & _payload_int[i]) >> 8);
// _payload_byte[i + 2] = (byte) ((0xff0000 & _payload_int[i]) >>
// 16);
// _payload_byte[i + 3] = (byte) ((0xff000000 & _payload_int[i]) >>
// 24);
}
String _result = new String(_payload_byte);
System.out.println("ssss:" + _result + " " + _result.length());
return _result;
}
public static byte[] WSP13Encode(String data)
{
// 一次最多127k,内容就只有125k,协议头2k
if (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 block
e.printStackTrace();
}
// 只使用了32位int的后8位,作为head中每个字节,因为之后 % 4 了
// 实载数据长度
int _payload_length = _payload_byte.length;
int _first4Byte = 129; // 1000 0001, fin and opcode
int _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 byte
int[] _head = new int[_head_length];
// mask's byte
int[] _mask = new int[_mask_length];
_head[0] = _first4Byte;
_head[1] = _second4Byte;
int _time_ms = (int) System.currentTimeMillis();
// mask是个随机数(位),用来加密
for (int i = 0; i < 4; i++)
{
_mask[i] = _time_ms % 255;
}
// 把mask key放进head
for (int i = 0, j = _head_FirstPart_length; i < _mask.length; i++, j++)
{
_head[j] = _mask[i];
}
for (int i = 0, j = _mask_length + _head_FirstPart_length; i < _payload_length; i++, j++)
{
_head[j] = _payload_byte[i] ^ _mask[i % 4];
}
byte[] _payload_byte_protocol = new byte[_head_length];
for (int i = 0; i < _head_length; i++)
{
_payload_byte_protocol[i + 0] = (byte) (0xff & _head[i]);
}
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 stub
try {
m_sha1 = MessageDigest.getInstance("SHA-1");
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.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[i].contains("Sec-WebSocket-Key")) {
String _comekey = _each[i].split(": ")[1];
String _fixkey = _comekey
+ "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
// 转换成byte
byte[] _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 求各种交流