libev事件库使用笔记
源码下载地址:http://dist.schmorp.de/libev/
libev是一个高性能的事件循环库,比libevent库的性能要好。
安装:
tar -zxf libev-4.15.tar.gz
cd libev-4.15
./configure
make
make install
设置环境变量:
设置一下环境变量(在文件/etc/profile中添加)。然后才可以运行。 export LIBDIR=/usr/local/lib
export LD_LIBRARY_PATH=/usr/local/lib
export LD_RUN_PATH=/usr/local/lib 添加完成后运行:source /etc/profile 使设置生效;
没有接触过libev的新手一般对概念也是比较蒙的,我也不多做介绍,教你如何快速上手
对比说明吧!
示例一:不使用libev
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#define DAEMON_PORT 8888
#define MAX_LISTEN 1024 char get_manager_ip[]; int adminserver();
void pthread_adminserver(int client_sd); int main(int argc, char** argv){
strcpy(get_manager_ip, argv[]);
adminserver();
}
int adminserver()
{
int ret = ;
int i = ;
int max = ;
int nCurrentSocket = ;
FILE *fp;
int res;
int client_sd;
int server_sd;
int reuse_addr;
pthread_t p_tcpserver;
int client_addr_size ; struct sockaddr_in client_addr;
struct sockaddr_in server_addr;
char line[];
char listen_ip[];
char cmd_ip[]; char *pt;
char *edit; sprintf(cmd_ip,"ifconfig %s |grep 'addr:' >/get_manager_ip",get_manager_ip);
system(cmd_ip); fp = fopen("/get_manager_ip","rb");
if (fp == NULL)
{
printf("Cann't open get_manger_ip file!\n");
exit(-);
} memset(line,,);
fgets(line,,fp);
fclose(fp); pt=strstr(line, "addr:");
if (pt != NULL)
{
pt+=;
edit=strtok(pt," ");
strcpy(listen_ip,edit);
} server_sd=socket( AF_INET, SOCK_STREAM, ); if (server_sd < )
{
printf("ERROR: Cann't create socket!!!\n");
exit(-);
} bzero(&server_addr, sizeof(struct sockaddr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr=inet_addr(listen_ip);
server_addr.sin_port = htons(DAEMON_PORT); reuse_addr = ;
if (setsockopt (server_sd, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)) < )
{
printf("setsockopt error\n");
close(server_sd);
return -;
} res = bind(server_sd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (res < )
{
printf("Cann't bind!res = %d,erro:%d, reason:%s.\n",res, errno, strerror(errno));
close(server_sd);
exit(-);
} if (listen( server_sd, MAX_LISTEN ) != ) {
printf("Cann't listen!\n");
close(server_sd);
exit(-);
} while()
{ client_addr_size = sizeof(client_addr);
client_sd = accept( server_sd, (struct sockaddr *)&client_addr, (socklen_t *)&client_addr_size);
if (pthread_create(&p_tcpserver, NULL, (void *)&pthread_adminserver, client_sd)!=)
{
printf("Could not create thread check_work_time\n");
return ;
}
}
close(server_sd);
exit();
} void pthread_adminserver(int client_sd)
{
int sockfd = ;
int rc;
char buffer[];
while()
{ //线程处理某个客户端的连接
memset(buffer,,);
rc=read(client_sd,buffer,);
if(strlen(buffer) == ){
close(client_sd); //关闭线程处理的客户端连接
pthread_exit();//终止该线程
}
printf("read date:\"%s\"\n",buffer); }
close(client_sd); //关闭线程处理的客户端连接
pthread_exit();//终止该线程
}
说明:这是一个处理多并发的socket服务端,通过while接收多条连接,然后通过线程去处理每条连接,简单易懂,但是 使用两个while(1),是一件很浪费系统资源是事情;
示例二:通过示例一改动,添加libev
先对比两个示例先用起来吧,欢迎大神指导。
#include <ev.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <unistd.h> #define PORT 8080
#define BUFFER_SIZE 1024
#define MAX_CONNECTIONS 10 struct ev_io *libevlist[MAX_CONNECTIONS] = {NULL}; void socket_accept_callback(struct ev_loop *loop, struct ev_io *watcher, int revents);
void socket_read_callback(struct ev_loop *loop, struct ev_io *watcher, int revents);
/*
Server Client socket socket
| |
v v
bind connect
| |
v v
listen write
| |
v v
accept read
| |
v v
read close
|
v
write
|
v
close
*/ int main() {
struct ev_loop *loop = ev_default_loop(); /* socket start */
int sd;
struct sockaddr_in addr;
int addr_len = sizeof(addr); struct ev_io *socket_watcher = (struct ev_io*)malloc(sizeof(struct ev_io));
struct ev_timer *timeout_watcher = (struct ev_timer*)malloc(sizeof(struct ev_timer)); // socket
sd = socket(PF_INET, SOCK_STREAM, );
if (sd < ) {
printf("socket error\n");
return -;
}
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = INADDR_ANY; // bind
if (bind(sd, (struct sockaddr*) &addr, sizeof(addr)) != ) {
printf("bind error\n");
return -;
}
// listen
if (listen(sd, SOMAXCONN) < ) {
printf("listen error\n");
return -;
}
// set sd reuseful
int bReuseaddr = ;
if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (const char*) &bReuseaddr, sizeof(bReuseaddr)) != ) {
printf("setsockopt error in reuseaddr[%d]\n", sd);
return -;
}
/* socket end */ ev_io_init(socket_watcher, socket_accept_callback, sd, EV_READ);
ev_io_start(loop, socket_watcher); // while(1) {
ev_run(loop, );
// } return ;
} void socket_accept_callback(struct ev_loop *loop, struct ev_io *watcher, int revents) {
printf("I am: %d\n", getpid()); struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int client_sd; if (EV_ERROR & revents) {
printf("error event in accept\n");
return;
} // socket accept: get file description
client_sd = accept(watcher->fd, (struct sockaddr*) &client_addr, &client_len);
if (client_sd < ) {
printf("accept error\n");
return;
}
// too much connections
if (client_sd > MAX_CONNECTIONS) {
printf("fd too large[%d]\n", client_sd);
close(client_sd);
return;
} if (libevlist[client_sd] != NULL) {
printf("client_sd not NULL fd is [%d]\n", client_sd);
return;
} printf("client connected\n");
// ev_io watcher for client
struct ev_io *client_watcher = (struct ev_io*) malloc(sizeof(struct ev_io));
if (client_watcher == NULL) {
printf("malloc error in accept_cb\n");
return;
}
// listen new client
ev_io_init(client_watcher, socket_read_callback, client_sd, EV_READ);
ev_io_start(loop, client_watcher); libevlist[client_sd] = client_watcher;
} void socket_read_callback(struct ev_loop *loop, struct ev_io *watcher, int revents) {
char buffer[BUFFER_SIZE];
ssize_t read; if (EV_ERROR & revents) {
printf("error event in read\n");
return;
}
// socket recv
read = recv(watcher->fd, buffer, BUFFER_SIZE, ); // read stream to buffer
if (read < ) {
printf("read error\n");
return;
} if (read == ) {
printf("client disconnected.\n"); if (libevlist[watcher->fd] == NULL) {
printf("the fd already freed[%d]\n", watcher->fd);
}
else {
printf("fd:%d will be closed!\n",watcher->fd);
close(watcher->fd);
ev_io_stop(loop, libevlist[watcher->fd]);
free(libevlist[watcher->fd]);
libevlist[watcher->fd] = NULL;
}
return;
}
else {
printf("receive message[%d]says:%s\n",watcher->fd, buffer);
if(memcmp(buffer,"quit",strlen("quit")) == )
{
printf("recv quit cmd,fd:%d will be closed!\n",watcher->fd);
close(watcher->fd);
ev_io_stop(loop, libevlist[watcher->fd]);
free(libevlist[watcher->fd]);
libevlist[watcher->fd] = NULL;
return ;
}
} // socket send to client
send(watcher->fd, buffer, read, );
bzero(buffer, sizeof(buffer));
}
libev事件库使用笔记的更多相关文章
- libev事件库学习笔记
一.libev库的安装 因为个人的学习环境是在ubuntu 12.04上进行的,所以本节仅介绍该OS下的安装步骤. 使用系统工具自动化安装: sudo apt-get install libev-de ...
- muduo网络库学习笔记(四) 通过eventfd实现的事件通知机制
目录 muduo网络库学习笔记(四) 通过eventfd实现的事件通知机制 eventfd的使用 eventfd系统函数 使用示例 EventLoop对eventfd的封装 工作时序 runInLoo ...
- muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor
目录 muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor Connector 系统函数connect 处理非阻塞connect的步骤: Connetor时序图 Accep ...
- muduo网络库学习笔记(三)TimerQueue定时器队列
目录 muduo网络库学习笔记(三)TimerQueue定时器队列 Linux中的时间函数 timerfd简单使用介绍 timerfd示例 muduo中对timerfd的封装 TimerQueue的结 ...
- 利用epoll写一个"迷你"的网络事件库
epoll是linux下高性能的IO复用技术,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率.另一点原因就是获取 ...
- ktouch移动端事件库
最近闲来无事,写了个移动端的事件库,代码贴在下面,大家勿拍. /** @version 1.0.0 @author gangli @deprecated 移动端触摸事件库 */ (function ( ...
- Yarn的服务库和事件库使用方法
事件类型定义: package org.apache.hadoop.event; public enum JobEventType { JOB_KILL, JOB_INIT, JOB_START } ...
- Threejs 的场景查看 - 几个交互事件库助你方便查看场景
Threejs 的场景查看 - 几个交互事件库助你方便查看场景 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致&q ...
- python 库安装笔记
python 库安装笔记 zoerywzhou@163.com http://www.cnblogs.com/swje/ 作者:Zhouwan 2017-2-22 友情提示 安装python库的过程中 ...
随机推荐
- MySQL Sniffer
MySQL Sniffer 是360开源的一个基于 MySQL 协议的抓包工具, 能实时抓取客户端端请求,并格式化输出操作语句,操作十分简单.对于问题的定位,操作的审核是个不错的利器. Github地 ...
- 简单总结在51cto平台的两日学习
许久未曾静下心写东西,希望这会是一个好习惯的开始. 一次偶然的机会,大概是160415在Applestore邂逅51cto,看了点评果断下载,着实是一款优秀的学习软件. 由于最近正在用python写自 ...
- python学习笔记(一)元组tuple
元组由简单的对象组构成,元组与列表相似,但是元组不能在原处修改.元组位置有序的对象集合,元组通过偏移来访问. 为什么有了列表还要元组?元组的不变性提供了某种完整性,可以确保元组在程序中不被另一个引用修 ...
- JS判断是否为数字或为空
function checkcc() { var reg = new RegExp("^[0-9]*$"); var obj = document.getEleme ...
- 一个可以将 json 字符串 直接绑定到 view 上的Android库
android-data-binding 这是一个可以将 json 字符串 直接绑定到 view 上的库, 不用先将 json 转换为 model 类. 传送门(https://github.com/ ...
- MP3 信息读取
MP3 信息读取 运行环境:Window7 64bit,.NetFramework4.61,C# 7.0: 编者:乌龙哈里 2017-03-13 参考: MP3-wikipedia ID3v1 MPE ...
- background-image 与 img 动画性能对比
开发H5常常会用到滑屏,目前大部分滑屏插件都是通过控制页面的transform属性来实现.尽管如此,我总是发现自己的H5滑动起来就是不如网上一些优秀案例流畅,表现为滑动动画会出现卡顿.跳帧. 后来我发 ...
- supermap开发webgis的经验
SuperMap 开发WebGIS的经验总结 - 综合课件 - 道客巴巴 http://www.doc88.com/p-743552004620.html
- [UWP]了解模板化控件(1):基础知识
1.概述 UWP允许开发者通过两种方式创建自定义的控件:UserControl和TemplatedControl(模板化控件).这个主题主要讲述如何创建和理解模板化控件,目标是能理解模板化控件常见的知 ...
- SpringMVC4+MyBatis+SQL Server2014+druid 监控SQL运行情况
前言 在基于SpringMVC+MyBatis的开发过程中,我们希望能看到自己手写SQL的执行情况,在开发阶段我们可以配置log4j在控制台里基于debug模式查看,那么上线后,在生产声我们想查看SQ ...