WebScoket 规范

WebScoket 规范

4.1 握手协议

websocket 是 独立的基于TCP的协议, 其跟http协议的关系仅仅是 WebSocket 的握手被http 服务器当做 Upgrade request http包处理。 websocket 有自己的握手处理。 TCP连接建立后,client 发送websocket 握手请求. 请求包需求如下:

  • 必须是有效的http request 格式
  • HTTP request method 必须是GET,协议应不小于1.1 如: Get /chat HTTP/1.1
  • 必须包括Upgrade 头域,并且其值为“websocket”
  • 必须包括"Connection" 头域,并且其值为 "Upgrade"
  • 必须包括"Sec-WebSocket-Key"头域,其值采用base64编码的随机16字节长的字符序列, 服务器端根据该域来判断client 确实是websocket请求而不是冒充的,如http。响应方式是,首先要获取到请求头中的Sec-WebSocket-Key的值,再把这一段GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"加到获取到的Sec-WebSocket-Key的值的后面,然后拿这个字符串做SHA-1 hash计算,然后再把得到的结果通过base64加密,就得到了返回给客户端的Sec-WebSocket-Accept的http响应头的值。
  • 如果请求来自浏览器客户端,还必须包括Origin头域 。 该头域用于防止未授权的跨域脚本攻击,服务器可以从Origin决定是否接受该WebSocket连接。
  • 必须包括"Sec-webSocket-Version" 头域,当前值必须是13.
  • 可能包括"Sec-WebSocket-Protocol",表示client(应用程序)支持的协议列表,server选择一个或者没有可接受的协议响应之。
  • 可能包括"Sec-WebSocket-Extensions", 协议扩展, 某类协议可能支持多个扩展,通过它可以实现协议增强
  • 可能包括任意其他域,如cookie

示例如下:

        GET /chat HTTP/1.1
        Host: server.example.com
        Upgrade: websocket
        Connection: Upgrade
        Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
        Origin: http://example.com
        Sec-WebSocket-Protocol: chat, superchat
        Sec-WebSocket-Version: 13

Server 接手到握手请求后应处理该请求包括:

  • 处理请求包括处理GET 方法
  • 验证Upgrader头域
  • 验证Connection 头域
  • 处理Sec-WebSocket-Key头域,方法见上;
  • 处理Sec-WebSocket-Version
  • 处理Origin头域,可选, 浏览器必须发送该头域
  • 处理Sec-WebSocket-Protocol头域,可选
  • 处理Sec-WebSocket-Extensions 头域,可选
  • 处理其他头域,可选
  • Server 发送握手响应,这里只介绍服务器接受该连接情况下,包括:
  • http Status-Line
  • Upgrade 头域 ,值必须是"websocket"
  • Conntion头域,值必须是:“Upgrade”
  • Sec-WebSocket-Accept” 头域,该头域的值即处理Sec-WebSocket-Key" 域后的结果。
  • 可选的"Sec-WebSocket-Protocol"头域
  • 可选的"Sec-WebSocket-Extensions"头域

响应可能如下:

        HTTP/1.1 101 Switching Protocols
        Upgrade: websocket
        Connection: Upgrade
        Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
        Sec-WebSocket-Protocol: chat
4.2 数据传输

该节主要参考了 http://blog.csdn.net/fenglibing/article/details/6852497。  在WebSocket 协议中,使用序列frames方式来传输数据。一个frame的标准格式如下:

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-------+-+-------------+-------------------------------+
     |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
     |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
     |N|V|V|V|       |S|             |   (if payload len==126/127)   |
     | |1|2|3|       |K|             |                               |
     +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
     |     Extended payload length continued, if payload len == 127  |
     + - - - - - - - - - - - - - - - +-------------------------------+
     |                               |Masking-key, if MASK set to 1  |
     +-------------------------------+-------------------------------+
     | Masking-key (continued)       |          Payload Data         |
     +-------------------------------- - - - - - - - - - - - - - - - +
     :                     Payload Data continued ...                :
     + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
     |                     Payload Data continued ...                |
     +---------------------------------------------------------------+

FIN:1位,是否是消息的结束帧(分片)

RSV1, RSV2, RSV3: 分别都是1位, 预留,用于约定自定义协议。 如果双方之间没有约定自定义协议,那么这几位的值都必须为0,否则必须断掉WebSocket连接;

Opcode:4位操作码,定义有效负载数据,如果收到了一个未知的操作码,连接也必须断掉,以下是定义的操作码:

