2012年(16)
分类: LINUX
2012-08-28 19:45:39
前言 本章节是用基本的Linux基本函数加上epoll调用编写一个完整的服务器和客户端例子,可在Linux上运行,客户端和服务端的功能如下: 客户端从标准输入读入一行,发送到服务端 服务端从网络读取一行,然后输出到客户端 客户端收到服务端的响应,输出这一行到标准输出 服务端 代码如下: View Code 1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 10 #include 11 #include 12 #include 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 } |