我创建了一个简单的应用程序来使用 select() 和 accept() 接受 IPv4 TCP 连接。
我使用 python 脚本来测试它。它依次打开 100 个连接。IE:
for i in range(100):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print s.connect((IP, PORT))
s.send("Test\r\n")
我观察到我的应用程序在第一个 X 连接后卡在 select() 中 2 秒。来自 strace 的输出:
1344391414.452208 select(30, [3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29], NULL, NULL, NULL) = 1 (in [3])
1344391416.742843 accept(3, 0, NULL) = 30
我的代码如下。知道我做错了什么吗?
#include <assert.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/select.h>
int
fd_create (void)
{
int fd;
int set = true;
struct sockaddr_in addr;
fd = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &set, sizeof(set));
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(1999);
addr.sin_addr.s_addr = INADDR_ANY;
bind(fd, (struct sockaddr *)&addr, sizeof(addr));
listen(fd, 1024);
return (fd);
}
int
fd_echo (int fd)
{
int n;
char buffer[128 + 1];
while ((n = recv(fd, buffer, 128, 0)) > 0);
return (n);
}
int
main (void)
{
int listen_fd;
fd_set working;
fd_set master;
int max_fd;
int i;
int new_fd;
int rc;
int con;
FD_ZERO(&master);
listen_fd = fd_create();
fcntl(listen_fd, F_SETFL, fcntl(listen_fd, F_GETFL) | O_NONBLOCK);
max_fd = listen_fd;
printf("%d\n", listen_fd);
FD_SET(listen_fd, &master);
con = 0;
for (;;) {
memcpy(&working, &master, sizeof(fd_set));
select(max_fd + 1, &working, NULL, NULL, NULL);
for (i = 0; i <= max_fd; i++) {
if (FD_ISSET(i, &working)) {
if (i == listen_fd) {
while ((new_fd = accept(i, NULL, NULL)) >= 0) {
fcntl(new_fd, F_SETFL, fcntl(new_fd, F_GETFL) | O_NONBLOCK);
FD_SET(new_fd, &master);
if (max_fd < new_fd) {
max_fd = new_fd;
}
printf("New connection %d (%d)\n", new_fd, ++con);
}
if ((new_fd == -1) && (errno != EAGAIN && errno != EWOULDBLOCK)) {
return(0);
}
} else {
rc = fd_echo(i);
if ((rc == 0) ||
((rc == -1) && ((errno != EAGAIN && errno != EWOULDBLOCK)))) {
close(i);
FD_CLR(i, &master);
}
}
}
}
}
return (0);
}