%x0 表示连续消息分片
%x1 表示文本消息分片

%x2 表未二进制消息分片

%x3-7 为将来的非控制消息片断保留的操作码

%x8 表示连接关闭  %x9 表示心跳检查的ping

%xA 表示心跳检查的pong

%xB-F 为将来的控制消息片断的保留操作码

Mask: 定义传输的数据是否有加掩码,如果设置为1,掩码键必须放在masking-key区域,客户端发送给服务端的所有消息,此位的值都是1;

Payload length: 传输数据的长度,以字节的形式表示:7位、7+16位、或者7+64位。如果这个值以字节表示是0-125这个范围,那这个值就表示传输数据的长度;如果这个值是126,则随后的两个字节表示的是一个16进制无符号数,用来表示传输数据的长度;如果这个值是127,则随后的是8个字节表示的一个64位无符合数,这个数用来表示传输数据的长度。多字节长度的数量是以网络字节的顺序表示。负载数据的长度为扩展数据及应用数据之和,扩展数据的长度可能为0,因而此时负载数据的长度就为应用数据的长度。注意Payload length不包括Masking-key在内。

Masking-key: 0或4个字节,客户端发送给服务端的数据,都是通过内嵌的一个32位值作为掩码的;掩码键只有在掩码位设置为1的时候存在。 数据Mask方法是,第 i byte 数据 = orig-data ^ (i % 4) .

Payload data: (x+y)位,负载数据为扩展数据及应用数据长度之和。

Extension data:x位,如果客户端与服务端之间没有特殊约定,那么扩展数据的长度始终为0,任何的扩展都必须指定扩展数据的长度,或者长度的计算方式,以及在握手时如何确定正确的握手方式。如果存在扩展数据,则扩展数据就会包括在负载数据的长度之内。

Application data:y位,任意的应用数据,放在扩展数据之后,应用数据的长度=负载数据的长度-扩展数据的长度。

把消息分片处理主要是处于以下两个原因:

  • 消息接收方事先并不知道消息大小, 而且也没必要预留一个足够大的buffer来处理;
  • multiplexing

消息分片一些规则如下(不全):

  • 为分片消息(single-frame) 其FIN置为1,并且opcode code 不是 0;
  • 分片消息序列如下, 第一帧FIN置为0,opcode code不是0; 接着是FIN置为0,opcode code也是0; 最后帧 FIN为1,opcode code为0.
  • 在分片消息发送期间可能插入了控制帧
  • 控制帧不能分片

控制帧的opcode符号位为1, 目前控制帧包括 0×8(Close), 0×9(Ping) 0xA (Pong). 0xB-0xF 被预留。

详细解析如下,来自http://blog.csdn.net/fenglibing/article/details/6852497

   ws-frame                = frame-fin
                             frame-rsv1
                             frame-rsv2
                             frame-rsv3
                             frame-opcode
                             frame-masked
                             frame-payload-length
                             [ frame-masking-key ]
                             frame-payload-data
   frame-fin               = %x0 ; 表示这不是当前消息的最后一帧,后面还有消息
                           / %x1 ; 表示这是当前消息的最后一帧
   frame-rsv1              = %x0
                             ; 1 bit, 如果没有扩展约定,该值必须为0
   frame-rsv2              = %x0
                             ; 1 bit, 如果没有扩展约定,该值必须为0
   frame-rsv3              = %x0
                             ; 1 bit, 如果没有扩展约定,该值必须为0
   frame-opcode            = %x0 ; 表示这是一个连续帧消息
                           / %x1 ; 表示文本消息
                           / %x2 ; 表示二进制消息
                           / %x3-7 ; 保留
                           / %x8 ; 表示客户端发起的关闭
                           / %x9 ; ping(用于心跳)
                           / %xA ; pong(用于心跳)
                           / %xB-F ; 保留
   frame-masked            = %x0 ; 数据帧没有加掩码,后面没有掩码key
                           / %x1 ; 数据帧加了掩码,后面有掩码key
   frame-payload-length    = %x00-7D
                           / %x7E frame-payload-length-16
                           / %x7F frame-payload-length-63
			   ; 表示数据帧的长度
   frame-payload-length-16 = %x0000-FFFF
			   ; 表示数据帧的长度
   frame-payload-length-63 = %x0000000000000000-7FFFFFFFFFFFFFFF
			   ; 表示数据帧的长度
   frame-masking-key       = 4( %0x00-FF ) ; 掩码key,只有当掩码位为1时出现
   frame-payload-data      = (frame-masked-extension-data
                              frame-masked-application-data)  
                  ; 当掩码位为1时,这里的数据为带掩码的数据,扩展数据及应用数据都带掩码
                           / (frame-unmasked-extension-data
                              frame-unmasked-application-data) ;
                 当掩码位为0时,这里的数据为不带掩码的数据,扩展数据及应用数据都不带掩码

   frame-masked-extension-data     = *( %x00-FF ) ; 目前保留,以后定义
   frame-masked-application-data   = *( %x00-FF )
   frame-unmasked-extension-data   = *( %x00-FF ) ; 目前保留,以后定义
   frame-unmasked-application-data = *( %x00-FF )

 

