libevent学习笔记 —— 牛刀小试:简易的服务器

时间:2024-11-29 21:03:25

回想起之前自己用纯c手动写epoll循环,libevent用起来还真是很快捷啊!重写了之前学习的时候的一个例子,分别用纯c与libevent来实现。嗯,为了方便对比一下,就一个文件写到黑了。

纯c版:

一个server.c与client.c共同引用的头文件func.h

 #include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<dirent.h>
#include<time.h>
#include<pwd.h>
#include<grp.h>
#include<stdlib.h>
#include<sys/time.h>
#include<sys/select.h>
#include<sys/mman.h>
#include<sys/wait.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/sem.h>
#include<signal.h>
#include<pthread.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<sys/epoll.h>
#include<fcntl.h>

client.c

  ///
/// @file client.c
/// @author marrs(chenchengxi993@gmail.com)
/// @date 2017-10-19 22:21:01
/// #include "func.h" int socket_init(char * pst_ip, short short_port);
int epoll_init(int int_sfd);
int epoll_add(int int_sfd, int int_epfd);
int epoll_del(int int_sfd, int int_epfd);
int epoll_loop(int int_sfd, int int_epfd);
int on_send_message_callback(int int_sfd, int int_epfd);
int on_recv_message_callback(int int_fd, int int_epfd); int main(int argc, char* argv[])
{
if(argc != )
{
printf("%s ip port\n",argv[]);
return -;
} char * pst_ip = argv[];
short short_port = atoi(argv[]); //初始化socket
int int_sfd = socket_init(pst_ip, short_port);
if (- == int_sfd)
{
printf("socket init fail...\n");
return -;
} //初始化epoll
int int_epfd = epoll_init(int_sfd); //epoll循环
epoll_loop(int_sfd, int_epfd);
return ;
} int socket_init(char * pst_ip, short short_port)
{
//初始化socket
int int_sfd = socket(AF_INET,SOCK_STREAM,);
if(- == int_sfd)
{
perror("socket");
return -;
}
int int_ret; //连接服务器
struct sockaddr_in sock_client;
sock_client.sin_family = AF_INET;
sock_client.sin_addr.s_addr = inet_addr(pst_ip);
sock_client.sin_port = htons(short_port); printf("prepare to connect ip:%s port:%d\n", pst_ip, short_port);
int_ret = connect(int_sfd, (struct sockaddr*)&sock_client, sizeof(sock_client));
if(- == int_ret)
{
perror("connect");
return -;
}
printf("connect ip:%s port:%d success!\n", pst_ip, short_port); //修改文件描述符状态为非阻塞
int status;
status=fcntl(int_sfd,F_GETFL);
status=status|O_NONBLOCK;
fcntl(int_sfd,F_SETFL,status); return int_sfd;
} int epoll_add(int int_fd, int int_epfd)
{
struct epoll_event epoll_ev;
epoll_ev.events = EPOLLIN|EPOLLET;
epoll_ev.data.fd = int_fd;
epoll_ctl(int_epfd, EPOLL_CTL_ADD, int_fd, &epoll_ev);
return ;
} int epoll_del(int int_fd, int int_epfd)
{
struct epoll_event epoll_ev;
epoll_ev.events = EPOLLIN|EPOLLET;
epoll_ev.data.fd = int_fd;
epoll_ctl(int_epfd, EPOLL_CTL_DEL, int_fd, &epoll_ev);
return ;
} int epoll_init(int int_sfd)
{
int int_epfd;
int_epfd = epoll_create();
epoll_add(, int_epfd);
epoll_add(int_sfd, int_epfd);
return int_epfd; } int on_send_message_callback(int int_sfd, int int_epfd)
{
char pst_buffer[];
int int_ret;
memset(pst_buffer, , sizeof(pst_buffer));
int_ret = read(, pst_buffer, sizeof(pst_buffer) - );
printf("input = %s; ret = %d\n", pst_buffer, int_ret);
if( == int_ret)
{
printf("bye~\n");
epoll_del(int_sfd, int_epfd);
epoll_del(, int_epfd);
return -;
} else
{
printf("send = %s\n", pst_buffer);
int_ret = send(int_sfd, (void*)pst_buffer, sizeof(pst_buffer) - , );
if(- == int_ret)
{
perror("send");
epoll_del(int_sfd, int_epfd);
epoll_del(, int_epfd);
return -;
}
printf("send success!\n");
}
return int_ret;
} int on_recv_message_callback(int int_fd, int int_epfd)
{
char pst_buffer[];
int int_ret;
while()
{
memset(pst_buffer, , sizeof(pst_buffer));
int_ret = recv(int_fd, (void*)pst_buffer, sizeof(pst_buffer) - , );
if( > int_ret)
{
break;
}
if( == int_ret)
{
printf("The server has been offline\n");
epoll_del(int_fd, int_epfd);
return -;
}
printf("%s", pst_buffer);
}
printf("\n"); return ;
} int epoll_loop(int int_sfd, int int_epfd)
{
struct epoll_event epoll_evs[];
int int_ret;
int int_event_num;
int int_idx;
int is_loop = ; //循环体
while(is_loop)
{
memset(epoll_evs, , sizeof(epoll_evs)); //等待事件
int_event_num = epoll_wait(int_epfd, epoll_evs, , -);
if (int_event_num > )
{
printf("someting in...\n");
for(int_idx = ; int_idx < int_event_num; ++int_idx)
{
if(epoll_evs[int_idx].events == EPOLLIN)
{
if(epoll_evs[int_idx].data.fd == )
{
//要发送消息
int_ret = on_send_message_callback(int_sfd, int_epfd);
if(- == int_ret)
{
printf("on send message callback fail...\n");
is_loop = ;
break;
} if( == int_ret)
{
is_loop = ;
break;
}
}
else if(epoll_evs[int_idx].data.fd == int_sfd)
{
//收到消息
int_ret = on_recv_message_callback(int_sfd, int_epfd);
if(- == int_ret)
{
printf("on recv message callback fail...\n");
is_loop = ;
break;
}
}
}
}
}
}
return ;
}

