#include <socklistener.h>
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 |
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()); }
echod.cpp, and listener.cpp.
void socklibpp::listener< T >::add | ( | sock | sb_, | |
const T & | data_ = T() | |||
) | [inline] |
Add a socket to be watched
sb_ | The socket to be watched | |
data_ | The data to be stored with this socket |
bool socklibpp::listener< T >::remove | ( | sock | sb_ | ) | [inline] |
Remove a socket from the listener.
sb_ | The socket to be removed |
unsigned socklibpp::listener< T >::size | ( | ) | const throw () [inline] |
bool socklibpp::listener< T >::empty | ( | ) | const throw () [inline] |
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.
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. |
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.
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.
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. |
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.
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.
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. |
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.
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.
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. |
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.