php部署网站,德州有做网站的,鞍山seo外包,wordpress 自定义htmlwebsocket的实现
什么是websocket#xff1f;
WebSocket 是一种网络通信协议#xff0c;旨在为客户端和服务器之间提供全双工、实时的通信通道。它是在 HTML5 规范中引入的#xff0c;可以让浏览器与服务器进行持久化连接#xff0c;以便实现低延迟的数据交换。
WebSock…
websocket的实现
什么是websocket
WebSocket 是一种网络通信协议旨在为客户端和服务器之间提供全双工、实时的通信通道。它是在 HTML5 规范中引入的可以让浏览器与服务器进行持久化连接以便实现低延迟的数据交换。
WebSocket 的特点
全双工通信客户端和服务器可以同时发送和接收消息而不必等待对方完成操作。轻量级相较于传统的 HTTP 协议WebSocket 头部信息更小这减少了网络开销。持久连接一旦建立连接双方可以一直保持这个连接直到主动关闭。这样避免了频繁建立和关闭连接带来的性能损耗。实时性适合需要即时数据更新的应用如在线聊天、游戏、股票行情等 通信过程
websocket通信协议是基于http的客户端首先发送连接请求request在该request中包含了基本的HTTP头信息
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw
Sec-WebSocket-Version: 13
以上这些信息以字符串的形式发送至服务端的rbuffer里当服务端识别到这些字符串信息后需要发送相应response进行确认后才能建立websocket连接。确认信息的response应该如下
接收到客户端的key-
key与“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”进行拼接得到新的key--
使用SHA1算法加密--
再使用base64加密--
加上http头信息以字符串形式的发送至客户端。当客户端收到后websocket建立。
int response_websock(struct conn *c){char* key_head Sec-WebSocket-Key;char* start strstr(c-rbuffer, key_head);start 19;char key[1024] {0};int set 0;while (*start ! ){key[set] *start;start;set;}key[set] \0;char* result strcat(key, GUID);unsigned char hash[SHA_DIGEST_LENGTH] {0};SHA1((unsigned char*)result, strlen(result), hash);char* base base64_encode(hash, SHA_DIGEST_LENGTH);//strcpy(c-wbuffer, base) ;snprintf(c-wbuffer, sizeof(c-wbuffer), HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: %s\r\n\r\n, base);c-wlength strlen(c-wbuffer);free(base);
} 建立websocket连接后可以互发信息但是信息是以websocket帧字节流的形式传送的所以需要进行编码和解码。
websocket帧结构如下 发送信息编码
int encoding(struct conn *c){//写入rbufferint message_len strlen(payload);int frame_len 0;// 设置 FIN 位和 Opcode文本帧c-wbuffer[0] 0x81; // FIN1, Opcode0x1文本帧// 设置 Payload Lengthif (message_len 125) {c-wbuffer[1] message_len; // 不需要额外长度字段memcpy(c-wbuffer[2], payload, message_len);frame_len 2 message_len;} else if(message_len 65535){c-wbuffer[1] 126; // 16 位扩展长度c-wbuffer[2] (message_len 8) 0xFF; // 高字节c-wbuffer[3] message_len 0xFF; // 低字节memcpy(c-wbuffer[4], payload, message_len);frame_len 4 message_len; }else{c-wbuffer[1] 127; // 64 位扩展长度// 这里假设消息长度小于 2^32因此高 4 字节为 0memset(c-wbuffer[2], 0, 4);c-wbuffer[6] (message_len 24) 0xFF;c-wbuffer[7] (message_len 16) 0xFF;c-wbuffer[8] (message_len 8) 0xFF;c-wbuffer[9] message_len 0xFF;memcpy(c-wbuffer[10], payload, message_len);frame_len 10 message_len;}
} 接收信息解码):
int encoding(struct conn *c){int fin (c-rbuffer[0] 0X80) 7;int opcode c-rbuffer[0] 0x0F; // 操作码int masked (c-rbuffer[1] 0x80) 7; // 是否有掩码int payload_len c-rbuffer[1] 0x7F;unsigned char *mask NULL; // 掩码键unsigned char *payload NULL; // 数据指针if (payload_len 125) {mask c-rbuffer[2];payload c-rbuffer[6];} else if (payload_len 126) {payload_len ntohs(*(uint16_t *)c-rbuffer[2]);mask c-rbuffer[4];payload c-rbuffer[8];} else if (payload_len 127) {payload_len ntohl(*(uint64_t *)c-rbuffer[2]);mask c-rbuffer[10];payload c-rbuffer[14];}for (int i 0; i payload_len; i) { //解析数据去除掩码payload[i] ^ mask[i % 4];}// 输出解码后的消息payload[payload_len] \0;printf(Message from client: %s\n, payload);
} 流程总结
由于在建立连接阶段和通信阶段发送的数据形式不同所以需要在结构体中引入状态机用于记录是哪种请求根据不同的状态机做出不同的response。
int ws_request(struct conn *c){//判断建立请求连接还是数据帧if (strstr(c-rbuffer, Sec-WebSocket-Key) ! NULL) {printf(HTTP handshake request detected.\n);printf(request: %s, c-rbuffer);c-wlength 0;c-status 0;} else {printf(WebSocket frame detected.\n);c-wlength 0;c-status 1;}return 0;
}
客户端发送request - 服务端读取数据判断是请求连接还是发送websocket帧 -根据不同status做出相应反应
int ws_response(struct conn *c){//返回建立连接if(c-status 0){response_websock(xxx);}else if (c-status 1){//解码encoding(xxx);//编码decoding(xxx);}return c-wlength;
}
整体流程如下
conn_list数组相当于一个用户和内核的中介用来存放内核建立的连接以及用于拷贝内核接收到的数据。在websocket时还额外引入了status的状态。
这个图可以清晰的显示出reactor的优点即将业务和网络io管理分开。websocket用来实现业务reactor用来实现网络io的管理。 课程地址www.github.com/0voice