最近在学习libevent,写了一些测试的例子,最开始是用共享内存实现的,后来改成了多线程。而且很多细节没有考虑。先存下档,后面再改(不改了)
main.cpp
#include "stdafx.h"
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<event.h>
#include<event2/bufferevent.h>
#include "ThreadPool.h"
#include "event2/thread.h"
#include "EventWork.h"
#include <vector>
void accept_cb(int fd, short events, void* arg);
int tcp_server_init(int port, int listen_num);
int THREAD_NUM = 10;
int g_count = 0;
int last_thread = 0;
EventWork* g_works;
int main(int argc, char** argv)
{
//加载套接字库
WSADATA wsaData;
int iRet = 0;
iRet = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iRet != 0)
{
return -1;
}
if (2 != LOBYTE(wsaData.wVersion) || 2 != HIBYTE(wsaData.wVersion))
{
WSACleanup();
return -1;
}
int listener = tcp_server_init(9999, 10000000);
if (listener == -1)
{
return -1;
}
evthread_use_windows_threads();
g_works = new EventWork[THREAD_NUM];
event_config *base_config = event_config_new();
event_config_set_flag(base_config, EVENT_BASE_FLAG_STARTUP_IOCP);
event_config_set_num_cpus_hint(base_config, 4);
event_base *base = event_base_new_with_config(base_config);
//listen client connect event
event *ev_listen = event_new(base, listener, EV_READ | EV_PERSIST, accept_cb, base);
event_add(ev_listen, nullptr);
event_base_dispatch(base);
event_base_free(base);
ThreadPool::getInstance().realase();
return 0;
}
void dispatch_conn_new(int sfd, enum conn_states init_state, int event_flags)
{
int tid = (last_thread + 1) % THREAD_NUM;
EventWork *work = g_works + tid;
last_thread = tid;
std::shared_ptr<EventTask> item = std::make_shared<EventTask>();
item->sfd = sfd;
item->init_state = init_state;
item->event_flags = event_flags;
work->addTask(item);
}
void accept_cb(int fd, short events, void* arg)
{
evutil_socket_t sockfd;
sockaddr_in client;
socklen_t len = sizeof(client);
sockfd = accept(fd, (sockaddr*)&client, &len);
evutil_make_socket_nonblocking(sockfd);
printf("accept a client %d total %d\n", sockfd, ++g_count);
dispatch_conn_new(sockfd, conn_new_cmd, EV_READ | EV_PERSIST);
}
int tcp_server_init(int port, int listen_num)
{
int errno_save;
evutil_socket_t listener;
listener = socket(AF_INET, SOCK_STREAM, 0);
if (listener == -1)
{
return -1;
}
//允许多次绑定同一地址
evutil_make_listen_socket_reuseable(listener);
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = 0;
sin.sin_port = htons(port);
do
{
if (bind(listener, (sockaddr*)&sin, sizeof(sin)) < 0)
{
break;
}
if (listen(listener, listen_num) < 0)
{
break;
}
evutil_make_socket_nonblocking(listener);
return listener;
} while (0);
errno_save = errno;
evutil_closesocket(listener);
errno = errno_save;
return -1;
}
EventWork.h
#ifndef WORKEVENT_H
#define WORKEVENT_H
#include <memory>
#include <thread>
#include <event.h>
enum conn_states
{
conn_new_cmd
};
struct EventTask
{
int sfd;
conn_states init_state;
int event_flags;
};
class EventWork
{
public:
EventWork();
~EventWork();
void addTask(std::shared_ptr<EventTask> task);
void processTask(evutil_socket_t input_t, short event);
private:
std::shared_ptr<std::thread> m_ptrWorkThread;
event_base* m_workBase;
};
#endif
EventWork.cpp
#include "stdafx.h"
#include "EventWork.h"
#include <iostream>
#include "event2/thread.h"
#include "ThreadPool.h"
EventWork::EventWork()
{
m_ptrWorkThread = std::make_shared<std::thread>([this] {
event_config *base_config = event_config_new();
event_config_set_flag(base_config, EVENT_BASE_FLAG_STARTUP_IOCP);
event_config_set_num_cpus_hint(base_config, 4);
m_workBase = event_base_new_with_config(base_config);
event *notifyEvent = event_new(m_workBase, -1, EV_PERSIST | EV_READ, nullptr, this);
timeval *tv = new timeval;
tv->tv_sec = 24 * 60 * 60;
tv->tv_usec = 0;
event_add(notifyEvent, tv);
event_base_dispatch(m_workBase);
});
}
EventWork::~EventWork()
{
}
void EventWork::addTask(std::shared_ptr<EventTask> task)
{
ThreadPool::getInstance().putTask([task, this] {
if (task)
{
bufferevent* bev = bufferevent_socket_new(m_workBase, task->sfd, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE);
bufferevent_setcb(bev,
[](bufferevent* bev, void * arg) {
char msg[1024];
size_t len = bufferevent_read(bev, msg, sizeof(msg));
//msg[4095] = '\0';
//printf("recv the client msg: %s", msg);
char reply[] = "i have recvieced the msg";
bufferevent_write(bev, reply, strlen(reply));
},
nullptr,
[](bufferevent* bev, short e, void* arg) {
if (e & BEV_EVENT_EOF)
{
printf("connect closed \n");
}
else if (e & BEV_EVENT_ERROR)
{
printf("connect error \n");
}
printf("close a client\n");
bufferevent_free(bev);
},
nullptr);
bufferevent_enable(bev, EV_READ | EV_PERSIST);
}
});
}
void EventWork::processTask(evutil_socket_t input_t, short event)
{
}