server.c

  ///
/// @file server.c
/// @author marrs(chenchengxi993@gmail.com)
/// @date 2017-10-19 21:27:33
/// #include "func.h" int socket_init();
int epoll_init(int int_sfd);
int epoll_add(int int_sfd, int int_epfd);
int epoll_del(int int_sfd, int int_epfd);
int epoll_loop(int int_sfd, int int_epfd);
int on_accept_callback(int int_sfd, int int_epfd);
int on_recv_message_callback(int int_fd, int int_epfd); int main()
{
//初始化socket
int int_sfd = socket_init();
if (- == int_sfd)
{
printf("socket init fail...\n");
return -;
} //初始化epoll
int int_epfd = epoll_init(int_sfd); //进入epoll循环
epoll_loop(int_sfd, int_epfd); } int socket_init()
{
//初始化socket
int int_sfd = socket(AF_INET,SOCK_STREAM,);
int int_ret; //绑定ip、port
char pst_ip[] = "127.0.0.1";
struct sockaddr_in sock_server;
sock_server.sin_family = AF_INET;
sock_server.sin_addr.s_addr = inet_addr(pst_ip);
short int_16_port;
for(int_16_port = ; int_16_port < ; ++int_16_port)
{
sock_server.sin_port = htons(int_16_port);
int_ret = bind(int_sfd, (struct sockaddr*)&sock_server, sizeof(struct sockaddr));
if(- == int_ret)
{
printf("bind port = %d fail..retry!\n",int_16_port);
continue;
}
break;
} if(- == int_ret)
{
perror("bind");
return -;
}
printf("bind port = %d success!\n",int_16_port); //监听
int_ret = listen(int_sfd, );
if(- == int_ret)
{
perror("listen");
return -;
} return int_sfd;
} int epoll_add(int int_fd, int int_epfd)
{
struct epoll_event epoll_ev;
epoll_ev.events = EPOLLIN|EPOLLET;
epoll_ev.data.fd = int_fd;
epoll_ctl(int_epfd, EPOLL_CTL_ADD, int_fd, &epoll_ev);
return ;
} int epoll_del(int int_fd, int int_epfd)
{
struct epoll_event epoll_ev;
epoll_ev.events = EPOLLIN|EPOLLET;
epoll_ev.data.fd = int_fd;
epoll_ctl(int_epfd, EPOLL_CTL_DEL, int_fd, &epoll_ev);
printf("close fd = %d\n", int_fd);
close(int_fd);
return ;
} int epoll_init(int int_sfd)
{
int int_epfd;
int_epfd = epoll_create();
epoll_add(int_sfd, int_epfd);
return int_epfd; } int on_accept_callback(int int_sfd, int int_epfd)
{
struct sockaddr_in sock_client;
socklen_t sock_len; //接入客户端
int int_new_fd = accept(int_sfd, (struct sockaddr*)&sock_client, &sock_len);
if(- == int_new_fd)
{
perror("accept");
return -;
} //把new_fd注册到epfd中
epoll_add(int_new_fd, int_epfd); //修改文件描述符状态为非阻塞
int int_status=fcntl(int_new_fd,F_GETFL);
int_status=int_status|O_NONBLOCK;
fcntl(int_new_fd,F_SETFL,int_status); printf("accept new_fd = %d success!\n", int_new_fd);
return int_new_fd;
} int on_recv_message_callback(int int_fd, int int_epfd)
{
printf("recv msg from fd = %d\n", int_fd);
char pst_buffer[];
int int_ret;
while()
{
memset(pst_buffer, , sizeof(pst_buffer));
int_ret = recv(int_fd, (void*)pst_buffer, sizeof(pst_buffer) - , );
if( > int_ret)
{
break;
}
if( == int_ret)
{
printf("The client has been offline\n");
epoll_del(int_fd, int_epfd);
return -;
}
printf("%s", pst_buffer);
}
printf("\n"); char pst_msg[] = "The server has recv your message...";
printf("%ld\n", sizeof(pst_msg)); int_ret = send(int_fd, (void*)pst_msg, sizeof(pst_msg) - , );
if(- == int_ret)
{
perror("send msg");
epoll_del(int_fd,int_epfd);
return -;
}
printf("%d\n", int_ret); return ;
} int epoll_loop(int int_sfd, int int_epfd)
{
struct epoll_event epoll_evs[];
int int_ret;
int int_event_num;
int int_idx;
printf("loop....\n"); //循环体
while()
{
memset(epoll_evs, , sizeof(epoll_evs)); //等待事件
int_event_num = epoll_wait(int_epfd, epoll_evs, , -);
if (int_event_num > )
{
for(int_idx = ; int_idx < int_event_num; ++int_idx)
{
if(epoll_evs[int_idx].events == EPOLLIN)
{
if(epoll_evs[int_idx].data.fd == int_sfd)
{
//有新客户端要接入
int_ret = on_accept_callback(int_sfd, int_epfd);
if(- == int_ret)
{
printf("on accept callback fail...\n");
continue;
}
}
else
{
//收到来自客户端的消息
int_ret = on_recv_message_callback(epoll_evs[int_idx].data.fd, int_epfd);
if(- == int_ret)
{
printf("on recv message callback fail...\n");
continue;
}
}
}
}
}
}
}

