`
o0211oo
  • 浏览: 2052 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

关于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" 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 求各种交流

分享到:
评论

相关推荐

    WebSocket协议手册(rfc6455中文翻译).pdf

    WebSocket协议手册(rfc6455中文翻译)详细介绍了...以上总结了rfc6455中文翻译版WebSocket协议手册的核心知识点,提供了关于WebSocket协议的详细技术指导和操作规范,对于理解和实现WebSocket通信具有重要参考价值。

    websocket规范 RFC6455 中文版

    websocket规范 RFC6455 中文版

    WebSocket协议手册(rfc6455英文原版).pdf

    RFC6455是WebSocket协议的官方文档标准版本,由互联网工程任务组(IETF)制定,是互联网标准跟踪文件。 ### WebSocket协议概述 WebSocket协议的主要目的是为了解决传统HTTP协议在需要服务器和客户端双向通信时效率...

    The WebSocket Protocol RFC

    《WebSocket Protocol RFC》是一份重要的技术文档,详细阐述了WebSocket协议的工作原理、设计思路以及具体的实现方式。此文档对于理解并运用WebSocket技术具有重要意义。 ### 背景与目标 随着互联网应用的不断扩展...

    WebSocket协议中英文版pdf

    通过阅读RFC6455中英文版,开发者可以深入理解WebSocket的工作原理,从而更好地在实际项目中运用WebSocket技术,构建高性能的实时交互应用。同时,中英文对照也有助于跨语言团队间的沟通和技术分享。

    WebSocket 协议实现.pdf

    三、WebSocket 协议的数据帧 WebSocket 协议的通信帧分为控制数据帧和普通数据帧两种。控制数据帧用于控制 WebSocket 链接状态,普通数据帧用于承载数据。WebSocket 协议的数据帧格式包括标志位、长度、数据负载等...

    WebSocket协议中文版

    标题和描述中提到的《WebSocket协议中文版》是RFC6455文档的中文翻译版本,该文档详细描述了WebSocket协议的技术细节。WebSocket协议是一种支持客户端和服务器之间进行全双工通信的协议,它允许在web浏览器和服务器...

    WebSocket协议中文完整版.zip

    在“WebSocket协议中文版.pdf”这个文档中,你可以详细了解到WebSocket的协议细节、握手流程、帧结构、错误处理机制以及如何在实际应用中部署和使用WebSocket。这份文档提供了完整的中文目录,方便读者查阅和理解,...

    易语言websocket支持多线程连接代理协议头操作

    本文将深入探讨易语言中关于WebSocket的多线程连接、代理协议头操作以及相关的技术细节。 首先,让我们了解WebSocket的基础特性。WebSocket协议允许客户端与服务器之间建立持久性的连接,进行全双工通信,极大地...

    WebSocket协议中文版.pdf

    WebSocket协议实现在受控环境中运行不受信任代码的一个客户端到一个从该代码已经选择加入通信的远程主机之间的全双工通信。用于这个的安全模型是通常由web浏览器使用的基于来源的安全模型。该协议包括一个打开阶段...

    The WebSocket Protocol-rfc6455

    RFC6455,即《WebSocket协议》,是互联网工程任务组(Internet Engineering Task Force,简称IETF)公布的一份关于WebSocket协议的官方标准文档。WebSocket协议允许运行在受控环境下的客户端与远程主机之间进行双向...

    基于websocket协议的简易视频直播

    WebSocket协议是一种在客户端和服务器之间建立长连接的协议,它为双向通信提供了低延迟、高效的数据传输方式。在传统的HTTP协议中,每次请求-响应都需要重新建立连接,而WebSocket则在连接建立后可以保持长时间打开...

    websocket通讯协议(10版本)简介

    WebSocket协议自2011年被定义为RFC 6455以来,已经发展到10版本,它极大地改善了Web应用程序与服务器之间的交互效率,尤其是在实时性要求高的应用场景中,如在线游戏、股票交易、聊天室、物联网设备控制等。...

    C#实现WebSocket协议客户端和服务器websocket sharp组件实例解析

    WebSocket Sharp 是一个C#实现的WebSocket协议库,它支持客户端和服务端的功能,符合RFC 6455标准。这个组件不仅提供了基本的WebSocket连接管理,还包含了一些高级特性,如消息压缩、安全连接、HTTP身份验证、代理...

    websocket协议中文版

    WebSocket协议定义了六种帧类型,预留了十种类型供未来扩展。 WebSocket协议的开放阶段握手是为了兼容HTTP服务器和中间件,使得在同一个端口上可以同时处理HTTP和WebSocket请求。握手请求模拟了一个HTTP请求,但...

Global site tag (gtag.js) - Google Analytics