我在下面有这个服务器代码,在这个代码中选择函数会抛出一些错误的文件描述符错误以及错误代码9当某个客户端尝试连接到此时,已经通过代码并且找不到任何错误这个,任何帮助将不胜感激,但这种行为并不是一成不变的!
main()
{
int server_fd, client_fd;
socklen_t server_len, client_len;
struct sockaddr_in server_address, client_address;
fd_set readfds, testfds;
char errorstr[128];
char req_buf[REQ_BUF_LEN];
int result;
struct itimerspec time_period = {{10,0},{10,0}}; /* periodic timer */
struct timeval sel_timeout = {0, 100000};
int lines = 0;
FD_ZERO(&readfds);
FD_ZERO(&testfds);
/* Create and name a socket for the server */
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if( server_fd < 0 ) {
printf("socket creation failed \n");
exit(0);
}
int on = 1;
/* Enable address reuse */
int ret = setsockopt( server_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(BL_MANAGER_PORT);
server_len = sizeof(server_address);
result = bind(server_fd, (struct sockaddr *)&server_address, server_len);
if( result < 0 ) {
printf("Bind faield \n");
exit(0);
}
/* Create a connection queue and wait for clients */
result = listen(server_fd, MAX_CLIENTS);
if( result < 0 ) {
printf("Listen failed\n");
exit(0);
}
FD_SET(server_fd, &readfds);
/* create timer to fire every one second */
int timer_fd = timerfd_create(CLOCK_MONOTONIC , 0);
if( timer_fd < 0 ) {
printf("Timer fd failed\n");
exit(0);
}
result = timerfd_settime(timer_fd, 0, &time_period, NULL);
if( result < 0 ) {
printf("timer fd set time failed\n");
exit(0);
}
FD_SET(timer_fd, &readfds);
while(1) {
int fd;
int nread;
int result;
char *ptr;
int len_read = 0;
uint64_t expired = 0;
testfds = readfds;
result = select(FD_SETSIZE, &testfds, NULL, NULL, &sel_timeout);
if( result < 0 ) {
perror ("The following error occurred");
printf("select failed");
exit(0);
}
/* There is activity. Find the descriptor */
for(fd = 0; fd < FD_SETSIZE; fd++) {
if(FD_ISSET(fd, &testfds)) {
if (fd == timer_fd) {
read(timer_fd, &expired, sizeof(uint64_t));
printf("rate = %d\n", (lines/(10 * (uint32_t)expired)));
lines = 0;
} else if( fd == server_fd ) { /* is this server fd? */
client_fd = accept(server_fd,
(struct sockaddr *)&client_address,
&client_len);
FD_SET(client_fd, &readfds);
} else { /* is this read fd? */
ioctl(fd, FIONREAD, &nread);
//assert(nread < REQ_BUF_LEN);
if( nread == 0 ) {
FD_CLR(fd, &readfds);
close(fd);
} else {
nread = read(fd, req_buf, REQ_BUF_LEN-1);
//req_buf[nread] = '\0';
//printf("%s\n", req_buf);
ptr = req_buf;
while ((*ptr != EOF) && ++len_read < nread) {
if (*ptr == '\n') {
++lines;
}
ptr++;
}
//printf("num of lines: %d\n", lines);
}
}
} /* FD_ISSET(fd, &testfds)? */
}
} /* while(1) */
}
答案 0 :(得分:0)
您滥用select()
,因此您会从中获得随机结果。尝试更像这样的东西:
main()
{
int server_fd, client_fd, max_fd = 0;
socklen_t server_len, client_len;
struct sockaddr_in server_address, client_address;
fd_set readfds, testfds;
char errorstr[128];
char req_buf[REQ_BUF_LEN];
int result;
struct itimerspec time_period = {{10,0},{10,0}}; /* periodic timer */
struct timeval sel_timeout;
int lines = 0;
FD_ZERO(&readfds);
/* Create and name a socket for the server */
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if( server_fd < 0 ) {
printf("socket creation failed \n");
exit(0);
}
int on = 1;
/* Enable address reuse */
int ret = setsockopt( server_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(BL_MANAGER_PORT);
server_len = sizeof(server_address);
result = bind(server_fd, (struct sockaddr *)&server_address, server_len);
if( result < 0 ) {
printf("Bind faield \n");
exit(0);
}
/* Create a connection queue and wait for clients */
result = listen(server_fd, MAX_CLIENTS);
if( result < 0 ) {
printf("Listen failed\n");
exit(0);
}
FD_SET(server_fd, &readfds);
max_fd = server_fd;
/* create timer to fire every one second */
int timer_fd = timerfd_create(CLOCK_MONOTONIC , 0);
if( timer_fd < 0 ) {
printf("Timer fd failed\n");
exit(0);
}
result = timerfd_settime(timer_fd, 0, &time_period, NULL);
if( result < 0 ) {
printf("timer fd set time failed\n");
exit(0);
}
FD_SET(timer_fd, &readfds);
if (max_fd < timer_fd)
max_fd = timer_fd;
while(1) {
int fd;
int nread;
int result;
char *ptr;
uint64_t expired = 0;
FD_ZERO(&testfds);
FD_COPY(&readfds, &testfds);
sel_timeout.tv_sec = 0;
sel_timeout.tv_usec = 100000;
result = select(max_fd+1, &testfds, NULL, NULL, &sel_timeout);
if( result < 0 ) {
perror ("The following error occurred");
printf("select failed");
exit(0);
}
/* There is activity. Find the descriptor */
for(fd = 0; fd <= max_fd; fd++) {
if(FD_ISSET(fd, &testfds)) {
if (fd == timer_fd) {
read(timer_fd, &expired, sizeof(uint64_t));
printf("rate = %d\n", (lines/(10 * (uint32_t)expired)));
lines = 0;
} else if( fd == server_fd ) { /* is this server fd? */
client_fd = accept(server_fd,
(struct sockaddr *)&client_address,
&client_len);
if (client_id < 0) {
perror ("The following error occurred");
printf("accept failed");
} else {
FD_SET(client_fd, &readfds);
if (max_fd < client_fd)
max_fd = client_fd;
}
} else { /* is this read fd? */
nread = read(fd, req_buf, REQ_BUF_LEN);
if( nread <= 0 ) {
FD_CLR(fd, &readfds);
close(fd);
if (fd == max_fd) {
max_fd = 0;
for (int fd2 = fd-1; fd2 >= 0; fd2--) {
if(FD_ISSET(fd2, &readfds)) {
max_fd = fd2;
break;
}
}
}
} else {
//printf("%.*s\n", nread, req_buf);
ptr = req_buf;
while ((nread > 0) && (*ptr != EOF)) {
if (*ptr == '\n') {
++lines;
}
ptr++;
nread--;
}
//printf("num of lines: %d\n", lines);
}
}
} /* FD_ISSET(fd, &testfds)? */
}
} /* while(1) */
}
话虽如此,最好在可用时使用poll()
或epoll()
,然后您根本不需要处理fd_set
。