使用libevent:

只需要写回调函数,然后添加到监听的事件集合里就行了。就使用上来说,还是很方便的。

client.c

  ///
/// @file client.c
/// @author marrs(chenchengxi993@gmail.com)
/// @date 2017-10-23 21:27:33
/// #include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <event.h> int socket_init(char * pst_ip, short short_port);
void on_send_message_callback(int int_fd, __attribute__((unused)) short short_events, void *arg);
void on_recv_message_callback(int int_fd, __attribute__((unused)) short short_events, __attribute__((unused)) void *arg); int main(int argc, char* argv[])
{
if(argc != )
{
printf("%s ip port\n",argv[]);
return -;
} char * pst_ip = argv[];
short short_port = atoi(argv[]); //初始化socket
int int_sfd = socket_init(pst_ip, short_port);
if (- == int_sfd)
{
printf("socket init fail...\n");
return -;
} //添加监听服务器消息事件
struct event_base * base = event_base_new();
struct event* event_recv_msg = event_new(base, int_sfd, EV_READ|EV_PERSIST, on_recv_message_callback, NULL);
event_add(event_recv_msg, NULL); //添加监听终端输入事件
struct event* event_send_msg = event_new(base, STDIN_FILENO, EV_READ|EV_PERSIST, on_send_message_callback, (void*)&int_sfd);
event_add(event_send_msg, NULL); //进入循环
event_base_dispatch(base); return ;
} void on_send_message_callback(int int_fd, __attribute__((unused)) short short_events, void *arg)
{
char pst_buffer[];
int int_ret;
int int_socket_fd = *(int*)arg;
memset(pst_buffer, , sizeof(pst_buffer));
int_ret = read(int_fd, pst_buffer, sizeof(pst_buffer) - );
printf("input = %s; ret = %d\n", pst_buffer, int_ret);
if( == int_ret)
{
printf("bye~\n");
exit(-);
} else
{
printf("send = %s\n", pst_buffer);
int_ret = write(int_socket_fd, (void*)pst_buffer, sizeof(pst_buffer) - );
if(- == int_ret)
{
perror("send");
exit(-);
}
printf("send success!\n");
}
} void on_recv_message_callback(int int_fd, __attribute__((unused)) short short_events, __attribute__((unused)) void *arg)
{
char pst_buffer[];
int int_ret;
while()
{
memset(pst_buffer, , sizeof(pst_buffer));
int_ret = recv(int_fd, (void*)pst_buffer, sizeof(pst_buffer) - , );
if( > int_ret)
{
break;
}
if( == int_ret)
{
printf("The server has been offline\n");
exit(-);
}
printf("%s", pst_buffer);
}
printf("\n");
} int socket_init(char * pst_ip, short short_port)
{
int int_sfd = socket(AF_INET,SOCK_STREAM,);
if(- == int_sfd)
{
perror("socket");
return -;
}
int int_ret; struct sockaddr_in sock_client;
sock_client.sin_family = AF_INET;
sock_client.sin_addr.s_addr = inet_addr(pst_ip);
sock_client.sin_port = htons(short_port); printf("prepare to connect ip:%s port:%d\n", pst_ip, short_port);
int_ret = connect(int_sfd, (struct sockaddr*)&sock_client, sizeof(sock_client));
if(- == int_ret)
{
perror("connect");
return -;
}
printf("connect ip:%s port:%d success!\n", pst_ip, short_port);
evutil_make_socket_nonblocking(int_sfd);
return int_sfd;
}

