Memcached源码分析之状态机(三)

按前面2篇文章的分析可以知道,从网络读取了数据之后,将会进入conn_parse_cmd状态,该状态是按协议来解析读取到的网络数据。

case conn_parse_cmd:
                //解析数据
                if (try_read_command(c) == 0)
		{
                     //如果读取到的数据不够,我们继续等待,等读取到的数据够了,再进行解析
                     conn_set_state(c, conn_waiting);
		}

		break;
//memcached支持二进制协议和文本协议
static int try_read_command(conn *c)
{
assert(c != NULL);
assert(c->rcurr <= (c->rbuf + c->rsize));
assert(c->rbytes > 0);

if (c->protocol == negotiating_prot || c->transport == udp_transport)
{
    //二进制协议有标志,按标志进行区分
    if ((unsigned char) c->rbuf[0] == (unsigned char) PROTOCOL_BINARY_REQ)
    {
        c->protocol = binary_prot;//二进制协议
    }
    else
    {
        c->protocol = ascii_prot;//文本协议
    }

    if (settings.verbose > 1)
    {
        fprintf(stderr, "%d: Client using the %s protocol\n", c->sfd,
                prot_text(c->protocol));
    }
}
//如果是二进制协议
if (c->protocol == binary_prot)
{
    //二进制协议读取到的数据小于二进制协议的头部长度
    if (c->rbytes < sizeof(c->binary_header))
    {
        //返回继续读数据
        return 0;
    }
    else
    {
#ifdef NEED_ALIGN
        //如果需要对齐,则按8字节对齐,对齐能提高CPU读取的效率
        if (((long)(c->rcurr)) % 8 != 0)
        {
            //调整缓冲区
            memmove(c->rbuf, c->rcurr, c->rbytes);
            c->rcurr = c->rbuf;
            if (settings.verbose > 1)
            {
                fprintf(stderr, "%d: Realign input buffer\n", c->sfd);
            }
        }
#endif
        protocol_binary_request_header* req;//二进制协议头
        req = (protocol_binary_request_header*) c->rcurr;
        //调试信息
        if (settings.verbose > 1)
        {
            /* Dump the packet before we convert it to host order */
            int ii;
            fprintf(stderr, "<%d Read binary protocol data:", c->sfd);
            for (ii = 0; ii < sizeof(req->bytes); ++ii)
            {
                if (ii % 4 == 0)
                {
                    fprintf(stderr, "\n<%d   ", c->sfd);
                }
                fprintf(stderr, " 0x%02x", req->bytes[ii]);
            }
            fprintf(stderr, "\n");
        }

        c->binary_header = *req;
        c->binary_header.request.keylen = ntohs(req->request.keylen);//二进制协议相关内容
        c->binary_header.request.bodylen = ntohl(req->request.bodylen);
        c->binary_header.request.cas = ntohll(req->request.cas);
        //判断魔数是否合法,魔数用来防止TCP粘包
        if (c->binary_header.request.magic != PROTOCOL_BINARY_REQ)
        {
            if (settings.verbose)
            {
                fprintf(stderr, "Invalid magic:  %x\n",
                        c->binary_header.request.magic);
            }
            conn_set_state(c, conn_closing);
            return -1;
        }

        c->msgcurr = 0;
        c->msgused = 0;
        c->iovused = 0;
        if (add_msghdr(c) != 0)
        {
            out_string(c, "SERVER_ERROR out of memory");
            return 0;
        }

        c->cmd = c->binary_header.request.opcode;
        c->keylen = c->binary_header.request.keylen;
        c->opaque = c->binary_header.request.opaque;
        //清除客户端传递的cas值
        c->cas = 0;

        dispatch_bin_command(c);//协议数据处理

        c->rbytes -= sizeof(c->binary_header);//更新已经读取到的字节数据
        c->rcurr += sizeof(c->binary_header);//更新缓冲区的路标信息
    }
}

文本协议的过程和二进制协议的过程类似,此处不分析,另外dispatch_bin_command是处理具体的(比如get,set等)操作的,和是二进制协议具体相关的,解析完一些数据之后,会进入到conn_nread的流程,也就是读取指定数目数据的过程,这个过程主要是做具体的操作了,比如get,add,set操作。

case bin_read_set_value:
		complete_update_bin(c);//执行Update操作
		break;
case bin_reading_get_key:
		process_bin_get(c);//执行get操作
		break;
状态机的整个处理过程就介绍到这里,其他的状态我们就不介绍了,后续的文章主要是分析一些数据的操作和内存结构,了解了这些之后,其实其他状态就相对容易很多。



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值