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 ...
随机推荐
- 支持向量机通俗导论(SVM学习)
1.了解SVM 支持向量机,因其英文名为support vector machine,故一般简称SVM,通俗来讲,它是一种二类分类模型,其基本模型定义为特征空间上的间隔最大的线性分类器,其学习策略便是 ...
- python中的类方法、静态方法、对象方法
注:以下都是以公有为前提,私有方法只能在类内部调用,不需多讲. 1.对象方法 这种方法都有一个默认参数:self 这代表实例的这个对象 def __init__(self): print(" ...
- P1642 规划
题目链接 题意分析 一看就知道是一道\(01\)分数规划的题 我们二分值之后 跑树形背包就可以了 CODE: #include<iostream> #include<cstdio&g ...
- 队列的理解和实现(二) ----- 链队列(java实现)
什么是链队列 链队是指采用链式存储结构实现的队列,通常链队用单链表俩表示.一个链队显然需要两个分别指示队头和队尾的指针,也称为头指针和尾指针,有了这两个指针才能唯一的确定. package 链队列; ...
- ArrayList集合与List与数组的区别
import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.Lis ...
- 基础概念——何为GNU与GCC
GNU:GNU 是一个自由软件操作系统.全称是GNU‘s Not Unix. GNU 是一款类似Unix的操作系统,它所采用的的典型内核是Linux. 该组合叫作GNU/Linux操作系统: GNU网 ...
- 01-django项目环境搭建
一.Web应用框架----Django http服务器:用来接受用户请求,并将请求转发给web应用框架进行处理. Web应用框架处理完以后再发送给http服务器,http服务器再返回给用户 二.工具准 ...
- Django中的Session--实现登录
Django中的Session--实现登录 Django Session Session Session 是什么 Session保存在服务端的键值对. 为什么要有 Session Cookie 虽然 ...
- 使用scp命令,远程上传下载文件/文件夹
1.从服务器下载文件 scp username@servername:/path/filename /local/path例如: scp ubuntu@117.50.20.56:/ygf/data/d ...
- C# this关键字(给底层类库扩展成员方法)
本文参考自唔愛吃蘋果的C#原始类型扩展方法—this参数修饰符,并在其基础上做了一些细节上的解释 1.this作为参数关键字的作用 使用this关键字,可以向this关键字后面的类型添加扩展方法,而无 ...