server.c

  ///
/// @file server.c
/// @author marrs(chenchengxi993@gmail.com)
/// @date 2017-10-22 19:58:15
/// #include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <event.h>
#include <arpa/inet.h> int socket_init();
void on_accept_callback(int int_fd, __attribute__((unused)) short short_events, void *arg);
void on_recv_message(int int_fd, __attribute__((unused)) short short_events, void *arg); int main()
{
//初始化socket
int int_sfd = socket_init();
if(- == int_sfd)
{
printf("socket init fail...\n");
return -;
} //初始化struct event_base对象
struct event_base * base = event_base_new(); //添加监听客户端请求连接事件
struct event* event_listen = event_new(base, int_sfd, EV_READ|EV_PERSIST, on_accept_callback, base);
event_add(event_listen, NULL); //进入循环
event_base_dispatch(base); } int socket_init()
{
int int_ret;
short short_port;
struct sockaddr_in sock_server; //初始化socket
evutil_socket_t socket_fd = socket(AF_INET, SOCK_STREAM, );
if(- == socket_fd)
{
goto error;
}
printf("get socket fd success\n"); //允许多次绑定同一个地址
evutil_make_listen_socket_reuseable(socket_fd); //绑定ip、port
sock_server.sin_family = AF_INET;
sock_server.sin_addr.s_addr = ;
for(short_port = ; short_port < ; ++short_port)
{
sock_server.sin_port = htons(short_port);
int_ret = bind(socket_fd, (struct sockaddr*)&sock_server, sizeof(sock_server));
if(- == int_ret)
{
continue;
}
break;
}
if(- == int_ret)
{
goto error;
} printf("bind port = %d success\n", short_port); //监听
int_ret = listen(socket_fd, );
if(- == int_ret)
{
goto error;
}
printf("listen success\n"); //修改文件描述符状态为非阻塞
evutil_make_socket_nonblocking(socket_fd);
return socket_fd; //error
error:
perror("socket init");
evutil_closesocket(socket_fd);
return -;
} void on_accept_callback(int int_fd, __attribute__((unused))short short_events, void *arg)
{
evutil_socket_t socket_fd;
struct sockaddr_in sock_client;
socklen_t sock_len; //接入
socket_fd = accept(int_fd, (struct sockaddr*)&sock_client, &sock_len);
if(- == socket_fd)
{
perror("accept");
return;
}
printf("accpet a new client...\n"); //修改文件描述符状态为非阻塞
evutil_make_socket_nonblocking(socket_fd); //添加监听客户端发送消息事件
struct event_base* base = (struct event_base*)arg;
struct event* event_client = event_new(NULL, -, , NULL, NULL);
event_assign(event_client, base, socket_fd, EV_READ|EV_PERSIST, on_recv_message, (void*)event_client);
event_add(event_client, NULL); } void on_recv_message(int int_fd, __attribute__((unused))short short_events, void *arg)
{
char pst_buffer[];
int int_ret;
struct event *event_client = (struct event*)arg;
while()
{
memset(pst_buffer, , sizeof(pst_buffer));
int_ret = read(int_fd, (void*)pst_buffer, sizeof(pst_buffer) - );
if( == int_ret)
{
printf("the client has been offline...\n");
event_free(event_client);
close(int_fd);
return;
}
else if( > int_ret)
{
break;
}
else
{
printf("%s", pst_buffer);
}
}
printf("\n"); char pst_msg[] = "the server has recv your msg....";
int_ret = write(int_fd, pst_msg, strlen(pst_msg));
}