Close 处理

Close 帧的opcode是0×8. 接收到 Close 帧后,如果之前没发送过Close帧,则其必须发送Close 帧响应,但其可以延迟发送Close响应帧,例如在其发送完数据之后发送;但是,协议不保证对方在发送Close 帧后仍会处理其后续的数据。Close帧可能Client发起也可能是Server发起。

Ping-Pong 帧

接收到Ping帧后将响应Pong帧, 主要用于检测网络连接情况。

Extensions

WebSocket 支持协议扩展。 例如增加一个认证处理或者速率控制等,这通过client-server 协商完成。在WebSocket 握手处理时,通过头域Sec-WebSocket-Extensions来完成协商。 例如:

Sec-WebSocket-Extensions: mux; max-channels=4; flow-control,
          deflate-stream

服务器接收一个或多个extensiions 通过再起响应的Sec-WebSocket-Extensions头域增加一个或多个extension完成。

 

说明:

 

服务器建立成功之后,如果有客户端请求连接本服务器,需要用socket_accept等方法建立一个新的socket连接,并接收客户端的请求信息,处理之后,返回响应信息,然后握手成功。  

接下来是字符串通信,客户端send过来一段字符串信息,服务器端接收到并返回给客户端这个字符串。   首先我们处理接收到的信息,根据上篇文章介绍的数据传输格式,并firefox的FIN一直为1,RSV1,2,3为0,如果是文本消息,那么opcode为1,所以数据包的第一个数据是0x81,然后是一位mask值,firefox发来的数据是加了掩码的,所以mask值为1,后面跟7位是数据信息长度,我们以客户端发送hi为例,那么长度就是2个字节,则第二个数据就是0x82,这里没有约定扩展数据,所以不存在扩展数据长度字节,接下来是4个数据的掩码(因为我们这里是发送hi,2个字节的信息,小于125个字节,所以掩码是第3-第6个数据,根据数据长度的不同,掩码的位置也不同,如果取到那7位表示的值是126,则掩码为第5-第8个数据,如果取到那7位表示的值是127,则掩码为第11-第14个数据),后面跟客户端发送的内容数据,处理接收到的数据我们需要用取到的掩码依次轮流跟内容数据做异或(^)运算,第一个内容数据与第一个掩码异或,第二个内容数据与第二个掩码异或……第五个内容数据与第一个掩码异或……以此类推,一直到结束,然后对内容进行编码。

 

根据数据长度的不同,掩码的位置也不同:

从第9个字节开始是 1111101=125,掩码是第3-第6个数据

从第9个字节开始是 1111110=126,掩码是第5-第8个数据

从第9个字节开始是 1111111=126,掩码是第11-第14个数据

 

举例一:

复制代码
 1 hi
 2 1000000110000010 1101011011101001
 3 111110 111000 10111110 10000000
 4 111110 111001 11010110 11101001
 5                1101000  1101001
 6                
 7         [0]    129    byte
 8         [1]    130    byte
 9         [2]    214    byte
10         [3]    233    byte
11         [4]    62     byte
12         [5]    56     byte
13         [6]    190     byte
14         [7]    128     byte
15 
16 
17 1234567890                 
18         [0]    129    byte
19         [1]    138    byte
20         
21         [2]    108    byte
22         [3]    255    byte
23         [4]    86    byte
24         [5]    166    byte
25         
26         [6]    93    byte
27         [7]    205    byte
28         [8]    101    byte
29         [9]    146    byte
30         [10]    89    byte
31         [11]    201    byte
32         [12]    97    byte
33         [13]    158    byte
34         [14]    85    byte
35         [15]    207    byte
复制代码


 举例二:

 

