Linux网络通信编程(套接字模型TCP\UDP与IO多路复用模型select\poll\epoll)

Linux下测试代码:

http://www.linuxhowtos.org/C_C++/socket.htm

TCP模型

 1 //TCPClient.c
 2 #include<string.h>
 3 #include<netinet/in.h>
 4 #include<sys/types.h>
 5 #include<sys/socket.h>
 6 #include<errno.h>
 7 #define MYPORT 4000
 8 #define BACKLOG 10
 9 #define MAX_LEN 100
10 
11 int main(void)
12 {
13     int sockfd;
14     int tmp_int;
15     char *msg_send = NULL;
16     char *msg_recv = NULL;
17     int sin_size;
18     int len,bytes_sent,bytes_recv;
19     struct sockaddr_in my_addr;
20     struct sockaddr_in dest_addr;
21     
22     sockfd=socket(AF_INET,SOCK_STREAM,0);
23     my_addr.sin_family=AF_INET;
24     my_addr.sin_port=htons(MYPORT);
25     my_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
26     bzero(&(my_addr.sin_zero),8);
27     tmp_int = connect(sockfd,(struct sockaddr*)(&my_addr),sizeof(struct sockaddr));
28     if( tmp_int < 0 )
29     {
30         printf("ERROR:connect erro %s!\n", strerror(errno));
31         close(sockfd);
32         return -1;
33     }
34     msg_send="This is TCPClient!\n";
35     len=strlen(msg_send);
36     bytes_sent=send(sockfd,msg_send,len,0);
37     while( len != bytes_sent )
38     {
39         tmp_int = bytes_sent;
40         len -= bytes_sent;
41         printf("send %d,%d packet!\n", bytes_sent,len);
42         bytes_sent = send( sockfd, msg_send+tmp_int, len, 0 );
43     }
44     msg_recv = (char *)malloc( MAX_LEN );
45     if( NULL == msg_recv )
46     {
47         printf("ERROR:malloc mem error!\n");
48         close(sockfd);
49         return -1;
50     }
51     memset(msg_recv, 0, MAX_LEN );
52     bytes_recv=recv(sockfd,msg_recv,MAX_LEN,0);
53     if( bytes_recv >0 )
54     {
55         printf("recv: %s\n!", msg_recv );
56     }
57     else
58     {
59         printf("ERROR:net error\n");
60     }
61     close(sockfd);
62     return 0;
63 }
View Code
 1 //TCPServer.c
 2 #include<string.h>
 3 #include<errno.h>
 4 #include<netinet/in.h>
 5 #include<sys/types.h>
 6 #include<sys/socket.h>
 7 #define MYPORT 4000
 8 #define BACKLOG 10
 9 #define MAX_LEN 100
10 
11 int main(void)
12 {
13     int sockfd;
14     char* msg_send;
15     char* msg_recv;
16     int sin_size;
17     int new_fd;
18     int tmp_int;
19     int len,bytes_sent,bytes_recv;
20     struct sockaddr_in my_addr;
21     struct sockaddr_in their_addr;
22     
23     sockfd=socket(AF_INET,SOCK_STREAM,0);
24     my_addr.sin_family=AF_INET;
25     my_addr.sin_port=htons(MYPORT);
26     my_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
27     bzero(&(my_addr.sin_zero),8);
28     bind(sockfd,(struct sockaddr*)(&my_addr),sizeof(struct sockaddr));
29     listen(sockfd,BACKLOG);
30     sin_size=sizeof(struct sockaddr_in);
31     new_fd=accept(sockfd,(struct sockaddr *)&their_addr, &sin_size);
32     msg_send="This is TCPServer!\n";
33     len=strlen(msg_send);
34     bytes_sent=send(new_fd,msg_send,len,0);
35     while( len != bytes_sent )
36     {
37         tmp_int = bytes_sent;
38         len -= bytes_sent;
39         printf("send %d packet\n", bytes_sent);
40         bytes_sent = send( new_fd, msg_send+tmp_int, len, 0 );
41     }
42     msg_recv = (char *)malloc( MAX_LEN );
43     if( NULL == msg_recv )
44     {
45         printf("ERROR:malloc mem error!\n");
46         close(new_fd);
47         return -1;
48     }
49     memset(msg_recv, 0, MAX_LEN );
50     bytes_recv=recv(new_fd,msg_recv,MAX_LEN,0);
51     if( bytes_recv >0 )
52     {
53         printf("recv: %s\n", msg_recv );
54     }
55     else
56     {
57         printf("ERROR:net error!\n");
58     }
59     close(new_fd);
60     close(sockfd);
61     return 0;
62 }
View Code

