Websocket

协议内容

WebSocket协议允许在受控环境中运行不受信任代码的客户端与已选择从该代码进行通信的远程主机之间进行双向通行。为此使用的安全模型是基于原点的安全模型。该协议包括一个开放的握手和基本的消息框架,通过TCP分层。该技术的目标是为基于浏览器的应用程序提供一种机制,该应用程序需要与服务器通信不依赖于打开多个HTTP连接(例如使用XMLHttp请求和http long poll长轮询)
它被设计用于处理HTTP端口80和443,并支持HTTP代理和中介
当客户端和服务器握手成功,然后就开始数据交换。这是一个双向通信通道,独立于另外一方随意发送数据。

解决问题

之前创建客户端和服务器的双向通讯web程序,客户端需要利用http来轮询服务器的更新,但以不同的HTTP调用发生上行信息,这将导致如下问题:
1.服务器被迫为每个客户端使用一些不同的底层TCP连接,一个用于发送消息到客户端,一个用于每一个消息的传如
2.线路层协议有较高的开销,因为每个客户端-服务器消息都有一个HTTP头信息
3.客户端脚本被迫维护一个传出的连接到传入的连接的映射来跟踪回复

设计概念

从概念上讲,WebSocket只是TCP之上的一层,执行以下操作。
1、为浏览器添加一个web基于来源的安全模型
2、添加一个寻址和协议命名机制来支持在一个IP地址的一个端口的多个主机名的多个服务。
3、在TCP之上分一个帧机制层已回到TCP基于的IP包机制,但没有长度限制。
4、包括一个额外的带内(in-band)关闭阶段握手,其被设计来工作在现存的代理和其他中间件。

与TCP和HTTP的区别

WebSocket协议是一个独立的基于TCP的协议。它与HTTP唯一的关系是它的握手是由HTTP服务器解释为一个Upgrade请求。
默认情况下,WebSocket协议使用端口80用于常规的WebSocket连接和端口443用于WebSocket连接的在传输层安全(TLS)之上的隧道化。

特点

  1. 建立TCP后的第一个数据,handshake,符合http协议
  2. 握手完成后消息体不需要符合http协议
  3. 于HTTP有交集,并支持HTTP的代理和中介

客户端发送的握手协议

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

GET /chat HTTP/1.1:表示请求的是websocket的子协议chat
Origin:用于保护防止未授权的被浏览器中使用WebSocket API的脚本跨域使用WebSocket服务器。服务器收到WebSocket连接请求生成的脚本来源。
Sec-WebSocket-Key:用来表示客户端的密钥
Sec-WebSocket-Protocol:可选字段,服务区可选的协议
Sec-WebSocket-Version:websocket的版本

服务器针对握手的返回内容

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

HTTP/1.1 101 Switching Protocols:101表示websocket握手成功
Upgrade和Connection字段表示完成对HTTP的升级
Sec-WebSocket-Protocol:可选,表示服务器选择的子协议为chat
Sec-WebSocket-Accept: 服务器为了证明收到的握手,服务器必须携带两条信息并组合它们并形成一个响应。 具体而言,如果在上面例子中,|Sec-WebSocket-Key|头字段的值为"dGhlIHNhbXBsZSBub25jZQ==",服务器将连接字符串"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"形成字符串"dGhlIHNhbXBsZSBub25jZQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11"。服务器使用SHA-1散列这个,并产生值0xb3 0x7a 0x4f 0x2c 0xc0 0x62 0x4f 0x16 0x90 0xf6 0x46 0x06 0xcf 0x38 0x59 0x45 0xb2 0xbe 0xc4 0xea。这个值接着使用base64编码(参见[RFC4648]第4章),产生值 “s3pPLMBiTxaQ9kYGzzhZRbK+xOo=”。这个值将接着在|Sec-WebSocket-Accept|头字段中回应。

关闭握手

两个节点中的任一个都能发送一个控制帧与包含一个指定控制序列的数据来开始关闭阶段的握手,当收到这样的一个帧的时候,另一个节点再响应中发送一个close帧,之后再完成TCP关闭握手。
通过发送一个Close帧并等待响应中的Close帧,某些情况下可避免数据不必要的丢失。

websocket URIs

ws-URI = “ws:” “//” host [ “:” port ] path [ “?” query ]
wss-URI = “wss:” “//” host [ “:” port ] path [ “?” query ]
port:可选,WS默认的端口是80,WSS默认的端口是443
path:路径组件,"/“表示为空
query:查询组件,”?"表示查询组件不为空

消息结构

0                   1                   2                   30 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 1bit 1表示是消息中的最后一个片段,第一个片段也可能是最后一个片段
RSV1 1bit 保留,不使用设置为0
RSV2 1bit 保留,不使用设置为0
RSV3 1bit 保留,不使用设置为0
opcode 4bit 操作码0继续帧1文本帧2二进制帧8关闭9ping10pong
MASk 1bit 0不启用掩码1启用掩码
Payload len 7bit 传输的数据长度
Payload length 16bit 当Payload len=126时,启用ushort的长度
Payload length 64bit 当Payload len=127时,启用uint64_t的长度
Marking-key 32bit 当Mask=1时,存在char[4]的掩码值,0则不存在,后面直接就是跟着数据
Paylaod Data (x+y)bytes 有效负载数据是指扩展数据和应用数据
Extension Data xbytes 除非协商过扩展,否则为0
Application Data ybytes 占用后面的所有字段,长度等于有效负载长度-扩展长度

