【网络库学习】libevent篇

(一)linux编译
./configure --prefix=xxx --disable-openssl # 针对libevent 2.1.12版本 我这里不需要ssl
make
make install

【网络库学习】libevent篇_第1张图片

(二) udp编程
#include 
#include 
#include 
#include 

#include 
#include 

void udp_read_cb(int fd, short ev, void *p)
{
    char buff[1024] = "";
    struct sockaddr_in sa;
    int sock_len = sizeof(sockaddr_in);
    memset(&sa,0,sock_len);

   ssize_t len = recvfrom(fd,buff,1023,0,(struct sockaddr*)&sa,(socklen_t*)&sock_len);
   if (len >= 0)
   {
        printf("recv:%s",buff);
   } else {
       evutil_closesocket(fd);
   }
}

int udp_handle_loop()
{
    /* 1.Creating an event_base */
    struct event_base* base = event_base_new();
    if (NULL == base)
    {
        perror("event_base_new failed");
        return -1;
    }
    printf("event base create\n");
    /* Working with events
     * Libevent’s basic unit of operation is the event. Every event represents a set of conditions, including:
     *   A file descriptor being ready to read from or write to.
     *   A file descriptor becoming ready to read from or write to (Edge-triggered IO only).
     *   A timeout expiring.
     *   A signal occurring.
     *   A user-triggered event.
    */
    struct event* timer_ev = evtimer_new(base,timer_cb,NULL);
    event_add(timer_ev,NULL);

    /* udp socket */
    int udpSocket = socket(AF_INET,SOCK_DGRAM,0);
    if (-1 == udpSocket)
    {
        perror("socket failed");
        return -1;
    }
    struct sockaddr_in sa;
    sa.sin_family = AF_INET;
    sa.sin_port = htons(8080);
    sa.sin_addr.s_addr = INADDR_ANY;

    int opt = 1;
    setsockopt(udpSocket,SOL_SOCKET,SO_REUSEADDR,(const void*)&opt,sizeof(opt));

    int ret = ::bind(udpSocket,(struct sockaddr*)&sa,sizeof(sa));
    if (ret < 0)
    {
        perror("bind error");
        return -1;
    }
    struct event* udp_ev = event_new(base,udpSocket,EV_READ | EV_PERSIST,udp_read_cb,NULL);

    struct timeval val;
    val.tv_usec = 150;

    event_add(udp_ev,NULL);
    /* 2.Working with an event loop */
    event_base_dispatch(base);

    event_base_free(base);
    evutil_closesocket(udpSocket);
}

【网络库学习】libevent篇_第2张图片

(三) tcp编程
(四) http编程
(五) 原理

【网络库学习】libevent篇_第3张图片
1) 事件源
Linux上是文件描述符,Windows上就是Socket或者Handle了,这里统一称为“句柄集”;程序在指定的句柄上注册关心的事件,比如I/O事件。
2) event demultiplexer——事件多路分发机制
由操作系统提供的I/O多路复用机制,比如select和epoll。
程序首先将其关心的句柄(事件源)及其事件注册到event demultiplexer上;
当有事件到达时,event demultiplexer会发出通知“在已经注册的句柄集中,一个或多个句柄的事件已经就绪”;
程序收到通知后,就可以在非阻塞的情况下对事件进行处理了。
对应到libevent中,依然是select、poll、epoll等,但是libevent使用结构体eventop进行了封装,以统一的接口来支持这些I/O多路复用机制,达到了对外隐藏底层系统机制的目的。
3) Reactor——反应器
Reactor,是事件管理的接口,内部使用event demultiplexer注册、注销事件;并运行事件循环,当有事件进入“就绪”状态时,调用注册事件的回调函数处理事件。
对应到libevent中,就是event_base结构体。
源码里最终还是调用io复用的接口,例如select、poll、epoll等
(以上转载自https://zhuanlan.zhihu.com/p/371223583)

struct event_base *
event_base_new(void)
{
	struct event_base *base = NULL;
	struct event_config *cfg = event_config_new();
	if (cfg) {
		base = event_base_new_with_config(cfg);
		event_config_free(cfg);
	}
	return base;
}
struct event_base *
event_base_new_with_config(const struct event_config *cfg)
{
...
	for (i = 0; eventops[i] && !base->evbase; i++) {
		if (cfg != NULL) {
			/* determine if this backend should be avoided */
			if (event_config_is_avoided_method(cfg,
				eventops[i]->name))
				continue;
			if ((eventops[i]->features & cfg->require_features)
			    != cfg->require_features)
				continue;
		}
		/* also obey the environment variables */
		if (should_check_environment &&
		    event_is_method_disabled(eventops[i]->name))
			continue;
		base->evsel = eventops[i];// eventops
		base->evbase = base->evsel->init(base);
	}
...
}
/* Array of backends in order of preference. */
static const struct eventop *eventops[] = {
#ifdef EVENT__HAVE_EVENT_PORTS
	&evportops,
#endif
#ifdef EVENT__HAVE_WORKING_KQUEUE
	&kqops,
#endif
#ifdef EVENT__HAVE_EPOLL
	&epollops,
#endif
#ifdef EVENT__HAVE_DEVPOLL
	&devpollops,
#endif
#ifdef EVENT__HAVE_POLL
	&pollops,
#endif
#ifdef EVENT__HAVE_SELECT
	&selectops,
#endif
#ifdef _WIN32
	&win32ops,
#endif
	NULL
};

const struct eventop selectops = {
	"select",
	select_init,
	select_add,
	select_del,
	select_dispatch,
	select_dealloc,
	0, /* doesn't need reinit. */
	EV_FEATURE_FDS,
	0,
};

static int
select_dispatch(struct event_base *base, struct timeval *tv)
{
...
res = select(nfds, sop->event_readset_out,
	    sop->event_writeset_out, NULL, tv);
...
}
(六) 参考资料

https://libevent.org/doc/
http://www.wangafu.net/~nickm/libevent-book/

你可能感兴趣的:(网络通信,网络)