为了使主线程监听客户端的连接请求,重新封装一个类,Tcpserver, 代码如下。
#ifndef TCPSERVER_H
#define TCPSERVER_H
#include "thread.h"
#include <event2/listener.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
class Tcpserver {
private:
Thread *m_threadPool; //线程池
int m_threadNum; //线程池大小
struct event_base *m_base; //事件集合
struct evconnlistener *m_listener; //监听事件
public:
Tcpserver(int threadNum = 8);
~Tcpserver();
int listen(int port, const char *ip = NULL); //ip=NULL 允许监听所有ip
void start(); //服务器的运行函数
protected:
static void listener_cb(struct evconnlistener *, evutil_socket_t ,struct sockaddr *, int, void *);
};
#endif//tcpserver.h
服务器类的初始构造包含一个监听函数listen,以及监听过程中的回调函数listener_cb,同时要注意创造一个evconnlistener格式的对象来存放监听事件。
服务器类的构造函数如下
Tcpserver::Tcpserver(int threadNum){
//初始化m_base
m_base=event_base_new();
if(!m_base){
printf("Could not creat an event_base: exiting\n");
exit(1);
}
//判断一下传参是否合理
if(0>=threadNum){
printf("threadNum error!\n");
exit(1);
}
//初始化线程池
m_threadNum=threadNum;
m_threadPool=new Thread[m_threadNum];
}
监听函数及其回调函数的具体代码如下:
int Tcpserver::listen(int port, const char *ip){
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
if(NULL!=ip){
inet_aton(ip, &sin.sin_addr);
}
m_listener = evconnlistener_new_bind (m_base, listener_cb, this, LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, -1, (struct sockaddr *) &sin, sizeof(sin));
if(!m_listener){
printf("Could not create a listener!\n");
return 1;
}
printf("done\n");
return 0;
}
void Tcpserver::listener_cb(struct evconnlistener *, evutil_socket_t ,struct sockaddr *, int, void *){
printf("有客户端请求连接\n");
}
void Tcpserver::start(){
//开始监听
event_base_dispatch(m_base);
evconnlistener_free(m_listener);
event_base_free(m_base);
}
服务器类封装完成后,进行简单测试:
int main () {
Tcpserver *t = new Tcpserver;
t->listen(8051);
t->start();
return 0;
}
由于服务器的端口库没开,在服务器端本地测试,先运行服务器端
输另开客户端进行连接测试
客户端收到连接请求
服务器类的初步封装测试完成