libevent做一个简单的服务器应答程序

#include <iostream>
#include <event2/event.h>
#ifndef _WIN32
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#endif
#include <thread>
#include <chrono>  
#include <cstring>
#include <stdlib.h>
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);
	}
}


 

libevent做一个简单的服务器应答程序libevent做一个简单的服务器应答程序 张哲瑞 发布了1033 篇原创文章 · 获赞 41 · 访问量 1万+ 他的留言板 关注
上一篇:你真的会Linux部署吗?


下一篇:Android属性动画完全解析(中)