views:

819

answers:

4

I've implemented a simple socket wrapper class. It includes a non-blocking function:

void Socket::set_non_blocking(const bool b) {
    mNonBlocking = b; // class member for reference elsewhere
    int opts = fcntl(m_sock, F_GETFL);
    if(opts < 0) return;
    if(b)
        opts |= O_NONBLOCK;
    else
        opts &= ~O_NONBLOCK;

    fcntl(m_sock, F_SETFL, opts);
}

The class also contains a simple receive function:

int Socket::recv(std::string& s) const {
    char buffer[MAXRECV + 1];
    s = "";
    memset(buffer,0,MAXRECV+1);
    int status = ::recv(m_sock, buffer, MAXRECV,0);

    if(status == -1) {
    if(!mNonBlocking)
        std::cout << "Socket, error receiving data\n";

        return 0;
    } else if (status == 0) {
        return 0;
    } else {
        s = buffer;
        return status;
    }
}

In practice, there seems to be a ~15ms delay when Socket::recv() is called. Is this delay avoidable? I've seen some non-blocking examples that use select(), but don't understand how that might help.

+1  A: 

It depends on how you using sockets. If you have multiple sockets and you loop over all of them checking for data that may account for the delay.

With non-blocking recv you are depending on data being there. If your application need to use more than one socket you will have to constantly pool each socket in turns to find out if any of them have data available.

This is bad for system resources because it means your application is constantly running even when there is nothing to do.

You can avoid that with select. You basically set up your sockets, add them to group and select on the group. When anything happens on any of the selected sockets select returns specifying what happened and on which socket.

For some code about how to use select look at beej's guide to network programming

stefanB
Thank you for the advice, but my problem considers literally 1 and only 1 socket where a call to recv() is rendering an unacceptable 15 millisec delay. Since it is only polling 1 socket, am I incorrect in guessing the problem lies elsewhere?
duckworthd
There might be other factors, can't tell based on the small amount of code what is happening. If there's only one socket and I assume you are waiting for data why do you use non-blocking? Does it mean that you are doing something else while waiting for data? Is it possible that the other work keeps you from receiving data as soon as it arrives?
stefanB
@duckworthd Do you start/stop your timers exactly around the recv() or are you including more in the measurement? Also, you really aren't doing error checking; that -1 might be something other than the EAGAIN you assume. Are you getting the data you expect?
Duck
@duckworthd: How are you measuring that recv is taking ~15 ms time to *receive*?
Aditya Sehgal
A: 

select will let you a specify a timeout, and can test if the socket is ready to be read from. So you can use something smaller than 15ms. Incidentally you need to be careful with that code you have, if the data on the wire can contain embedded NULs s won't contain all the read data. You should use something like s.assign(buffer, status);.

Logan Capaldo
A: 

In addition to stefanB, I see that you are zeroing out your buffer every time. Why bother? recv returns how many bytes were actually read. Just zero out the one byte after ( buffer[status+1]=NULL )

MadCoder
While effectively true in almost any implementation, I'm not sure the NULL constant (intended for pointers) is guaranteed to always be the same as the character '\0'.
Tyler McHenry
A: 

How big is your MAXRECV? It might just be that you incur a page fault on the stack growth. Others already mentioned that zeroing out the receive buffer is completely unnecessary. You also take memory allocation and copy hit when you create a std::string out of received character data.

Nikolai N Fetissov