UDP模型

 1 //UDPServer.c
 2 #include <stdio.h>
 3 #include <sys/types.h>
 4 #include <sys/socket.h>
 5 #include <netinet/in.h>
 6 #include <arpa/inet.h>
 7 #include <netdb.h>
 8 #include <string.h>
 9 #include <unistd.h>
10 #include <stdlib.h>
11 #include <sys/wait.h>
12 #include <sys/stat.h>
13 #include <errno.h>
14 
15 #define RET_OK   0
16 #define RET_ERR -1
17 #define LISTEN_QUEUE_NUM 5
18 #define BUFFER_SIZE 256
19 #define ECHO_PORT 2029
20 
21 int main(int argc, char **argv)
22 {
23     int sockfd, len, opt = 1;
24     struct sockaddr_in cliaddr;
25     uint8_t buffer[BUFFER_SIZE];
26     int ret = RET_OK;
27     
28     if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
29     {
30         perror("ERROR: opening socket!");
31         return RET_ERR;
32     }
33     if((ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) < 0)
34     {
35         perror("ERROR: set sockopt!");
36         close(sockfd);
37         return 0;
38     }
39     memset(&cliaddr, 0, sizeof(cliaddr));
40     cliaddr.sin_family = AF_INET;
41     cliaddr.sin_addr.s_addr = INADDR_ANY;
42     cliaddr.sin_port = htons(ECHO_PORT);
43     if ((ret = bind(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr))) < 0)
44     {
45         perror("ERROR: on binding");
46         goto failed;
47     }
48     
49     do 
50     {
51         len = sizeof(cliaddr);
52         if((ret = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&cliaddr, &len)) > 0)
53         {
54             printf("Recv from %s\r\n", inet_ntoa(cliaddr.sin_addr));
55             ret = sendto(sockfd, buffer, ret, 0, (struct sockaddr *)&cliaddr, len);
56         }
57     }while(ret >= 0);
58     
59     close(sockfd);
60     return 0;
61 }
View Code
 1 //UDPClient.c
 2 #include <stdio.h>
 3 #include <sys/types.h>
 4 #include <sys/socket.h>
 5 #include <netinet/in.h>
 6 #include <arpa/inet.h>
 7 #include <netdb.h>
 8 #include <string.h>
 9 #include <unistd.h>
10 #include <stdlib.h>
11 #include <sys/wait.h>
12 #include <sys/stat.h>
13 #include <errno.h>
14 
15 #define RET_OK   0
16 #define RET_ERR -1
17 #define LISTEN_QUEUE_NUM 5
18 #define BUFFER_SIZE 256
19 #define ECHO_PORT 2029
20 
21 int main(int argc, char *argv[])
22 {
23     int sockfd, ret = RET_OK;
24     struct sockaddr_in servaddr;
25     struct hostent *server;
26     char buffer[BUFFER_SIZE];
27     
28     if (argc < 2) {
29         fprintf(stderr,"ERROR: usage %s hostname\n", argv[0]);
30         return RET_ERR;
31     }
32     if((server = gethostbyname(argv[1])) == NULL)
33     {
34         herror("ERROR: get host by name. ");
35         return RET_ERR;
36     }
37     
38     if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
39     {
40         perror("ERROR: opening socket");
41         return RET_ERR;
42     }
43     memset(&servaddr, 0, sizeof(servaddr));
44     servaddr.sin_family = AF_INET;
45     servaddr.sin_addr.s_addr = *(uint32_t *)server->h_addr;
46     servaddr.sin_port = htons((uint16_t)ECHO_PORT);
47     
48     while(1)
49     {
50         printf("Enter the message  : ");
51         if(fgets(buffer, sizeof(buffer) - 1, stdin) == NULL)
52         {
53             break;
54         }
55         if((ret = sendto(sockfd, buffer ,strlen(buffer), 0, (struct sockaddr *)&servaddr, sizeof(servaddr))) < 0)
56         {
57             perror("ERROR: writing to socket");
58             break;
59         }
60         if((ret = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, NULL, NULL)) < 0)
61         {
62             perror("ERROR: reading from socket");
63             break;
64         }
65         buffer[ret] = 0;
66         printf("Server echo message: %s\n",buffer);
67     }
68     close(sockfd);
69     return ret < 0 ? RET_ERR : RET_OK;
70 }
View Code
 1 #Makefile
 2 
 3 PROGRAM_CLIENT = client
 4 PROGRAM_SERVER = server
 5 
 6 CC      = gcc
 7 
 8 LDPATH = /usr/local/lib
 9 
