• (二)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
    ", strIP.c_str());
    
        TcpServer *pServer = static_cast<TcpServer*>(arg);
        pServer->Process(sockfd);
    
        close(sockfd);
        printf("close
    ");
    }
    
    
    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...
    ");
    
        char msg[4096];  
        int len = read(fd, msg, sizeof(msg) - 1);
        if( len <= 0 )
        {
            printf("some error happen when read
    ");
            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.
    
  • 相关阅读:
    hadoop2.2.0伪分布式搭建
    HBase详解
    Hbase常用命令
    hbase读取数据原理
    约瑟夫环
    哈希表设计
    哈夫曼树的建立
    TCP的连接和释放
    什么是Kmp算法?
    什么是https
  • 原文地址:https://www.cnblogs.com/walkinginthesun/p/9403648.html
Copyright © 2020-2023  润新知