您的位置:首页 > 理论基础 > 计算机网络

在libevent事件基础上实现一个TCPServer类

2016-04-28 14:22 696 查看
说明:实现的目标为,本地启动一个TCP服务器,接收来自客户端的连接和数据,采用多线程和回调的方式,方便上层调用。由于初学,如果有哪边问题,请务必指出。

/***********************************************************************MyTcpServer.h**********************************************************/

#ifndef MYTCPSERVER_H

#define MYTCPSERVER_H

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <assert.h>

#include <WS2tcpip.h >

#include "event2/event.h"

#include "event2/bufferevent.h"

#include "event2/thread.h"

#include "event2/listener.h"

#include <WinSock2.h>

#define MAX_LINE 1024

//实现以下的所有函数

void do_accept(evutil_socket_t listener, short event, void *arg);//接受连接

void read_cb(struct bufferevent *bev, void *arg);
//读

void error_cb(struct bufferevent *bev, short event, void *arg);//错误

void write_cb(struct bufferevent *bev, void *arg);
//写

typedef void (CALLBACK* DEALPROC)(SOCKET s,struct bufferevent *bev,unsigned char *buf,int len,char *IP);//处理接收数据

typedef void (CALLBACK* DEALERROR)(SOCKET s,char *IP);//处理错误

typedef struct NODE

{

struct event_base*base;//基础对象

struct event *listen_event;//监听事件

}Node;

class MyTcpServer

{

public:

MyTcpServer(void);

~MyTcpServer(void);

int GetErrcode();

BOOL CreateServer(int port,int backlog);

BOOL StopServer();//停止服务

DEALPROC
lpDealFunc; //处理数据

DEALERROR lpDealError;//处理

protected:

BOOL m_bWSAStartup;

int err;

evutil_socket_t listener;

public:

int SetDealFunc(DEALPROC lpDealFunc);// 设置回调函数

int SetDealError(DEALERROR lpDealError);// 设置错误

BOOL IsSended(SOCKET s);

BOOL IsSockConnected(SOCKET s);

};

/*******************************************************************************MyTcpServer.cpp***************************************************/

#include "MyTcpServer.h"

#include <vector>

using namespace std;

MyTcpServer *gThis = NULL; //保存对象

vector<Node> m_baseArray;

//每有一个连接开启一个处理的线程

void MyThread(LPARAM pa)

{

evutil_socket_t fd = (evutil_socket_t)pa;

evthread_use_windows_threads();

struct event_base *base = event_base_new();

if (base == NULL)

{

return ;

}

struct event *listen_event;

listen_event = event_new(base, fd, EV_READ|EV_PERSIST, do_accept, (void*)base);

event_add(listen_event, NULL);

Node newBase;

newBase.base = base;

newBase.listen_event = listen_event;

m_baseArray.push_back(newBase);

OutputDebugString("添加一个新的连接事件循环");

event_base_dispatch(base);//进入事件循环

//跳出事件循环,关闭监听

OutputDebugString("return\n");

}

MyTcpServer::MyTcpServer(void)

{

WSADATA wsadata;

m_bWSAStartup = FALSE;

err = 0;

listener = 0;

if(WSAStartup(0x202, &wsadata) == 0)

{

m_bWSAStartup = TRUE;

err = 0;

}

else

{

m_bWSAStartup = FALSE;

err = WSAGetLastError();

}

}

MyTcpServer::~MyTcpServer(void)

{

if(m_bWSAStartup) WSACleanup();

}

int MyTcpServer::GetErrcode()

{

return err;

}

//创建一个TCP Server

BOOL MyTcpServer::CreateServer(int port,int backlog)

{

gThis = this;

listener = socket(AF_INET, SOCK_STREAM, 0);

if (listener < 0)

{

err = WSAGetLastError();

return FALSE;

}

if(evutil_make_listen_socket_reuseable(listener) < 0) return FALSE;

struct sockaddr_in sin;

sin.sin_family = AF_INET;

sin.sin_addr.s_addr = 0;

sin.sin_port = htons(port);

if (bind(listener, (struct sockaddr *)&sin, sizeof(sin)) < 0)

{

err = WSAGetLastError();

return FALSE;

}

if (listen(listener, backlog) < 0)

{

err = WSAGetLastError();

return FALSE;

}

if(evutil_make_socket_nonblocking(listener) < 0) return FALSE;

//创建一个线程来进入监听事件的循环

HANDLE m_hServerHandle = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)MyThread,(LPVOID)listener,CREATE_SUSPENDED,0);

