一、websocket
解决http一连接只有一请求、服务器不能主动发请求的弊端。
二、两次握手过程
服务器收到请求后,会判断出不是http协议而是websocket协议,同时获取从websocket客户端传来的key ,然后server接收处理后返回一个value给客户端。 具体的处理过程分为以下3步 1.str = key|GUID 2.sha = SHA-1(str) 3.value = base64_encode(sha)
#define GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
int ws_handshark(struct ntyevent *ev) {
int idx = 0;
char sec_data[128] = {0};
char sec_accept[128] = {0};
do {
char linebuf[1024] = {0};
idx = readline(ev->buffer, idx, linebuf);
if (strstr(linebuf, "Sec-WebSocket-Key")) {
strcat(linebuf, GUID);
SHA1(linebuf+19, strlen(linebuf+19), sec_data);
base64_encode(sec_data, strlen(sec_data), sec_accept);
printf("idx: %d, line: %ld\n",idx, sizeof("Sec-WebSocket-Key: "));
memcpy(ev->sec_accept, sec_accept, ACCEPT_KEY_LENGTH);
}
} while((ev->buffer[idx] != '\r' || ev->buffer[idx+1] != '\n') && idx != -1);
}
三、传输格式
握手成功后表示建立连接完成,开始数据传输,数据格式如下: 前面2字节头部主要关注Mask 和Payload len ,Mask位为1,表示该帧数据采用密文传输。那密文从哪算起呢?后面的Extended payload length是变化的。如果Payload len = 126,就占16bit ,如果Payload = 17,就占64位,如果小于126,就没有Extended payload length。 然后Mask为1,从Extended payload lenth后就是4字节的Masking-key, 为0则表示明文没有Masking-key,最后是我们的Payload Data数据。代码片如下:
struct ws_ophdr {
unsigned char opcode:4,
rsv3:1,
rsv2:1,
rsv1:1,
fin:1;
unsigned char pl_len:7,
mask:1;
};
int ws_tranmission(struct ntyevent *ev) {
struct ws_ophdr *hdr = (struct ws_ophdr *)ev->buffer;
if (hdr->pl_len < 126) {
unsigned char *payload = NULL;
if (hdr->mask) {
payload = ev->buffer + 6;
umask(payload, hdr->pl_len, ev->buffer + 2);
} else {
payload = ev->buffer + 2;
}
}
四、解码实现
解密需要用到加密后的payload数据、长度、mask_key参数。
void umask(char *payload, int length, char *mask_key) {
int i = 0;
for (i = 0;i < length;i ++) {
payload[i] ^= mask_key[i%4];
}
}
|