复制代码
  1 01234567890123456789012345678901234567890123456789
  2 01234567890123456789012345678901234567890123456789
  3 01234567890123456789012345678901234567890123456789
  4 01234567890123456789012345678901234567890123456789
  5 
  6 01234567890123456789012345678901
  7 10000001111111100110010011001101
  8 
  9         [0]    129    byte
 10         [1]    254    byte
 11         [2]    0    byte
 12         [3]    201    byte
 13         
 14         [4]    77    byte
 15         [5]    175    byte
 16         [6]    124    byte
 17         [7]    107    byte
 18         
 19         [8]    125    byte
 20         [9]    158    byte
 21         [10]    78    byte
 22         [11]    88    byte
 23         [12]    121    byte
 24         [13]    154    byte
 25         [14]    74    byte
 26         [15]    92    byte
 27         [16]    117    byte
 28         [17]    150    byte
 29         [18]    76    byte
 30         [19]    90    byte
 31         [20]    127    byte
 32         [21]    156    byte
 33         [22]    72    byte
 34         [23]    94    byte
 35         [24]    123    byte
 36         [25]    152    byte
 37         [26]    68    byte
 38         [27]    82    byte
 39         [28]    125    byte
 40         [29]    158    byte
 41         [30]    78    byte
 42         [31]    88    byte
 43         [32]    121    byte
 44         [33]    154    byte
 45         [34]    74    byte
 46         [35]    92    byte
 47         [36]    117    byte
 48         [37]    150    byte
 49         [38]    76    byte
 50         [39]    90    byte
 51         [40]    127    byte
 52         [41]    156    byte
 53         [42]    72    byte
 54         [43]    94    byte
 55         [44]    123    byte
 56         [45]    152    byte
 57         [46]    68    byte
 58         [47]    82    byte
 59         [48]    125    byte
 60         [49]    158    byte
 61         [50]    78    byte
 62         [51]    88    byte
 63         [52]    121    byte
 64         [53]    154    byte
 65         [54]    74    byte
 66         [55]    92    byte
 67         [56]    117    byte
 68         [57]    150    byte
 69         [58]    76    byte
 70         [59]    90    byte
 71         [60]    127    byte
 72         [61]    156    byte
 73         [62]    72    byte
 74         [63]    94    byte
 75         [64]    123    byte
 76         [65]    152    byte
 77         [66]    68    byte
 78         [67]    82    byte
 79         [68]    125    byte
 80         [69]    158    byte
 81         [70]    78    byte
 82         [71]    88    byte
 83         [72]    121    byte
 84         [73]    154    byte
 85         [74]    74    byte
 86         [75]    92    byte
 87         [76]    117    byte
 88         [77]    150    byte
 89         [78]    76    byte
 90         [79]    90    byte
 91         [80]    127    byte
 92         [81]    156    byte
 93         [82]    72    byte
 94         [83]    94    byte
 95         [84]    123    byte
 96         [85]    152    byte
 97         [86]    68    byte
 98         [87]    82    byte
 99         [88]    125    byte
