Search code examples
c++socketspollingreceiver

Polling using Select function in C++ on Windows


I am new in Socket Programming. I am trying to create a Application that uses Sockets for Communication.

I have doubt in the Receive function because sometime it just hangs in recvfrom function. I am using select function for polling. It works when Camera is connected but If I remove Camera it doesn't show the Error Message.

My Code for Polling:

FD_ZERO(&m_readFds);
FD_SET(Sock, &m_readFds);

m_timeInterval.tv_usec = 30;            //30 Microseconds for Polling
m_socketLength = sizeof(m_cameraInfo);

m_lastBlockId = -1;

while (m_acquiringThreadStatus)
{
    FD_CLR(Sock, &m_readFds);
    FD_SET(Sock, &m_readFds);

    m_receivingStatus = select(Sock + 1, &m_readFds, NULL, NULL, &m_timeInterval);
    if (m_receivingStatus < 0)
    {
        std::cout << "No Data to Receive"<<std::endl;
    }
    else
    {
        if ((m_receivedBytes = recvfrom(Sock, m_packetBuffer, RECEIVING_BUFFER_SIZE, 0, (struct sockaddr*)&m_cameraInfo, &m_socketLength)) == SOCKET_ERROR)
        {
            std::cout << "ERROR" << std::endl;
        }
        else
        {
            std::cout<<"Data Received"<<std::endl;
        }
     }
}

An one more question is that when I continously printing the Data Received Statement after sometime It stop. So how can I increase the size of Socket Receiving Buffer.

Thanks in Advance

Edit

SOCKET m_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(m_sock == INVALID_SOCKET)
{
// Error
}
else
{
//In the else part bind the socket 
}

Solution

  • If you read select()'s documentation, you would see that select() returns -1 on error, 0 on timeout, and > 0 on requested event(s). However, that is not how you are treating the return value. You are treating -1 as timeout and >= 0 as data events. So, you end up calling recvfrom() when there is nothing available to read. If the socket is in blocking mode (its default mode), recvfrom() will block the calling thread until data is actually available.

    Try this instead:

    m_lastBlockId = -1;
    
    while (m_acquiringThreadStatus)
    {
        FD_ZERO(&m_readFds);
        FD_SET(Sock, &m_readFds);
    
        m_timeInterval.tv_sec = 0;
        m_timeInterval.tv_usec = 30; //30 Microseconds for Polling
    
        m_receivingStatus = select(Sock + 1, &m_readFds, NULL, NULL, &m_timeInterval);
    
        if (m_receivingStatus == SOCKET_ERROR)
        {
            std::cout << "ERROR" << std::endl;
            break;
        }
    
        if (m_receivingStatus == 0)
        {
            std::cout << "No Data to Receive" << std::endl;
            continue;
        }
    
        m_socketLength = sizeof(m_cameraInfo);
        if ((m_receivedBytes = recvfrom(Sock, m_packetBuffer, RECEIVING_BUFFER_SIZE, 0, (struct sockaddr*)&m_cameraInfo, &m_socketLength)) == SOCKET_ERROR)
        {
            std::cout << "ERROR" << std::endl;
            break;
        }
    
        std::cout << "Data Received" << std::endl;
    }
    

    As for the size of the socket's receive buffer, you can set it via setsockopt() using the SO_RCVBUF option, eg:

    int bufsize = ...;
    setsockopt(Sock, SOL_SOCKET, SO_RCVBUF, (char*)&bufsize, sizeof(bufsize));