websocket传输协议分析

websocket 简介

这里介绍的是 websocket 的一些内容,主要就是最小可运行的 websocket 的基础部分,更深层次的内容不在这里。

先看一张图

在这里插入图片描述

代码分析

对于 handleshake 部分这里不分析了,与 http 的交互很相似,只是字段的变化

主要看看在内容交互阶段对消息格式的解析

解析部分

以下为伪代码

    /*read fin and op code*/
    int n = cm_conn_tcp_recv_simple(conn, tmpdata, &len);
    if (n <= 0) {
        return n == 0 ? 0 : -1;
    }
    // 1. 读取前两个字节后,解析是否是最后一条消息以及消息中的 payload 格式
    head->cFin = (p[0] & 0x80) == 0x80;
    head->cOpcode = p[0] & 0x0F;

    n = cm_conn_tcp_recv_simple(conn, tmpdata, &len);
    if (n <= 0) {
        return n == 0 ? 0 : -2;
    }
    // 2. 继续读取2个字节,提取出是否对内容做的 掩码计算,掩码值在后面读取,如果没有掩码值 ,后面直接就是内容
    // 同时取出此字节表示的数据长度
    head->cMask = (p[0] & 0x80) == 0x80;
    head->ullPayloadLength = p[0] & 0x7f;

    // 3. 数据长度分两种,
    // 3.1 126 表示后面有两个字节来表示真实的负载长度,读取两个字节并提取出长度
    // 3.2 127 表示后面有8个字节来表示真实的负载长度,读取8个字节并提取长度
    // 注意:这里面的长度是 网络字节序,如果系统使用的不是这样的,应当进行转化,即小端序与大端序的区别
    if (head->ullPayloadLength == 126)
    {
        char extern_len[2];
        len = 2;
        n = cm_conn_tcp_recv_simple(conn, extern_len, &len);
        if (n <= 0)
        {
            return n == 0 ? 0 : -3;
        }
        head->ullPayloadLength = (extern_len[0]&0xFF) << 8 | (extern_len[1]&0xFF);
    }
    else if (head->ullPayloadLength == 127)
    {
        char extern_len[8];
        len = 8;
        n = cm_conn_tcp_recv_simple(conn, extern_len, &len);
        if (n <= 0)
        {
            return n == 0 ? 0 : -4;
        }
        cm_ws_invert_string(extern_len,8);
        memcpy(&(head->ullPayloadLength),extern_len,8);
    }

    // 4. 如果有掩码,需要读取出来,4个字节长度
    /*read masking-key*/
    if (head->cMask) {
        len = 4;
        n = cm_conn_tcp_recv_simple(conn, tmpdata, &len);
        if (n <= 0) {
            return n == 0 ? 0 : -5;
        }
    }
    // 5. 下面则是实际内容部分
组装部分
    // 1. 定义相关的头部分
    // Generate websocket header
    CMWSFrameHeader header;
    memset(&header, 0, sizeof(CMWSFrameHeader));
    CMWSFrameHeader resheader;
    memset(&resheader, 0, sizeof(CMWSFrameHeader));

    char *head_str = NULL;
    int head_str_len = 0;

    // 2. 设置长度和掩码
    // 2.1 随机生成掩码值,用于后面的 掩码计算
    // Set header
    header.ullPayloadLength = len;
    header.cMask = 1;
    cm_random_with_num_char(header.cMasking_key, 4);
    // 3. 下面这个函数会跟据数据长度,去填充对应的字段,并设置掩码标志位等信息,这里就不列出了
    cm_ws_generate_frame_head(&header, &head_str, &head_str_len);

    cmdebug("websocket request generated header length is [%d] payload length is [%d]\n", head_str_len, len);

    // Send with data
    int sendlen = head_str_len + len;
    char *senddata = (char*)malloc(sendlen);
    memcpy(senddata, head_str, head_str_len);

    // 4. 生成掩码并写入头结构中
    cmdebug("websocket request send data \n[%s]\n", msg);
    if (header.cMask) {
        cm_ws_umask((char*)msg, len, header.cMasking_key);
    }

掩码计算

    // 根据 rfc 文档而来
    for (i=0;i<len;++i)
        *(data+i) ^= *(mask+(i%4));
附件
  • 参见工程源码 jklibs, common/cm_conn_ws.c, common/cm_http.c, common/cm_http_tcp.c
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值