操作码

占用字节 说明
0x0 表示一个持续帧
0x1 表示一个文本帧
0x2 表示一个二进制帧
0x3-7 预留给以后的非控制帧
0x8 表示一个连接关闭包
0x9 表示一个ping包
0xA 表示一个pong包
0xB- F 预留给以后的控制帧

掩码

websocket中掩码时单向的,只有客户端发送的时候需要对掩码进行设置,服务端发送的时候Mask设置为

消息帧头的组成

typedef struct _ws_ophdr {unsigned char opcode:4,//操作符rsv3:1,rsv2:1,rsv1:1,fin:1;//最有一个消息帧unsigned char pl_len:7,//payload的长度mask:1;//是否开启掩码
} ws_ophdr;//payload_len=126时启用, payload_length=ushot
typedef struct _ws_head_126 {unsigned short payload_length;char mask_key[4];
} ws_head_126;//payload_len=127时启用, payload_length=longlong
typedef struct _ws_head_127 {long long payload_length;char mask_key[4];
} ws_head_127;

服务端发送数据程序实现

ws_ophdr ophdr;
memset(&ophdr, 0, sizeof(ws_ophdr));
ophdr.opcode = (unsigned char)1;
ophdr.fin = (unsigned char)1;
ophdr.mask = (unsigned char)1;
ophdr.pl_len = 5;
memset(ev->buffer, 0, BUFFER_LENGTH);
memcpy(ev->buffer, &ophdr, sizeof(ws_ophdr));
char data[25] = "12345";
strcat(ev->buffer + sizeof(ws_ophdr), data);
len = send(fd, ev->buffer, strlen(ev->buffer), 0);

客户端解析程序实现

void umask(char* payload, int length, char *mask_key) {int i = 0;for(i = 0; i < length; i++) {payload[i] ^= mask_key[i % 4];}
}int transmission(struct ntyevent* ev) {ws_ophdr *hdr = (ws_ophdr*)ev->buffer;printf("length: %d\n", hdr->pl_len);if(hdr->pl_len < 126) {char * payload = ev->buffer + sizeof(ws_ophdr) + 4;if(hdr->mask) {umask(payload, hdr->pl_len, ev->buffer + 2);}printf("opcode: %d\n", hdr->opcode);printf("fin: %d\n", hdr->fin);printf("mask: %d\n", hdr->mask);printf("payload: %s\n", payload);} else if(hdr->pl_len == 126) {} else if(hdr->pl_len == 127) {}return 0;
}

握手程序实现

