0

I am using an infinite loop in sockets in which if it receives some data it should receive it or if it wants to send data it sends. Something like given below. I am using select. I have only one socket sd.

fd_set readsd;
int maxsd = readsd +1;
// all those actions of setting maxsd to the maximum fd +1 and FDSETing the FDs.
while(1)
{
     FD_ZERO(&read_sd);
     FD_SET(sd, &read_sd);
     if(FD_ISSET(sd, &readsd))
     {
       //recv call
     }
     else
     {
       //send call
     }
}

As far as I know, select selects one of the socket descriptors on which data arrives first. But here I have only one socket, and I want to recv if there is some data or I want to send otherwise.

In that case, is the code given above fine? Or there is some other option for me which I don't know about?

Natha Kamat
  • 71
  • 1
  • 5
  • 16
  • Since you only have one socket to watch, I don't understand how you decide if you should send or not. After all, select will return when data arrived and since you only have one socket it is the same as waiting snchronously, unless there is more to your code which you didn't show yet. In the above sample, if you add a select it will always receive but never send, the way you wrote it. – Devolus May 15 '13 at 12:24
  • Yes! Thats what I am saying. what I did was I set a recv call, but it blocks until there is any data to send. Since all my other clients have same code, all block until it receives something. That way Nobody sends. So, What I want to do is, check if there is any data received, if not go to send. Is there any way? – Natha Kamat May 15 '13 at 12:36
  • Yes, use the answer from Evans. fcntl is portable, so you should use this. recv will return -1 and errno is EAGAIN or EWOULDBLOCK if there is no data to read. If the returnvalue is 0 the socket has been properly closed, otherwise it returns as much as there is currently available. – Devolus May 15 '13 at 12:38

4 Answers4

3

In that case, is the code given above fine ?

I don't see any call to select. Also, if “maxsd” is designed to be the first argument of select, its value is wrong : it must be the bigest file descriptor +1. Anyway, you could simply call recv with the flag MSG_DONTWAIT, in which case it will return an error if there is no data to read.

Taurre
  • 323
  • 1
  • 7
  • Oh sorry, I missed it. But it is at start of the while loop. – Natha Kamat May 15 '13 at 12:36
  • 1
    Depending on the system, MSG_DONTWAIT may not be available, which you should consider if you want to port the code to another OS. – Devolus May 15 '13 at 12:40
  • @NathaKamat Note that the `MSG_DONTWAIT` is not on all platforms. It's not specified by [POSIX](http://pubs.opengroup.org/onlinepubs/007904975/) and it's not in the [WINSOCK library](http://msdn.microsoft.com/en-us/library/windows/desktop/ms740121%28v=vs.85%29.aspx). – Some programmer dude May 15 '13 at 12:42
2

It kind of depends... First of all, you actually do have a select call in your real code?

Now about the blocking... If select returns with your socket set in the read-set, then you are guaranteed that you can call recv without blocking. But there are no guarantees about the amount of data available. If you use UDP then there will be at least one (hopefully complete) packet, but if you use TCP you may get only one byte. For some protocols with message boundaries, you might not get full messages, and you have to call recv in a loop to get all of the message, and unfortunately this will sooner or later cause the recv call to block.

So in short, using select helps, but it does not help in all cases. The only way to actually guarantee that a recv call won't block is to make the socket non-blocking.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
2

Im not very sure about what you are trying to do, so I can think about two options:

Set a socket to be non-blocking

Since seems like you have only one socket, you can set the socket to non-blocking mode using fcntl and call the recv()

fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
// if fcntl returns no error, sock is now non-blocking

Set the select timer

Using select you can set a timer to force the return after some time happened even if no data was received.

Evans
  • 1,589
  • 1
  • 14
  • 25
0

First, I cannot find any select in your code.

However, you may call fcntl(fd, F_SETFL, flags | O_NONBLOCK) first to make your socket non-blocking. Then check if errno == EWOULDBLOCK when you cannot read anything from recv. You need not to use select in this case.

Naruil
  • 2,300
  • 11
  • 15