socklibpp::listener< T > Class Template Reference

This class is an efficient way for testing many sockets for readability/writeability. More...

#include <socklistener.h>

List of all members.

Public Member Functions

void add (sock sb_, const T &data_=T())
bool remove (sock sb_)
unsigned size () const throw ()
 Return the number of sockets in the listener.
bool empty () const throw ()
 Return true if the listener is empty.
void readable (std::list< std::pair< sock, T > > &readlist, int usec=0, int sec=0)
 Test all sockets for readability, and return them in a list.
template<class Op>
void for_each_read (Op op, int usec=0, int sec=0)
 Test all sockets for readability, and apply an operation over them.
void writeable (std::list< std::pair< sock, T > > &writelist, int usec=0, int sec=0)
 Test all sockets for writeability, and return them in a list.
template<class Op>
void for_each_write (Op op, int usec=0, int sec=0)
 Test all sockets for writeability, and apply an operation over them.

Classes

struct  Compare


Detailed Description

template<class T = int>
class socklibpp::listener< T >

This class is an efficient way for testing many sockets for readability/writeability.

Just add socklibpp::sock objects - with some optional data - to the listener; then use the readable() or for_each_read() methods to process incomming data, and writeable() or for_each_write() to process outgoing data.

Here's an example that shows how to use a socklibpp::listener to read many connections; the getline() is used to show how the handling works in each iteraction; the USE_FOREACH macro can be undefined to show how to do the same thing without for_each_read().

#include <iostream>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <socklibpp/socklistener.h>

using namespace std;
using namespace socklibpp;

listener<> server;
int global_counter = 1;

#define USE_FOREACH

bool do_stuffs(sock sb, int i)
{
        if (i == 0) {
                addr_in a;
                sock newconn = sb.accept(a);
                if (!sb.error) {        // No error
                        cout << "Received connection " << global_counter <<
                                '(' << newconn.fd << ')' << " from " << a << endl;
                        server.add(newconn, global_counter++);
                }
        } else {
                char buffer[256];
                int r = sb.recv(buffer, sizeof buffer);
                if (r<1) {
                        cout << "Lost connection " << i << '(' << sb.fd << ')' << endl;
                        sb.close();
                        #ifndef USE_FOREACH
                        // If we aren't using for_each_read, we need to remove it explicitly.
                        server.remove(sb);
                        #endif
                        return true;
                }

                cout << "Receiving data from connection " << i << '(' << sb.fd << ')' << ":\n" <<
                        string(buffer, r) << endl;
        }
        return false;
}

void do_stuffs_helper(const pair<sock,int>& data)
{
        do_stuffs(data.first, data.second);
}


int main(int argc, char **argv)
{
        uint16_t port = 3747;
        
        if (argc>1)
                port = strtoul(argv[1], NULL, 10);
        
        addr_in local(addr_in::addr_any, port);
        sock passive(sock::pf_inet, sock::sock_stream);
        if (!passive.bind(local) || !passive.listen())
                return 1;

        server.add(passive);
        
        #ifndef USE_FOREACH
        list< pair<sock, int> > to_read;
        #endif

        cout << "We are going to test the server using "
        #ifdef USE_FOREACH
                "server::for_each_read"
        #else
                "server::readable"
        #endif
               " on port " << port << endl;

        do {
                cout << "Listening to " << server.size() << " sockets.\n"
                        "Press enter to test for readability (Ctrl+C to exit)" << endl;
                cin.ignore();

                #ifndef USE_FOREACH
                to_read.clear();
                server.readable(to_read);
                for_each(to_read.begin(), to_read.end(), do_stuffs_helper);
                #else
                server.for_each_read(do_stuffs);
                #endif

        } while (cin.good());
}
Examples:

echod.cpp, and listener.cpp.


Member Function Documentation

template<class T = int>
void socklibpp::listener< T >::add ( sock  sb_,
const T &  data_ = T() 
) [inline]

Add a socket to be watched

Parameters:
sb_ The socket to be watched
data_ The data to be stored with this socket
Note:
It's not a good idea to add the same socket multiple times.

template<class T = int>
bool socklibpp::listener< T >::remove ( sock  sb_  )  [inline]

Remove a socket from the listener.

Parameters:
sb_ The socket to be removed

template<class T = int>
unsigned socklibpp::listener< T >::size (  )  const throw () [inline]

Return the number of sockets in the listener.

Note:
Be careful, this function may take linear time. Use empty() when you can.
See also:
empty

