一、websocket的使用场景
websocket 使用场景:扫码登录、股票、比赛实时比分 当 服务器主动推送数据给浏览器时 一般选择websocket来解
二、websocket握手的流程(handshake)
1.websocket 握手时 浏览器发送给服务器的请求协议
GET / HTTP/1.1
Host: 192.168.247.132:8888
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36 Edg/106.0.1370.42
Upgrade: websocket
Origin: null
Sec-WebSocket-Version: 13
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Sec-WebSocket-Key: gSZyocBKTG+fB5zgNUdP+g==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
2.value计算流程
Key = Sec-WebSocket-Key: gSZyocBKTG+fB5zgNUdP+g==
GUID = 258EAFA5-E914-47DA-95CA-C5AB0DC85B11
str= gSZyocBKTG+fB5zgNUdP+g==258EAFA5-E914-47DA-95CA-C5AB0DC85B11
sha = SHA-1(str);
value = base64-encode(sha);
3.websocket 握手时 服务器返回给浏览器的协议
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: value
三、基于reactor实现websocket
1.websocket_request
int websocket_request(struct ntyevent *ev) {
if (ev->status_machine == WS_HANDSHARK) {
ev->status_machine = WS_TRANMISSION;
handshark(ev);
} else if (ev->status_machine == WS_TRANMISSION) {
transmission(ev);
} else {
}
printf("websocket_request --> %d\n", ev->status_machine);
}
2. transmission
int transmission(struct ntyevent *ev) {
ws_ophdr *hdr = (ws_ophdr*)ev->buffer;
printf("length: %d\n", hdr->pl_len);
if (hdr->pl_len < 126) {
unsigned char *payload = ev->buffer + sizeof(ws_ophdr) + 4;
if (hdr->mask) {
umask(payload, hdr->pl_len, ev->buffer+2);
}
printf("payload : %s\n", payload);
} else if (hdr->pl_len == 126) {
ws_head_126 *hdr126 = ev->buffer + sizeof(ws_ophdr);
} else {
ws_head_127 *hdr127 = ev->buffer + sizeof(ws_ophdr);
}
}
3.base64_encode
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);
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;
}
4.handshark
#define WEBSOCK_KEY_LENGTH 19
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);
SHA1(linebuf + WEBSOCK_KEY_LENGTH, strlen(linebuf + WEBSOCK_KEY_LENGTH), 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;
}
void umask(char *payload, int length, char *mask_key) {
int i = 0;
for (i = 0;i < length;i ++) {
payload[i] ^= mask_key[i%4];
}
}
5.效果展示
|