热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

websocket协议与服务器实现

1什么是websocketWebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC6455,并


1 什么是websocket

WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输


原理

很多网站为了实现推送技术,所用的技术都是轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。

而比较新的技术去做轮询的效果是Comet。这种技术虽然可以双向通信,但依然需要反复发出请求。而且在Comet中,普遍采用的长链接,也会消耗服务器资源。

在这种情况下,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯


特点

较少的控制开销。在连接创建后,服务器和客户端之间交换数据时,用于协议控制的数据包头部相对较小。在不包含扩展的情况下,对于服务器到客户端的内容,此头部大小只有2至10字节(和数据包长度有关);对于客户端到服务器的内容,此头部还需要加上额外的4字节的掩码。相对于HTTP请求每次都要携带完整的头部,此项开销显著减少了。

更强的实时性。由于协议是全双工的,所以服务器可以随时主动给客户端下发数据。相对于HTTP请求需要等待客户端发起请求服务端才能响应,延迟明显更少;即使是和Comet等类似的长轮询比较,其也能在短时间内更多次地传递数据。

保持连接状态。与HTTP不同的是,Websocket需要先创建连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息。而HTTP请求可能需要在每个请求都携带状态信息(如身份认证等)。

更好的二进制支持。Websocket定义了二进制帧,相对HTTP,可以更轻松地处理二进制内容。

可以支持扩展。Websocket定义了扩展,用户可以扩展协议、实现部分自定义的子协议。如部分浏览器支持压缩等。

更好的压缩效果。相对于HTTP压缩,Websocket在适当的扩展支持下,可以沿用之前内容的上下文,在传递类似的数据时,可以显著地提高压缩率。


2 websocket的应用场景

主要应用于服务器主动的像客户端推送数据的情况下,当然不排除其他的情况也可以是用websocket协议来通讯

 

举个例子

eg:当我们通过(浏览器)网页端开始登陆CSDN账号的时候,有一种登陆的方式是通过微信扫码进行登陆

我们微信扫码后,手机微信会将扫码的到的信息发送到微信服务器,微信服务器会分析出接收到的信息是关于CSDN的信息,然后这个信息请求转发到CSDN的服务器上面,然后CSDN服务器会将一个CSDN登陆成功后的页面信息主动发送到浏览器上面.而CSDN服务器向浏览器主动发送信息D的这个过程就是采用的是websocet协议


3 websocket协议的解析分析


1websocket的协议格式

握手的协议格式

http协议是无状态的,不支持持久(非持久化)连接的(长连接、轮询连接除外的话)

websocket是一个持久化的协议

http和websocket协议都是基于TCP/IP协议之上,websocket可以说是基于http协议的一个持久化协议。

websocket协议连接需要以http形式发起,三次握手告诉将http协议转换为websocket协议后,之后客户端和服务端就会开启持久化的TCP信道进行信息传输。

 信息传输的协议格式

 


2 websocket如何验证客户端合法



websocket客户端发送的请求消息

首先客户端在websocket的请求下消息中会有一个 

websocket服务器收到客户端发送过来的websocket请求后将sec-websocket-key 后面的base64格式的字符串后面加上一个websocket公认的GUID字符串

GUID:

 

 将GUID拼接在sec-websocket-key后面然后 进行sha1(哈希),将hash结果再base64编码生成一串base64编码的结果放入服务器 返回客户端的信当中进行返回,然后客户端将接收到的结果和自己的算的结果进行对比,如果一样则握手成功。



3 明文和密文如何传输

 

如果传输明文:的mask设置为0,payload data直接存放的是明文就可以了。makeing-key不会有值

如果传输的是密文:mask的标志位则会被设置成1,payload data会是密文,making-key有四个字节的值。用于密文的加密和解密。

加密过程

payload[i] = payload[i] ^masking-key[i%4]

解密过程(就是再异或一遍)

payload[i] = payload[i] ^masking-key[i%4]


4 websocket如何断开

直接将FIN位置1就可以,payload可以不用填数据。

 


4 自定义实现websocket的服务器的代码实现和关键代码展示

websocket协议交互的状态机和opcode内容和部分协议内容

enum {WS_HANDSHARK = 0,WS_TRANMISSION = 1,WS_END = 2,
};typedef struct _ws_ophdr {unsigned char opcode:4,rsv3:1,rsv2:1,rsv1:1,fin:1;unsigned char pl_len:7,mask:1;
} ws_ophdr;typedef struct _ws_head_126 {unsigned short payload_length;char mask_key[4];} ws_head_126;typedef struct _ws_head_127 {long long payload_length;char mask_key[4];} ws_head_127;

 握手的过程实现

int handshark(struct ntyevent *ev) {//ev->buffer , ev->lengthchar 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")) {//linebuf: Sec-WebSocket-Key: QWz1vB/77j8J8JcT/qtiLQ==strcat(linebuf, GUID);//linebuf: //Sec-WebSocket-Key: QWz1vB/77j8J8JcT/qtiLQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11SHA1(linebuf + WEBSOCK_KEY_LENGTH, strlen(linebuf + WEBSOCK_KEY_LENGTH), sec_data); // opensslbase64_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;
}

 解析收到的数据的代码实现(此处用的是密文)

int transmission(struct ntyevent *ev) {//ev->buffer; ev->lengthws_ophdr *hdr &#61; (ws_ophdr*)ev->buffer;printf("length: %d\n", hdr->pl_len);if (hdr->pl_len <126) { //unsigned char *payload &#61; ev->buffer &#43; sizeof(ws_ophdr) &#43; 4; // 6 payload length <126if (hdr->mask) { // mask set 1umask(payload, hdr->pl_len, ev->buffer&#43;2);}printf("payload : %s\n", payload);} else if (hdr->pl_len &#61;&#61; 126) {ws_head_126 *hdr126 &#61; ev->buffer &#43; sizeof(ws_ophdr);} else {ws_head_127 *hdr127 &#61; ev->buffer &#43; sizeof(ws_ophdr);}}

全部代码连接

https://github.com/xiaoyeyihao/xioayeyihao.github.io/blob/master/websocket_server.c


5 一个疑问&#xff1a;既然客户端可以直接调用一个close来断开tcp的连接&#xff0c;为什么websocket还需要留出一个fin位来断开连接

客户端再调用close之前&#xff0c;先发送一个应用层的fin的包给服务器&#xff0c;服务器接收到这个fin的包&#xff0c;把对应的客户端的用户数据&#xff0c;业务数据做清空&#xff0c;然后再调用close时候&#xff0c;服务器调用close会比较顺畅&#xff0c;不会出现存在大量的close_wait的情况存在。


推荐阅读
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文介绍了一个适用于PHP应用快速接入TRX和TRC20数字资产的开发包,该开发包支持使用自有Tron区块链节点的应用场景,也支持基于Tron官方公共API服务的轻量级部署场景。提供的功能包括生成地址、验证地址、查询余额、交易转账、查询最新区块和查询交易信息等。详细信息可参考tron-php的Github地址:https://github.com/Fenguoz/tron-php。 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • flowable工作流 流程变量_信也科技工作流平台的技术实践
    1背景随着公司业务发展及内部业务流程诉求的增长,目前信息化系统不能够很好满足期望,主要体现如下:目前OA流程引擎无法满足企业特定业务流程需求,且移动端体 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
  • Whatsthedifferencebetweento_aandto_ary?to_a和to_ary有什么区别? ... [详细]
author-avatar
CHEN--MIN--珊
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有