Websocket协议

简介:

1Websocket简介

1WebSocket protocol 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-duplex)。

HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽并达到实时通讯



2Websocket原理

1他是基于TCP SOCKET上添加了一些上层协议。

2很多网站为了实现即时通信, 所用的技术都是轮询(polling), 轮询是在特定的时间间隔(比如1秒),

由浏览器对服务器发出HTTP request,然后由服务器返回最新数据给客户端浏览器,这种传统的HTTP

request的模式带来明显的缺点, 浏览器要不断向服务器发请求, 而HTTP request的header(头信息)非常长,

包含我们要用的数据却很小, 这样会占用很多宽带,

3Websocket API,浏览器和服务器只需要做一个握手的动作,然后浏览器和服务器之间就形成了一条

快速通道, 两者之间就直接可以数据互相传送。这样互相沟通的header还是很小的,大概是2Bytes



3长连接和短连接

长连接: 初始化的时候建立连接,一直不关闭

1服务器与客户端能以最快的速度发送数据

2服务器能主动的向客户端发送数据

3长连接长期占用网络资源

4长连接的服务器不方便直接重启


短连接: 发起连接-->发送数据-->获取数据-->关闭

1不会长期占用资源

2方便服务器直接重启

3每次请求与获取数据都要重新建立连接

4服务器不能像客户端主动发送数据


比如说正常访问百度,一旦连上百度,他就会get网页数据,然后就断开连接了




4websocket 握手连接

1 客户端向服务器发送请求websocket的http报文

然后服务器来验证这个http报文是不是符合websocket的协议

2如果符合,服务器返回握手报文,给客户端连接成功




5使用js写一个客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!DOCTYPE html>
<html>
<head>
     <title>websocket test</title>
</head>
 
<body>
     <script>
         var  ws =  new  WebSocket( 'ws://127.0.0.1:8002/ws' );  
         //socket打开了
         ws.onopen =  function (){
         alert( "open" );
         ws.send( 'WebSocket' );
         };
         
         //websocket有数据过来了
         ws.onmessage =  function (ev){
         alert(ev.data);
         };
         
         //socket关闭了
         ws.onclose =  function (ev){
         alert( "close" );
         };
         
         //websocket有错误发生
         ws.onerror =  function (ev){
         alert( "error" );
         };
     </script>
</body>
</html>

服务器接到http报文

$T(@ST[VX0PKY)3[A})_I@P.png

现在服务器要做的就是验证这个报文了,看他是否符合websocket规范

首先就是Upgrade:websocket  如果不是就要直接关掉这个请求

其中很重要的一点就是:Sec-WebSocket-key

这个key是客户端随机生成的。



6解析http报文

使用c语言的库,http_parser  这个库 百度一下就可下载到

github:https://github.com/nodejs/http-parser  

我们最终要一部分就是要把Sec-WebSocket-key这个值取出来

我们用key+migic的方式,使用SHA-1加密,base-64加密编码

migic是一个固定的值258EAFA5-E914-47DA-95CA-C5AB0DC85B11

然后生成报文发送给客户端,这样他们就建立了websocket的握手连接了.



初始化

1
2
3
4
5
//第一步 借助http_parser,解析客户端给我们发送来的http报文头部
struct  http_parser p;
//初始化  第二个参数是解析类型
//HTTP_REQUEST请求,HTTP_RESPONSE响应,HTTP_BOTH都解析
http_parser_init(&p, HTTP_REQUEST);




解析http的时候 解析到头的时候 用这个结构体回调

http_parser_settings 这个结构体


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct  http_parser_settings {
   http_cb      on_message_begin;   //消息开始的时候
   http_data_cb on_url;             //解析到url的时候回调
   http_data_cb on_status;
   http_data_cb on_header_field;      // key
   http_data_cb on_header_value;      //  值
   http_cb      on_headers_complete;
   http_data_cb on_body;
   http_cb      on_message_complete;
   /* When on_chunk_header is called, the current chunk length is stored
    * in parser->content_length.
    */
   http_cb      on_chunk_header;
   http_cb      on_chunk_complete;
};

要用到这个回调 on_header_field 就是解析key的时候

1
2
3
4
5
6
7
static  int  on_header_field(http_parser* p,  const  char * at,  size_t  length);
static  int  on_header_value(http_parser* p,  const  char * at,  size_t  length);
 
struct  http_parser_settings s;
http_parser_settings_init(&s);  //初始化要用
s.on_header_field = on_header_field;
s.on_header_value = on_header_value;


开始解析http报文  http_str就是你的报文

1
http_parser_execute(&p, &s, http_str,  strlen (http_str));


//解析head报文 key回调函数


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//http 解析回调函数 key
static  int  on_header_field(http_parser* p,  const  char * at,  size_t  length)
{
     strncpy (key_buffer,at,length);
     key_buffer[length] = 0;
     printf ( "%s:" ,key_buffer);
 
 
     return  0;
}
 
 
//http 解析回调函数 value
static  int  on_header_value(http_parser* p,  const  char * at,  size_t  length)
{
     char  buffer[128];
     strncpy (buffer, at, length);
     buffer[length] = 0;
     printf ( "%s\n" ,buffer);
 
     return  0;
}


