我们在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消息的时候我们曾经讲过,后者是表明使用非阻塞模式,默认是阻塞模式的。
而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; }
其他函数目前来看不是我们分析过程中的重点,可能最后会有一章会分析这些函数。现在你已经迫不及待地准备去看各种socket的代码了吧!
6-2我们就会讲一下req和rep这一对socket,会拿个最简单的tutorial代码并结合源码分析。敬请期待!希望有兴趣的朋友可以和我联系,一起学习。 [email protected]