libevent学习笔记【使用篇】——8. 连接监听:接收TCP连接

news/2024/5/17 19:25:32 标签: libevent, tcp

原文:blog.csdn.com/windeal3203
译自:http://www.wangafu.net/~nickm/libevent-book/Ref8_listener.html

libevent 提供了一种用于监听和接受TCP连接的便捷方式——evconnlistener机制

创建和释放 evconnlistener 的接口

下面接口用于创建和释放evconnlistener

struct evconnlistener *evconnlistener_new(struct event_base *base,
    evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
    evutil_socket_t fd);
struct evconnlistener *evconnlistener_new_bind(struct event_base *base,
    evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
    const struct sockaddr *sa, int socklen);
void evconnlistener_free(struct evconnlistener *lev);

函数evconnlistener_newevconnlistener_new_bind都用于分配和返回一个新的用于监听连接的对象。 每个用于监听的对象都使用event_base来维护一个建立的连接。当有新的TCP 连接发生时,回调函数就会调用。
下面介绍以上接口使用到的参数“

  • base: event_base对象。参考event_base。
  • cb: 回调函数, 当有新的TCP连接发生时,会唤醒回调函数。
  • ptr: 传递给回调函数的参数。
  • flags: 一些标志, 后面会进一步介绍。
  • backlog: 监听队列允许容纳的最大连接数。
  • fd: 函数evconnlistener_new假设我们已经绑定了套接字到要监听的端口上,fd参数就是我们已经绑定的socket套接字。
  • sa: evconnlistener_new_bind帮助我们绑定监听地址。sa就是传入的监听地址。
  • socklen: sa的长度。

如果使用的是evconnlistener_new,需要保证传入的socket套接字处于non-blocking模式,可以通过evutil_make_socket_nonblocking等方法进行设置

常用的flag值:

  • LEV_OPT_LEAVE_SOCKETS_BLOCKING:默认情况下listener会把接收到的连接设置为non-blocking模式。 这个flag则是将连接设置为blocking状态(少用)
  • LEV_OPT_CLOSE_ON_FREE:释放listener时,先关闭潜在的套接字
  • LEV_OPT_REUSEABLE:一些系统平台在默认情况下即使已经关闭了socket,也要等待一段时间才能使用对应的port, 而这个flag则设置成只要已关闭socket就是重新使用对应的port。

关于回调函数

回调函数原型如下:

typedef void (*evconnlistener_cb)(struct evconnlistener *listener,
    evutil_socket_t sock, struct sockaddr *addr, int len, void *ptr);

参数解释如下:

  • listener: 即接受连接的lister
  • sock: 新连接创建的新套接字
  • addr: 连接发起者的地址
  • len: 地址长度
  • ptr:evconnlistener_newevconnlistener_bind_new传来的参数。

libevent提供调整回调函数的接口
下面接口可以重新设置回调函数,或者调整回调函数中的参数。

void evconnlistener_set_cb(struct evconnlistener *lev,
    evconnlistener_cb cb, void *arg);

开启和关闭监听

listener允许临时关闭和重新开启监听

int evconnlistener_disable(struct evconnlistener *lev);
int evconnlistener_enable(struct evconnlistener *lev);

Example

#include <event2/listener.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>

#include <arpa/inet.h>

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

static void
echo_read_cb(struct bufferevent *bev, void *ctx)
{
        /* This callback is invoked when there is data to read on bev. */
        struct evbuffer *input = bufferevent_get_input(bev);
        struct evbuffer *output = bufferevent_get_output(bev);

        /* Copy all the data from the input buffer to the output buffer. */
        evbuffer_add_buffer(output, input);
}

static void
echo_event_cb(struct bufferevent *bev, short events, void *ctx)
{
        if (events & BEV_EVENT_ERROR)
                perror("Error from bufferevent");
        if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) {
                bufferevent_free(bev);
        }
}

static void
accept_conn_cb(struct evconnlistener *listener,
    evutil_socket_t fd, struct sockaddr *address, int socklen,
    void *ctx)
{
        /* We got a new connection! Set up a bufferevent for it. */
        struct event_base *base = evconnlistener_get_base(listener);
        struct bufferevent *bev = bufferevent_socket_new(
                base, fd, BEV_OPT_CLOSE_ON_FREE);

        bufferevent_setcb(bev, echo_read_cb, NULL, echo_event_cb, NULL);

        bufferevent_enable(bev, EV_READ|EV_WRITE);
}

