zeromq源代码分析6-1------zeromq各种类型的socket之socket_base

我们在zeromq源代码分析6中分析zeromq所有类型的socket,主要集中分析send和recv函数。

今天我们先分析一下所有socket中base class------socket_base:

先看send(2)函数:

int zmq::socket_base_t::send (::zmq_msg_t *msg_, int flags_)
{
    //  Check whether the library haven't been shut down yet.
    if (unlikely (ctx_terminated)) {
        errno = ETERM;
        return -1; 
    }   

    //  Check whether message passed to the function is valid.
    if (unlikely ((msg_->flags | ZMQ_MSG_MASK) != 0xff)) {
        errno = EFAULT;
        return -1; 
    }   

    //  Process pending commands, if any.
    int rc = process_commands (false, true); // 先处理pending的消息,不过是非阻塞模式去处理的
    if (unlikely (rc != 0)) 
        return -1; 

    //  At this point we impose the MORE flag on the message.
    if (flags_ & ZMQ_SNDMORE) // 如果设置ZMQ_SNDMORE,说明是multipart message,将msg的flags增加ZMQ_MSG_MORE标志
        msg_->flags |= ZMQ_MSG_MORE;

    //  Try to send the message.
    rc = xsend (msg_, flags_); // 尝试发消息
    if (rc == 0)
        return 0;

    //  In case of non-blocking send we'll simply propagate
    //  the error - including EAGAIN - upwards.
    if (flags_ & ZMQ_NOBLOCK) // 非阻塞模式
        return -1; 

    //  Oops, we couldn't send the message. Wait for the next
    //  command, process it and try to send the message again.
    while (rc != 0) { // 阻塞模式如果发消息失败,会等待writer重新被激活并且重发消息
        if (errno != EAGAIN)
            return -1; 
        if (unlikely (process_commands (true, false) != 0)) 
            return -1; 
        rc = xsend (msg_, flags_);
    }   
    return 0;
}
1. 第二个参数表明消息的flag,而目前支持的flag主要有ZMQ_MSG_MORE和ZMQ_NOBLOCK,前者在分析multipart消息的时候我们曾经讲过,后者是表明使用非阻塞模式,默认是阻塞模式的。
2.  阻塞模式下会不断地尝试发消息。失败返回EAGAIN的话就说明当前管道满了(到达HWM,并且swap文件也容不下新消息了),因此这时候socket中的writer就会non-active,所以我们就会调用process_commands(2)来等到激活writer的消息,然后再重发。其它错误的话就直接返回-1。
3. 非阻塞模式就直接返回-1。


而recv(2)函数也是类似,也是默认是阻塞模式,能够设置成非阻塞模式。

int zmq::socket_base_t::recv (::zmq_msg_t *msg_, int flags_)
{
    //  Check whether the library haven't been shut down yet.
    if (unlikely (ctx_terminated)) {
        errno = ETERM;
        return -1;
    }

    //  Check whether message passed to the function is valid.
    if (unlikely ((msg_->flags | ZMQ_MSG_MASK) != 0xff)) {
        errno = EFAULT;
        return -1;
    }

    //  Get the message.
    int rc = xrecv (msg_, flags_); // 先从管道中收消息
    int err = errno;

    //  Once every inbound_poll_rate messages check for signals and process
    //  incoming commands. This happens only if we are not polling altogether
    //  because there are messages available all the time. If poll occurs,
    //  ticks is set to zero and thus we avoid this code.
    //
    //  Note that 'recv' uses different command throttling algorithm (the one
    //  described above) from the one used by 'send'. This is because counting
    //  ticks is more efficient than doing RDTSC all the time.
    if (++ticks == inbound_poll_rate) {
        if (unlikely (process_commands (false, false) != 0))
            return -1;
        ticks = 0;
    }

    //  If we have the message, return immediately.
    if (rc == 0) { // 获得了消息
        rcvmore = msg_->flags & ZMQ_MSG_MORE; // 后面还有子消息。。。
        if (rcvmore)
            msg_->flags &= ~ZMQ_MSG_MORE;
        return 0;
    }

    //  If we don't have the message, restore the original cause of the problem.
    errno = err;

    //  If the message cannot be fetched immediately, there are two scenarios.
    //  For non-blocking recv, commands are processed in case there's an
    //  activate_reader command already waiting int a command pipe.
    //  If it's not, return EAGAIN.
    if (flags_ & ZMQ_NOBLOCK) { // 非阻塞模式
        if (errno != EAGAIN) 
            return -1;
        if (unlikely (process_commands (false, false) != 0)) // 探测一下reader是否被重新激活,第一个参数表明non-block,木有的话就返回-1
            return -1;
        ticks = 0;

        rc = xrecv (msg_, flags_);
        if (rc == 0) {
            rcvmore = msg_->flags & ZMQ_MSG_MORE;
            if (rcvmore)
                msg_->flags &= ~ZMQ_MSG_MORE;
        }
        return rc;
    }

    //  In blocking scenario, commands are processed over and over again until
    //  we are able to fetch a message.
    bool block = (ticks != 0);
    while (rc != 0) {  // 阻塞模式则不断地去取消息,不断地去等待reader被重新激活的command消息
        if (errno != EAGAIN)
            return -1;
        if (unlikely (process_commands (block, false) != 0))
            return -1;
        rc = xrecv (msg_, flags_);
        ticks = 0;
        block = true;
    }

    rcvmore = msg_->flags & ZMQ_MSG_MORE;
    if (rcvmore)
        msg_->flags &= ~ZMQ_MSG_MORE;
    return 0;
}

这边也是和write(2)差不多的工作流程。。。


其他函数目前来看不是我们分析过程中的重点,可能最后会有一章会分析这些函数。现在你已经迫不及待地准备去看各种socket的代码了吧!

6-2我们就会讲一下req和rep这一对socket,会拿个最简单的tutorial代码并结合源码分析。敬请期待!希望有兴趣的朋友可以和我联系,一起学习。 kaka11.chen@gmail.com


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值