if (m_hServerHandle)

{

ResumeThread(m_hServerHandle);

}else

{

return FALSE;

}

return TRUE;

}

void do_accept(evutil_socket_t listener, short event, void *arg)

{

struct event_base *base = (struct event_base *)arg;

evutil_socket_t fd;

struct sockaddr_in sin;

socklen_t slen;

slen = sizeof(struct sockaddr_in);

char *pIPdata = new char[20];

memset(pIPdata,0,20);

fd = accept(listener, (struct sockaddr *)&sin, &slen);

if (fd <0)

{

OutputDebugString("fd < 0");

return ;

}else

{

OutputDebugString("fd ");

}

memcpy(pIPdata,inet_ntoa(sin.sin_addr),20);

struct bufferevent *bev = bufferevent_socket_new(base, fd,BEV_OPT_CLOSE_ON_FREE);

bufferevent_setcb(bev, read_cb,NULL, error_cb, pIPdata);

bufferevent_enable(bev, EV_READ|EV_PERSIST|EV_WRITE);

}

void read_cb(struct bufferevent *bev, void *arg)

{

char line[MAX_LINE+1];

memset(line,0,MAX_LINE+1);

int n;

evutil_socket_t fd = bufferevent_getfd(bev);

while (n = bufferevent_read(bev, (char *)line, MAX_LINE), n > 0) {

//处理数据

gThis->lpDealFunc(fd,bev,(unsigned char*)line,n,(char *)arg);

//OutputDebugString("222");

}

}

void error_cb(struct bufferevent *bev, short event, void *arg)

{

evutil_socket_t fd = bufferevent_getfd(bev);

printf("fd = %u, ", fd);

if (event & BEV_EVENT_TIMEOUT) {

printf("Timed out\n"); //if bufferevent_set_timeouts() called

}

else if (event & BEV_EVENT_EOF) {

OutputDebugString("connection closed\n");

gThis->lpDealError(fd,(char *)arg);

delete[] arg;

arg = NULL;

}

else if (event & BEV_EVENT_ERROR) {

printf("some other error\n");

}

bufferevent_free(bev);

}

// 设置回调函数

int MyTcpServer::SetDealFunc(DEALPROC lpDealFunc)

{

this->lpDealFunc = lpDealFunc;

return 0;

}

int MyTcpServer::SetDealError(DEALERROR lpDealError)

{

this->lpDealError = lpDealError;

return 0;

}

BOOL MyTcpServer::IsSended(SOCKET s)

{

int nRet = 0;

struct fd_set Fd_Send;

struct timeval Time_Send;

memset(&Fd_Send, 0, sizeof(struct fd_set));

FD_CLR(s, &Fd_Send);

FD_SET(s, &Fd_Send);

Time_Send.tv_sec = 2;

Time_Send.tv_usec = 0;

nRet = select(s,NULL, &Fd_Send, NULL, &Time_Send);

if (nRet > 0)

{

return TRUE;

}

return FALSE;

}

BOOL MyTcpServer::IsSockConnected(SOCKET s)

{

int nRet = 0;

struct fd_set Fd_Recv;

struct timeval Time_Recv;

memset(&Fd_Recv, 0, sizeof(struct fd_set));

FD_CLR(s, &Fd_Recv);

FD_SET(s, &Fd_Recv);

Time_Recv.tv_sec = 2;

Time_Recv.tv_usec = 0;

nRet = select(s, &Fd_Recv, NULL, NULL, &Time_Recv);

return (nRet == 0);

}

//停止服务

BOOL MyTcpServer::StopServer()

{

for (vector<Node>::iterator iter = m_baseArray.begin(); iter != m_baseArray.end(); iter ++)

{

event_base_loop(iter->base,EVLOOP_ONCE);

//event_base_free(iter->base);

event_free(iter->listen_event);

}

m_baseArray.clear();

closesocket(listener);

WSACleanup();

return TRUE;

}

#endif

补充:如果向socket发送数据,采用普通的send等函数就可以。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: