epoll实例

epoll的程序实例

  1. #include <stdio.h>

  2. #include <stdlib.h>

  3. #include <unistd.h>

  4. #include <errno.h>

  5. #include <sys/socket.h>

  6. #include <netdb.h>

  7. #include <fcntl.h>

  8. #include <sys/epoll.h>

  9. #include <string.h>

  10. #define MAXEVENTS 64

  11. //函数:

  12. //功能:创建和绑定一个TCP socket

  13. //参数:端口

  14. //返回值:创建的socket

  15. staticint

  16. create_and_bind (char *port)  

  17. {  

  18. struct addrinfo hints;  

  19. struct addrinfo *result, *rp;  

  20. int s, sfd;  

  21.  memset (&hints, 0, sizeof (struct addrinfo));  

  22.  hints.ai_family = AF_UNSPEC;     /* Return IPv4 and IPv6 choices */

  23.  hints.ai_socktype = SOCK_STREAM; /* We want a TCP socket */

  24.  hints.ai_flags = AI_PASSIVE;     /* All interfaces */

  25.  s = getaddrinfo (NULL, port, &hints, &result);  

  26. if (s != 0)  

  27.    {  

  28.      fprintf (stderr, "getaddrinfo: %s\n", gai_strerror (s));  

  29. return -1;  

  30.    }  

  31. for (rp = result; rp != NULL; rp = rp->ai_next)  

  32.    {  

  33.      sfd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol);  

  34. if (sfd == -1)  

  35. continue;  

  36.      s = bind (sfd, rp->ai_addr, rp->ai_addrlen);  

  37. if (s == 0)  

  38.        {  

  39. /* We managed to bind successfully! */

  40. break;  

  41.        }  

  42.      close (sfd);  

  43.    }  

  44. if (rp == NULL)  

  45.    {  

  46.      fprintf (stderr, "Could not bind\n");  

  47. return -1;  

  48.    }  

  49.  freeaddrinfo (result);  

  50. return sfd;  

  51. }  

  52. //函数

  53. //功能:设置socket为非阻塞的

  54. staticint

  55. make_socket_non_blocking (int sfd)  

  56. {  

  57. int flags, s;  

  58. //得到文件状态标志

  59.  flags = fcntl (sfd, F_GETFL, 0);  

  60. if (flags == -1)  

  61.    {  

  62.      perror ("fcntl");  

  63. return -1;  

  64.    }  

  65. //设置文件状态标志

  66.  flags |= O_NONBLOCK;  

  67.  s = fcntl (sfd, F_SETFL, flags);  

  68. if (s == -1)  

  69.    {  

  70.      perror ("fcntl");  

  71. return -1;  

  72.    }  

  73. return 0;  

  74. }  

  75. //端口由参数argv[1]指定

  76. int

  77. main (int argc, char *argv[])  

  78. {  

  79. int sfd, s;  

  80. int efd;  

  81. struct epoll_event event;  

  82. struct epoll_event *events;  

  83. if (argc != 2)  

  84.    {  

  85.      fprintf (stderr, "Usage: %s [port]\n", argv[0]);  

  86.      exit (EXIT_FAILURE);  

  87.    }  

  88.  sfd = create_and_bind (argv[1]);  

  89. if (sfd == -1)  

  90.    abort ();  

  91.  s = make_socket_non_blocking (sfd);  

  92. if (s == -1)  

  93.    abort ();  

  94.  s = listen (sfd, SOMAXCONN);  

  95. if (s == -1)  

  96.    {  

  97.      perror ("listen");  

  98.      abort ();  

  99.    }  

  100. //除了参数size被忽略外,此函数和epoll_create完全相同

  101.  efd = epoll_create1 (0);  

  102. if (efd == -1)  

  103.    {  

  104.      perror ("epoll_create");  

  105.      abort ();  

  106.    }  

  107.  event.data.fd = sfd;  

  108.  event.events = EPOLLIN | EPOLLET;//读入,边缘触发方式

  109.  s = epoll_ctl (efd, EPOLL_CTL_ADD, sfd, &event);  

  110. if (s == -1)  

  111.    {  

  112.      perror ("epoll_ctl");  

  113.      abort ();  

  114.    }  

  115. /* Buffer where events are returned */

  116.  events = calloc (MAXEVENTS, sizeof event);  

  117. /* The event loop */

  118. while (1)  

  119.    {  

  120. int n, i;  

  121.      n = epoll_wait (efd, events, MAXEVENTS, -1);  

  122. for (i = 0; i < n; i++)  

  123.        {  

  124. if ((events[i].events & EPOLLERR) ||  

  125.              (events[i].events & EPOLLHUP) ||  

  126.              (!(events[i].events & EPOLLIN)))  

  127.            {  

  128. /* An error has occured on this fd, or the socket is not

  129.                 ready for reading (why were we notified then?) */

  130.              fprintf (stderr, "epoll error\n");  

  131.              close (events[i].data.fd);  

  132. continue;  

  133.            }  

  134. elseif (sfd == events[i].data.fd)  

  135.            {  

  136. /* We have a notification on the listening socket, which

  137.                 means one or more incoming connections. */

  138. while (1)  

  139.                {  

  140. struct sockaddr in_addr;  

  141.                  socklen_t in_len;  

  142. int infd;  

  143. char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];  

  144.                  in_len = sizeof in_addr;  

  145.                  infd = accept (sfd, &in_addr, &in_len);  

  146. if (infd == -1)  

  147.                    {  

  148. if ((errno == EAGAIN) ||  

  149.                          (errno == EWOULDBLOCK))  

  150.                        {  

  151. /* We have processed all incoming

  152.                             connections. */

  153. break;  

  154.                        }  

  155. else

  156.                        {  

  157.                          perror ("accept");  

  158. break;  

  159.                        }  

  160.                    }  

  161. //将地址转化为主机名或者服务名

  162.                  s = getnameinfo (&in_addr, in_len,  

  163.                                   hbuf, sizeof hbuf,  

  164.                                   sbuf, sizeof sbuf,  

  165.                                   NI_NUMERICHOST | NI_NUMERICSERV);//flag参数:以数字名返回

  166. //主机地址和服务地址

  167. if (s == 0)  

  168.                    {  

  169.                      printf("Accepted connection on descriptor %d "

  170. "(host=%s, port=%s)\n", infd, hbuf, sbuf);  

  171.                    }  

  172. /* Make the incoming socket non-blocking and add it to the

  173.                     list of fds to monitor. */

  174.                  s = make_socket_non_blocking (infd);  

  175. if (s == -1)  

  176.                    abort ();  

  177.                  event.data.fd = infd;  

  178.                  event.events = EPOLLIN | EPOLLET;  

  179.                  s = epoll_ctl (efd, EPOLL_CTL_ADD, infd, &event);  

  180. if (s == -1)  

  181.                    {  

  182.                      perror ("epoll_ctl");  

  183.                      abort ();  

  184.                    }  

  185.                }  

  186. continue;  

  187.            }  

  188. else

  189.            {  

  190. /* We have data on the fd waiting to be read. Read and

  191.                 display it. We must read whatever data is available

  192.                 completely, as we are running in edge-triggered mode

  193.                 and won't get a notification again for the same

  194.                 data. */

  195. int done = 0;  

  196. while (1)  

  197.                {  

  198.                  ssize_t count;  

  199. char buf[512];  

  200.                  count = read (events[i].data.fd, buf, sizeof(buf));  

  201. if (count == -1)  

  202.                    {  

  203. /* If errno == EAGAIN, that means we have read all

  204.                         data. So go back to the main loop. */

  205. if (errno != EAGAIN)  

  206.                        {  

  207.                          perror ("read");  

  208.                          done = 1;  

  209.                        }  

  210. break;  

  211.                    }  

  212. elseif (count == 0)  

  213.                    {  

  214. /* End of file. The remote has closed the

  215.                         connection. */

  216.                      done = 1;  

  217. break;  

  218.                    }  

  219. /* Write the buffer to standard output */

  220.                  s = write (1, buf, count);  

  221. if (s == -1)  

  222.                    {  

  223.                      perror ("write");  

  224.                      abort ();  

  225.                    }  

  226.                }  

  227. if (done)  

  228.                {  

  229.                  printf ("Closed connection on descriptor %d\n",  

  230.                          events[i].data.fd);  

  231. /* Closing the descriptor will make epoll remove it

  232.                     from the set of descriptors which are monitored. */

  233.                  close (events[i].data.fd);  

  234.                }  

  235.            }  

  236.        }  

  237.    }  

  238.  free (events);  

  239.  close (sfd);  

  240. return EXIT_SUCCESS;  

  241. }  



你可能感兴趣的:(epoll)