views:

532

answers:

5

I have the following problem to solve. I want to make a number of requests to a number of "remote" servers (actually, a server farm we control). The connection is very simple. Send a line, and then read lines back. Because of the number of requests and the number of servers, I use pthreads, one for each request.

The naive approach, using blocking sockets, does not work; very occasionally, I'll have a thread stuck in 'connect'. I cannot use SIGALRM because I am using pthreads. I tried converting the code to O_NONBLOCK but this vastly complicated the code to read single lines.

What are my options? I'm looking for the simplest solution that allows the following pseudocode:


// Inside a pthread
try {
    req = connect(host, port);
    req.writeln("request command");
    while (line = req.readline()) {
        // Process line
    }
} catch TimeoutError {
    // Bitch and complain
}

My code is in C++ and I'm using Boost. A quick look at Boost ASIO shows me that it probably isn't the correct approach, but I could be wrong. ACE is far, far too heavy-weight to solve this problem.

+4  A: 

I saw the comments and i think you can use boost::asio with boost::asio::deadline_timer

Fragment of a code:

    void restart_timer()
    {
       timer_.cancel();
       timer_.expires_from_now(boost::posix_time::seconds(5));
       timer_.async_wait(boost::bind(&handleTimeout,
       MyClass::shared_from_this(), boost::asio::placeholders::error));
    }

Where handleTimeout is a callback function, timer_ is boost::asio::deadline_timer and MyClass is similar to

    class Y: public enable_shared_from_this<Y>
    {
     public:

     shared_ptr<Y> f()
     {
       return shared_from_this();
     }
    }

You can call restart_timer before connect ou read/write

More information about share_from_this()

coelhudo
I spent some time converting my code over to boost asio and it does indeed appear to work well. Asynchronous socket i/o and deadline timers seemed to do what I need, and my code is now seemingly stable. Took a bit of rewriting behind the scenes but the rest of my code is almost unchanged.
ChrisInEdmonton
+6  A: 

Have you looked at libevent?

http://www.monkey.org/~provos/libevent/

It's totally different paradigm but the performance is so amazing.

memcached is built on top of libevent.

ZZ Coder
libevent is a good idea, I'm going to read up on that now to see if it better fits my needs.
ChrisInEdmonton
A: 

You may also be able close the socket from the other thread. That should cause the connect to fail.

Norman
A: 

This libs help you
C++ Socket library - ComPP 1.3
Simple Sockets

lsalamon
+1  A: 

You mentioned this happens 'very occasionally'. Your 'connect' side should have the fault tolerance and error handling you are looking for but you should also consider the stability of your servers, DNS, network connections, etc.

The underlying protocols are very sturdy and work very well, so if you are experiencing these kind of problems that often then it might be worth checking.

Hayato