• Linux网络通信编程(套接字模型TCPUDP与IO多路复用模型selectpollepoll)


    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!
    ", strerror(errno));
    31         close(sockfd);
    32         return -1;
    33     }
    34     msg_send="This is TCPClient!
    ";
    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!
    ", 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!
    ");
    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
    !", msg_recv );
    56     }
    57     else
    58     {
    59         printf("ERROR:net error
    ");
    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!
    ";
    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
    ", 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!
    ");
    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
    ", msg_recv );
    54     }
    55     else
    56     {
    57         printf("ERROR:net error!
    ");
    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
    ", 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
    ", 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
    ",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
    ",
     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
    ",fd);
     97                     FD_CLR(fd, &set);
     98                     close(fd);
     99                     continue;
    100                 }
    101                 buf[bytesread] = 0;
    102                 printf("%s: %d bytes from %d: %s
    ", 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
    ", 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
    ");
     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
    ");
     96                 exit(0);    
     97             }
     98             buf[bytesread] = 0;
     99             printf("%s
    ",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
    ", servPort);
     68     printf("max connection is %d
    ", OPEN_MAX);
     69 
     70     for ( ; ; )  {
     71         nready = poll(clients, maxi + 1, -1);
     72         //printf("nready is %d
    ", 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
    ", 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
    ", 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]
    ", ev->fd);
     49     else
     50         printf("Event Add OK[fd=%d]
    ", 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]
    ", 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] = '';
    114         printf("C[%d]:%s
    ", 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.
    ", fd);
    123     }
    124     else
    125     {
    126         close(ev->fd);
    127         printf("recv[fd=%d] error[%d]:%s
    ", 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]
    ", 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
    ", 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
    ", 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]
    ", 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].
    ", 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
    ");
    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多路复用之系列

  • 相关阅读:
    个人博客开发之blogapi项目统一结果集api封装
    个人博客开发之blogapi 项目整合JWT实现token登录认证
    C语言I博客作业06
    C语言l博客作业03
    C语言I博客作业04
    C语言I博客作业05
    C语言I博客作业01
    C语言I博客作业07
    C语言I博客作业02
    UVA 11427 Expect the Expected [概率]
  • 原文地址:https://www.cnblogs.com/gjianw217/p/3352755.html
Copyright © 2020-2023  润新知