static void
accept_error_cb(struct evconnlistener *listener, void *ctx)
{
        struct event_base *base = evconnlistener_get_base(listener);
        int err = EVUTIL_SOCKET_ERROR();
        fprintf(stderr, "Got an error %d (%s) on the listener. "
                "Shutting down.\n", err, evutil_socket_error_to_string(err));

        event_base_loopexit(base, NULL);
}

int
main(int argc, char **argv)
{
        struct event_base *base;
        struct evconnlistener *listener;
        struct sockaddr_in sin;

        int port = 9876;

        if (argc > 1) {
                port = atoi(argv[1]);
        }
        if (port<=0 || port>65535) {
                puts("Invalid port");
                return 1;
        }

        base = event_base_new();
        if (!base) {
                puts("Couldn't open event base");
                return 1;
        }

        /* Clear the sockaddr before using it, in case there are extra
         * platform-specific fields that can mess us up. */
        memset(&sin, 0, sizeof(sin));
        /* This is an INET address */
        sin.sin_family = AF_INET;
        /* Listen on 0.0.0.0 */
        sin.sin_addr.s_addr = htonl(0);
        /* Listen on the given port. */
        sin.sin_port = htons(port);

        listener = evconnlistener_new_bind(base, accept_conn_cb, NULL,
            LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1,
            (struct sockaddr*)&sin, sizeof(sin));
        if (!listener) {
                perror("Couldn't create listener");
                return 1;
        }
        evconnlistener_set_error_cb(listener, accept_error_cb);

        event_base_dispatch(base);
        return 0;
}

http://www.niftyadmin.cn/n/1078878.html

相关文章

Leetcode217——Contains Duplicate

Given an array of integers, find if the array contains any duplicates. Your function should return true if any value appears at least twice in the array, and it should return false if every element is distinct. 实现 bool containsDuplicate(vector<int&g…

libevent学习笔记【使用篇】——9. Libevent和DNS解析

原文&#xff1a;blog.csdn.com/windeal3203 译自&#xff1a;http://www.wangafu.net/~nickm/libevent-book/Ref9_dns.html Libevent 提供了一些用于解析DNS域名的API&#xff0c; 以及一些用于实现DNS Server的接口。 可移植的阻塞型域名解析 Libevent 提供了标准库函数g…

HTTP_X_FORWARDED_FOR 和 REMOTE_ADDR的使用(转载)

PHP中HTTP_X_FORWARDED_FOR 和 REMOTE_ADDR的使用 博客分类&#xff1a; LAMPPHP浏览器Blog参考来源&#xff1a;http://qq398705749.iteye.com/blog/963818 1.REMOTE_ADDR:浏览当前页面的用户计算机的ip地址 2.HTTP_X_FORWARDED_FOR: 浏览当前页面的用户计算机的网关 3.HTTP_C…

99%的人都理解错了 HTTP 中 GET 与 POST 的区别

GET和POST是HTTP请求的两种基本方法&#xff0c;要说它们的区别&#xff0c;接触过WEB开发的人都能说出一二。 最直观的区别就是GET把参数包含在URL中&#xff0c;POST通过request body传递参数。 你可能自己写过无数个GET和POST请求&#xff0c;或者已经看过很多权威网站总结…

委托之异步(转自http://www.cnblogs.com/inforasc/archive/2009/10/21/1587756.html

委托之异步在 使用BackgroundWorker组件 一文中&#xff0c;阐述了在Winform编程中&#xff0c;使用BackgroundWorker组件实现异步调用&#xff0c;本文主要讲述利用委托实现异步。 以下描述摘抄于MSDN: 异步委托提供以异步方式调用同步方法的能力。 当同步调用委托时&#xff…

LeetCode226——Invert Binary Tree

话说&#xff0c;几天前&#xff0c;Max Howell&#xff08;Homebrew的作者&#xff09;去Google面试&#xff0c;Google就出了这个题&#xff0c;结果他竟然写不出来。。。 然后&#xff0c;他就在twitter上吐槽了: Google: 90% of our engineers use the software you wrote …

C语言正则表达式详解 regcomp() regexec() regfree()详解

转载自&#xff1a;http://c.biancheng.net/cpp/html/1428.html 部分内容有修改。 标准的C和C都不支持正则表达式&#xff0c;但有一些函数库可以辅助C/C程序员完成这一功能&#xff0c;其中最著名的当数Philip Hazel的Perl-Compatible Regular Expression库&#xff0c;许多…

全民Scheme(0):lat的定义

接下来我会写一写Scheme的学习笔记。嗯&#xff0c;Scheme是属于小众的语言&#xff0c;但合适用来教学的。 什么是lat&#xff0c;就是遍历list里的每个S-expression,如果发现其中某个不是atom的&#xff0c;则返回false&#xff0c;否则返回true。 (define atom? (lambd…