RFC文档地址:http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76。
原来的程序在GOOGLE的CHROME中使用WEBSOCKET通讯是没有问题,但有一次发现原来的程序在没有改动的情况下,在CHROME里面使用WEBSOCKET是,建立不了连接了,刚开始还以为是不小心改动了程序,后面经过仔细排查,终于发现是WEBSOCKET协议变了的原因,随着CHROME升级的时候一起就升级了。
现在最新的WEBSOCKET协议为76号协议,它较原来的协议比较,增加了安全性方面的验证,要求服务在接到握手请求后,必须返回三个要素给客户端确认,两个信息分类来自Sec-WebSocket-Key1及Sec-WebSocket-Key2中的去除其它字符后的所有数字拼装串,除以其本身的空格后的各32位,第三部份是是后8个字节,再加MD5加密后,返回给客户端,然后客户端确认后,才算握手成功。
以上提到的内容,参看协议文档中的“1.3. Opening handshake”
以下是一个JAVA示例,通过NETTY根据请求,组装WEBSOCKET握手返回的源代码实现:
private HttpResponse buildWebSocketRes(HttpRequest req) {
HttpResponse res = new DefaultHttpResponse(HttpVersion.HTTP_1_1,
new HttpResponseStatus(101, "Web Socket Protocol Handshake"));
res.addHeader(HttpHeaders.Names.UPGRADE, HttpHeaders.Values.WEBSOCKET);
res.addHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.UPGRADE);
// Fill in the headers and contents depending on handshake method.
if (req.containsHeader(Names.SEC_WEBSOCKET_KEY1) && req.containsHeader(Names.SEC_WEBSOCKET_KEY2)) {
// New handshake method with a challenge:
res.addHeader(Names.SEC_WEBSOCKET_ORIGIN, req.getHeader(Names.ORIGIN));
res.addHeader(Names.SEC_WEBSOCKET_LOCATION, getWebSocketLocation(req));
String protocol = req.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
if (protocol != null) {
res.addHeader(Names.SEC_WEBSOCKET_PROTOCOL, protocol);
}
// Calculate the answer of the challenge.
String key1 = req.getHeader(Names.SEC_WEBSOCKET_KEY1);
String key2 = req.getHeader(Names.SEC_WEBSOCKET_KEY2);
int a = (int) (Long.parseLong(filterNonNumeric(key1)) / filterNonSpace(key1).length());
int b = (int) (Long.parseLong(filterNonNumeric(key2)) / filterNonSpace(key2).length());
long c = req.getContent().readLong();
ChannelBuffer input = ChannelBuffers.buffer(16);
input.writeInt(a);
input.writeInt(b);
input.writeLong(c);
ChannelBuffer output = null;
try {
output = ChannelBuffers.wrappedBuffer(MessageDigest.getInstance("MD5").digest(input.array()));
} catch (NoSuchAlgorithmException e) {
if (logger.isInfoEnabled()) {
logger.info("no such Algorithm : MD5. " + e);
}
e.printStackTrace();
}
res.setContent(output);
} else {
// Old handshake method with no challenge:
res.addHeader(Names.WEBSOCKET_ORIGIN, req.getHeader(Names.ORIGIN));
res.addHeader(Names.WEBSOCKET_LOCATION, getWebSocketLocation(req));
String protocol = req.getHeader(Names.WEBSOCKET_PROTOCOL);
if (protocol != null) {
res.addHeader(Names.WEBSOCKET_PROTOCOL, protocol);
}
}
return res;
}
/**
* 过滤掉非数字的字符<br>
* 例如:str="uis sdj13 e8 kj*<ks90ao",则返回"13890"
*
* @param str
* @return 过滤后的字符串.如果str为空,则直接返回str
*/
public static String filterNonNumeric(String str) {
if (StringUtil.isEmpty(str)) {
return str;
}
StringBuffer sb = new StringBuffer();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (NumberUtils.isNumber(String.valueOf(c))) {//NumberUtils是org.apache.commons.lang.math.NumberUtils
sb.append(c);
}
}
return sb.toString();
}
/**
* 过滤掉非空格的字符<br>
* 例如:str="uis sdj13 e8 kj*<ks90ao",则返回" "
*
* @param str
* @return 过滤后的字符串.如果str为空,则直接返回str
*/
public static String filterNonSpace(String str) {
if (StringUtil.isEmpty(str)) {
return str;
}
StringBuffer sb = new StringBuffer();
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (" ".equals(String.valueOf(c))) {
sb.append(c);
} else {
sb.append("");
}
}
return sb.toString();
}
分享到:
相关推荐
用Netty实现的Spring-boot-protocol将springboot的WebServer更改为NettyTcpServer,为用户扩展了网络编程的能力。多协议服务器,Springboot协议扩展包,允许单端口提供多协议服务。其中内置多个网络传输(标准与规范...
jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...
jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...
5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...
5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...
jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...
jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...
jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...
jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...
jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...
jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...
jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...
jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...
jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...
jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...
jSIP这个Java包目标是用Java实现SIP(SIP:Session Initiation Protocol)协议及SIP协议的其它扩展部 分。 Java表达式语法解析库 parboiled parboiled 是一个纯Java库提供了一种轻量级,易于使用,功能强大和优雅的PEG...