Example: fix listen queue overflow.

According to the FreeBSD Manual Page:
- When kevent() returns and if `flags` is EVFILT_READ, sockets which have previously been passed to listen() return when there is an incoming connection pending. `data` contains the size of the listen backlog.

So if an EVFILT_READ event reaches and it is the listen socket, we must accept `event->data` times. And for `ff_epoll` interface, we should continue to accept until it fails.

In the previous version, we only accept once when event reaches, it will cause listen queue overflow.
dev
logwang 2017-12-21 22:45:10 +08:00
parent b9d9ead050
commit b9e91cfd6a
2 changed files with 32 additions and 40 deletions

View File

@ -66,38 +66,34 @@ int loop(void *arg)
/* Handle disconnect */
if (event.flags & EV_EOF) {
/* Simply close socket */
ff_close(clientfd);
//printf("A client has left the server...,fd:%d\n", clientfd);
} else if (clientfd == sockfd) {
int nclientfd = ff_accept(sockfd, NULL, NULL);
if (nclientfd < 0) {
printf("ff_accept failed:%d, %s\n", errno, strerror(errno));
continue;
}
int available = (int)event.data;
do {
int nclientfd = ff_accept(sockfd, NULL, NULL);
if (nclientfd < 0) {
printf("ff_accept failed:%d, %s\n", errno,
strerror(errno));
break;
}
/* Add to event list */
kevSet.data = 0;
kevSet.fflags = 0;
kevSet.filter = EVFILT_READ;
kevSet.flags = EV_ADD;
kevSet.ident = nclientfd;
kevSet.udata = NULL;
/* Add to event list */
EV_SET(&kevSet, nclientfd, EVFILT_READ, EV_ADD, 0, 0, NULL);
assert(ff_kevent(kq, &kevSet, 1, NULL, 0, NULL) == 0);
//printf("A new client connected to the server..., fd:%d\n", nclientfd);
if(ff_kevent(kq, &kevSet, 1, NULL, 0, NULL) < 0) {
printf("ff_kevent error:%d, %s\n", errno,
strerror(errno));
return -1;
}
available--;
} while (available);
} else if (event.filter == EVFILT_READ) {
char buf[256];
size_t readlen = ff_read(clientfd, buf, sizeof(buf));
//printf("bytes %zu are available to read...,fd:%d\n", (size_t)event.data, clientfd);
ff_write(clientfd, html, sizeof(html));
} else {
printf("unknown event: %8.8X\n", event.flags);
}
@ -133,12 +129,7 @@ int main(int argc, char * argv[])
exit(1);
}
kevSet.data = MAX_EVENTS;
kevSet.fflags = 0;
kevSet.filter = EVFILT_READ;
kevSet.flags = EV_ADD;
kevSet.ident = sockfd;
kevSet.udata = NULL;
EV_SET(&kevSet, sockfd, EVFILT_READ, EV_ADD, 0, MAX_EVENTS, NULL);
assert((kq = ff_kqueue()) > 0);

View File

@ -65,33 +65,34 @@ int loop(void *arg)
for (i = 0; i < nevents; ++i) {
/* Handle new connect */
if (events[i].data.fd == sockfd) {
int nclientfd = ff_accept(sockfd, NULL, NULL);
if (nclientfd < 0) {
printf("ff_accept failed:%d, %s\n", errno, strerror(errno));
continue;
}
while (1) {
int nclientfd = ff_accept(sockfd, NULL, NULL);
if (nclientfd < 0) {
break;
}
/* Add to event list */
ev.data.fd = nclientfd;
ev.events = EPOLLIN;
assert(ff_epoll_ctl(epfd, EPOLL_CTL_ADD, nclientfd, &ev) == 0);
//printf("A new client connected to the server..., fd:%d\n", nclientfd);
/* Add to event list */
ev.data.fd = nclientfd;
ev.events = EPOLLIN;
if (ff_epoll_ctl(epfd, EPOLL_CTL_ADD, nclientfd, &ev) != 0) {
printf("ff_epoll_ctl failed:%d, %s\n", errno,
strerror(errno));
break;
}
}
} else {
if (events[i].events & EPOLLERR ) {
/* Simply close socket */
ff_epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
ff_close(events[i].data.fd);
//printf("A client has left the server...,fd:%d\n", events[i].data.fd);
} else if (events[i].events & EPOLLIN) {
char buf[256];
size_t readlen = ff_read( events[i].data.fd, buf, sizeof(buf));
//printf("bytes are available to read..., readlen:%d, fd:%d\n", readlen, events[i].data.fd);
if(readlen > 0) {
ff_write( events[i].data.fd, html, sizeof(html));
} else {
ff_epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
ff_close( events[i].data.fd);
//printf("A client has left the server...,fd:%d\n", events[i].data.fd);
}
} else {
printf("unknown event: %8.8X\n", events[i].events);