Loading

【Linux系统编程】libevent库实现简易tcp服务器

libevent库实现简易tcp服务器

流程分析

  1. 创建socket,设置端口复用,绑定四元组,开始监听。
  2. 初始化event_base结构体。
  3. 编写监听事件的回调函数和客户端读事件的回调函数。
  4. 初始化tcp监听事件,并加入event_base中。
  5. 开始event事件处理循环。
  6. 释放所有事件占用资源。
  7. 释放event_base占用资源。

服务端源码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <event2/event.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <cerrno>
#include <unistd.h>

void conncb(evutil_socket_t fd, short events, void *arg);
void readcb(evutil_socket_t fd, short events, void *arg);

int main(int argc, char *argv[]) {
    // 创建socket
    int lfd = socket(AF_INET, SOCK_STREAM, 0);
    
    // 设置端口复用
    int opt = 1;
    setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    // 绑定
    sockaddr_in serv;
    memset(&serv, 0, sizeof(serv));
    serv.sin_addr.s_addr = htonl(INADDR_ANY);
    serv.sin_port = htons(8888);
    serv.sin_family = AF_INET;
    bind(lfd, (sockaddr*)&serv, sizeof(serv));

    // 监听
    listen(lfd, 1024);
    
    // 创建event_base
    event_base *base = event_base_new();
    if (base == nullptr) {
       perror("event_base_new()"); 
       exit(-1);
    }

    // 创建监听文件描述符对应事件
    event *ev = event_new(base, lfd, EV_READ|EV_PERSIST, conncb, base);
    if (ev == nullptr) {
        perror("event_new(lfd)");
        exit(-1);
    }

    // 将新的事件添加到event_base
    event_add(ev, nullptr);

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

    // 释放事件
    event_base_free(base);
    event_free(ev);

    close(lfd);

    return 0;
}

void conncb(evutil_socket_t fd, short events, void *arg) {
    sockaddr_in addr;
    socklen_t addrlen = sizeof(addr);
    int cfd = accept(fd, (sockaddr*)&addr, &addrlen);
    if (cfd == -1) {
        perror("accept");
        exit(-1);
    }
    char ipstr[1024];
    if (nullptr == inet_ntop(AF_INET, &addr.sin_addr.s_addr, ipstr, 1024)) {
        perror("inet_ntop()");
        exit(-1);
    }
    std::cout << "Accept from " << ipstr << ":" << ntohs(addr.sin_port) << " on " << cfd << std::endl;
    
    // 创建客户端监听事件并放进event_base
    event *connev = event_new((event_base*)arg, cfd, EV_READ|EV_PERSIST, readcb, connev);
    if (connev == nullptr) {
        perror("event_new(cfd)");
        exit(-1);
    }
    event_add(connev, 0);
}

void readcb(evutil_socket_t fd, short events, void *arg) {
    int n;
    char buffer[1024];
    memset(buffer, 0, sizeof(buffer));   
    n = read(fd, buffer, sizeof(buffer));
    if (n <= 0) {
        close(fd);
        // 将读事件从event_base移除
        event_del((event*)arg);
    }
    std::cout << "Read from " << fd << ":" << buffer << std::endl;
    write(fd, buffer, n);
}
posted @ 2024-04-14 15:54  杨谖之  阅读(55)  评论(0编辑  收藏  举报