100         [89]    158    byte
101         [90]    78    byte
102         [91]    88    byte
103         [92]    121    byte
104         [93]    154    byte
105         [94]    74    byte
106         [95]    92    byte
107         [96]    117    byte
108         [97]    150    byte
109         [98]    76    byte
110         [99]    90    byte
111         [100]    127    byte
112         [101]    156    byte
113         [102]    72    byte
114         [103]    94    byte
115         [104]    123    byte
116         [105]    152    byte
117         [106]    68    byte
118         [107]    82    byte
119         [108]    125    byte
120         [109]    158    byte
121         [110]    78    byte
122         [111]    88    byte
123         [112]    121    byte
124         [113]    154    byte
125         [114]    74    byte
126         [115]    92    byte
127         [116]    117    byte
128         [117]    150    byte
129         [118]    76    byte
130         [119]    90    byte
131         [120]    127    byte
132         [121]    156    byte
133         [122]    72    byte
134         [123]    94    byte
135         [124]    123    byte
136         [125]    152    byte
137         [126]    68    byte
138         [127]    82    byte
139         [128]    125    byte
140         [129]    158    byte
141         [130]    78    byte
142         [131]    88    byte
143         [132]    121    byte
144         [133]    154    byte
145         [134]    74    byte
146         [135]    92    byte
147         [136]    117    byte
148         [137]    150    byte
149         [138]    76    byte
150         [139]    90    byte
151         [140]    127    byte
152         [141]    156    byte
153         [142]    72    byte
154         [143]    94    byte
155         [144]    123    byte
156         [145]    152    byte
157         [146]    68    byte
158         [147]    82    byte
159         [148]    125    byte
160         [149]    158    byte
161         [150]    78    byte
162         [151]    88    byte
163         [152]    121    byte
164         [153]    154    byte
165         [154]    74    byte
166         [155]    92    byte
167         [156]    117    byte
168         [157]    150    byte
169         [158]    76    byte
170         [159]    90    byte
171         [160]    127    byte
172         [161]    156    byte
173         [162]    72    byte
174         [163]    94    byte
175         [164]    123    byte
176         [165]    152    byte
177         [166]    68    byte
178         [167]    82    byte
179         [168]    125    byte
180         [169]    158    byte
181         [170]    78    byte
182         [171]    88    byte
183         [172]    121    byte
184         [173]    154    byte
185         [174]    74    byte
186         [175]    92    byte
187         [176]    117    byte
188         [177]    150    byte
189         [178]    76    byte
190         [179]    90    byte
191         [180]    127    byte
192         [181]    156    byte
193         [182]    72    byte
194         [183]    94    byte
195         [184]    123    byte
196         [185]    152    byte
197         [186]    68    byte
198         [187]    82    byte
199         [188]    125    byte
200         [189]    158    byte
201         [190]    78    byte
202         [191]    88    byte
203         [192]    121    byte
204         [193]    154    byte
205         [194]    74    byte
206         [195]    92    byte
207         [196]    117    byte
208         [197]    150    byte
209         [198]    76    byte
210         [199]    90    byte
211         [200]    127    byte
212         [201]    156    byte
213         [202]    72    byte
214         [203]    94    byte
215         [204]    123    byte
216         [205]    152    byte
217         [206]    68    byte
218         [207]    82    byte
219         [208]    71    byte
复制代码

 

 

代码分析掩码:

复制代码
 1 /// <summary>
 2 ///判断传入数据是否存在掩码
 3 /// 传入数据:hi
 4 /// socket接收到的二进制数据:
 5 ///      1000000110000010 1101011011101001
 6 ///      111110 111000 10111110 10000000
 7 /// 掩码异或的操作:
 8 ///             111110 111000 10111110 10000000
 9 ///   进行异或^ 111110 111001 11010110 11101001 
10 ///    结果:                   1101000  1101001
11 /// 数据样例:
12 ///        [0]    129    byte
13 ///        [1]    130    byte
14 ///        [2]    214    byte
15 ///        [3]    233    byte
16 ///        [4]    62     byte
17 ///        [5]    56     byte
18 ///        [6]    190     byte
19 ///        [7]    128     byte
20 /// </summary>
21 /// <returns></returns>
22         private string UnWrap()
23         {
24             string result = string.Empty;
25 
26             // 计算非空位置
27             int lastStation = GetLastZero();
28 
29             // 利用掩码对org-data进行异或
30             int frame_masking_key = 1;
31             for (int i = 6; i <= lastStation; i++)
32             {
33                 frame_masking_key = i % 4;
34                 frame_masking_key = frame_masking_key == 0 ? 4 : frame_masking_key;
35                 frame_masking_key = frame_masking_key == 1 ? 5 : frame_masking_key;
36                 receivedDataBuffer[i] = Convert.ToByte(receivedDataBuffer[i] ^ receivedDataBuffer[frame_masking_key]);
37             }
38 
39             System.Text.UTF8Encoding decoder = new System.Text.UTF8Encoding();
40             result = decoder.GetString(receivedDataBuffer, 6, lastStation - 6 + 1);
41 
42             return result;
43 
44         }
复制代码

 

 

