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

http://www.cnblogs.com/debian/archive/2012/02/16/2354139.html

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

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

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

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

 

服务端

代码如下:

View Code
复制代码
  1 #include<unistd.h>
  2 #include<sys/types.h>       /* basic system data types */
  3 #include<sys/socket.h>      /* basic socket definitions */
  4 #include<netinet/in.h>      /* sockaddr_in{} and other Internet defns */
  5 #include<arpa/inet.h>       /* inet(3) functions */
  6 #include<sys/epoll.h> /* epoll function */
  7 #include<fcntl.h>     /* nonblocking */
  8 #include<sys/resource.h> /*setrlimit */
  9 
 10 #include<stdlib.h>
 11 #include<errno.h>
 12 #include<stdio.h>
 13 #include<string.h>
 14 
 15 
 16 
 17 #define MAXEPOLLSIZE 10000
 18 #define MAXLINE 10240
 19 int handle( int connfd );
 20 int setnonblocking( int sockfd )
 21 {
 22     if ( fcntl( sockfd, F_SETFL, fcntl( sockfd, F_GETFD, 0 ) | O_NONBLOCK ) == -1 )
 23     {
 24         return -1;
 25     }
 26     return 0;
 27 }
 28 
 29 int main( int argc, char **argv )
 30 {
 31     int  servPort = 6888;
 32     int listenq = 1024;
 33 
 34     int listenfd, connfd, kdpfd, nfds, n, nread, curfds, acceptCount = 0;
 35     struct sockaddr_in servaddr, cliaddr;
 36     socklen_t socklen = sizeof( struct sockaddr_in );
 37     struct epoll_event ev;
 38     struct epoll_event events[MAXEPOLLSIZE];
 39     struct rlimit rt;
 40     char buf[MAXLINE];
 41 
 42     /* 设置每个进程允许打开的最大文件数 */
 43     rt.rlim_max = rt.rlim_cur = MAXEPOLLSIZE;
 44     if ( setrlimit( RLIMIT_NOFILE, &rt ) == -1 )
 45     {
 46         perror( "setrlimit error" );
 47         return -1;
 48     }
 49 
 50     bzero( &servaddr, sizeof( servaddr ) );
 51     servaddr.sin_family = AF_INET;
 52     servaddr.sin_addr.s_addr = htonl ( INADDR_ANY );
 53     servaddr.sin_port = htons ( servPort );
 54 
 55     listenfd = socket( AF_INET, SOCK_STREAM, 0 );
 56     if ( listenfd == -1 )
 57     {
 58         perror( "can't create socket file" );
 59         return -1;
 60     }
 61 
 62     int opt = 1;
 63     setsockopt( listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof( opt ) );
 64 
 65     if ( setnonblocking( listenfd ) < 0 )
 66     {
 67         perror( "setnonblock error" );
 68     }
 69 
 70     if ( bind( listenfd, ( struct sockaddr * ) &servaddr, sizeof( struct sockaddr ) ) == -1 )
 71     {
 72         perror( "bind error" );
 73         return -1;
 74     }
 75 
 76     if ( listen( listenfd, listenq ) == -1 )
 77     {
 78         perror( "listen error" );
 79         return -1;
 80     }
 81 
 82     /* 创建 epoll 句柄,把监听 socket 加入到 epoll 集合里 */
 83     kdpfd = epoll_create( MAXEPOLLSIZE );
 84     ev.events = EPOLLIN | EPOLLET;
 85     ev.data.fd = listenfd;
 86     if ( epoll_ctl( kdpfd, EPOLL_CTL_ADD, listenfd, &ev ) < 0 )
 87     {
 88         fprintf( stderr, "epoll set insertion error: fd=%d\n", listenfd );
 89         return -1;
 90     }
 91     curfds = 1;
 92 
 93     printf( "epollserver startup,port %d, max connection is %d, backlog is %d\n", servPort, MAXEPOLLSIZE, listenq );
 94 
 95     for ( ;; )
 96     {
 97         /* 等待有事件发生 */
 98         nfds = epoll_wait( kdpfd, events, curfds, -1 );
 99         if ( nfds == -1 )
100         {
101             perror( "epoll_wait" );
102             continue;
103         }
104 
105         /* 处理所有事件 */
106         for ( n = 0; n < nfds; ++n )
107         {
108             if ( events[n].data.fd == listenfd )
109             {
110                 connfd = accept( listenfd, ( struct sockaddr * )&cliaddr, &socklen );
111                 if ( connfd < 0 )
112                 {
113                     perror( "accept error" );
114                     continue;
115                 }
116 
117                 sprintf( buf, "accept form %s:%d\n", inet_ntoa( cliaddr.sin_addr ), cliaddr.sin_port );
118                 printf( "%d:%s", ++acceptCount, buf );
119 
120                 if ( curfds >= MAXEPOLLSIZE )
121                 {
122                     fprintf( stderr, "too many connection, more than %d\n", MAXEPOLLSIZE );
123                     close( connfd );
124                     continue;
125                 }
126                 if ( setnonblocking( connfd ) < 0 )
127                 {
128                     perror( "setnonblocking error" );
129                 }
130                 ev.events = EPOLLIN | EPOLLET;
131                 ev.data.fd = connfd;
132                 if ( epoll_ctl( kdpfd, EPOLL_CTL_ADD, connfd, &ev ) < 0 )
133                 {
134                     fprintf( stderr, "add socket '%d' to epoll failed: %s\n", connfd, strerror( errno ) );
135                     return -1;
136                 }
137                 curfds++;
138                 continue;
139             }
140 
141             // 处理客户端请求
142             if ( handle( events[n].data.fd ) < 0 )
143             {
144                 epoll_ctl( kdpfd, EPOLL_CTL_DEL, events[n].data.fd, &ev );
145                 curfds--;
146             }
147         }
148     }
149     close( listenfd );
150     return 0;
151 }
152 int handle( int connfd )
153 {
154     int nread;
155     char buf[MAXLINE];
156     nread = read( connfd, buf, MAXLINE );
157 
158     if ( nread == 0 )
159     {
160         printf( "client close the connection\n" );
161         close( connfd );
162         return -1;
163     }
164 
165     if ( nread < 0 )
166     {
167         perror( "read error" );
168         close( connfd );
169         return -1;
170     }
171 
172     write( connfd, buf, nread );
173     return 0;
174 }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值