• Linxu epoll开发服务端


    int epoll_create(int size);

    函数说明:创建一个树,返回一个树根节点

    函数参数:

    size:必须传一个>0的数;

    返回值:

    成功返回一个文件描述符,这个文件描述符就表示epoll树的数根节点;

    1. RETURN VALUE
    2. On success, these system calls return a nonnegative file descriptor.
    3. On error, -1 is returned, and errno is set to indicate the error.

    int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

    函数说明:能把fd上epoll树,从树上删除和修改

    函数参数:

    epfd:树根节点

    op:

    1. Valid values for the op argument are:
    2. EPOLL_CTL_ADD//上树
    3. Add fd to the interest list and associate the settings speci‐
    4. fied in event with the internal file linked to fd.
    5. EPOLL_CTL_MOD//修改
    6. Change the settings associated with fd in the interest list to
    7. the new settings specified in event.
    8. EPOLL_CTL_DEL//从树上删除文件描述符(节点)
    9. Remove (deregister) the target file descriptor fd from the in
    10. terest list. The event argument is ignored and can be NULL
    11. (but see BUGS below).

    fd:要操作的文件描述符

    event

      struct epoll_event {
                   uint32_t     events;      /* Epoll events */
                   epoll_data_t data;        /* User data variable */
               };

     event.events:

    • EPOLLIN:可读事件
    • EPOLLOUT:可写事件
    •  EPOLLERR:异常事件
    1. typedef union epoll_data {
    2. void *ptr;
    3. int fd;//委托内核监控的文件描述符
    4. uint32_t u32;
    5. uint64_t u64;
    6. } epoll_data_t;

     使用:

    struct epoll_event ev;

    ev. events=EPOLLIN;//可读事件

    ev.data.fd=fd;//委托内核监控文件描述符

    epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&ev);

    int epoll_wait(int epfd, struct epoll_event *events,
                          int maxevents, int timeout); 

    函数说明:委托内核监控epoll树的事件节点

    函数参数:

    epfd:epoll树根节点

    events:传出参数,结构体数组,把发生变化的文件描述符放入传出参数events.data.fd

     maxevents:events数组大小

    timeout:

    • -1:阻塞
    • 0:不阻塞
    • >0:阻塞的时长

    注意:epoll_wait函数返回数组中事件节点的值不会被修改,是当时上epoll树的时候建立的值。

    返回值:

    1. When successful, epoll_wait() returns the number of file descriptors
    2. ready for the requested I/O

     返回发生变化的文件描述符的数量。

    可以确切的知道发生的变化的文件描述符,就不用遍历了

    开发服务器代码:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. int main()
    12. {
    13. int lfd=socket(AF_INET,SOCK_STREAM,0);
    14. if(lfd<0)
    15. {
    16. perror("socket error");
    17. return -1;
    18. }
    19. int opt=1;
    20. setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(int));
    21. struct sockaddr_in sev;
    22. sev.sin_family=AF_INET;
    23. sev.sin_port=htons(8888);
    24. inet_pton(AF_INET,"192.168.230.130",&sev.sin_addr.s_addr);
    25. int ret=bind(lfd,(struct sockaddr*)&sev,sizeof(sev));
    26. if(ret<0)
    27. {
    28. perror("bind error");
    29. return -1;
    30. }
    31. ret=listen(lfd,128);
    32. if(ret<0)
    33. {
    34. perror("listen error");
    35. return -1;
    36. }
    37. int epfd=epoll_create(1);//创建一个epoll树
    38. if(epfd<0)
    39. {
    40. perror("epoll_create error");
    41. return -1;
    42. }
    43. //int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
    44. struct epoll_event event;
    45. event. events= EPOLLIN;//让内核监控lfd的可读事件
    46. event.data.fd=lfd;
    47. ret=epoll_ctl(epfd, EPOLL_CTL_ADD,lfd,&event);//lfd上树
    48. int cfd;
    49. struct epoll_event e[1024];//创建数组
    50. int nready;
    51. int i;
    52. int sockfd;
    53. int n;
    54. int j;
    55. char buf[64];
    56. while(1)
    57. {
    58. // int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
    59. nready=epoll_wait(epfd,e,1024,-1);//返回发生变化的文件描述符的数量,并且可以确切的知道是哪些文件描述符发生变化,只有发生变化的文件描述符存放到e数组中
    60. if(nready<0)
    61. {
    62. if(errno==EINTR)//被信号打断
    63. {
    64. continue;
    65. }
    66. break;
    67. }
    68. for(i=0;i
    69. {
    70. sockfd=e[i].data.fd;
    71. if(sockfd==lfd)//有客户端连接请求
    72. {
    73. cfd=accept(lfd,NULL,NULL);
    74. event. events=EPOLLIN;//让内核监控cfd的可读事件
    75. event.data.fd=cfd;
    76. ret=epoll_ctl(epfd, EPOLL_CTL_ADD,cfd,&event);//将cfd上树
    77. continue;//继续for循环
    78. }
    79. //客户端发来数据
    80. memset(buf,0x00,sizeof(buf));
    81. n=read(sockfd,buf,sizeof(buf));
    82. if(n<=0)
    83. {
    84. printf("read error or client close,n==[%d]\n",n);
    85. close(sockfd);//关闭此cfd
    86. epoll_ctl(epfd,EPOLL_CTL_DEL,cfd,NULL);//并将此cfd下树,不再让内核监控
    87. }
    88. else
    89. {
    90. printf("n==[%d],buf==[%s]\n",n,buf);
    91. for(j=0;j
    92. {
    93. buf[j]=toupper(buf[j]);
    94. }
    95. write(sockfd,buf,strlen(buf));
    96. }
    97. }
    98. }
    99. close(lfd);
    100. return 0;
    101. }

    结果:

  • 相关阅读:
    AutoSAR入门:开发工具链介绍
    【密评】商用密码应用安全性评估从业人员考核题库(十五)
    SpringBoot+MyBatis flex实现简单增删改查
    【学习笔记】 - 基础数据结构 :Link-Cut Tree(进阶篇)
    随手笔记-Jackson -> @JsonFormat -> 失真问题解决
    R语言Bootstrap、百分位Bootstrap法抽样参数估计置信区间分析通勤时间和学生锻炼数据
    Unity 游戏设计模式:观察者模式
    GO的安装和配置
    ​在线问题反馈模块实战(九)​:实现图片上传功能(下)
    安卓考试答题APP源码
  • 原文地址:https://blog.csdn.net/luosuss/article/details/136591292