Linux IO多路复用之epoll网络编程

作者:蜗牛201 时间:2021-05-07 08:31:19 

前言

本章节是用基本的Linux基本函数加上epoll调用编写一个完整的服务器和客户端例子,可在Linux上运行,客户端和服务端的功能如下:

  • 客户端从标准输入读入一行,发送到服务端

  • 服务端从网络读取一行,然后输出到客户端

  • 客户端收到服务端的响应,输出这一行到标准输出

服务端

代码如下:


#include <unistd.h>
#include <sys/types.h>    /* basic system data types */
#include <sys/socket.h>   /* basic socket definitions */
#include <netinet/in.h>   /* sockaddr_in{} and other Internet defns */
#include <arpa/inet.h>    /* inet(3) functions */
#include <sys/epoll.h> /* epoll function */
#include <fcntl.h>   /* nonblocking */
#include <sys/resource.h> /*setrlimit */
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#define MAXEPOLLSIZE 10000
#define MAXLINE 10240
int handle(int connfd);
int setnonblocking(int sockfd)
{
 if (fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK) == -1) {
   return -1;
 }
 return 0;
}
int main(int argc, char **argv)
{
 int servPort = 6888;
 int listenq = 1024;
 int listenfd, connfd, kdpfd, nfds, n, nread, curfds,acceptCount = 0;
 struct sockaddr_in servaddr, cliaddr;
 socklen_t socklen = sizeof(struct sockaddr_in);
 struct epoll_event ev;
 struct epoll_event events[MAXEPOLLSIZE];
 struct rlimit rt;
 char buf[MAXLINE];
 /* 设置每个进程允许打开的最大文件数 */
 rt.rlim_max = rt.rlim_cur = MAXEPOLLSIZE;
 if (setrlimit(RLIMIT_NOFILE, &rt) == -1)
 {
   perror("setrlimit error");
   return -1;
 }
 bzero(&servaddr, sizeof(servaddr));
 servaddr.sin_family = AF_INET;
 servaddr.sin_addr.s_addr = htonl (INADDR_ANY);
 servaddr.sin_port = htons (servPort);
 listenfd = socket(AF_INET, SOCK_STREAM, 0);
 if (listenfd == -1) {
   perror("can't create socket file");
   return -1;
 }
 int opt = 1;
 setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
 if (setnonblocking(listenfd) < 0) {
   perror("setnonblock error");
 }
 if (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) == -1)
 {
   perror("bind error");
   return -1;
 }
 if (listen(listenfd, listenq) == -1)
 {
   perror("listen error");
   return -1;
 }
 /* 创建 epoll 句柄,把监听 socket 加入到 epoll 集合里 */
 kdpfd = epoll_create(MAXEPOLLSIZE);
 ev.events = EPOLLIN | EPOLLET;
 ev.data.fd = listenfd;
 if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, listenfd, &ev) < 0)
 {
   fprintf(stderr, "epoll set insertion error: fd=%d\n", listenfd);
   return -1;
 }
 curfds = 1;
 printf("epollserver startup,port %d, max connection is %d, backlog is %d\n", servPort, MAXEPOLLSIZE, listenq);
 for (;;) {
   /* 等待有事件发生 */
   nfds = epoll_wait(kdpfd, events, curfds, -1);
   if (nfds == -1)
   {
     perror("epoll_wait");
     continue;
   }
   /* 处理所有事件 */
   for (n = 0; n < nfds; ++n)
   {
     if (events[n].data.fd == listenfd)
     {
       connfd = accept(listenfd, (struct sockaddr *)&cliaddr,&socklen);
       if (connfd < 0)
       {
         perror("accept error");
         continue;
       }
       sprintf(buf, "accept form %s:%d\n", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port);
       printf("%d:%s", ++acceptCount, buf);

if (curfds >= MAXEPOLLSIZE) {
         fprintf(stderr, "too many connection, more than %d\n", MAXEPOLLSIZE);
         close(connfd);
         continue;
       }
       if (setnonblocking(connfd) < 0) {
         perror("setnonblocking error");
       }
       ev.events = EPOLLIN | EPOLLET;
       ev.data.fd = connfd;
       if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, connfd, &ev) < 0)
       {
         fprintf(stderr, "add socket '%d' to epoll failed: %s\n", connfd, strerror(errno));
         return -1;
       }
       curfds++;
       continue;
     }
     // 处理客户端请求
     if (handle(events[n].data.fd) < 0) {
       epoll_ctl(kdpfd, EPOLL_CTL_DEL, events[n].data.fd,&ev);
       curfds--;
     }
   }
 }
 close(listenfd);
 return 0;
}
int handle(int connfd) {
 int nread;
 char buf[MAXLINE];
 nread = read(connfd, buf, MAXLINE);//读取客户端socket流
 if (nread == 0) {
   printf("client close the connection\n");
   close(connfd);
   return -1;
 }
 if (nread < 0) {
   perror("read error");
   close(connfd);
   return -1;
 }  
 write(connfd, buf, nread);//响应客户端
 return 0;
}

编译

编译和启动服务端


gcc epollserver.c -o epollserver
./epollserver

来源:https://blog.csdn.net/woniu211111/article/details/47318843

标签:linux,io多路复用,epoll
0
投稿

猜你喜欢

  • 详解使用Docker进行Redis主从复制实践

    2022-09-28 16:58:22
  • Linux下安装jdk1.8并配置环境变量的教程

    2023-06-14 18:43:27
  • WIN2003服务器安全配置终极技巧(4)

    2007-11-21 14:14:00
  • 保障远程桌面Web连接安全四注意

    2009-01-23 15:08:00
  • 域名转发可劫持PR吗 关于PR劫持的小思考

    2009-03-17 13:36:00
  • 三大网站正面PK MSN、QQ、HI大斗法

    2008-03-05 21:36:00
  • 选择虚拟主机网站的5点技巧

    2008-08-21 17:52:00
  • Linux操作系统下以太网卡的安装及配置

    2009-02-10 18:36:00
  • 中文域名加邮箱 企业推广新思路

    2009-05-24 12:34:00
  • Linux下Web性能压力测试工具http_load使用教程

    2023-10-04 09:39:57
  • 月光:Google AdSense的技巧和心得

    2008-02-26 09:38:00
  • Google去年调整搜索算法450次

    2008-04-19 22:07:00
  • 网络时代如何保护自己的隐私

    2007-10-02 20:04:00
  • ubantu 16.4下Hadoop完全分布式搭建实战教程

    2022-03-15 22:23:18
  • 九城在美第五次遭集体诉讼 股价应声大跌

    2009-11-05 12:18:00
  • 纵贯线北京演唱会一票难求 网友纷淘二手票

    2009-11-23 15:04:00
  • Web服务器负载均衡方案

    2008-12-22 17:22:00
  • 做站内容为王,内容到底有多重要

    2008-10-12 18:20:00
  • Apache与Tomcat服务器整合的基本配置方法及概要说明

    2023-10-19 16:32:32
  • 网民对博客广告的信任度高于社区广告

    2009-02-20 14:50:00
  • asp之家 网站运营 m.aspxhome.com