libevent实践06:监听TCP服务器

news/2024/10/25 18:28:30/

简介

函数evconnlistener_new_bind

struct evconnlistener *
evconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb,void *ptr, unsigned flags, int backlog, const struct sockaddr *sa,int socklen)

参数解析:

base:事件集合

 evconnlistener_cb:cb是call back的缩写,就是回调函数定义如下:

typedef void (*evconnlistener_cb)(struct evconnlistener *, evutil_socket_t, struct sockaddr *, int socklen, void *);

ptr:传递给cb的参数

flags:属性标志位,可取值9个(掰手指头数的),下面是9个取值的宏定义,在evconnlistener_new_bind函数源码中也可以看出来。

/** Flag: Indicates that we should not make incoming sockets nonblocking* before passing them to the callback. */
#define LEV_OPT_LEAVE_SOCKETS_BLOCKING	(1u<<0)
/** Flag: Indicates that freeing the listener should close the underlying* socket. */
#define LEV_OPT_CLOSE_ON_FREE		(1u<<1)
/** Flag: Indicates that we should set the close-on-exec flag, if possible */
#define LEV_OPT_CLOSE_ON_EXEC		(1u<<2)
/** Flag: Indicates that we should disable the timeout (if any) between when* this socket is closed and when we can listen again on the same port. */
#define LEV_OPT_REUSEABLE		(1u<<3)
/** Flag: Indicates that the listener should be locked so it's safe to use* from multiple threadcs at once. */
#define LEV_OPT_THREADSAFE		(1u<<4)
/** Flag: Indicates that the listener should be created in disabled* state. Use evconnlistener_enable() to enable it later. */
#define LEV_OPT_DISABLED		(1u<<5)
/** Flag: Indicates that the listener should defer accept() until data is* available, if possible.  Ignored on platforms that do not support this.** This option can help performance for protocols where the client transmits* immediately after connecting.  Do not use this option if your protocol* _doesn't_ start out with the client transmitting data, since in that case* this option will sometimes cause the kernel to never tell you about the* connection.** This option is only supported by evconnlistener_new_bind(): it can't* work with evconnlistener_new_fd(), since the listener needs to be told* to use the option before it is actually bound.*/
#define LEV_OPT_DEFERRED_ACCEPT		(1u<<6)
/** Flag: Indicates that we ask to allow multiple servers (processes or* threads) to bind to the same port if they each set the option. * * SO_REUSEPORT is what most people would expect SO_REUSEADDR to be, however* SO_REUSEPORT does not imply SO_REUSEADDR.** This is only available on Linux and kernel 3.9+*/
#define LEV_OPT_REUSEABLE_PORT		(1u<<7)
/** Flag: Indicates that the listener wants to work only in IPv6 socket.** According to RFC3493 and most Linux distributions, default value is to* work in IPv4-mapped mode. If there is a requirement to bind same port* on same ip addresses but different handlers for both IPv4 and IPv6,* it is required to set IPV6_V6ONLY socket option to be sure that the* code works as expected without affected by bindv6only sysctl setting in* system.** This socket option also supported by Windows.*/
#define LEV_OPT_BIND_IPV6ONLY		(1u<<8)

backlog:设置监听队列的大小,同listen函数的第二个参数。

int listen(int s, int backlog);

sa:IP和端口,同bind函数的第二个参数

socklen:结构体长度,同bind函数的第三个参数

int bind(int sockfd, struct sockaddr *sa, socklen_t socklen)

返回值:struct evconnlistener *

从源码简单分析可知 evconnlistener_new_bind内部实现了创建socket,绑定IP地址和端口,最后监听socket。

/**Allocate a new evconnlistener object to listen for incoming TCP connectionson a given address.@param base The event base to associate the listener with.@param cb A callback to be invoked when a new connection arrives. If thecallback is NULL, the listener will be treated as disabled until thecallback is set.@param ptr A user-supplied pointer to give to the callback.@param flags Any number of LEV_OPT_* flags@param backlog Passed to the listen() call to determine the length of theacceptable connection backlog.  Set to -1 for a reasonable default.@param addr The address to listen for connections on.@param socklen The length of the address.*/
struct evconnlistener *
evconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb,void *ptr, unsigned flags, int backlog, const struct sockaddr *sa,int socklen)
{struct evconnlistener *listener;evutil_socket_t fd;int on = 1;int family = sa ? sa->sa_family : AF_UNSPEC;int socktype = SOCK_STREAM | EVUTIL_SOCK_NONBLOCK;if (backlog == 0)return NULL;if (flags & LEV_OPT_CLOSE_ON_EXEC)socktype |= EVUTIL_SOCK_CLOEXEC;fd = evutil_socket_(family, socktype, 0);if (fd == -1)return NULL;if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&on, sizeof(on))<0)goto err;if (flags & LEV_OPT_REUSEABLE) {if (evutil_make_listen_socket_reuseable(fd) < 0)goto err;}if (flags & LEV_OPT_REUSEABLE_PORT) {if (evutil_make_listen_socket_reuseable_port(fd) < 0)goto err;}if (flags & LEV_OPT_DEFERRED_ACCEPT) {if (evutil_make_tcp_listen_socket_deferred(fd) < 0)goto err;}if (flags & LEV_OPT_BIND_IPV6ONLY) {if (evutil_make_listen_socket_ipv6only(fd) < 0)goto err;}if (sa) {if (bind(fd, sa, socklen)<0)goto err;}listener = evconnlistener_new(base, cb, ptr, flags, backlog, fd);if (!listener)goto err;return listener;
err:evutil_closesocket(fd);return NULL;
}

