duckworthd
duckworthd

Reputation: 15207

Speeding up non-blocking Unix Sockets (C++)

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.

Upvotes: 0

Views: 3590

Answers (4)

Nikolai Fetissov
Nikolai Fetissov

Reputation: 84169

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.

Upvotes: 0

MadCoder
MadCoder

Reputation: 1342

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 )

Upvotes: 0

Logan Capaldo
Logan Capaldo

Reputation: 40336

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);.

Upvotes: 0

stefanB
stefanB

Reputation: 79810

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

Upvotes: 1

Related Questions