天天看點

libevent伺服器頁面顯示,libevent做一個簡單的伺服器應答程式

#include using namespace std;

#define SPORT 5001

void listen_cb(evutil_socket_t, short which, void* arg);

void client_cb(evutil_socket_t fd, short which, void* arg);

int main() {

#ifdef _WIN32

// windows 需要初始化socket庫

WSADATA wsa;

WSAStartup(MAKEWORD(2, 2), &wsa);

#else

if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {

return -1;

}

#endif

event_base* base = event_base_new();

evutil_socket_t sock = socket(AF_INET, SOCK_STREAM, 0);

if (sock == -1) {

cout << "socket 失敗" << endl;

return -1;

}

// 設定位址複用 和 非阻塞

evutil_make_socket_nonblocking(sock);

evutil_make_listen_socket_reuseable(sock);

sockaddr_in sin;

memset(&sin, 0, sizeof(sockaddr_in));

sin.sin_family = AF_INET;

sin.sin_port = htons(SPORT);

int re = ::bind(sock, (sockaddr*)&sin, sizeof(sockaddr_in));

if (re != 0) {

perror("bind 失敗");

return -1;

}

listen(sock, 10);

event* ev = event_new(base, sock, EV_PERSIST | EV_READ, listen_cb, base);

event_add(ev, 0);

// 進入事件主循環

event_base_dispatch(base);

evutil_closesocket(sock);

// 結束之後清理空間

event_base_free(base);

return 0;

}

void listen_cb(evutil_socket_t fd, short which, void* arg) {

cout << "listen_cb" << endl;

sockaddr_in sin;

socklen_t size = sizeof(sockaddr_in);

memset(&sin, 0, sizeof(sockaddr_in));

evutil_socket_t client = accept(fd, (sockaddr*)&sin, &size);

char ip[16] = { 0 };

evutil_inet_ntop(AF_INET, &sin.sin_addr, ip, 15);

cout << "client IP = " << ip << " PORT = " << sin.sin_port << endl;

// 資料讀取事件

event_base* base = (event_base*)arg;

event* ev = event_new(base, client, EV_PERSIST | EV_READ, client_cb, event_self_cbarg());

// 預設是水準觸發,測試邊沿觸發

//event* ev = event_new(base, client, EV_PERSIST | EV_READ | EV_ET , client_cb, event_self_cbarg());

timeval t = { 5,0 };

event_add(ev, &t);

}

// 經過測試,如果是水準觸發并且不處理用戶端發來的資料,那麼會一直進入這個回調函數

// 如果是邊沿觸發是用戶端發送一次,進入一次回調函數

// 以上測試都是在伺服器端的buffer充足的情況下,接下來測試buffer比較小的情況下

// 在邊沿觸發時,如果資料量大于buffer,每次隻會接收到buffer大小的資料量,隻有當下次進入的時候才會從buffer中繼續讀取,

// 是以如果采用的邊沿觸發,并且資料量比較大的時候,最好在一次進入之後就全部讀完然後在傳回

// 如果是水準觸發并且buffer比較小,那麼這個回調函數會一直進入,直到buffer中沒有資料為止

void client_cb(evutil_socket_t fd, short which, void* arg) {

if (which & EV_TIMEOUT) {

// 如果是由于逾時而引起的事件觸發

cout << "timeout" << endl;

event* ev = (event*)arg;

// 釋放事件資源

event_free(ev);

// 關閉socket

evutil_closesocket(fd);

return;

}

char buf[1024] = { 0 };

int len = recv(fd, buf, 1023,0);

if (len > 0) {

cout << "client say: " << buf << endl;

send(fd, "ok\r\n", 4, 0);

}

else {

// 用戶端連接配接斷開

cout << "client disconnect" << endl;

event* ev = (event*)arg;

// 釋放事件資源

event_free(ev);

// 關閉socket

evutil_closesocket(fd);

}

}