实例:监听服务器

#include <sys/types.h>
#include <event2/event-config.h>
#include <event2/listener.h>
#include <stdio.h>
#include <event.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define _DEBUG_INFO
#ifdef _DEBUG_INFO
#define DEBUG_INFO(format, ...) printf("%s:%d $$ " format "\n" \
,__func__,__LINE__ \
, ##__VA_ARGS__)
#else
#define DEBUG_INFO(format, ...)
#endif/**/void server_evconnlistener_cb(struct evconnlistener *listener, evutil_socket_t new_client, struct sockaddr *addr, int socklen, void *arg)
{struct sockaddr_in *paddr = (struct sockaddr_in *)addr;DEBUG_INFO("a new client fd = %d",new_client);//char *inet_ntoa(struct in_addr in);DEBUG_INFO("ip = %s,port = %d",inet_ntoa(paddr->sin_addr),ntohs(paddr->sin_port));
}int main(int argc, char **argv){struct event_base *base;struct evconnlistener *listener;struct sockaddr_in addr;base = event_base_new();if(base == NULL){DEBUG_INFO("Couldn't create event_base");exit(-1);}addr.sin_family = AF_INET;// addr.sin_addr.s_addr = INADDR_ANY;// addr.sin_addr.s_addr = inet_addr("0.0.0.0");// addr.sin_addr.s_addr = inet_addr("127.0.0.1");addr.sin_addr.s_addr = inet_addr("192.168.0.11");addr.sin_port = htons(6666);listener = evconnlistener_new_bind(base,server_evconnlistener_cb,NULL,//传给cb的参数,本例中就是server_evconnlistener_cbLEV_OPT_CLOSE_ON_EXEC|LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE,5,//listen的第二个参数(struct sockaddr*)&addr,//bind的第二个参数sizeof(addr) //bind的第三个参数);if(listener == NULL){DEBUG_INFO("evconnlistener_new_bind error");exit(-1);}//开始监听集合中的事件event_base_dispatch(base);evconnlistener_free(listener);event_base_free(base);DEBUG_INFO("bye bye");return 0;
}

测试:

运行程序,使用网络调试助手连接服务器的6666端口

程序输出信息:

 

实验分析:

从调试信息可知,输出信息中包含新客户端的文件描述符,客户端的IP地址和客户端的端口号。 

小结


http://www.ppmy.cn/news/671595.html

相关文章

小白开酒吧前要知道的几个知识(二)

第三、选址关于酒吧的选址&#xff0c;首先你要清楚你酒吧的定位。根据酒吧的定位来选择你的店址&#xff0c;酒吧一条街的人流量通常较大&#xff0c;所以适合比较热闹的酒吧风格类型。而比如较小的酒馆&#xff0c;静吧就适合稍微安静一些的店址。还有就是店址一定要明确&…

游戏脚本中控台多线程完整详解

1.1理解需要使用的组件 1.2自动登录的原理 1.3中央控制台的功能分析 2.1帐户库生成 2.10周期编号计时判断 2.11线程已添加 2.12监视线程使用情况&#xff08;单窗口多线程&#xff09; 2.13菜单应用程序方法&#xff08;控制单个帐户&#xff09; …

游戏脚本多线程与中控台完整详解

游戏脚本多线程与中控台完整详解

中控PHP开发,易语言PHP按键精灵搭建中控系统

此中控系统功能如下&#xff1a; 1.用户在电脑可以按指定端口号(实际就是一个用户标识&#xff0c;用于区分的)导入批量账号密码 2.可以使用按键精灵安卓版读取导入的账号&#xff0c;实现多手机读取 涉及到的语言&#xff1a; PHPMYSQL (数据库和中控与按键精灵的核心操作) 易…

宝骏530中控屏怎么安装软件_宝骏530中控屏无反应

宝骏530中控屏幕宝骏530中控屏幕多媒体功能解析,宝骏530的仪表盘与中控导航给你最详细的图文解说 其他配置方面,宝骏530配备了前排侧气囊、胎压监测、定速巡航、前后驻车雷达、无钥匙进入等高级配置。其他配置方面,宝骏530配备了前排侧气囊、胎压监测、定速巡航、前后驻车雷…

雷电模拟器中控助手使用教程

雷电模拟目前使用率比较高的模拟器&#xff0c;录制了&#xff0c;雷电模拟器模块&#xff0c;adb模块的调用示范制作&#xff0c;为了赶制雷电中控的视频教程&#xff0c;写了这个模拟器&#xff0c;方便我们对雷电的控制&#xff0c;查看&#xff0c;修改&#xff0c;安装等等…

大漠Android模拟器中控,最新如意大漠多线程中控模板,适用于手游模拟器脚本...

主要功能: 一:支持雷电任何版本使用 二:支持数据库与文本方式写入脚本 三:支持模拟器窗口消失自动恢复,大小被改变自动还原 四:日志功能,可随时开启或关闭,并且可将日志显示到界面或者通过Debug测试工具查看(之后会加入显示到文本以及只查看自己想看到的窗口的日志) 五…

Unity 中控(一)

项目上有需求要控制投影机一键开和关&#xff0c;在主控主机上写一个中控软件控制&#xff0c;在网上查了一些资料&#xff0c;投影机都可通过串口线来控制(部分可以用网口控制)&#xff0c;这里我用的是串口控制&#xff0c;首先要拿到投影机的中控代码&#xff0c;直接找厂商…