一、epoll服务器 :
epoll — 服务器 — 监听 — fd ----可读 ---- epoll返回 ---- read — 小写转大写 — write ---- epoll继续监听。
epoll 反应堆模型:
创建efd(epoll_create) ---- 增加fd(epoll_ctl) ---- epoll_wait返回----fd可读 ---- read ---- fd从树上摘下 ---- 设置监听fd写事件, 操作senddata ---- 小写转大写(或者直接回射) ---- 等待epoll_wait 返回 ---- 回写给客户端 ----efd从树上摘下 ---- 设置监听cfd读事件, 操作recvdata----epoll继续监听
1.增加了判断fd是否可以写,由于滑动窗口机制可以会造成服务器此刻不能通过fd向客户端回写数据。
2.evt[i].events = EPOLLIN;evt[I].data.fd不简单的传递fd了,而是传递一个指针(结构体指针)*ptr
1 /*
2 *epoll基于非阻塞I/O事件驱动
3 */
#include <stdio.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#define MAX_EVENTS 1024 //红黑树所能监听的上限数
#define BUFLEN 4096
#define SERV_PORT 8080
void recvdata(int fd, int events, void *arg);
void senddata(int fd, int events, void *arg);
/* 描述就绪文件描述符相关信息 */
struct myevent_s {
int fd; //要监听的文件描述符
int events; //对应的监听事件
void *arg; //泛型参数
void(*call_back)(int fd, int events, void *arg); //回调函数
int status; //是否在监听:1->在红黑树上(监听), 0->不在(不监听)
char buf[BUFLEN];
int len;
long last_active; //记录每次加入红黑树 g_efd 的时间值(若长时间不发数据,则踢掉),eventset和add会重置此时间
};
int g_efd; //全局变量, 保存epoll_create返回的文件描述符
struct myevent_s g_events[MAX_EVENTS + 1]; //自定义结构体类型数组. +1-->listen fd
/*将结构体 myevent_s 成员变量 初始化*/
//回调函数call_back的参数arg就是结构体myevent_s本身
void eventset(struct myevent_s *ev, int fd, void(*call_back)(int, int, void *), void *arg)
{
ev->fd = fd;
ev->call_back = call_back;
ev->events = 0;
ev->arg = arg;
ev->status = 0;
memset(ev->buf, 0, sizeof(ev->buf));
ev->len = 0;
ev->last_active = time(NULL); //调用eventset函数的时间(一旦调用就会改变),若长时间没改变(没收数据),就会被删除
return;
}
/* 向 epoll监听的红黑树 添加一个 文件描述符 */
void eventadd(int efd, int events, struct myevent_s *ev)
{
struct epoll_event epv = {
0, {
0 } };
int op;
epv.data.ptr