成功解析出来了  至于怎么拿到想要的 就不用多说了吧

506V_B7WK`)PCGR[J]TOFPM.png


通过加密后然后回给客户端报文


buffer 就是你通过 migic+key通过  sha1 +  base64加密获得的

这两个加密 网上搜索一大堆 c语言写的就行了


//会给客户端的报文

char  accept_str[256];

char* wb_accept = "HTTP/1.1 101 Switching Protocols\r\n" \

"Upgrade:websocket\r\n" \

"Connection:Upgrade\r\n" \

"Sec-WebSocket-Accept:%s\r\n" \

"WebSocket-Location: ws://%s:%d\r\n" \

"WebSocket-Protocol:\r\n\r\n";

sprintf(accept_str, wb_accept, buffer,"127.0.0.1",8002);

printf(accept_str);


//发送给客户端

send(socket, accept_str,strlen(accept_str),0);







7websocket接收数据,

只需要在开始的时候握手,后面就不用去动了2

websocket接收数据的协议

Q~8Z31ZJ$LNH`P2_20ON119.png

1 固定字节(1000 0001 或 1000 0010) 也就是一个字节 十进制:129-130  十六进制:0x81-0x82


2包长度字节,第一位是1,他是固定的 也就是

剩下7位得到一个整数(0,127)数据范围(表示数据的长度);

也就是他125以内就用一个字节表示长度

如果是126就是2个字节表示长度

如果是127就是8个字节表示长度

就是最后面 数据的长度  不包含前面这些的长度


3mask掩码为包长之后的4个字节,掩码后面才是数据,

利用这个掩码,我们可以将这个数据,将他还原回来,

也就是服务器收到的数据实际上,还是要自己还原的.



4兄弟数据: 得到真实数据的方法:将兄弟数据的每一个字节x,和掩码的

的第i%4字节做异或运算,其中i是x在兄弟数据中的索引。

bb.png






8websocket发送数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
static  void 
on_ws_send_data( struct  session*s, unsigned  char * pkg_data,  int  pkg_len)
{
//printf("================send_ws_data============================\n");
//
static  unsigned  char  send_buffer[8096];
//固定的头
send_buffer[0] = 0x81;
unsigned  int  ws_send_len;
if  (pkg_len <= 125){
//最高位是0  不用管
send_buffer[1] = pkg_len;
ws_send_len = 2;
}
else  if  (pkg_len <= 0xffff){  //255
send_buffer[1] = 126;
send_buffer[2] = (pkg_len & 0x000000ff);
send_buffer[3] = (pkg_len & 0x0000ff00>>8);
ws_send_len = 4;
}
else {
send_buffer[1] = 127;
send_buffer[2] = (pkg_len & 0x000000ff);
send_buffer[3] = ((pkg_len & 0x0000ff00) >> 8);
send_buffer[4] = ((pkg_len & 0x00ff0000)>>16 );
send_buffer[5] = ((pkg_len & 0xff000000) >> 24);
send_buffer[6] = 0;
send_buffer[7] = 0;
send_buffer[8] = 0;
send_buffer[9] = 0;
ws_send_len = 10;
}
//原始数据
memcpy (send_buffer + ws_send_len,pkg_data,pkg_len);
ws_send_len += pkg_len;
send(s->c_sock, send_buffer, ws_send_len,0);
//printf("send_len%d\n", pkg_len);
//printf("send_data%s\n", pkg_data);
//printf("============================================\n");
}








 本文转自超级极客51CTO博客,原文链接:http://blog.51cto.com/12158490/2059082,如需转载请自行联系原作者





相关文章
|
4月前
|
网络协议 数据处理
WebSocket协议基础
WebSocket协议基础
35 0
|
4月前
|
XML 存储 网络协议
tcp支持浏览器websocket协议
tcp支持浏览器websocket协议
|
7月前
|
缓存 移动开发 网络协议
WebSocket 协议原理抓包分析
WebSocket 协议原理抓包分析
299 0
|
4月前
|
移动开发 缓存 网络协议
Websocket协议原理及Ws服务器代码实现
Websocket协议原理及Ws服务器代码实现
|
8月前
|
网络协议
百度搜索:蓝易云【websocket和http有什么不同?以及websocket协议如何实现?】
WebSocket和HTTP协议是两种不同的协议,它们在协议设计上有着显著的区别。
63 0
|
4月前
|
网络协议 C++ 数据格式
websocket协议介绍与基于reactor模型的websocket服务器实现
websocket协议介绍与基于reactor模型的websocket服务器实现
61 0
|
10天前
|
前端开发 网络协议 定位技术
WebSocket协议
【5月更文挑战第3天】WebSocket协议,WebSocket的主要应用场景是什么?
38 10
|
11天前
|
网络协议 前端开发 开发者
WebSocket协议
【5月更文挑战第2天】WebSocket协议
21 4
|
3月前
|
前端开发 网络协议 JavaScript
|
4月前
|
网络协议 Linux C++
Linux C/C++ websocket协议与服务器实现
Linux C/C++ websocket协议与服务器实现
77 0