template<class T = int>
bool socklibpp::listener< T >::empty (  )  const throw () [inline]

Return true if the listener is empty.

Use empty() when you need to check if there's at last one socket in the listener; avoid using size() for this.

See also:
size

template<class T = int>
void socklibpp::listener< T >::readable ( std::list< std::pair< sock, T > > &  readlist,
int  usec = 0,
int  sec = 0 
) [inline]

Test all sockets for readability, and return them in a list.

Parameters:
readlist a list where the pairs of socklibpp::sock and T of each readable socket will be copied.
usec How much time to wait in each internal select() call, in microseconds.
sec How much time to wait in each internal select() call, in seconds.
Note:
The elements are simply appended on readlist; if readlist is not empty before you call this function, no element is removed.

select() may be called multiple times, depending on how many sockets there are in the listener, and how big is FD_SETSIZE; so the sec and usec parameteres may be multiplied by ceil(size() / FD_SETSIZE). e.g. if FD_SETSIZE=64, size()=260, and you call this function with sec=1, you may have to wait for 5 seconds until this function returns.

template<class T = int>
template<class Op>
void socklibpp::listener< T >::for_each_read ( Op  op,
int  usec = 0,
int  sec = 0 
) [inline]

Test all sockets for readability, and apply an operation over them.

Parameters:
op Must be a function or a functor, that returns true if the socket should be removed from the listener.
usec How much time to wait in each internal select() call, in microseconds.
sec How much time to wait in each internal select() call, in seconds.
Note:
You should never try to remove a socket from the listener by hand; do it by returning true from op. It's safe to add sockets to the listener.

select() may be called multiple times, depending on how many sockets there are in the listener, and how big is FD_SETSIZE; so the sec and usec parameteres may be multiplied by ceil(size() / FD_SETSIZE). e.g. if FD_SETSIZE=64, size()=260, and you call this function with sec=1, you may have to wait for 5 seconds until this function returns.

Some systems may give false-positives - i.e. select() will lie about a socket being readable - when using non-blocking mode. Be prepared for a socklibpp::sock::try_again error.

See also:
socklibpp::sock::recv(), socklibpp::sock::block()

template<class T = int>
void socklibpp::listener< T >::writeable ( std::list< std::pair< sock, T > > &  writelist,
int  usec = 0,
int  sec = 0 
) [inline]

Test all sockets for writeability, and return them in a list.

Parameters:
writelist a list where the pairs of socklibpp::sock and T of each writeable socket will be copied.
usec How much time to wait in each internal select() call, in microseconds.
sec How much time to wait in each internal select() call, in seconds.
Note:
The elements are simply appended on writelist; if writelist is not empty before you call this function, no element is removed.

select() may be called multiple times, depending on how many sockets there are in the listener, and how big is FD_SETSIZE; so the sec and usec parameteres may be multiplied by ceil(size() / FD_SETSIZE). e.g. if FD_SETSIZE=64, size()=260, and you call this function with sec=1, you may have to wait for 5 seconds until this function returns.

template<class T = int>
template<class Op>
void socklibpp::listener< T >::for_each_write ( Op  op,
int  usec = 0,
int  sec = 0 
) [inline]

Test all sockets for writeability, and apply an operation over them.

Parameters:
op Must be a function or functor, that receives socklibpp::sock and T as arguments, and returns true if the socket should be removed from the listener.
usec How much time to wait in each internal select() call, in microseconds.
sec How much time to wait in each internal select() call, in seconds.
Note:
You should never try to remove a socket from the listener by hand; do it by returning true from op. It's safe to add sockets to the listener.

select() may be called multiple times, depending on how many sockets there are in the listener, and how big is FD_SETSIZE; so the sec and usec parameteres may be multiplied by ceil(size() / FD_SETSIZE). e.g. if FD_SETSIZE=64, size()=260, and you call this function with sec=1, you may have to wait for 5 seconds until this function returns.

Many sockets are checked for writeability at once; if you send too much data in op, you may fill the buffers, and the other "writeable" sockets there were checked together may block if you try to socklibpp::sock::send() over them. It's a good idea to make them non-blocking.

Some systems may give false-positives - i.e. select() will lie about a socket being writeable - when using non-blocking mode. Be prepared for a socklibpp::sock::try_again error.

See also:
socklibpp::sock::send(), socklibpp::sock::block()


The documentation for this class was generated from the following file:
Generated on Thu Jan 18 19:26:35 2007 for socklib++ by  doxygen 1.5.1