int handshark(struct ntyevent * ev) {char linebuf[1024] = {0};int idx = 0;char sec_data[128] = {0};char sec_accept[32] = {0};do {memset(linebuf, 0 , 1024);idx = readline(ev->buffer, idx, linebuf);if(strstr(linebuf, "Sec-WebSocket-Key")) {strcat(linebuf, GUID);//Sec-WebSocket-Key: QWz1vB/77j8J8JcT/qtiLQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11SHA1((const unsigned char*)linebuf + WEBSOCK_KEY_LENGTH,strlen(linebuf + WEBSOCK_KEY_LENGTH), (unsigned char*)sec_data);base64_encode(sec_data, strlen(sec_data), sec_accept);memset(ev->buffer, 0, BUFFER_LENGTH);ev->length = sprintf(ev->buffer, "HTTP/1.1 101 Switching Protocols\r\n" "Upgrade: websocket\r\n" "Connection: Upgrade\r\n" "Sec-WebSocket-Accept: %s\r\n\r\n", sec_accept);printf("ws response : %s\n", ev->buffer);break;}} while ((ev->buffer[idx] != '\r' || ev->buffer[idx - 1] != '\n') &&idx != -1);return 0;
}

握手中base64编码实现

int base64_encode(char *in_str, int in_len, char* out_str) {BIO *b64, *bio;BUF_MEM *bptr = NULL;size_t size = 0;if(in_str == NULL || out_str == NULL) {return -1;}b64 = BIO_new(BIO_f_base64());bio = BIO_new(BIO_s_mem());bio = BIO_push(b64, bio);BIO_write(bio, in_str, in_len);if(BIO_flush(bio));//消除警告BIO_get_mem_ptr(bio, &bptr);memcpy(out_str, bptr->data, bptr->length);out_str[bptr->length - 1] = '\0';size = bptr->length;BIO_free_all(bio);return size;
}

Sec-WebSocket-key和GUID通过strcat连接字符串
SHA1函数通过openssl库来
openssl

  1. websocket协议格式?
  2. websocket如何验证客户端合法?
  3. 明文和密文如何传输?
  4. websocket如何断开?

websocket协议和服务实现相关推荐

  1. 魔坊APP项目-16-种植园、websocket协议、服务端基于socket提供服务(基于房间管理分发信息)、种植园页面展示

    种植园 我们需要完成的种植园,是一个互动频繁,并且要求有一定即时性的模块,所以如果继续基于http协议开发,那么需要通过ajax发送大量http请求,同时因为http本身属于单向通讯,所以服务端无法主 ...

  2. http协议与https协议+UDP协议和TCP协议+WebSocket协议下服务端主动去发送信息+对称加密与非对称加密+get和post请求方式区别详解+浏览器内核以及jsj解析引擎

    TCP和UDP协议是TCP/IP协议的核心. 在TCP/IP网络体系结构中,TCP(传输控制协议,Transport Control Protocol).UDP(用户数据报协议,User Data P ...

  3. WebSocket 协议讲解

    来源 通常 Web 应用的交互模式是由客户端向服务端发送 HTTP 请求, 服务端根据客户端的的请求返回相应的数据, 在这样的交互模式下, 通信双方并不是对等的, 因为所有的请求都是由客户端主动发起, ...

  4. php即时聊天的框架_workerman-chat(PHP开发的基于Websocket协议的聊天室框架)(thinkphp也是支持socket聊天的)...

    workerman-chat(PHP开发的基于Websocket协议的聊天室框架)(thinkphp也是支持socket聊天的) 一.总结 1.下面链接里面还有一个来聊的php聊天室源码可以学习 2. ...

  5. dotnet core 开发无缝兼容Http和Websocket协议的接口服务

    在应用接口开发中往往要针对不同协义开发相应的代理服务,但对于Websocket和http这两种协议来说就有些不同,从实现上来看Websocket可以说是Http的升级子协议, 两者在协议处理上基本一致 ...

  6. netty 游戏服务器框图_基于Netty和WebSocket协议实现Web端自动打印订单服务方法与流程...

    本发明涉及电子商务技术领域,尤其涉及一种基于netty和websocket协议实现web端自动打印订单服务方法. 背景技术: 电子商务是以信息网络技术为手段,以商品交换为中心的商务活动:也可理解为在互 ...

  7. 用C语言解析通讯协议数据,C/C++知识点之服务端使用c++实现websocket协议解析及通信...

    C/C++知识点之服务端使用c++实现websocket协议解析及通信 小标 2018-12-03 来源 : 阅读 2289 评论 0 摘要:本文主要向大家介绍了 C/C++知识点之服务端使用c++实 ...

  8. 服务端使用c++实现websocket协议解析及通信

    WebSocket 设计出来的目的就是要使客户端浏览器具备像 C/S 架构下桌面系统的实时通讯能力. 浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后, ...

  9. Java Websocket实例【服务端与客户端实现全双工通讯】

    Java Websocket实例[服务端与客户端实现全双工通讯] 现很多网站为了实现即时通讯,所用的技术都是轮询(polling).轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发 出HTTP ...

最新文章

  1. 关于软件开发环境的思考
  2. BZOJ[1713][Usaco2007 China]The Bovine Accordion and Banjo Orchestra 音乐会 二维斜率优化
  3. VC++ 访问数据库实例详解图解
  4. python虚拟环境-conda
  5. 计算机net use命令使用,网络命令net之net use应用
  6. 高性能mysql 小查询_高性能MySql进化论(十一):常见查询语句的优化
  7. 设计灵感|时尚潮流品牌如何通过网页设计呈现
  8. 【PAT乙】1003 我要通过! (20分) 字符串条件判定
  9. [转]六步使用ICallbackEventHandler实现无刷新回调
  10. leetcode最小面积_LeetCode 题解 |力扣杯 LCP 13.寻宝
  11. SERVER 2008 +MSSQL2008+SCCM安装记录
  12. 百度地图API加载点位
  13. [4G+5G专题-132]: 传输层 - 以太网电缆的类型(Cat5,Cat5e,Cat6,Cat6a)
  14. Nginx实现文件共享
  15. E. Thematic Contests【dp】
  16. 荣耀手表magicwatch2鸿蒙,荣耀手表2 NFC门禁卡功能正式上线:再不怕忘带钥匙
  17. mc服务器怎么回到床的位置,《我的世界》MC床的功能居然跟这四个指令有关系?很多人不知道!...
  18. wireshark 安装与使用
  19. 把网页保存成markdowm的方法
  20. win10企业版 LTSC 安装 MSIX(msixbundle) 文件

热门文章

  1. 计算机专业答辩开场白,毕业论文答辩开场白
  2. PMBOK(第六版) PMP笔记——《七》第七章(项目成本管理)
  3. python中跳过本次循环的语句是_Python跳过for循环
  4. openEuler Summit | 胡欣蔚:全场景欧拉 – 志之所趋,无远弗届
  5. js定义一个函数,返回所有水仙花数
  6. RTT Nano学习笔记 8 - 信号量
  7. 04.修改Docker镜像源地址为网易镜像源地址
  8. 别在那抱怨高考怎么不考DOTA呢!!高考就是考DOTA你也不行!
  9. 邮箱发送附件,附件变成了bin文件
  10. NTL密码算法开源库——模二整数上的矩阵(mat_GF2)