linux网络编程(六)epoll反应堆

简介: linux网络编程(六)epoll反应堆

1.epoll反应堆(了解)


epoll反应堆建立思路:

1670952743398.jpg

#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);
/*Describes information about the ready file descriptor */
struct myevents_s{
  int fd; //The file descriptor to listen 
  int events; //The corresponding listening event
  void *arg;//Generic type pointer
  void (*call_back)(int fd,int events,void *arg); //callback function
  int status;//1->listen 0-> stop to listen
  char buf[BUFLEN];
  int len;
  long last_active;//Record the time value of each addition of red-black tree "g_efd"
};
int g_efd;//A global variable that holds the file descriptor returned by "epoll_create"
struct myevent_s g_events[MAX_EVENTS+1];//+1--->listen fd
/*Initialize the structure "myevent_s"*/
//eventset(&g_events[MAX_EVENTS],lfd,acceptconn,&g_events[MAX_EVENTS]);
//void acceptconn(int lfd ,int events,void *arg)
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);
  return;
}
/*Adds a file descriptor to the red-black tree on which epoll listens */
//eventadd(efd,EPOLLIN,&g_events[MAX_EVENTS]);
void eventadd(int efd,int events,struct myevent_s *ev)
{
  struct epoll_event epv ={0,{0}};
  int op;
  epv.data.ptr =ev;
  epv.events = ev-> events = events;
  if(ev->status == 0){
  op = EPOLL_CTL_ADD;
  ev->status  = 1;
  }
  if(epoll_ctl(efd,op,e->fd,&epv)<0)
  printf("event add failed[fd = %d],events[%d]\n",ev->fd,events);
  else
  printf("event add OK [fd = %d],op= %d,events[%0X]\n",ev->fd,op,events);
  return;
}
// eventdel(g_efd,ev);
void eventdel(int efd,struct myevent_s *ev)
{
  struct epoll_event epv ={0,{0}};
  if(ev->status != 1)
  return ;
  //epv.data.ptr=NULL;
  epv.data.ptr = NULL;
  ev->status = 0;
  epoll_ctl(efd,EPOLL_CTL_DEL,ev->fd.&epv);
  return ;
}
void acceptconn(int lfd ,int events,void *arg)
{
  struct sockaddr_in cin; //client address
  socklen_t len = sizeof(cin);
  int cfd,i;
  if((cfd==accept(lfd,(struct sockaddr *)&cin,&len))==-1)
  {
  if(errno != EAGAIN && errno != EINTR)
  {
  /*not going to error handle it for now*/
  printf("%s:accept,%s\n",__func__,strerror(errno));
  return ;
  }
  do{
  for(i = 0;i < MAX_EVENTS;i++)//
    if(g_events[i].status == 0)//Find a free element from the global array g events
    break;
  if(i == MAX_EVENTS){
    printf("%s:max connect limit[%d]\n",__func__,MAX_EVENTS);
    break;
  }
  int flag = 0;
  if((flag = fcntl(cfd,F_SET,O_NONBLOCK))<0){  //cdf -->nonblocking
    printf("%s:fcntl nonblocking failed ,%s\n",__func__,strerror(errno));
    break;
  }
  eventset(&g_events[i],cfd,recvdata,&g_events[i]);
  eventadd(g_efd,EPOLLIN,&g_events[i]);
  }while(0);
  printf("new connect [%s:%d][time :%ld],pos[%d]\n",
    inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),g_events[i].last_active,i);
  return ;
}
}
/*create "socket", initlize "lfd" */
void initlistensocket(int efd,short port)
{
  struct sockaddr_in sin;
  int lfd = socket(AF_INET,SOCK_STREAM,0);
  fcntl(lfd,F_SETFL,O_NONBLOCK);//Set the socket to non-blocking
  memset(&sin,0,sizeof(sin));//bzero(&sin,sizeof(sin))
  sin.sin_family = AF_INET;
  sin.sin_addr.s_addr = INADDR_ANY;
  sin.sin_port = htons(port);
  bind(lfd,(struct sockaddr *)&sin,sizeof(sin));
  listen(lfd,20);
  /*void eventset(struct myevent_s *ev,int fd,void(*call_back)(int,int,void *),void *arg);*/
  eventset(&g_events[MAX_EVENTS],lfd,acceptconn,&g_events[MAX_EVENTS]);
  /*void eventadd(int efd,int eventsmstruct myevent_s *ev) */
  eventadd(efd,EPOLLIN,&g_events[MAX_EVENTS]);
  return ;
} 
//eventset(&g_events[i],cfd,recvdata,&g_events[i]);
void recvdata(int fd,int events,void *arg)
{
  struct myevent_s *ev = (struct myevent_s *)arg;
  int len;
  len = recv(fd,ev->buf,sizeof(ev->buf),0); //=read(),only use in network programming,setting flags == 0;
  eventdel(g_efd,ev);
  if(len > 0){
  ev->len = len;
  ev->buf[len]='\0';
  printf("C[%d]:%s\n",fd,ev->buf);
  eventset(ev,fd,senddata,ev);
  eventadd(g_efd,EPOLLOUT,ev);
  }else if(len == 0){
  close(ev->fd);
  printf("[fd=%d] pos[%ld],closed\n",fd,ev-g_events);
  }else{
  close(ev->fd);
  printf("recv[fd=%d] error[%d]:%s\n",fd,errno,strerror(errno));
  }
  return;
}
void senddata(int fd,int events,void *arg)
{
  struct myevent_s *ev=(struct myevent_s *)arg;
  int len;
  len = send(fd,ev->buf,ev->len,0);
  eventdel(g_efd,ev);
  if(len > 0){
  printf("send[fd = %d],[%d]%s\n",fd,len,ev->buf);
  eventset(ev,fd,recvdata,ev);
  eventadd(g_efd,EPOLLIN,ev);
  }else{
  close(ev->fd);
  printf("send[fd=%d] error %s\n",fd,strerror(errno));
  }
  return;
}
int main(int argc,char *argv[])
{
  unsigned short port = SERV_PORT; //Use the user-specified port. If no port is specified, use the default port
  if(argc == 2){
  port = atoi(argv[1]);
  }
  g_efd = epoll_create(MAX_EVENTS+1);//create the red black tree, return "g_efd"
  if(g_efd <= 0)
  printf("create efd in %s err %s\n",_func_ ,strerror(errno));
  initlistensocket(g_efd,port); //Initialize the listening socket
  struct epoll_event events[MAX_EVENTS+1];//Store an array of file descriptors that satisfy the ready events
  printf("server running : port[%d]\n",port);
  int checkpos = 0,i;
  while(1){
  /*1.Timeout verification. Test 100 links each time without testing listenfd. If the client has not communicated with the server within 60 seconds, close the client link*/
  long now = time(NULL);//present time
  for(i = 0;i<100;i++,checkpos++){//Check 100 at a time and use checkpos to control the check objects
    if(checkpos == MAX_EVENTS)
    checkpos = 0;
    if(g_events[checkpos].status != 1)//Not on the red-black tree "g_efd"
    continue;
  long duration = now - g_events[checkpos].last_active;//Time when the client is inactive
  if(duration >= 60){
    close(g_events[checkpos].fd);//Close the link with the client
    printf("[fd=%d] timeout\n",g_events[checkpos].fd);
    eventdel(g_efd,&g_events[checkpos]);//Remove the client from the red black tree "g_efd"
    }
  }
  /*2.Listen to the red-black tree "g_efd" and add the described file descriptor  to the events array. If no event is satisfied for 1 second, return 0*/
  int nfd =epoll_wait(g_efd,events,MAX_EVENTS+1,1000);//timeout = 1000
  if(nfd < 0){
    printf("epoll_wait error,exit\n");
    break;
  }
   for(i=0;i<nfd;i++){
    /* Accepts void *ptr members of the union data using a custom struct pointer of type myevent_s */
    struct myevent_s *ev = (struct myevent_s *)events[i].data.ptr;
    if((events[i].events & EPOLLIN)&&(ev -> events & EPOLLIN)){ //Read ready event
      ev->call_back(ev->fd,events[i].events,ev->arg);
    }
    if((events[i].events&EPOLLOUT)&&(ev->events & EPOLLOUT)){ //write ready event
      ev->call_back(ev->fd,events[i].events,ev->arg);
    }
   }
  }
  return 0;
}
相关文章
|
1月前
|
监控 安全 Linux
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景,包括 ping(测试连通性)、traceroute(跟踪路由路径)、netstat(显示网络连接信息)、nmap(网络扫描)、ifconfig 和 ip(网络接口配置)。掌握这些命令有助于高效诊断和解决网络问题,保障网络稳定运行。
72 2
|
3月前
|
安全 Linux 网络安全
Web安全-Linux网络协议
Web安全-Linux网络协议
80 4
|
2月前
|
运维 监控 网络协议
|
1月前
|
存储 JSON Java
细谈 Linux 中的多路复用epoll
大家好,我是 V 哥。`epoll` 是 Linux 中的一种高效多路复用机制,用于处理大量文件描述符(FD)事件。相比 `select` 和 `poll`,`epoll` 具有更高的性能和可扩展性,特别适用于高并发服务器。`epoll` 通过红黑树管理和就绪队列分离事件,实现高效的事件处理。本文介绍了 `epoll` 的核心数据结构、操作接口、触发模式以及优缺点,并通过 Java NIO 的 `Selector` 类展示了如何在高并发场景中使用多路复用。希望对大家有所帮助,欢迎关注威哥爱编程,一起学习进步。
|
2月前
|
Ubuntu Linux 虚拟化
Linux虚拟机网络配置
【10月更文挑战第25天】在 Linux 虚拟机中,网络配置是实现虚拟机与外部网络通信的关键步骤。本文介绍了四种常见的网络配置方式:桥接模式、NAT 模式、仅主机模式和自定义网络模式,每种模式都详细说明了其原理和配置步骤。通过这些配置,用户可以根据实际需求选择合适的网络模式,确保虚拟机能够顺利地进行网络通信。
108 1
|
2月前
|
网络协议 安全 Ubuntu
Linux中网络连接问题
【10月更文挑战第3天】
37 1
|
2月前
|
Linux C++
Linux C/C++之IO多路复用(poll,epoll)
这篇文章详细介绍了Linux下C/C++编程中IO多路复用的两种机制:poll和epoll,包括它们的比较、编程模型、函数原型以及如何使用这些机制实现服务器端和客户端之间的多个连接。
36 0
Linux C/C++之IO多路复用(poll,epoll)
|
2月前
|
监控 Linux 测试技术
Linux系统命令与网络,磁盘和日志监控总结
Linux系统命令与网络,磁盘和日志监控总结
67 0
|
2月前
|
监控 Linux 测试技术
Linux系统命令与网络,磁盘和日志监控三
Linux系统命令与网络,磁盘和日志监控三
45 0
|
3月前
|
网络协议 Linux
Linux 网络配置
了解基本命令与权限后,如何让Linux系统联网?可通过编辑`/etc/sysconfig/network-scripts/`下的`ifcfg-ethX`文件配置网卡,其中`ethX`代表第X块网卡。对于DHCP自动获取或静态IP,需设置`BOOTPROTO`参数,并指定IP、子网掩码和网关等。配置完成后,运行`/etc/init.d/network restart`重启网络。DNS可在`/etc/resolv.conf`中设置,添加`nameserver`行即可,无需重启网卡。配置好后,可用`ifconfig`查看IP信息,并通过远程工具如SecureCRT连接服务器。
85 0
下一篇
DataWorks