我有这样的事情:
#define QUIT_TIME 5
int main(int argc, char **argv) {
//... SOCKETS STUFF ....
fdmax = parentfd;
while (notdone) {
//Set the timers
waitd.tv_sec = 1;
waitd.tv_usec = 0;
FD_ZERO(&tempreadfds);
FD_ZERO(&tempwritefds);
FD_ZERO(&readfds); /* initialize the read fd set */
FD_ZERO(&writefds); /* initialize the write fd set */
FD_SET(parentfd, &readfds); /* add listener socket fd */
FD_SET(0, &readfds); /* add stdin fd (0) */
tempreadfds = readfds; //make a copy
tempwritefds = writefds; //make a copy
if (select(fdmax+1, &tempreadfds, &tempwritefds, (fd_set*) 0, &waitd) < 0) {
error("ERROR in select");
}
for(i = 1; i <= fdmax; i++) {
if(FD_ISSET(i, &readfds)) {
if(i == parentfd) {
//This is a new connection
childfd = accept(parentfd, (struct sockaddr *) &clientaddr, &clientlen);
if (childfd < 0)
error("ERROR on accept");
InitializeDataStructures(childfd);
FD_SET(childfd, &readfds); //add to the master set
if(childfd > fdmax)
fdmax = childfd;
} else {
//Existing connection
if((nBytes = read(i, connections[i].buffer, MAXBUFFER)) <= 0) {
if(nBytes == 0) {
//Connection closed
printf("Socket %d hung up\n", read_write_loop);
} else {
error("\nReceive error\n");
}
FD_CLR(i, &readfds);
} else {
//We have some data from the connection
//... Manipulate the buffer
//Handle the message
}
}
}
if(FD_ISSET(i, &writefds)) {
.....
FD_CLR(i, &writefds);
}
//Timer checking
if(connections[i].active) {
gettimeofday(&TimeNow, NULL);
timeval_diff(&Interval, &TimeNow, &connections[i].TimeConnected);
printf("*_*_*__*_*_*__*_*_*_*_* difference is %ld seconds, %ld microseconds\n",
Interval.tv_sec,
Interval.tv_usec
);
if(Interval.tv_sec >= QUIT_TIME) {
printf("Timer elapsed!!\n");
}
}
}
}
/* clean up */
printf("Terminating server.\n");
close(parentfd);
return 0;
}
void InitializeDataStructures(int i) {
clients[i].active = YES;
clients[i].fd = i;
//Initialize other members of the structure
}
long long timeval_diff(struct timeval *difference, timeval *end_time, struct timeval *start_time) {
struct timeval temp_diff;
if(difference==NULL)
difference=&temp_diff;
difference->tv_sec =end_time->tv_sec -start_time->tv_sec ;
difference->tv_usec=end_time->tv_usec-start_time->tv_usec;
while(difference->tv_usec<0)
{
difference->tv_usec+=1000000;
difference->tv_sec -=1;
}
return 1000000LL*difference->tv_sec + difference->tv_usec;
}
我原本期望在执行期间每隔至少打印一次“Timer elapsed”行(TimeConnected初始化为if条件之一),但由于某种原因,它永远不会打印出来。我以为我的while循环应该继续打印它......任何人都知道我是否在某处乱搞?
编辑: 实际上,我正在使用计时器断开超时后的时间。我刚观察到,如果另一个客户端连接到服务器,它会打印“Timer elapsed”。我确实传递了最后一个参数来进行选择,但我不确定为什么它没有任何效果。
感谢bdk !!如果你有兴趣知道我在这段代码中遇到的“愚蠢”错误,请详细阅读下面的讨论......这是一个明显的错误,我忽略了...因为教程中有一句话:“select modifies你原来的描述符“。
更改列表:
工作代码:
#define QUIT_TIME 5
int main(int argc, char **argv) {
//... SOCKETS STUFF ....
fdmax = parentfd;
FD_ZERO(&readfds); /* initialize the read fd set */
FD_ZERO(&writefds); /* initialize the write fd set */
while (notdone) {
//Set the timers
waitd.tv_sec = 1;
waitd.tv_usec = 0;
FD_ZERO(&tempreadfds);
FD_ZERO(&tempwritefds);
FD_SET(parentfd, &readfds); /* add listener socket fd */
FD_SET(0, &readfds); /* add stdin fd (0) */
tempreadfds = readfds; //make a copy
tempwritefds = writefds; //make a copy
if (select(fdmax+1, &tempreadfds, &tempwritefds, (fd_set*) 0, &waitd) < 0) {
error("ERROR in select");
}
for(i = 1; i <= fdmax; i++) {
if(FD_ISSET(i, &tempreadfds)) {
if(i == parentfd) {
//This is a new connection
childfd = accept(parentfd, (struct sockaddr *) &clientaddr, &clientlen);
if (childfd < 0)
error("ERROR on accept");
InitializeDataStructures(childfd);
FD_SET(childfd, &readfds); //add to the master set
if(childfd > fdmax)
fdmax = childfd;
} else {
//Existing connection
if((nBytes = read(i, connections[i].buffer, MAXBUFFER)) <= 0) {
if(nBytes == 0) {
//Connection closed
printf("Socket %d hung up\n", read_write_loop);
} else {
error("\nReceive error\n");
}
FD_CLR(i, &readfds);
} else {
//We have some data from the connection
//... Manipulate the buffer
//Handle the message
}
}
}
if(FD_ISSET(i, &tempwritefds)) {
.....
FD_CLR(i, &writefds);
}
//Timer checking
if(connections[i].active) {
gettimeofday(&TimeNow, NULL);
timeval_diff(&Interval, &TimeNow, &connections[i].TimeConnected);
printf("*_*_*__*_*_*__*_*_*_*_* difference is %ld seconds, %ld microseconds\n",
Interval.tv_sec,
Interval.tv_usec
);
if(Interval.tv_sec >= QUIT_TIME) {
printf("Timer elapsed!!\n");
}
}
}
}
/* clean up */
printf("Terminating server.\n");
close(parentfd);
return 0;
}
void InitializeDataStructures(int i) {
clients[i].active = YES;
clients[i].fd = i;
//Initialize other members of the structure
}
long long timeval_diff(struct timeval *difference, timeval *end_time, struct timeval *start_time) {
struct timeval temp_diff;
if(difference==NULL)
difference=&temp_diff;
difference->tv_sec =end_time->tv_sec -start_time->tv_sec ;
difference->tv_usec=end_time->tv_usec-start_time->tv_usec;
while(difference->tv_usec<0)
{
difference->tv_usec+=1000000;
difference->tv_sec -=1;
}
return 1000000LL*difference->tv_sec + difference->tv_usec;
}
答案 0 :(得分:1)
看看你的选择循环参数,它们看起来很腥。主要是你在tempreadfd和tempwritefd上调用select,但是当你调用FD_ISSET时,你传递readfd和writefd。在调用select之前,您正在使用FD_SET来设置您感兴趣的所有fd。由于这些变量未被发送到select,因此未触发的fds不会被屏蔽。因此,您将在所有描述符上检测到“活动”。该接受描述符上确实没有任何活动,因此它会阻塞,直到新客户端连接。
至少我的猜测。
答案 1 :(得分:1)
如果我正在读你的代码,你输入你的while循环,然后检查描述符是否在读集中。如果是,则转到if语句的accept()部分。如果不是,则输入else部分,在此处立即阻止读取。如果套接字处于活动状态,则机器人没有可用的数据,您将阻塞该数据,直到数据可用。它不会进入甚至检查定时器的部分,直到它成功读取或输入错误为止。
如果select返回大于零的值,则只应输入检查套接字的代码,然后在尝试读取套接字之前,应检查套接字是否在读取集中。
通常你会构建一个fdset来检查你接受连接的套接字,另一个用于你接受并正在读取数据的套接字。我想你可以按照你提出的方式做到,但我建议你从read()切换到recv()并使用MSG_PEEK标志。
答案 2 :(得分:0)
这是一个特定于代码的问题,但是谁知道......也许这对其他人有所帮助..我最终使用一个线程来解决问题(我知道......不是最好但我是只是疯了试图调试这个...)。感谢所有有耐心帮助我的人......
在上面的代码中,我没有在main()的while循环中测试计时器,而是按如下方式对其进行了修改:
if(ThreadSpawned == 0) {
pthread_create(&thread, NULL, cleanup, (void *) &fdmax);
ThreadSpawned = 1;
}
然后清理功能如下:
void *cleanup(void *arg) {
//Timer checking
int i, *fdmax;
fdmax = (int *) arg;
while(1) {
for(i = 1; i <= *fdmax; i++) {
if(connections[i].active == 1) {
gettimeofday(&TimeNow, NULL);
timeval_diff(&Interval, &TimeNow, &clients[i].TimeConnected);
printf("*_*_*__*_*_*__*_*_*_*_* difference is %ld seconds, %ld microseconds\n",
Interval.tv_sec,
Interval.tv_usec
);
fflush(stdout);
if((int) Interval.tv_sec >= QUIT_TIME) {
printf("Timer elapsed!!\n");
fflush(stdout);
}
}
}
sleep(20);
}
}
欢迎任何清洁解决方案。也许,bdk在他的一个答案中提出的原因是程序在接受时阻塞的原因然后,如果它阻塞那里,我将无法计算超时...所以我最终使用一个线程来做这个任务......