#pragma once
#include "CLibEventData.h"
#include "LibEventFunction.h"
#include "LibUserFunction.h"
class CLibEvent
{
public:CLibEvent(void);~CLibEvent(void);
private://当前服务器对象Server m_Server;
public:bool StartServer(int port, short workernum, unsigned int connnum, int read_timeout, int write_timeout);void StopServer();
private:void LoadFuns();static void DoAccept(struct evconnlistener *listener, evutil_socket_t fd,struct sockaddr *sa, int socklen, void *user_data);static void DoError(struct bufferevent *bev, short error, void *ctx);static void CloseConn(Conn *pConn,int nFunID);static void CloseConn(Conn *pConn);static void DoRead(struct bufferevent *bev, void *ctx);static DWORD WINAPI ThreadServer(LPVOID lPVOID);static DWORD WINAPI ThreadWorkers(LPVOID lPVOID);
};
#include "StdAfx.h"
#include "LibEvent.h"#include <string>
#include <iostream>
using namespace std;#include <assert.h>
#include <signal.h>#include <WinSock2.h>
#pragma comment (lib,"ws2_32.lib")
#pragma comment (lib,"wsock32.lib")#include "LibEventFunction.h"#ifdef _DEBUG
#pragma comment (lib,"libevent.lib")
#else
#pragma comment (lib,"libevent.lib")
#endifCLibEvent::CLibEvent(void)
{   LoadFuns();ZeroMemory(&m_Server,sizeof(m_Server));WSADATA WSAData;WSAStartup(0x0201, &WSAData);
}CLibEvent::~CLibEvent(void)
{WSACleanup();
}bool CLibEvent::StartServer(int port, short workernum, unsigned int connnum, int read_timeout, int write_timeout)
{   m_Server.bStart=false;m_Server.nCurrentWorker=0;m_Server.nPort=port;m_Server.workernum=workernum;m_Server.connnum=connnum;m_Server.read_timeout=read_timeout;m_Server.write_timeout=write_timeout;evthread_use_windows_threads();m_Server.pBase=event_base_new();if (m_Server.pBase==NULL){return false;}struct sockaddr_in sin;memset(&sin, 0, sizeof(sin));sin.sin_family = AF_INET;sin.sin_port = htons(m_Server.nPort);m_Server.pListener=evconnlistener_new_bind(m_Server.pBase,DoAccept,(void*)&m_Server,LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE,-1,(struct sockaddr*)&sin,sizeof(sin));if (m_Server.pListener==NULL){return false;}   CLibEventFunction::RegistConnectedFunc(CLibUserFunction::Connect);CLibEventFunction::RegistDisconnectedFunc(CLibUserFunction::DisConnect);  CLibEventFunction::RegistStx(emStx);m_Server.pWorker=new Worker[workernum];for (int i=0;i<workernum;i++){m_Server.pWorker[i].pWokerbase=event_base_new();if (m_Server.pWorker[i].pWokerbase== NULL){delete []m_Server.pWorker;return false;}//初始化连接对象{m_Server.pWorker[i].pListConn=new ConnList();if (m_Server.pWorker[i].pListConn==NULL){return false;}m_Server.pWorker[i].pListConn->plistConn=new Conn[m_Server.connnum+1];m_Server.pWorker[i].pListConn->head=&m_Server.pWorker[i].pListConn->plistConn[0];m_Server.pWorker[i].pListConn->tail=&m_Server.pWorker[i].pListConn->plistConn[m_Server.connnum];for (int j=0; j<m_Server.connnum; j++) {m_Server.pWorker[i].pListConn->plistConn[j].index=j;m_Server.pWorker[i].pListConn->plistConn[j].next=&m_Server.pWorker[i].pListConn->plistConn[j+1];}m_Server.pWorker[i].pListConn->plistConn[m_Server.connnum].index=m_Server.connnum;m_Server.pWorker[i].pListConn->plistConn[m_Server.connnum].next=NULL;//设置当前事件Conn *p=m_Server.pWorker[i].pListConn->head;while (p!=NULL){p->bufev=bufferevent_socket_new(m_Server.pWorker[i].pWokerbase,-1, BEV_OPT_CLOSE_ON_FREE);if (p->bufev==NULL) {return false;}bufferevent_setcb(p->bufev, DoRead, NULL, DoError, p);bufferevent_setwatermark(p->bufev, EV_READ, 0, emMaxBuffLen);bufferevent_enable(p->bufev, EV_READ|EV_WRITE);struct timeval delayWriteTimeout;delayWriteTimeout.tv_sec=m_Server.write_timeout;delayWriteTimeout.tv_usec=0;struct timeval delayReadTimeout;delayReadTimeout.tv_sec=m_Server.read_timeout;delayReadTimeout.tv_usec=0;bufferevent_set_timeouts(p->bufev,&delayReadTimeout,&delayWriteTimeout);p->owner=&m_Server.pWorker[i];p=p->next;}}m_Server.pWorker[i].hThread=CreateThread(NULL,0,ThreadWorkers,&m_Server.pWorker[i],0,NULL);}m_Server.hThread=CreateThread(NULL,0,ThreadServer,&m_Server,0,NULL);if (m_Server.hThread==NULL){return false;}m_Server.bStart=true;return true;
}void CLibEvent::StopServer()
{if (m_Server.bStart){struct timeval delay = { 2, 0 };event_base_loopexit(m_Server.pBase, &delay);WaitForSingleObject(m_Server.hThread,INFINITE);if (m_Server.pWorker){for (int i=0;i<m_Server.workernum;i++){event_base_loopexit(m_Server.pWorker[i].pWokerbase, &delay);WaitForSingleObject(m_Server.pWorker[i].hThread,INFINITE);}for (int i=0;i<m_Server.workernum;i++){if (m_Server.pWorker[i].pListConn){delete []m_Server.pWorker[i].pListConn->plistConn;delete m_Server.pWorker[i].pListConn;m_Server.pWorker[i].pListConn=NULL;}event_base_free(m_Server.pWorker[i].pWokerbase);}            delete[]m_Server.pWorker;m_Server.pWorker=NULL;}   evconnlistener_free(m_Server.pListener);event_base_free(m_Server.pBase);}m_Server.bStart=false;
}void CLibEvent::DoRead(struct bufferevent *bev, void *ctx)
{struct evbuffer * input=bufferevent_get_input(bev);if (evbuffer_get_length(input)) {Conn *c = (Conn*) ctx;while (evbuffer_get_length(input)) {c->in_buf_len+=evbuffer_remove(input, c->in_buf,emMaxBuffLen-c->in_buf_len);         }      while(true){//一个协议包的请求头还没读完,则继续循环读或者等待下一个libevent时间进行循环读if (c->in_buf_len<sizeof(Head)){return;}Head *h=(Head*)c->in_buf;if (h->pkglen >emMaxBuffLen-sizeof(Head)||h->pkglen<sizeof(Head)||h->stx!=CLibEventFunction::LoadStx()) {//请求包不合法CloseConn(c);return;}//读取的数据不够if (c->in_buf_len<h->pkglen) {return;}//执行协议指令if (h->nFunID>emFunBase&&CLibEventFunction::DispatchFunction(h->nFunID,NULL)) {switch(CLibEventFunction::DispatchFunction(h->nFunID,c)){case emFunReturnSend:{struct evbuffer * output=bufferevent_get_output(bev);evbuffer_add(output,c->out_buf,c->out_buf_len);}break;case emFunReturClose:{CloseConn(c);}return;case emFunReturnRecv:break;}             } else {CloseConn(c);return;}//处理下一个协议包,或者继续读c->in_buf_len-=h->pkglen;if (c->in_buf_len==0){break;}else{assert(c->in_buf_len>0);memmove(c->in_buf,c->in_buf+h->pkglen,c->in_buf_len);}}}
}void CLibEvent::CloseConn(Conn *pConn,int nFunID)
{pConn->in_buf_len = 0;CLibEventFunction::DispatchFunction(nFunID,pConn);bufferevent_disable(pConn->bufev, EV_READ | EV_WRITE);evutil_closesocket(pConn->fd);pConn->owner->PutFreeConn(pConn);
}void CLibEvent::CloseConn(Conn *pConn)
{CloseConn(pConn,emFunClosed);
}void CLibEvent::DoError(struct bufferevent *bev, short error, void *ctx)
{Conn *c=(Conn*)ctx;emFunID id=emFunNull;if (error&EVBUFFER_TIMEOUT) {id=emFunTimeout;} else if (error&EVBUFFER_EOF){id=emFunClosed;} else if (error&EVBUFFER_ERROR) {id=emFunError;}CloseConn(c, id);
}void CLibEvent::DoAccept(struct evconnlistener *listener, evutil_socket_t fd,struct sockaddr *sa, int socklen, void *user_data)
{//此处为监听线程的event.不做处理.Server *pServer = (Server *)user_data;//主线程处做任务分发.int nCurrent=pServer->nCurrentWorker++%pServer->workernum;//当前线程所在ID号Worker &pWorker=pServer->pWorker[nCurrent];//通知线程开始读取数据,用于分配哪一个线程来处理此处的event事件Conn *pConn=pWorker.GetFreeConn();if (pConn==NULL){return;}  pConn->fd=fd;evutil_make_socket_nonblocking(pConn->fd);bufferevent_setfd(pConn->bufev, pConn->fd);//转发发送事件CLibEventFunction::DispatchFunction(emFunConnected,pConn);bufferevent_enable(pConn->bufev, EV_READ | EV_WRITE);
}DWORD WINAPI CLibEvent::ThreadServer(LPVOID lPVOID)
{Server * pServer=reinterpret_cast<Server *>(lPVOID);if (pServer==NULL){return -1;}event_base_dispatch(pServer->pBase);return GetCurrentThreadId();
}DWORD WINAPI CLibEvent::ThreadWorkers(LPVOID lPVOID)
{Worker *pWorker=reinterpret_cast<Worker *>(lPVOID);if (pWorker==NULL){return -1;}event_base_dispatch(pWorker->pWokerbase);return GetCurrentThreadId();
}void CLibEvent::LoadFuns()
{CLibEventFunction::RegistFunc(emFunLogin,CLibUserFunction::Login);CLibEventFunction::RegistFunc(emFunLogout,CLibUserFunction::Logout);
}

网络开源框架之libevent使用实例相关推荐

  1. 网络开源框架之libev使用实例

    // libev.cpp : 定义控制台应用程序的入口点. //#include "stdafx.h"#include <stdio.h> #include <s ...

  2. [13]深入浅出工作开源框架Camunda:多实例并行用户任务

    Camunda提供了多实例并行用户任务,比如下面的并行多任务流程! 必须选择三条竖杠. 选择之后,就可以让"并行会签预审批"任务同时由多个人处理~ 参考<基于camunda如 ...

  3. Android_开源框架_Volley实例

    2019独角兽企业重金招聘Python工程师标准>>> 1.自定义相关类 在 Android_开源框架_Volley(Google IO 2013)源代码及内部实现过程分析一文中,简 ...

  4. 开源 Python网络爬虫框架 Scrapy

    开源 Python 网络爬虫框架 Scrapy:http://blog.csdn.net/zbyufei/article/details/7554322 介绍 所谓网络爬虫,就是一个在网上到处或定向抓 ...

  5. 有限状态机的C++实现(2)-bayonet开源网络服务器框架

    有限状态机的C++实现(2)-bayonet开源网络服务器框架 | Vimer的程序世界 有限状态机的C++实现(2)-bayonet开源网络服务器框架 Published on 二月 18, 201 ...

  6. 开源的网络服务框架:Apache Etch 1.4.0 发布

    Apache Etch是一个开源.跨平台.语言和传输方式独立的网络服务框架,可用来构建和使用网络服务.Etch提供的工具集包括一个网络服务描述语言.一个编译器和与各种语言进行绑定的库.它具有传输方式独 ...

  7. 开源Unity服务端客户端(双端C#)网络通讯框架(Lidgren)[一]

    开源Unity服务端客户端(双端C#)网络通讯框架(Lidgren)[一] 1. 简介 1.1 结识Lidgren的机缘巧合 开发Unity的各位或多或少都可能在工作中遇到非客户端开发的一些内容.大型 ...

  8. 国产开源网络编程框架tio的得意之作—谭聊介绍

    想各位对即时通讯源码有追求人,必然有所了解谭聊,谭聊是完全基于开源网络编程框架t-io开发的一款即时通讯软件,也是t-io作者亲自操刀,性能上的强大能力完全继承了t-io的特性,即单机版可以达到近百万 ...

  9. 跨平台微信网络开源Mars与网络框架Okhttp、Volley、Retrofit,Cookie持久化

    > 1. Mars 移动端IM网络层跨平台组件库Mars- https://github.com/Tencent/mars Android.iOS.OS X 平台的 demo(微信开源Mars的 ...

最新文章

  1. jQuery源码-jQuery.fn.each jQuery.each
  2. linux下字符编码转换
  3. Git学习记录 力做全网最强入门教程
  4. IDEA中Mybatis逆向工程使用方法
  5. PHP中的SESSION机制应用
  6. C# 窗口全屏 隐藏任务栏 (代码)
  7. 开源开放 | 计算机科学示意图问答数据集CSDQA(CCKS2021)
  8. 面试官:你知道怎么求素数吗?
  9. 教你用SingalR实现后台开发程序运行时时检测
  10. 15/7/2017 暑期第一次集训小总结
  11. mysql查询当前时间和用户_MySQL学习笔记(3) - 查询服务器版本,当前时间,当前用户...
  12. 在div 底部显示背景图片
  13. Entity Resolution(实体解析)
  14. Classic Poems ----Tagore, Stray birds
  15. robbe+base64+Mysql简易有效的php全文索引实现
  16. Windows 注册表清理
  17. Python游戏篇:细节之大型游戏爆炸效果(附代码)
  18. opencv存取视频的编码格式 fourcc
  19. PostgresSQL 使用实践
  20. ASP.NET MVC中商品模块小样

热门文章

  1. ftok file php,Linux和PHP中的ftok函数返回值不一致问题跟踪
  2. wget ip_10分钟搭建个人开源博客+域名ip解析
  3. 1—YOLO2:环境搭建
  4. 15.基于Hadoop的数据仓库Hive第3部分(Hive编程实践)
  5. 【Linux】13.linux内核切换
  6. Caffe:solver及其配置
  7. caffe卷积层代码阅读笔记
  8. Oracle编程入门经典 第9章 掌握SQL*Plus
  9. 跟我一起写 Makefile(七)
  10. 一步步教你Hadoop多节点集群安装配置