libevent evbuffer_peek 解析

源代码

/** Function to peek at data inside an evbuffer without removing it or
    copying it out.

    Pointers to the data are returned by filling the 'vec_out' array
    with pointers to one or more extents of data inside the buffer.

    The total data in the extents that you get back may be more than
    you requested (if there is more data last extent than you asked
    for), or less (if you do not provide enough evbuffer_iovecs, or if
    the buffer does not have as much data as you asked to see).

    @param buffer the evbuffer to peek into,
    @param len the number of bytes to try to peek.  If len is negative, we
       will try to fill as much of vec_out as we can.  If len is negative
       and vec_out is not provided, we return the number of evbuffer_iovecs
       that would be needed to get all the data in the buffer.
    @param start_at an evbuffer_ptr indicating the point at which we
       should start looking for data.  NULL means, "At the start of the
       buffer."
    @param vec_out an array of evbuffer_iovec
    @param n_vec the length of vec_out.  If 0, we only count how many
       extents would be necessary to point to the requested amount of
       data.
    @return The number of extents needed.  This may be less than n_vec
       if we didn't need all the evbuffer_iovecs we were given, or more
       than n_vec if we would need more to return all the data that was
       requested.
 */
EVENT2_EXPORT_SYMBOL
int evbuffer_peek(struct evbuffer *buffer, ev_ssize_t len,
    struct evbuffer_ptr *start_at,
    struct evbuffer_iovec *vec_out, int n_vec);

解析

首先这个函数是非常有用的,主要作用于 Tcp 数据的解析。
该函数的特点是

Function to peek at data inside an evbuffer without removing it or
    copying it out.

获得 tcp 内核中的数据,并且不会删除或者复制 evbuffer 中的数据,这就意味着我们不用从 evbuffer 中复制出 tcp 缓存中接收到的数据,节省了大量的资源。
使用方法:我们可以获得当前 evbuffer 中接收到了多少数据,以及这些数据的内容。常见的协议中,协议包头都会带有该数据包总长度,使用该函数我们就可以在不用复制 evbuffer 中已经接受到数据的情况下获得该数据中的内容,并且我们就可以从数据中获得 协议的总长度。

example

		if (evbuffer_peek(input, -1, NULL, &image, 1)) {
            BYTE *tmp_ptr = static_cast<BYTE *>(image.iov_base);
            size_t framePos = 0;
            LOG_C(LOG_DEBUG, "Recv RawData:[%s]", ToolKits::byteTohex((void *)tmp_ptr, image.iov_len).c_str());
            
            if (protocol_->parseOnePackage(tmp_ptr, image.iov_len, framePos, frameSize_, readWant_)) {
                // parseOnePackage 返回 true 时, framePos 可能大于 0
                // size known; now get the rest of the frame
                if (framePos > 0) { //move ptr to package begin postion
                    // 删除数据包前的多余数据
                    evbuffer_drain(input, framePos);
                }
                // 处理 完整的数据包
                transition();
            }
            // 没有一个完整的数据包
            if (framePos > 0) {
                // 如果非完整数据包前有 无用的数据,则丢弃
                evbuffer_drain(input, framePos);
            }
        }
        break;

获得 evbuffer 中接受到数据的指针,使用 parseOnePackage() 对接收到的数据进行判断,是否接受到了一个完整的数据包,或者数据包接受不完整。

猜你喜欢

转载自blog.csdn.net/weixin_40021744/article/details/87899295