WebSocket握手总结- CHROME与safari区别

经过本人对WebSocket协议的研究和WebSocket服务器的编写,对WebSocket有了深入的了解,在此写个总结供以后研究参考。

本文地址:http://www.hoverlees.com/blog/?p=1413

1.概要

WebSocket是最新提出用于实现服务器与浏览器双向通信的一种解决方案,用于取代一些传统的数据推送方案(如iframe长连接,ajax轮询等)。该方案由于一直在草案阶段,最新的版本为version 13.该版本出现在RFC6455中。而在safari(包括桌面和移动版本)上则是使用的websocket的 draft-ietf-hybi版。照这个趋势看来,WebSocket早晚会向RFC6455的方向定型。

在本文中,称RFC6455版的chrome版,safari使用的版本为safari版。

这两个文件我已经下载下来作为本文附件,可直接参考。chrome版 safari版

2.握手协议

HTTP服务器识别WebSocket协议的方式首先是判断HTTP头中的Connection和Upgrade头,如果Connection是Upgrade,且Upgrade头是WebSocket,则可以确定为WebSocket请求,这时候要进行WebSocket的握手处理,两个版本的握手方式不同,最新的Chrome版本通过Sec-WebSocket-Key的设置进行一些计算返回Sec-WebSocket-Accept响应头,而safari版本通过Sec-WebSocket-Key1,Sec-WebSocket-Key2及请求主体三个共同计算响应主体的。下面进行分别讨论。

chrome版
Sec-WebSocket-Key是客户端随机生成并进行base64的字符串,它的原始内容是什么服务器不需要关心,服务器需要将这个字符串,与”258EAFA5-E914-47DA-95CA-C5AB0DC85B11″这个字符串进行拼接,然后对这个拼接好的字符串进行sha-1运算,再把sha-1散列得到的20字节进行base64编码即为响应头Sec-WebSocket-Accept的值。

safari版

这个版本让人觉得有点意思,有种小学玩数数棍的感觉。下面给个示例请求:

1
2
3
4
Sec-WebSocket-Key1: 18x 6]8vM;54 *(5:  {   U1]8  z [  8
Sec-WebSocket-Key2: 1_ tx7X d  <  nw  334J702) 7]o}` 0
 
Tm[K T2u

首先,我们把Sec-WebSocket-Key1和Sec-WebSocket-Key2中的所有数字从左到右提出来组成一个整数,那么上面的示例可以组成1868545188 和 1733470270两个数。

接下来我们去数两个串各自的空格数,数出来分别为12和10

然后将上面的数除以下面的数,可得到155712099 和 173347027

这两个数是32位的整数,以Big-Endian的方式( 低地址存放最高字节)各保存为4个字节,再与请求体中的8个字节拼接,可以得到一个16字节的串.再对这个串进行md5,md5结果的16字节即作为响应体返回给客户端.
这个示例将返回fQJ,fN/4F4!~K~MH,示例是巧合,实际上返回的内容可以是乱码的.但key中不会出现乱码.

下面是我已经写好的计算响应值的C函数:

/**
  * chrome版websocket响应值计算
  */
void websocket_accept_key( const char * key, int key_len, char * out){
     char tmp[128];
     unsigned char sha[20];
     if (key_len==0) key_len= strlen (key);
     strcpy (tmp,key);
     strcpy (tmp+key_len, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" );
     sha1(tmp,key_len+36,sha);
     base64_encode(sha,20,out);
}
/**
  * safari版websocket响应值计算
  */
void websocket_accept_key_old( const char * key1, int key1Len, const char * key2, int key2Len, char * body, char * out){
     char tmp[16];
     unsigned long long kv1=0;
     unsigned long long kv2=0;
     int c1=0;
     int c2=0;
     int i;
     if (key1Len<=0) key1Len= strlen (key1);
     if (key2Len<=0) key2Len= strlen (key2);
     for (i=0;i<key1Len;i++){
         if (key1[i]>= '0' && key1[i]<= '9' ) kv1=kv1*10+(key1[i]- '0' );
         else if (key1[i]== ' ' ) c1++;
     }
     for (i=0;i<key2Len;i++){
         if (key2[i]>= '0' && key2[i]<= '9' ) kv2=kv2*10+(key2[i]- '0' );
         else if (key2[i]== ' ' ) c2++;
     }
     kv1/=c1;
     kv2/=c2;
     for (i=3;i>=0;i--){
         tmp[i]=kv1&0xff;
         tmp[i+4]=kv2&0xff;
         kv1=kv1>>8;
         kv2=kv2>>8;
     }
     for (i=0;i<8;i++){
         tmp[i+8]=body[i];
     }
     md5(tmp,16,out);
     out[16]=0;
}

为什么要做这么复杂的握手?这是为了让客户端知道这个服务器是否真的支持websocket,因为这个协议本来很像HTTP协议,如果直接向HTTP服务器发起这样的请求,服务器同样会响应并返回Bad request.

3.结论

经过分析可以知道两种方式的握手步骤,对比下来version13版的websocket握手更加简单.目前version13已经正为websocket正式版本,后期的改动应该不会有太多大的变动.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值