Hi I'm creating a proxyserver that wait for packets from client with an UDP connection and checks if all of them are effectively arrived or same of them have been rejected .
In that case I should send an "ack" to the clients for each lost packet (with send_ack() ) but just after have sent the first ack the "if part" of the select loops sending unlimited acks never going back to the "else part" were the select listen data from client (receive _pkt() function )
fd_set rset, allset;
int maxfd, nready;
struct timeval timeout;
timeout.tv_sec = 4;
timeout.tv_usec = 150000;
maxfd = socketfd;
FD_ZERO(&allset);
FD_SET(socketfd, &allset);
rset = allset;
for( i=0; ;i++){
do {
nready=select( (maxfd +1), &rset, NULL, NULL, &timeout);
} while ((nready<0) & (errno==EINTR));
if( nready<0) {
perror("Error main: select failed: ");
exit(32);
}
if( nready==0){
send_ack(socketfd,head);
}
else{
receive_pkt(socketfd, head);
}
}
Hope it's enough clear, thanks for the advices!
On some systems (Linux in particular), a select call modifies the timeout to show how much time is left. So in your case, if it waits 3 seconds for a packet, timeout will be reduced to 1.15 seconds, and after a total of 4.15 seconds, timeout will be 0, so later calls to select will immediately return with nready == 0.
If you want to wait again after sending an ack, you need to reset the timeout to non-zero.
One has to reset the fd_set rset before every call to select. The select call expects a bit set of field descriptors to monitor and overwrites with a bit set of field descriptors with notifications to read.
for( i=0; ;i++){
do {
rset = allset;
nready=select( (maxfd +1), &rset, NULL, NULL, &timeout);
} while ((nready<0) & (errno==EINTR));
Related
I have developed a C program that receive can traffics from vcan0 interface.
I would like to add timeout on reception, I mean when a timeout expired (10 seconds for example) with no data received during this time, I print "no data received during 10 seconds" and I make a reboot of my pc(the reboot is made if a specific condition is satisfied).
I have tested with select function I get the timeout but when the specific condition is not satisfied I can't receive can traffics anymore.
should I add something for reactivate reception when I have timeout and specific condition is not satisfied? if yes how?
My program is like this:
...
while(1)
{
FD_ZERO(&set); /* clear the set */
FD_SET(filedesc, &set); /* add our file descriptor to the set */
timeout.tv_sec = 0;
timeout.tv_usec = 10000000; // 10 second
rv = select(fd_max + 1, &set, NULL, NULL, &timeout);
if(rv == -1)
perror("select"); /* an error accured */
else if(rv == 0)
{
printf("no data received within 10 second"); /* a timeout occured */
if (specific condition is true)
{
reboot(RB_AUTOBOOT);
}
}
else
int s;
/* loop on all sockets */
for(i=s;i<=fd_max;i++)
{
read( i, buff, len );
/* some other instruction*/
}
}
...
I am trying to write and read data to a serial port file /dev/ttyUSB0, If the operation is unsuccessful for 5 sec I will move ahead. To implement this I chose using the select() system call. However, the exact case in which I am using it seems to not work as expected. Following code:
Simply, I need to check status from 8 devices. So I must write() first a query command. Then wait for a response from the device for timeout seconds.
This procedure should be done for all 8 devices connected on UART.
I am not sure if I must re initialize fdset for using select.
Result: First time select waits for 5 sec timeout. But after that it immediately shows "timeout" without waiting.
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 10;
for(i=0; i <= noOfDevicesDiscovered; i++)
{
if( i < 9 && i > 0)
{
uart_init();
printf("ID: %d\n", i);
address = ((i-1)<<1) | 0x01;
command = 0xA0;
fd_set set;
FD_ZERO(&set);
FD_SET(uart_fd, &set);
write(uart_fd, &address, 1);
write(uart_fd, &command, 1);
rv = select(uart_fd + 1, &set, NULL, NULL, &timeout);
if(rv == -1)
perror("select\n");
else if(rv == 0)
{
printf("timeout\n");
new.level = 0;
new.address = i;
fwrite(&new, sizeof(struct Light_Info), 1, fptr);
continue;
}
else
{
read( uart_fd, &level, 1 );
new.level = level;
}
new.address = i;
fwrite(&new, sizeof(struct Light_Info), 1, fptr);
close(uart_fd);
FD_ZERO(&set);
}
}
How can we solve this.
You need to reinitialise "timeout" after each call of select. From the select man page; "On Linux, select() modifies timeout to reflect the amount of time not slept". So in your case, after the first select call, your timeout values are all 0. Hence subsequent calls to select will timeout immediately.
I wrote a ping program sending syn packet to destination ip address 1.1.1.1 port 0. I used wireshark that i saw packets returned with RST/ACK flags on. But the problem is when i use select() to try to read the socket, select() always returns 0. So I have no idea how to debug the program. I'm sure I reset the fd_set readset everytime. Is there anything i just missed ?
i discovered the reply from 1.1.1.1 returned back in 0.0003 second using wireshark
the timeout i set is 1 second(1000 ms)
Here is the code
void readloop() {
....
while(nsent < 4) {
send_v4();
wait_for_reply(1000); // wait for 1 second;
}
}
int wait_for_reply(long wait_time) {
....
result = recving_time(...);
if(result < 0) // because time out
return 0;
....
}
int recving_time(...) {
......
fd_set readset;
select_again:
set timeout value to structure *to*
FD_ZERO(&readset);
FD_SET(sockfd, &readset);
readable = select(sockfd+1, &readset, NULL, NULL, &to);
#ifdef DEBUG
fprintf(stderr, "readable is %d\n",readable); // **Why readable always be 0 although packets returned.**
#endif
if(readable < 0) {
if(errno == EINTR)
goto select_again;
else {
perror("select() error");
exit(1);
}
if(readable == 0) {
return -1;
}
......
}
I'm not sure there is enough code here to understand what I am trying to saying. I will be very very appreciate if you can help me
Select() returns the number of ready descriptors that are contained in the descriptor sets, or -1 if an error occurred. If the time limit expires, select() returns 0.
It would seem like your timeout (which you're not showing the setup of) is elapsing.
I am currently creating an echo server that disconnects clients after a maxWaitTime of being in idle.
I was hoping the program would block the socket until the client sent data but when I run the program in gdb it goes through the select and blocks on Readline.
I know retval = 0 whenever it goes through the select and that the fd_set sock goes to [256, (31 zeroes)] and after the select, sock goes to [32 zeroes].
The accepting of the connection happens in another function and the connection descriptor is passed to the echo function.
If you are able to help point me in the right direction or let me know how I can disconnect a client after a certain amount of time please let me know.
If you require any further information please let me know.
Thanks in advance!
FD_ZERO(&sock);
FD_SET(sockfd,&sock);
int opt = 3;
setsockopt(sockfd, SOL_SOCKET, SO_RCVLOWAT,&opt,sizeof(opt));
timeout.tv_sec = maxWaitTime;
timeout.tv_usec = 0;
for ( ; ; ) {
FD_SET(sockfd,&sock);
printf("Set is %d\n",FD_ISSET(sockfd,&sock));
int retval;
retval = select(1, &sock, NULL, NULL, &timeout);
if(retval)
{
quitProgram(number);
}
else
{
printf("n is %d\n",retval);
if ( (n = Readline(sockfd, line, MAXLINE)) == 0)
{
return; /* connection closed by other end */
}
Writen(sockfd, line, n);
}
`
As others have commented, you have some logic holes in your code. By your own admission:
I know retval = 0 whenever it goes through the select and that the fd_set sock goes to [256, (31 zeroes)] and after the select, sock goes to [32 zeroes].
That should have been an indication to you that something was going wrong. The socket was not in the fd_set after select() exited, which meant the socket was not readible yet. retval=0 means select() timed out.
You have to reset not only the fd_set every time select() is called, but also the timeval as well. Try this instead:
int opt = 3;
setsockopt(sockfd, SOL_SOCKET, SO_RCVLOWAT,&opt,sizeof(opt));
for ( ; ; )
{
timeout.tv_sec = maxWaitTime;
timeout.tv_usec = 0;
FD_ZERO(&sock);
FD_SET(sockfd,&sock);
int retval = select(sockfd+1, &sock, NULL, NULL, &timeout);
if (retval <= 0)
{
quitProgram(number); /* error or connection timed out */
}
else
{
if ( (n = Readline(sockfd, line, MAXLINE)) <= 0)
{
return; /* error or connection closed by other end */
}
Writen(sockfd, line, n);
}
}
Unix/C question here.
I have multiple sockets that I am trying to poll for periodic data. I don't want select to wait indefinitely so I have a timeout in place and I'm running in a loop. I have found that once a socket is ready to read, it is always ready to read. As in, I cannot have select go to sleep when there is no data to be read from any of the sockets.
for (i = 0; i < n_connections; i++) {
FD_SET( sockfd[i], &master );
if (sockfd[i] > fdmax)
fdmax = sockfd[i];
}
for(;;) {
int nready = 0;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
read_fds = master;
if ( (nready = select(fdmax+1, &read_fds, NULL, NULL, NULL)) == -1 ) {
fprintf( stderr, "Select Error\n" );
return FAILURE;
}
printf( "Number of ready descriptors: %d\n", nready );
for (i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &read_fds)) {
if (( nbytes = recv(i, buf, sizeof(buf), 0)) <= 0 ) {
if (nbytes == 0) {
//connection closed
printf("Socket %d hung up\n", i );
}
else {
fprintf( stderr, "Recv Error %d\n", nbytes);
}
}
else {
printf( "Data Received on %d: %s\n", i, buf );
}
}
} // end file descriptor loop
It seems that after my first read, the 1 second timeout no longer applies and the socket is always "ready to read", even if there are 0 bytes available. How can I get select to sleep until data comes in (for the one second, or by switching the final argument to NULL, indefinitely waiting for data to come in on the socket?)
Output:
Number of Ready Descriptors: 2
Data Received on 4: GreetingsChap
Data Received on 5: HiMatengsChap
Loop...
Number of Ready Descriptors: 2
Socket 4 hung up
Socket 5 hung up
Loop...
Number of Ready Descriptors: 2
Socket 4 hung up
Socket 5 hung up
Loop...
Thank you,
Note: Code updated for clarity
Updated based on #yvesBraumes suggestions - still doesn't work.
If you detect that a connection is closed, remove the socket from the fd set, otherwise select is going to report them (Socket 4 hung up).. select is not edge triggered, if you don't handle the event, it's going to report it again.
Indeed, if recv returns 0 (and not -1, with errno=EWOULDBLOCK), the socket is closed. You should call close() on it as well, and take it out of the select() call. Otherwise it will remain in WAIT1 and release select() each time.
You are using FD_ISSET incorrectly. You need to be passing a socket ID to the "fd" parameter, not an index:
if (FD_ISSET(i, &read_fds))...
needs to be
if (FD_ISSET(sockfd[i], &read_fds))...
Likewise with recv.