Linux实现远程通信——服务端创建

服务端创建

创建event_base对象

 如果要实现远程通信的功能,那么一定要建立C/S架构,也就是客户端/服务端。这里我们首先来在Linux系统上建立服务端,服务端的监听使用libevent来实现。整体采用多线程来处理客户端请求,因为多线程的开销小。当有客户端向服务端发起连接请求时,就创建一个新的线程用来处理该请求事件。
 在使用 libevent 函数之前需要分配一个或者多个 event_base 结构体。每个event_base 结构体持有一个事件集合,可以检测以确定哪个事件是激活的。创建事件集合使用event_base_new函数,创建event_base的过程:先调用 event_config_new()分配一个 event_config配置文件。然后,对event_config调用其它函数,设置所需要的 event_base特征。最后,调用event_base_new_with_config()获取新的event_base。完成工作后, 使用event_config_free()释放event_config。

struct event_base * event_base_new(void);		//创建一个event_base

创建socket

 在创建event事件集合后,就可以创建socket对象了,这里我们用evconnlistener_new_bind函数创建,相较于平常的socket、bind、listen和accept,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)

用户仅仅需要定义struct sockaddr_in套接字地址结构,并完成对应的初始化即可。其中当有连接事件发生时,会调用系统默认的回调函数listener_read_cb,然后由它调用自定义的监听回调函数,来对本次连接事件做出相应处理。

struct sockaddr_in addr;
memset(&addr,0,sizeof(addr));   		//清除内存碎片
addr.sin_family = AF_INET;      		//IPV4传输
addr.sin_port = htons(port);    		//在公网(网络)上传输,转换为网络字节序
addr.sin_addr.s_addr = inet_addr(ip);   //服务端地址

 在evconnlistener_new_bind函数使用完毕后,该监听事件已经绑定到最开始创建的event_base中,这样只需要检测当前事件是否有激活即可。在这些过程结束后,需要对该事件循环监控,event_base_dispatch和event_base_loop函数都可实现,这里我们调用event_base_dispatch函数即可。

监听回调函数

 evconnlistener_new_bind函数参数中的监听回调函数evconnlistener_cb cb用来处理连接发生时的数据。从多线程的角度,每当发生客户端连接时,就创建一个线程处理。这里我们调用Thread类来创建线程对象,并将此时C/S连接的文件描述符fd当作参数传入执行函数。为了让线程能够单独运行,自动回收,所以将线程detach,而不是join等待。这里举例:

thread client_thread(cb,fd);     //创建执行cb,参数为fd
client_thread.detach();          //线程分离,自动回收               

线程处理

 接下来,就在小线程里处理此次连接事件就好啦。对于客户端传输的数据,我们用bufferevent来处理,基于套接字的bufferevent是最简单的,它使用libevent的底层事件机制来检测底层网络套接字是否已经就绪,可以进行读写操作,并且使用底层网络调用(如readv、writev、WSASend、WSARecv)来发送和接收数据。但是在调用bufferevent前,我们需要创建一个新的event_base事件集合,用来存放和检测bufferevent缓冲区。

struct bufferevent * bufferevent_socket_new(
                     struct event_base *base,
                     evutil_socket_t fd,
                     enum bufferevent_options options
);

 创建完bufferevent对象,当数据传输到服务端时,就调用其回调函数bufferevent_setcb。因为服务端作为接收数据方,我们设置读取回调函数即可,当然你也可以设置eventcb,用来监听一些不寻常的情况。需要注意的是,在设置完回调函数后,需要将其使能,一般情况下,写回调函数writecb是使能的,而读回调函数readcb是没有使能的。

void bufferevent_setcb(
		struct bufferevent *bufev,
		bufferevent_data_cb readcb,     
		bufferevent_data_cb writecb,       		 
        bufferevent_event_cb eventcb, 		
		void *cbarg //共用的传入回调函数的参数
	);

 在上述操作都执行完毕后,就可以进行正常的数据读取以及处理了,我们自定义一个数据缓冲区,用来存放bufferevent中readcb读取的数据,bufferevent中带了bufferevent_read函数,可以将接收的数据放进我们自定义的缓冲区中。

size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size);

 在接收完数据后,你可以判断一下返回值,如果返回值不为0,那么就接收到数据,接下来,就可以进行处理了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值