libevent学习笔记 —— 牛刀小试:简易的服务器
回想起之前自己用纯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));
}
libevent学习笔记 —— 牛刀小试:简易的服务器的更多相关文章
- libevent学习笔记 一、基础知识【转】
转自:https://blog.csdn.net/majianfei1023/article/details/46485705 欢迎转载,转载请注明原文地址:http://blog.csdn.net/ ...
- 【传智播客】Libevent学习笔记(一):简介和安装
目录 00. 目录 01. libevent简介 02. Libevent的好处 03. Libevent的安装和测试 04. Libevent成功案例 00. 目录 @ 01. libevent简介 ...
- Libevent学习笔记
学习: /Users/baidu/Documents/Data/Interview/服务器-检索端/libevent参考手册(中文版).pdf 讲的不好.翻译的..
- Vue.js 学习笔记之三:与服务器的数据交互
显而易见的,之前的02_toDoList存在着一个很致命的缺陷.那就是它的数据只存在于浏览器端,一但用户关闭或重新载入页面,他之前加入到程序中的数据就会全部丢失,一切又恢复到程序的初始状态.要想解决这 ...
- linux网络编程学习笔记之四 -----多-threaded服务器
对于使用过程中并发.通过实现更轻量级线程. 每个线程都是一个独立的逻辑流. 主题是CPU在执行调度的最小独立单位,这个过程是资源分配单元.当然,这是在微内核操作系统说.总之,这是唯一的一个操作系统内核 ...
- Android学习笔记————利用JDBC连接服务器数据库
/******************************************************************************************** * auth ...
- Libevent学习笔记(五) 根据例子学习bufferevent
libevent中提供了一个Hello-world.c 的例子,从这个例子可以学习libevent是如何使用bufferevent的. 这个例子在Sample中 这个例子之前讲解过,这次主要看下buf ...
- libevent学习笔记(参考libevent深度剖析)
最近自学libevent事件驱动库,参考的资料为libevent2.2版本以及张亮提供的<Libevent源码深度剖析>, 参考资料: http://blog.csdn.net/spark ...
- 【传智播客】Libevent学习笔记(三):事件循环
目录 00. 目录 01. event_base_loop函数 02. event_base_dispatch函数 03. event_base_loopexit函数 04. event_base_l ...
随机推荐
- Linux磁盘及文件系统(一)
一.磁盘 1.IO接口类型 (1)传输类型分类 并口:同一个线缆可以接多块设备 IDE口:两个,一个主设备,一个从设备 SCSI:宽带:16-1:窄带:8-1 串口:同一个线缆只可以接一个设备 (2) ...
- logstash5.5.0同步sql server数据
注意:jdbc.conf和jdbc.sql文件编码都为ANSI jdbc.conf内容如下: input { stdin { } jdbc { jdbc_connection_string => ...
- Using the JDBC Driver
Download JDBC Driver This section provides quick start instructions for making a simple connection t ...
- 前端必学内容:webpack3快速入门 1-23节内容参考
前端必学内容:webpack(模块打包器) webpack3 学习内容,点击即可到达 (1).webpack快速入门——如何安装webpack及注意事项 (2).webpack快速入门——webpac ...
- 如何无人值守安装linux系统(上)
如何开始 Linux 的无人值守安装 一.预备知识: I.什么是PXE PXE并不是一种安装方式,而是一种引导方式.进行PXE安装的必要条件是要安装的计算机中包含一个PXE支持的网卡(NIC),即网卡 ...
- Unicode字符串索引
一.目标 在通讯录中,我们有很多联系人,需要把这些联系人进行索引.对于每一个索引项对应的若干字符串,需要对这些字符串进行排序. 需要解决两个问题: 如何确定某个汉字应该被哪个字符索引? 某个索引项对应 ...
- Oracle ltrim() rtrim() 函数详细用法
今天在论坛里看了一篇帖子,讨论ltrim() 函数的详细用法,下面我借几个高手的回答总结一下: 先看几个实例: SQL> select ltrim('109224323','109') from ...
- Cocoa对象——根类
[转载自:http://mobile.51cto.com/iphone-274229.htm] Cocoa对象 根类是本文要介绍的内容,仅凭Objective-C语言和运行环境并不足以构造哪怕是最简单 ...
- Linux之解决命令行cat命令中文乱码
临时解决cat中文乱码 cat test.txt | iconv -f GBK -t UTF-8
- IDEA 笔记汇总
Intellij IDEA 像eclipse那样给maven添加依赖 Intellij idea maven 引用无法搜索远程仓库的解决方案 Intellij IDEA 封装Jar包(提示错误: 找不 ...