复制代码
 1 /// <summary>
 2 /// 对传入数据进行无掩码转换
 3 /// </summary>
 4 /// <returns></returns>
 5         public static byte[] Wrap(string msg, int maxBufferSize)
 6         {
 7             // 掩码开始位置
 8             int masking_key_startIndex = 2;
 9 
10             byte[] msgByte = Encoding.UTF8.GetBytes(msg);
11 
12             // 计算掩码开始位置
13             if (msgByte.Length <= 125)
14             {
15                 masking_key_startIndex = 2;
16             }
17             else if (msgByte.Length > 65536)
18             {
19                 masking_key_startIndex = 10;
20             }
21             else if (msgByte.Length > 125)
22             {
23                 masking_key_startIndex = 4;
24             }
25 
26             // 创建返回数据
27             byte[] result = new byte[msgByte.Length + masking_key_startIndex];
28 
29             // 开始计算ws-frame
30         // frame-fin + frame-rsv1 + frame-rsv2 + frame-rsv3 + frame-opcode
31             result[0] = 0x81;       // 129
32 
33             // frame-masked+frame-payload-length
34             // 从第9个字节开始是 1111101=125,掩码是第3-第6个数据
35             // 从第9个字节开始是 1111110>=126,掩码是第5-第8个数据
36             if (msgByte.Length <= 125)
37             {
38                 result[1] = Convert.ToByte(msgByte.Length);
39             }
40             else if (msgByte.Length > 65536)
41             {
42                 result[1] = 0x7F;   // 127
43             }
44             else if (msgByte.Length > 125)
45             {
46                 result[1] = 0x7E;   // 126
47                 result[2] = Convert.ToByte(msgByte.Length >> 8);
48                 result[3] = Convert.ToByte(msgByte.Length % 256);
49             }
50 
51             // 将数据编码放到最后
52             Array.Copy(msgByte, 0, result, masking_key_startIndex, msgByte.Length);
53 
54             return result;
55         }
复制代码



 

 WebSocket 协议:

 

复制代码
public enum WebSocketProtocol
    {
        /*
         * 
         * Request
            GET /WebIM5?uaid=200513807p8912-8de8c7e2-c963-4f67-8aca-8028797efbc1&re=0 HTTP/1.1
            Upgrade: WebSocket
            Connection: Upgrade
            Host: 10.10.150.60:5002
            Origin: https://localhost:444
            Sec-WebSocket-Key1: 3+3 1  8kgV"m 0 8  64u43
            Sec-WebSocket-Key2: 3_7891 6 4 `50 `8
         * 
         * Response
            HTTP/1.1 101 WebSocket Protocol Handshake
            Upgrade: WebSocket
            Connection: Upgrade
            Sec-WebSocket-Origin: https://localhost:444
            Sec-WebSocket-Location: ws://192.168.110.....
            Sec-WebSocket-Protocol: WebIM5
         * 
         *  asdfalskdfa
         * */
        draft_00 = 0,

        /*
         * 
         * Request
            GET /WebIM5?uaid=200513807p8912-2e695e5b-9b46-4511-b59e-28981b4ab327&re=0 HTTP/1.1
            Upgrade: websocket
            Connection: Upgrade
            Host: 10.10.150.60:5002
            Origin: https://localhost:444
            Sec-WebSocket-Key: 1o4Jk9XPGvTX66OxmNMaww==
            Sec-WebSocket-Version: 13
         * 
         * Response
            HTTP/1.1 101 Switching Protocols
            Upgrade: websocket
            Connection: Upgrade
            Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
            Sec-WebSocket-Protocol: WebIM5
         * */
        draft_17 = 17
    }
复制代码

 

 支持safari+chrome+firefox:

复制代码
 1 // 开始连接到服务器
 2     var pollingInterval;
 3     _ws = new WebSocket("ws://192.168.0.103:5002/WebIM5?uaid=200513807p8912-5a78ae8a-cabb-46ee-8d8a-85874bbc942c&re=0");
 4     //_ws = new window.MozWebSocket("ws://192.168.0.103:5002/WebIM5?uaid=200513807p8912-5a78ae8a-cabb-46ee-8d8a-85874bbc942c&re=0");
 5     _ws.onopen = function () {
 6         alert("onopen");
 7 
 8         _socketCreated = true;
 9         var args
10         _ws.send("1234567890");
11         _ws.send("33322233");
12     };
13     _ws.onmessage = function (event) {
14         console.log("event.data=" + event.data);
15                     
16     };
17     _ws.onclose = function () {
18         alert("onclose");
19         console.log("onclose");
20     };
21     _ws.onerror = function () {
22         console.log("onerror");
23     };
24     function send() {
25         _ws.send(document.getElementById("msg").value);
26     }
复制代码

 

其中,safari和chrome都是 :_ws = new WebSocket("ws://ip:port");  但是firefox是:_ws = new window.MozWebSocket("ws://ip:port");

 

浏览器方面:

chrome可以查看WebSocket的访问日志: chrome://net-internals/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值