(二)libevent库的使用
参考:
1. libevent
使用第三方库我一般都偏爱最新的版本,libevent也是如此,所以我以 libevent-2.1.8-stable.tar.gz
为例,在官网上可以下载。
编译、使用
./configure
make
头文件在include
文件夹下,编译生成的动态库在.libs
文件夹下。
使用时,需要包含头文件和连接libevent.so动态库。
2. 示例
2.1 TcpServer.h
#ifndef TCP_SERVER_H
#define TCP_SERVER_H
struct event_base;
class TcpServer
{
public:
using callback = void(int, short, void*);
//typedef void (callback)(int, short, void*);
public:
TcpServer(const int port);
~TcpServer();
int Initialize();
int Start();
void Process();
private:
int m_fd;
int m_port;
event_base* m_base;
callback *m_accept_callback;
};
#endif // TCP_SERVER_H
2.2 TcpServer.cpp
#include "TcpServer.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <string>
#include "libevent/event.h"
void accept_cb(int fd, short events, void* arg)
{
struct sockaddr_in client;
socklen_t len = sizeof(client);
int sockfd = ::accept(fd, (struct sockaddr*)&client, &len );
if(sockfd < 0){
return;
}
/* 提取客户端IP地址 */
char szIP[64] = { 0 }; // 客户端IP地址
std::string strIP = inet_ntop(AF_INET, &client.sin_addr, szIP, sizeof(szIP));
printf("connect from client: %s\n", strIP.c_str());
TcpServer *pServer = static_cast<TcpServer*>(arg);
pServer->Process(sockfd);
close(sockfd);
printf("close\n");
}
TcpServer::TcpServer(const int port):
m_fd(-1),
m_port(port),
m_base(nullptr),
m_accept_callback(nullptr)
{
m_accept_callback = accept_cb;
}
TcpServer::~TcpServer()
{
close(m_fd);
}
int TcpServer::Initialize()
{
m_fd = ::socket(AF_INET, SOCK_STREAM, 0);
if( m_fd == -1 )
return -1;
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = 0;
sin.sin_port = htons(m_port);
int flag = 1;
socklen_t len = sizeof(flag);
if(::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, &flag, len) < 0)
{
return -4;
}
if( ::bind(m_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0 )
{
return -2;
}
if( ::listen(m_fd, 10) < 0)
{
return -3;
}
return 0;
}
int TcpServer::Start()
{
m_base = event_base_new();
if(nullptr == m_base)
{
return -4;
}
//添加监听客户端请求连接事件
struct event* ev_listen = event_new(m_base, m_fd, EV_READ | EV_PERSIST,
m_accept_callback, this);
event_add(ev_listen, NULL);
event_base_dispatch(m_base);
return 0;
}
void TcpServer::Process(int fd)
{
printf("process...\n");
char msg[4096];
int len = read(fd, msg, sizeof(msg) - 1);
if( len <= 0 )
{
printf("some error happen when read\n");
return ;
}
printf("%s",msg);
if(strcmp(msg,"get stats") != 0)
{
// return;
}
// {'stat':'1', 'version':'${project.name}-V${project.version}-B${SVN.revision}'}
char reply_msg[4096] = "{'stat':'1', 'version':'middleware-V1.0.0-B12965'}";
write(fd, reply_msg, strlen(reply_msg) );
}
2.3 main.cpp
#include "TcpServer.h"
// #include <unistd.h>
#include <memory>
#include <iostream>
using namespace std;
int main()
{
shared_ptr<TcpServer> spServer = make_shared<TcpServer>(999);
int ret = 0;
ret = spServer->Initialize();j
if (ret != 0){
std::cout<<"initialize failed "<<ret<<std::endl;
}
spServer->Start();
// while(true)
// {
// sleep(1);
// }
return 0;
}
2.4 CMakeLists.txt
cmake_minimum_required(VERSION 2.6)
project(demo)
# 设置编译器(gcc/g++)
set(CMAKE_CXX_COMPILER "g++")
#设置Debug/Release
set(CMAKE_BUILD_TYPE "Debug")
# 设置编译选项
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pthread -g -Wall")
# 设置可执行二进制文件的目录
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
# 设置存放编译出来的库文件的目录
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
# 并把该目录设置为链接目录
link_directories(${PROJECT_SOURCE_DIR}/lib)
# 设定头文件目录
include_directories(${PROJECT_SOURCE_DIR}/include)
# 增加子文件夹(src路径是通过子文件夹形式添加)
add_subdirectory(${PROJECT_SOURCE_DIR}/src)
# 编译静态、动态链接库
add_library(TcpServer SHARED TcpServer.cpp)
target_link_libraries(TcpServer libevent.so)
# 编译可执行文件和设置链接库(注意顺序)
add_executable(main main.cpp)
target_link_libraries(main libTcpServer.so)
2.5 测试
可以通过curl命令来查看是否可以连接服务器
curl http://ip:port
或者telnet
命令来检查
[root@thor ~]# telnet 127.0.0.1 999
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
get stats
{'stat':'1', 'version':'middleware-V1.0.0-B12965'}Connection closed by foreign host.