libevent庫實現簡易tcp伺服器
流程分析
- 建立socket,設定埠複用,繫結四元組,開始監聽。
- 初始化
event_base
結構體。
- 編寫監聽事件的回撥函式和客戶端讀事件的回撥函式。
- 初始化tcp監聽事件,並加入
event_base
中。
- 開始
event
事件處理迴圈。
- 釋放所有事件佔用資源。
- 釋放
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);
}