所以我一直在浏览Beej的网络指南。在之前的一个问题上,我被告知要删除由于阻塞I / OI需要使用select来检查文件描述符之类的大量冻结,然后才接收,所以我只收到什么东西在套接字中等待 - 我试图还有一个用户可以发送和接收的程序 - 所以我想尝试为stdin添加select并尽可能使用fgets-我假设它只是在0处检查fd ...
问题是,我现有的代码没有做任何事情 - 任何想法?
char prev[100];
char nil[100];
memset(nil, 0, sizeof nil);
struct timeval tv;
fd_set read_fds;
tv.tv_sec = 0;
tv.tv_usec = 500000;
FD_ZERO(&read_fds);
FD_SET(sockfd, &read_fds);
FD_SET(STDIN, &read_fds);
int fdmax = new_fd+1;
while (1) {
/* if (send(sockfd, "Howdy", 100, 0) == -1) {
perror("send");
exit(1);
}*/
if (select(fdmax, &read_fds, NULL, NULL, &tv) == -1) {
perror("select");
exit(4);
}
int i = 0;
for (i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &read_fds)) {
if (i == STDIN) {
printf("You have input");
}
if (i == sockfd) {
if ((numbytes = recv(sockfd, buf, 99, 0)) == -1) {
perror("recv");
exit(1);
}
if (strcmp(prev, buf) == 0 || strcmp(nil, buf) == 0 ) {
continue;
}
buf[numbytes] = '\0';
printf("\n%s\n", buf);
memmove(prev, buf, sizeof buf);
}
}
}
答案 0 :(得分:1)
这是因为您可能在select
系统上使用Linux
,而您可能没有看到其手册页的这一部分:
在Linux上,select()修改超时以反映未经过的时间 睡觉;大多数其他实现不会这样做。 (POSIX.1-2001 允许任何行为 ior。)这会导致读取超时的Linux代码移植到其他操作系统以及代码移植时出现问题 移植到重用了Linux的Linux struct loopval用于循环中的多个select(),而不重新初始化它。考虑在select()之后未定义超时 回报。
这意味着传递给timeval
的{{1}}结构会在内部修改,您应该在调用select
函数之间重置它。
作为旁注,您可能还需要查看epoll
,它可以帮助您查看文件描述符更改select
之类的事件,但更自然地使用,远更具可扩展性。
答案 1 :(得分:0)
下面块中的所有代码都应该在while()循环中(即在每次调用select()之前)。 select()在返回之前修改这些数据结构的状态,因此在每次调用select()之前必须将它们重新初始化为默认状态。
struct timeval tv;
fd_set read_fds;
tv.tv_sec = 0;
tv.tv_usec = 500000;
FD_ZERO(&read_fds);
FD_SET(sockfd, &read_fds);
FD_SET(STDIN, &read_fds);
此外,fdmax应设置为您传递给FD_SET的所有fd的最大值,再加上1:
int fdmax = std::max(sockfd, STDIN)+1;
最后,你的for循环是不必要的;你可以改为
if (FD_ISSET(STDIN, &read_fds)) {
printf("You have input");
}
else if (FD_ISSET(sockfd, &read_fds)) {
// code to recv() from sockfd goes here
}