首页 > 其他 > 详细

libevent库1.4升级到2.0时无法flush的解决办法

时间:2014-03-18 20:11:29      阅读:629      评论:0      收藏:0      [点我收藏+]

libevent的接口兼容性做的还算不错,基本上替换一下就转到新版本了。但是,强制flush数据的时候出了问题。目前的应用场景是,遇到顶号登录这种情形,先用bufferevent_write向客户端发送错误信息,然后再断开socket。用的flush是这样的:

void try_flush(bufferevent *bev) {
    int size = evbuffer_get_length(bufferevent_get_output(bev));
    if (size > 0) {
        evbuffer_write(bufferevent_get_output(bev), fd);
    }  
}

 

在1.4的时候,这段代码工作良好。但是,在2.0的libevent里,这段代码不能刷出数据。看了下errno和socket_errno,错误码是EINPROGRESS。百思不得其解下,在脚本层将关闭socket放在下一次libevent事件循环里完成,结果就好了。

 

 

大致猜测下,应该是libevent为了效率做的优化。因为write是比较昂贵的系统调用,若因为evbuffer_write的反复调用,而引起多次write,会影响性能。翻了一下libevent 2.0的代码,evbuffer_write是调用evbuffer_write_atmost的,对比下1.4 evbuffer_write和2.0的evbuffer_write_atmost:

bubuko.com,布布扣
int
evbuffer_write(struct evbuffer *buffer, int fd)
{
    int n;

#ifndef WIN32
    n = write(fd, buffer->buffer, buffer->off);
#else
    n = send(fd, buffer->buffer, buffer->off, 0);
#endif
    if (n == -1)
        return (-1);
    if (n == 0)
        return (0);
    evbuffer_drain(buffer, n);

    return (n);
}
bubuko.com,布布扣
bubuko.com,布布扣
int
evbuffer_write_atmost(struct evbuffer *buffer, evutil_socket_t fd,
    ev_ssize_t howmuch)
{
    int n = -1;

    EVBUFFER_LOCK(buffer);

    if (buffer->freeze_start) {
        goto done;
    }

    if (howmuch < 0 || (size_t)howmuch > buffer->total_len)
        howmuch = buffer->total_len;

    if (howmuch > 0) {
#ifdef USE_SENDFILE
        struct evbuffer_chain *chain = buffer->first;
        if (chain != NULL && (chain->flags & EVBUFFER_SENDFILE))
            n = evbuffer_write_sendfile(buffer, fd, howmuch);
        else {
#endif
#ifdef USE_IOVEC_IMPL
        n = evbuffer_write_iovec(buffer, fd, howmuch);
#elif defined(WIN32)
        /* XXX(nickm) Don‘t disable this code until we know if
         * the WSARecv code above works. */
        void *p = evbuffer_pullup(buffer, howmuch);
        n = send(fd, p, howmuch, 0);
#else
        void *p = evbuffer_pullup(buffer, howmuch);
        n = write(fd, p, howmuch);
#endif
#ifdef USE_SENDFILE
        }
#endif

    if (n > 0)
        evbuffer_drain(buffer, n);

done:
    EVBUFFER_UNLOCK(buffer);
    return (n);
}
bubuko.com,布布扣

2.0有个显眼的freeze_start的检查,正是这个检查,让evbuffer_write的调用直接跳过了发送阶段。于是,在flush的时候加了一个dirty trick,直接调用了evbuffer_unfreeze:

bubuko.com,布布扣
void try_flush(bufferevent *bev) {
    int size = evbuffer_get_length(bufferevent_get_output(bev));
    if (size > 0) {
        evbuffer_unfreeze(bufferevent_get_output(bev), 1);
        evbuffer_write(bufferevent_get_output(bev), fd);
    } 
}
bubuko.com,布布扣

问题解决

libevent库1.4升级到2.0时无法flush的解决办法,布布扣,bubuko.com

libevent库1.4升级到2.0时无法flush的解决办法

原文:http://www.cnblogs.com/Lifehacker/p/libevent_upgrade_from_1-4_to_2-0-21.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!