前言
本章节是用基本的Linux基本函数加上epoll调用编写一个完整的服务器和客户端例子,可在Linux上运行,客户端和服务端的功能如下:
客户端从标准输入读入一行,发送到服务端
服务端从网络读取一行,然后输出到客户端
客户端收到服务端的响应,输出这一行到标准输出
服务端
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }