1
votes

I want to make a non-blocking send() and recv() with select() and FD_ISSET(). I run into this behavior in which FD_ISSET() will be true for the first socket, and all other sockets are always not ready. I am confused why that is happening and I am wondering if I am using select() properly.

If I sent 100 requests, eventually one of the socket other than the first will be ready to recv(), but I am not getting that behavior.

  for(int i = 0; i < P - 1; i++) {
    sockArr[i] = GetSocket(server, port);
    if (sockArr[i] < 0) {
      // handle error
    }
    fcntl(sockArr[i], F_SETFL, O_NONBLOCK);
    if(sockArr[i] > maxfd) {
      maxfd = sockArr[i];
    }
  }

  fd_set sockSet;
  for(int i = 0; i < P - 1; i++) {
    numBytes = send(sockArr[i], request, requestLen, 0);
    if (numBytes < 0 || numBytes != requestLen) {
      // handle error
    }

    // read from other stackoverflow post you need to rest
    // per select() call
    FD_ZERO(&sockSet);
    for(int i = 0; i < P - 1; i++) {
      FD_SET(sockArr[i], &sockSet);
    }

    if(select(maxfd+1, &sockSet, NULL, NULL, NULL)) {
      for(int j = 0; j < i; j++) {
        if(FD_ISSET(sockArr[j], &sockSet)) { // <------ only true for j = 0
         numBytes = recv(sockArr[j], buffer, MAXBUFLEN - 1, 0);
          if (numBytes < 0) {
            // handle error
          }
        }
      }
    }
  }
1
Why do you have the select inside a for loop? That seems weird. Are you really intending to do one send followed by a select, and then two send followed by a select, and so on? Or did you mean to do all the send calls followed by a single select? - kaylum
Basically I need to sent P amount of requests to a server in parallel and record the request time of the tail latency (90% completion time vs 100% completion time). There are more logic inside the for-loop to keep track of the amount recv()'ed - Sugihara
Well you are not sending P requests in parallel. You are sending one request and then blocking on select. - kaylum
You are not quite understanding the whole picture. O_NONBLOCK only affects the actual IO operations read, write, send, recv, etc. It doesn't affect select. It wouldn't make sense if it did. What is the point of select if it doesn't block? In that case you may as well just immediately call recv and check its return value to see if any data was read. - kaylum
No. Your code is almost there. Just need to take out the select/recv block to be outside the for loop. Then you have a single select call inside either an infinete loop or a loop that exits on an appropriate condition. After the select call you have exactly the recv code that you have now (including its enclosing for loop). - kaylum

1 Answers

1
votes

Your first for loop needs to terminate after the send() calls, and you should then start another to handle the selects and receives.

You need to check for recv() returning zero as well as -1, and close the socket and remove it from the FD set in either case.

You also need to loop while j <= P.