10 INCLUDEDIR = .
11 
12 SOURCE_PATH = .
13 
14 OPTS    = -g -Wall -I. -I$(INCLUDEDIR)
15 
16 CFLAGS  = $(OPTS) -fPIC
17 
18 LIBS    = -L./ -L$(LDPATH)
19 
20 all: $(PROGRAM_SERVER) $(PROGRAM_CLIENT)
21 
22 clean:
23     rm -f *.o *.core *.bak $(PROGRAM_CLIENT) $(PROGRAM_SERVER) *.a core.* *.exe 
24 
25 $(PROGRAM_CLIENT): $(LIBRARY) $(SOURCE_PATH)/client.c
26     $(CC) $(CFLAGS) $(SOURCE_PATH)/client.c $(LIBS)  -o $(PROGRAM_CLIENT) $(OBJS)  -Wl,-rpath,./ 
27 
28 $(PROGRAM_SERVER): $(LIBRARY) $(SOURCE_PATH)/server.c
29     $(CC) $(CFLAGS) $(SOURCE_PATH)/server.c $(LIBS)  -o $(PROGRAM_SERVER) $(OBJS)  -Wl,-rpath,./ 
View Code

select模型

  1 //server.c
  2 #include <sys/types.h>
  3 #include <ctype.h>
  4 #include <strings.h>
  5 #include <unistd.h>
  6 #include <sys/socket.h>
  7 #include <netinet/in.h>
  8 #include <netdb.h>
  9 #include <arpa/inet.h>
 10 #include <ctype.h>
 11 #include <errno.h>
 12 #include <sys/time.h>
 13 #include <stdio.h>
 14 #include <string.h>
 15 #include <sys/select.h>
 16 #include <stdlib.h>
 17 
 18 #define LISTEN_QUEUE_NUM 5
 19 #define BUFFER_SIZE 256
 20 #define ECHO_PORT 2029
 21 
 22 int main(int argc, char **argv)
 23 {
 24     struct sockaddr_in servaddr, remote;
 25     int request_sock, new_sock;
 26     int nfound, fd, maxfd, bytesread;
 27     uint32_t  addrlen;
 28     fd_set rset, set;
 29     struct timeval timeout;
 30     char buf[BUFFER_SIZE];
 31 
 32     if ((request_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
 33         perror("socket");
 34         return -1;
 35     }
 36     memset(&servaddr, 0, sizeof(servaddr));
 37     servaddr.sin_family = AF_INET;
 38     servaddr.sin_addr.s_addr = INADDR_ANY;
 39     servaddr.sin_port = htons((uint16_t)ECHO_PORT);
 40 
 41     if (bind(request_sock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) 
 42     {
 43         perror("bind");
 44         return -1;
 45     }
 46     if (listen(request_sock, LISTEN_QUEUE_NUM) < 0) 
 47     {
 48         perror("listen");
 49         return -1;
 50     }
 51 
 52     FD_ZERO(&set);
 53     FD_SET(request_sock, &set);
 54     maxfd = request_sock;
 55     while(1) {
 56         rset = set;
 57         timeout.tv_sec = 0;
 58         timeout.tv_usec = 500000;
 59         if((nfound = select(maxfd + 1, &rset, (fd_set *)0, (fd_set *)0, &timeout)) < 0) 
 60         {
 61             perror("select");
 62         return -1;
 63         }
 64         else
 65             if (nfound == 0) 
 66             {
 67                 printf("."); fflush(stdout);
 68                 continue;
 69             }
 70         if (FD_ISSET(request_sock, &rset)) 
 71         {
 72             addrlen = sizeof(remote);
 73             if ((new_sock = accept(request_sock, (struct sockaddr *)&remote, &addrlen)) < 0) 
 74             {
 75                 perror("accept");
 76                 return -1;
 77             }
 78             printf("connection from host %s, port %d, socket %d\r\n",
 79                     inet_ntoa(remote.sin_addr), ntohs(remote.sin_port),
 80                     new_sock);
 81             FD_SET(new_sock, &set);
 82             if (new_sock > maxfd)
 83                 maxfd = new_sock;
 84             FD_CLR(request_sock, &rset);
 85             nfound --;
 86         }
 87         for (fd=0; fd <= maxfd && nfound > 0; fd++) {
 88             if (FD_ISSET(fd, &rset)) {
 89                 nfound --;
 90                 if ((bytesread = read(fd, buf, sizeof buf - 1))<0) 
 91                 {
 92                     perror("read");
 93                 }
 94                 if (bytesread == 0) 
 95                 {
 96                     fprintf(stderr, "server: end of file on %d\r\n",fd);
 97                     FD_CLR(fd, &set);
 98                     close(fd);
 99                     continue;
100                 }
101                 buf[bytesread] = 0;
102                 printf("%s: %d bytes from %d: %s\n", argv[0], bytesread, fd, buf);
103                 if (write(fd, buf, bytesread) < 0)
104                 {
105                     perror("echo");
106                     FD_CLR(fd, &set);
107                     close(fd);
108                 }
109             }
110         }
111     }
112     return 0;
113 }
View Code
  1 //client.c
  2 #include <sys/types.h>
  3 #include <sys/socket.h>
  4 #include <sys/time.h>
  5 #include <netinet/in.h>
  6 #include <errno.h>
  7 #include <ctype.h>
  8 #include <netdb.h>
  9 #include <stdio.h>
 10 #include <string.h>
 11 #include <stdlib.h>
 12 #include <unistd.h>
 13 #include <sys/select.h>
 14 
 15 
 16 #define RET_OK   0
 17 #define RET_ERR -1
 18 #define LISTEN_QUEUE_NUM 5
 19 #define BUFFER_SIZE 256
 20 #define ECHO_PORT 2029
 21 
 22 int main(int argc, char **argv)
 23 {
 24     int sock, maxfd = 0;
 25     struct sockaddr_in servaddr;
 26     struct hostent *server; 
 27     fd_set rset, set;
 28     int nfound, bytesread;
 29     char buf[BUFFER_SIZE];
 30 
 31     if (argc < 2) 
 32     {
 33         fprintf(stderr,"usage %s hostname\n", argv[0]);
 34         return RET_ERR;
 35     }
 36     if((server = gethostbyname(argv[1])) == NULL)
 37     {
 38         herror("gethostbyname. ");
 39         return RET_ERR;
 40     }
 41     if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
 42     {
 43         perror("socket");
 44         return -1;
 45     }
 46     memset(&servaddr, 0, sizeof(servaddr));
 47     servaddr.sin_family = AF_INET;
 48     servaddr.sin_addr.s_addr = *(uint32_t *)server->h_addr;
 49     servaddr.sin_port = htons((uint16_t)ECHO_PORT);
 50     if (connect(sock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) 
 51     {
 52         perror("connect");
 53         return -1;
 54     }
 55     maxfd = fileno(stdin);
 56     FD_ZERO(&set);
 57     FD_SET(sock, &set);
 58     FD_SET(maxfd, &set);
 59     maxfd = (maxfd > sock ? maxfd : sock) + 1;
 60     while(1) 
 61     {
 62         rset = set;
 63         if ((nfound = select(maxfd, &rset, (fd_set *)0, (fd_set *)0, NULL)) < 0) 
 64         {
 65             if (errno == EINTR) {
 66                 fprintf(stderr, "interrupted system call\n");
 67                 continue;
 68             }
 69             perror("select");
 70             exit(1);
 71         }
 72         if (FD_ISSET(fileno(stdin), &rset)) {
 73             if (fgets(buf, sizeof(buf), stdin) == NULL) {
 74                 if (ferror(stdin)) {
 75                     perror("stdin");
 76                     return -1;
 77                 }
 78                 return 0;
 79             }
 80             if (write(sock, buf, strlen(buf)) < 0) 
 81             {
 82                 perror("write");
 83                 return -1;
 84             }
 85         }
 86         if (FD_ISSET(sock,&rset)) {
 87             if((bytesread = read(sock, buf, sizeof buf)) < 0)
 88             {
 89                 perror("read");
 90                 exit(1);    
 91             }
 92             else
 93             if(bytesread == 0)
 94             {
 95                 fprintf(stderr, "server disconnect\n");
 96                 exit(0);    
 97             }
 98             buf[bytesread] = 0;
 99             printf("%s\n",buf);
100         }
101     }
102     return 0;
103 } 
View Code
 1 #Makefile
 2 PROGRAM_CLIENT = client
 3 PROGRAM_SERVER = server
 4 
 5 CC      = gcc
 6 
 7 LDPATH = /usr/local/lib
 8 
 9 INCLUDEDIR = .
10 
11 SOURCE_PATH = .
12 
13 OPTS    = -g -Wall -I. -I$(INCLUDEDIR)
14 
15 CFLAGS  = $(OPTS) -fPIC
16 
17 LIBS    = -L./ -L$(LDPATH)
18 
19 all: $(PROGRAM_SERVER) $(PROGRAM_CLIENT)
20 
21 clean:
22     rm -f *.o *.core *.bak $(PROGRAM_CLIENT) $(PROGRAM_SERVER) *.a core.* *.exe 
23 
24 $(PROGRAM_CLIENT): $(LIBRARY) $(SOURCE_PATH)/client.c
25     $(CC) $(CFLAGS) $(SOURCE_PATH)/client.c $(LIBS)  -o $(PROGRAM_CLIENT) $(OBJS)  -Wl,-rpath,./ 
26 
27 $(PROGRAM_SERVER): $(LIBRARY) $(SOURCE_PATH)/server.c
28     $(CC) $(CFLAGS) $(SOURCE_PATH)/server.c $(LIBS)  -o $(PROGRAM_SERVER) $(OBJS)  -Wl,-rpath,./ 
View Code

poll模型

  1 //server.c
  2 #include  <unistd.h>
  3 #include  <sys/types.h>       /* basic system data types */
  4 #include  <sys/socket.h>      /* basic socket definitions */
  5 #include  <netinet/in.h>      /* sockaddr_in{} and other Internet defns */
  6 #include  <arpa/inet.h>       /* inet(3) functions */
  7 
  8 #include <stdlib.h>
  9 #include <errno.h>
 10 #include <stdio.h>
 11 #include <string.h>
 12 
 13 
 14 #include <poll.h> /* poll function */
 15 #include <limits.h>
 16 
 17 #define MAXLINE 10240
 18 
 19 #ifndef OPEN_MAX
 20 #define OPEN_MAX 40960
 21 #endif
 22 
 23 void handle(struct pollfd* clients, int maxClient, int readyClient);
 24 
 25 int  main(int argc, char **argv)
 26 {
 27     int servPort = 6888;
 28     int listenq = 1024;
 29     int listenfd, connfd;
 30     struct pollfd clients[OPEN_MAX];
 31     int  maxi;
 32     socklen_t socklen = sizeof(struct sockaddr_in);
 33     struct sockaddr_in cliaddr, servaddr;
 34     char buf[MAXLINE];
 35     int nready;
 36 
 37     bzero(&servaddr, socklen);
 38     servaddr.sin_family = AF_INET;
 39     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
 40     servaddr.sin_port = htons(servPort);
 41 
 42     listenfd = socket(AF_INET, SOCK_STREAM, 0);
 43     if (listenfd < 0) {
 44         perror("socket error");
 45     }
 46 
 47     int opt = 1;
 48     if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
 49         perror("setsockopt error");
 50     }
 51 
 52     if(bind(listenfd, (struct sockaddr *) &servaddr, socklen) == -1) {
 53         perror("bind error");
 54         exit(-1);
 55     }
 56     if (listen(listenfd, listenq) < 0) {
 57         perror("listen error");    
 58     }
 59 
 60     clients[0].fd = listenfd;
 61     clients[0].events = POLLIN;
 62     int i;
 63     for (i = 1; i< OPEN_MAX; i++) 
 64         clients[i].fd = -1; 
 65     maxi = listenfd + 1;
 66 
 67     printf("pollechoserver startup, listen on port:%d\n", servPort);
 68     printf("max connection is %d\n", OPEN_MAX);
 69 
 70     for ( ; ; )  {
 71         nready = poll(clients, maxi + 1, -1);
 72         //printf("nready is %d\n", nready);
 73         if (nready == -1) {
 74             perror("poll error");
 75         }
 76         if (clients[0].revents & POLLIN) {
 77             connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &socklen);
 78             sprintf(buf, "accept form %s:%d\n", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port);
 79             printf(buf, "");
 80 
 81             for (i = 0; i < OPEN_MAX; i++) {
 82                 if (clients[i].fd == -1) {
 83                     clients[i].fd = connfd;
 84                     clients[i].events = POLLIN;
 85                     break;
 86                 }
 87             }
 88 
 89             if (i == OPEN_MAX) {
 90                 fprintf(stderr, "too many connection, more than %d\n", OPEN_MAX);
 91                 close(connfd);
 92                 continue;
 93             }
 94 
 95             if (i > maxi)
 96                 maxi = i;
 97 
 98             --nready;
 99         }
100 
101         handle(clients, maxi, nready);
102     }
103 }
104 
105 void handle(struct pollfd* clients, int maxClient, int nready) {
106     int connfd;
107     int i, nread;
108     char buf[MAXLINE];
109 
110     if (nready == 0)
111         return;
112 
113     for (i = 1; i< maxClient; i++) {
114         connfd = clients[i].fd;
115         if (connfd == -1) 
116             continue;
117         if (clients[i].revents & (POLLIN | POLLERR)) {
118             nread = read(connfd, buf, MAXLINE);//读取客户端socket流
119             if (nread < 0) {
120                 perror("read error");
121                 close(connfd);
122                 clients[i].fd = -1;
123                 continue;
124             }
125             if (nread == 0) {
126                 printf("client close the connection");
127                 close(connfd);
128                 clients[i].fd = -1;
129                 continue;
130             }
131 
132             write(connfd, buf, nread);//响应客户端  
133             if (--nready <= 0)//没有连接需要处理,退出循环
134                 break;
135         }
136     }
137 }
View Code

epoll模型

  1 #include <sys/socket.h>
  2 #include <sys/epoll.h>
  3 #include <netinet/in.h>
  4 #include <arpa/inet.h>
  5 #include <fcntl.h>
  6 #include <unistd.h>
  7 #include <stdio.h>
  8 #include <errno.h>
  9 #include <iostream>
 10 using namespace std;
 11 #define MAX_EVENTS 500
 12 struct myevent_s
 13 {
 14     int fd;
 15     void (*call_back)(int fd, int events, void *arg);
 16     int events;
 17     void *arg;
 18     int status; // 1: in epoll wait list, 0 not in
 19     char buff[128]; // recv data buffer
 20     int len;
 21     long last_active; // last active time
 22 };
 23 // set event
 24 void EventSet(myevent_s *ev, int fd, void (*call_back)(int, int, void*), void *arg)
 25 {
 26     ev->fd = fd;
 27     ev->call_back = call_back;
 28     ev->events = 0;
 29     ev->arg = arg;
 30     ev->status = 0;
 31     ev->last_active = time(NULL);
 32 }
 33 // add/mod an event to epoll
 34 void EventAdd(int epollFd, int events, myevent_s *ev)
 35 {
 36     struct epoll_event epv = {0, {0}};
 37     int op;
 38     epv.data.ptr = ev;
 39     epv.events = ev->events = events;
 40     if(ev->status == 1){
 41         op = EPOLL_CTL_MOD;
 42     }
 43     else{
 44         op = EPOLL_CTL_ADD;
 45         ev->status = 1;
 46     }
 47     if(epoll_ctl(epollFd, op, ev->fd, &epv) < 0)
 48         printf("Event Add failed[fd=%d]\n", ev->fd);
 49     else
 50         printf("Event Add OK[fd=%d]\n", ev->fd);
 51 }
 52 // delete an event from epoll
 53 void EventDel(int epollFd, myevent_s *ev)
 54 {
 55     struct epoll_event epv = {0, {0}};
 56     if(ev->status != 1) return;
 57     epv.data.ptr = ev;
 58     ev->status = 0;
 59     epoll_ctl(epollFd, EPOLL_CTL_DEL, ev->fd, &epv);
 60 }
 61 int g_epollFd;
 62 myevent_s g_Events[MAX_EVENTS+1]; // g_Events[MAX_EVENTS] is used by listen fd
 63 void RecvData(int fd, int events, void *arg);
 64 void SendData(int fd, int events, void *arg);
 65 // accept new connections from clients
 66 void AcceptConn(int fd, int events, void *arg)
 67 {
 68     struct sockaddr_in sin;
 69     socklen_t len = sizeof(struct sockaddr_in);
 70     int nfd, i;
 71     // accept
 72     if((nfd = accept(fd, (struct sockaddr*)&sin, &len)) == -1)
 73     {
 74         if(errno != EAGAIN && errno != EINTR)
 75         {
 76             printf("%s: bad accept", __func__);
 77         }
 78         return;
 79     }
 80     do
 81     {
 82         for(i = 0; i < MAX_EVENTS; i++)
 83         {
 84             if(g_Events[i].status == 0)
 85             {
 86                 break;
 87             }
 88         }
 89         if(i == MAX_EVENTS)
 90         {
 91             printf("%s:max connection limit[%d].", __func__, MAX_EVENTS);
 92             break;
 93         }
 94         // set nonblocking
 95         if(fcntl(nfd, F_SETFL, O_NONBLOCK) < 0) break;
 96         // add a read event for receive data
 97         EventSet(&g_Events[i], nfd, RecvData, &g_Events[i]);
 98         EventAdd(g_epollFd, EPOLLIN|EPOLLET, &g_Events[i]);
 99         printf("new conn[%s:%d][time:%d]\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), g_Events[i].last_active);
100     }while(0);
101 }
102 // receive data
103 void RecvData(int fd, int events, void *arg)
104 {
105     struct myevent_s *ev = (struct myevent_s*)arg;
106     int len;
107     // receive data
108     len = recv(fd, ev->buff, sizeof(ev->buff)-1, 0); 
109     EventDel(g_epollFd, ev);
110     if(len > 0)
111     {
112         ev->len = len;
113         ev->buff[len] = '\0';
114         printf("C[%d]:%s\n", fd, ev->buff);
115         // change to send event
116         EventSet(ev, fd, SendData, ev);
117         EventAdd(g_epollFd, EPOLLOUT|EPOLLET, ev);
118     }
119     else if(len == 0)
120     {
121         close(ev->fd);
122         printf("[fd=%d] closed gracefully.\n", fd);
123     }
124     else
125     {
126         close(ev->fd);
127         printf("recv[fd=%d] error[%d]:%s\n", fd, errno, strerror(errno));
128     }
129 }
130 // send data
131 void SendData(int fd, int events, void *arg)
132 {
133     struct myevent_s *ev = (struct myevent_s*)arg;
134     int len;
135     // send data
136     len = send(fd, ev->buff, ev->len, 0);
137     ev->len = 0;
138     EventDel(g_epollFd, ev);
139     if(len > 0)
140     {
141         // change to receive event
142         EventSet(ev, fd, RecvData, ev);
143         EventAdd(g_epollFd, EPOLLIN|EPOLLET, ev);
144     }
145     else
146     {
147         close(ev->fd);
148         printf("recv[fd=%d] error[%d]\n", fd, errno);
149     }
150 }
151 void InitListenSocket(int epollFd, short port)
152 {
153     int listenFd = socket(AF_INET, SOCK_STREAM, 0);
154     fcntl(listenFd, F_SETFL, O_NONBLOCK); // set non-blocking
155     printf("server listen fd=%d\n", listenFd);
156     EventSet(&g_Events[MAX_EVENTS], listenFd, AcceptConn, &g_Events[MAX_EVENTS]);
157     // add listen socket
158     EventAdd(epollFd, EPOLLIN|EPOLLET, &g_Events[MAX_EVENTS]);
159     // bind & listen
160     sockaddr_in sin;
161     bzero(&sin, sizeof(sin));
162     sin.sin_family = AF_INET;
163     sin.sin_addr.s_addr = INADDR_ANY;
164     sin.sin_port = htons(port);
165     bind(listenFd, (const sockaddr*)&sin, sizeof(sin));
166     listen(listenFd, 5);
167 }
168 int main(int argc, char **argv)
169 {
170     short port = 12345; // default port
171     if(argc == 2){
172         port = atoi(argv[1]);
173     }
174     // create epoll
175     g_epollFd = epoll_create(MAX_EVENTS);
176     if(g_epollFd <= 0) printf("create epoll failed.%d\n", g_epollFd);
177     // create & bind listen socket, and add to epoll, set non-blocking
178     InitListenSocket(g_epollFd, port);
179     // event loop
180     struct epoll_event events[MAX_EVENTS];
181     printf("server running:port[%d]\n", port);
182     int checkPos = 0;
183     while(1){
184         // a simple timeout check here, every time 100, better to use a mini-heap, and add timer event
185         long now = time(NULL);
186         for(int i = 0; i < 100; i++, checkPos++) // doesn't check listen fd
187         {
188             if(checkPos == MAX_EVENTS) checkPos = 0; // recycle
189             if(g_Events[checkPos].status != 1) continue;
190             long duration = now - g_Events[checkPos].last_active;
191             if(duration >= 60) // 60s timeout
192             {
193                 close(g_Events[checkPos].fd);
194                 printf("[fd=%d] timeout[%d--%d].\n", g_Events[checkPos].fd, g_Events[checkPos].last_active, now);
195                 EventDel(g_epollFd, &g_Events[checkPos]);
196             }
197         }
198         // wait for events to happen
199         int fds = epoll_wait(g_epollFd, events, MAX_EVENTS, 1000);
200         if(fds < 0){
201             printf("epoll_wait error, exit\n");
202             break;
203         }
204         for(int i = 0; i < fds; i++){
205             myevent_s *ev = (struct myevent_s*)events[i].data.ptr;
206             if((events[i].events&EPOLLIN)&&(ev->events&EPOLLIN)) // read event
207             {
208                 ev->call_back(ev->fd, events[i].events, ev->arg);
209             }
210             if((events[i].events&EPOLLOUT)&&(ev->events&EPOLLOUT)) // write event
211             {
212                 ev->call_back(ev->fd, events[i].events, ev->arg);
213             }
214         }
215     }
216     // free resource
217     return 0;
218 }
View Code

 

 

参考:

Linux/Unix IO多路复用之系列

 

posted on 2013-10-05 19:34  鹰之翔  阅读(1178)  评论(0编辑  收藏  举报

导航