Search code examples
c++socketsnonblockingvxworks

Socket can't accept connections when non-blocking?


EDIT: Messed up my pseudo-coding of the accept call, it now reflects what I'm actually doing.

I've got two sockets going. I'm trying to use send/recv between the two. When the listening socket is blocking, it can see the connection and receive it. When it's nonblocking, I put a busy wait in (just to debug this) and it times out, always with the error EWOULDBLOCK. Why would the listening socket not be able to see a connection that it could see when blocking?

The code is mostly separated in functions, but here's some pseudo-code of what I'm doing.

int listener = -2;
int connector = -2;
int acceptedSocket = -2;

getaddrinfo(port 27015, AI_PASSIVE) results loop for listener socket
{
  if (listener socket() == 0)
  {
    if (listener bind() == 0)
      if (listener listen() == 0)
        break;
    listener close(); //if unsuccessful
  }
}
SetBlocking(listener, false);


getaddrinfo("localhost", port 27015) results loop for connector socket
{
  if (connector socket() == 0)
  {
    if (connector connect() == 0)
      break; //if connect successful
    connector close(); //if unsuccessful
  }
}

loop for 1 second
{
  acceptedSocket = listener accept();
  if (acceptedSocket > 0)
    break; //if successful
}

This just outputs a huge list errno of EWOULDBLOCK before ultimately ending the timeout loop. If I output the file descriptor for the accepted socket in each loop interation, it is never assigned a file descriptor.

The code for SetBlocking is as so:

int SetBlocking(int sockfd, bool blocking)
{
  int nonblock = !blocking;

  return ioctl(sockfd,
    FIONBIO,
    reinterpret_cast<int>(&nonblock));
}

If I use a blocking socket, either by calling SetBlocking(listener, true) or removing the SetBlocking() call altogether, the connection works no problem.

Also, note that this connection with the same implementation works in Windows, Linux, and Solaris.


Solution

  • Because of the tight loop you are not letting the OS complete your request. That's the difference between VxWorks and others - you basically preempt your kernel.

    Use select(2) or poll(2) to wait for the connection instead.