概述:
使用libev实现TCP服务器,提升处理效率。原理其实都一样,都是文件描述符,检查读写条件,使用epoll事件轮询机制。
实例Demo:
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <ev.h>
#define PORT 12100
#define BUFFER_SIZE 1024
#define MAX_LISTEN 5
/*初始化服务端*/
int server_socket_init(int *sd, char *ipaddr, uint16_t port)
{
//创建socket
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == sock)
goto err1;
//设置立即释放端口并可以再次使用
int reuse = 1;
if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)))
goto err2;
//设置为非阻塞
if (-1 == fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK))
goto err2;
struct sockaddr_in addr;
memset(&addr, 0 , sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
if (NULL == ipaddr) {
addr.sin_addr.s_addr = htonl(INADDR_ANY);
} else {
addr.sin_addr.s_addr = inet_addr(ipaddr);
}
//绑定监听
if (-1 == bind(sock, (struct sockaddr *)&addr, sizeof(addr)))
goto err2;
if (-1 == listen(sock, MAX_LISTEN))
goto err2;
*sd = sock;
return 0;
err2:
close(sock);
err1:
return -1;
}
/*读回调*/
void read_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
{
char buffer[BUFFER_SIZE] = {0};
if (EV_ERROR & revents) {
printf("read got invalid event...\r\n");
return;
}
int res = 0;
int32_t bytes = read(watcher->fd, buffer, sizeof(buffer));
if (-1 == bytes) {
//tcp Error
if (EINTR != errno && EAGAIN != errno) {
res = 1;
}
} else if (0 == bytes) {
//tcp Close
res = 2;
}
if (0 != res) {
//关闭事件循环并释放watcher
printf("TCP CLOSE\r\n");
ev_io_stop(loop,watcher);
free(watcher);
} else {
printf("READ:\r\n %s\r\n", buffer);
}
}
/*accept回调函数*/
void accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
{
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
if (EV_ERROR & revents) {
printf("accept got invalid event...\r\n");
return;
}
//accept连接
int sock = accept(watcher->fd, (struct sockaddr *)&client_addr, &client_len);
if (-1 == sock) {
return;
}
//设置非阻塞
if(-1 == fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK)) {
close(sock);
return;
}
printf("Successfully connected with client: %s:%u\r\n", \
inet_ntoa(client_addr.sin_addr), client_addr.sin_port);
//加入事件循环
struct ev_io *w_client = (struct ev_io*) malloc (sizeof(struct ev_io));
ev_io_init(w_client, read_cb, sock, EV_READ);
ev_io_start(loop, w_client);
}
int main()
{
int sd;
struct ev_io w_accept;
struct ev_loop *loop = ev_loop_new(EVBACKEND_EPOLL);
if (NULL == loop) {
printf("loop create failed\r\n");
return -1;
}
if (server_socket_init(&sd, NULL, PORT) < 0) {
printf("server init failed\r\n");
return -1;
}
ev_io_init(&w_accept, accept_cb, sd, EV_READ);
ev_io_start(loop, &w_accept);
ev_run(loop, 0);
return 0;
}
编译:
//编译
gcc -o ev_server ev_server.c -lev