push sockt&epoll samples
[socket_samples.git] / epoll / epoll.c
blob63f9bbe7300830dc199db0e1014ca56134b733bb
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>
11 #define MAXEVENTS 64
13 //函数:
14 //功能:创建和绑定一个TCP socket
15 //参数:端口
16 //返回值:创建的socket
17 static int
18 create_and_bind (char *port)
20 struct addrinfo hints;
21 struct addrinfo *result, *rp;
22 int s, sfd;
24 memset (&hints, 0, sizeof (struct addrinfo));
25 hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */
26 hints.ai_socktype = SOCK_STREAM; /* We want a TCP socket */
27 hints.ai_flags = AI_PASSIVE; /* All interfaces */
29 s = getaddrinfo (NULL, port, &hints, &result);
30 if (s != 0)
32 fprintf (stderr, "getaddrinfo: %s\n", gai_strerror (s));
33 return -1;
36 for (rp = result; rp != NULL; rp = rp->ai_next)
38 sfd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol);
39 if (sfd == -1)
40 continue;
42 s = bind (sfd, rp->ai_addr, rp->ai_addrlen);
43 if (s == 0)
45 /* We managed to bind successfully! */
46 break;
49 close (sfd);
52 if (rp == NULL)
54 fprintf (stderr, "Could not bind\n");
55 return -1;
58 freeaddrinfo (result);
60 return sfd;
64 //函数
65 //功能:设置socket为非阻塞的
66 static int
67 make_socket_non_blocking (int sfd)
69 int flags, s;
71 //得到文件状态标志
72 flags = fcntl (sfd, F_GETFL, 0);
73 if (flags == -1)
75 perror ("fcntl");
76 return -1;
79 //设置文件状态标志
80 flags |= O_NONBLOCK;
81 s = fcntl (sfd, F_SETFL, flags);
82 if (s == -1)
84 perror ("fcntl");
85 return -1;
88 return 0;
91 //端口由参数argv[1]指定
92 int
93 main (int argc, char *argv[])
95 int sfd, s;
96 int efd;
97 struct epoll_event event;
98 struct epoll_event *events;
100 if (argc != 2)
102 fprintf (stderr, "Usage: %s [port]\n", argv[0]);
103 exit (EXIT_FAILURE);
106 sfd = create_and_bind (argv[1]);
107 if (sfd == -1)
108 abort ();
110 s = make_socket_non_blocking (sfd);
111 if (s == -1)
112 abort ();
114 s = listen (sfd, SOMAXCONN);
115 if (s == -1)
117 perror ("listen");
118 abort ();
121 //除了参数size被忽略外,此函数和epoll_create完全相同
122 efd = epoll_create1 (0);
123 if (efd == -1)
125 perror ("epoll_create");
126 abort ();
129 event.data.fd = sfd;
130 event.events = EPOLLIN | EPOLLET;//读入,边缘触发方式
131 s = epoll_ctl (efd, EPOLL_CTL_ADD, sfd, &event);
132 if (s == -1)
134 perror ("epoll_ctl");
135 abort ();
138 /* Buffer where events are returned */
139 events = calloc (MAXEVENTS, sizeof event);
141 /* The event loop */
142 while (1)
144 int n, i;
146 n = epoll_wait (efd, events, MAXEVENTS, -1);
147 for (i = 0; i < n; i++)
149 if ((events[i].events & EPOLLERR) ||
150 (events[i].events & EPOLLHUP) ||
151 (!(events[i].events & EPOLLIN)))
153 /* An error has occured on this fd, or the socket is not
154 ready for reading (why were we notified then?) */
155 fprintf (stderr, "epoll error\n");
156 close (events[i].data.fd);
157 continue;
160 else if (sfd == events[i].data.fd)
162 /* We have a notification on the listening socket, which
163 means one or more incoming connections. */
164 while (1)
166 struct sockaddr in_addr;
167 socklen_t in_len;
168 int infd;
169 char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
171 in_len = sizeof in_addr;
172 infd = accept (sfd, &in_addr, &in_len);
173 if (infd == -1)
175 if ((errno == EAGAIN) ||
176 (errno == EWOULDBLOCK))
178 /* We have processed all incoming
179 connections. */
180 break;
182 else
184 perror ("accept");
185 break;
189 //将地址转化为主机名或者服务名
190 s = getnameinfo (&in_addr, in_len,
191 hbuf, sizeof hbuf,
192 sbuf, sizeof sbuf,
193 NI_NUMERICHOST | NI_NUMERICSERV);//flag参数:以数字名返回
194 //主机地址和服务地址
196 if (s == 0)
198 printf("Accepted connection on descriptor %d "
199 "(host=%s, port=%s)\n", infd, hbuf, sbuf);
202 /* Make the incoming socket non-blocking and add it to the
203 list of fds to monitor. */
204 s = make_socket_non_blocking (infd);
205 if (s == -1)
206 abort ();
208 event.data.fd = infd;
209 event.events = EPOLLIN | EPOLLET;
210 s = epoll_ctl (efd, EPOLL_CTL_ADD, infd, &event);
211 if (s == -1)
213 perror ("epoll_ctl");
214 abort ();
217 continue;
219 else
221 /* We have data on the fd waiting to be read. Read and
222 display it. We must read whatever data is available
223 completely, as we are running in edge-triggered mode
224 and won't get a notification again for the same
225 data. */
226 int done = 0;
228 while (1)
230 ssize_t count;
231 char buf[512];
233 count = read (events[i].data.fd, buf, sizeof(buf));
234 if (count == -1)
236 /* If errno == EAGAIN, that means we have read all
237 data. So go back to the main loop. */
238 if (errno != EAGAIN)
240 perror ("read");
241 done = 1;
243 break;
245 else if (count == 0)
247 /* End of file. The remote has closed the
248 connection. */
249 done = 1;
250 break;
253 /* Write the buffer to standard output */
254 s = write (1, buf, count);
255 if (s == -1)
257 perror ("write");
258 abort ();
262 if (done)
264 printf ("Closed connection on descriptor %d\n",
265 events[i].data.fd);
267 /* Closing the descriptor will make epoll remove it
268 from the set of descriptors which are monitored. */
269 close (events[i].data.fd);
275 free (events);
277 close (sfd);
279 return EXIT_SUCCESS;