For sockets,
Giallo provides
,
connection<>
and
connector<>
classes.
acceptor<>
In most socket code, there is a one-time design choice to use blocking, non-blocking (reactive) or asynchronous (proactive) system calls. In Giallo this choice becomes an implementation detail, that can be changed at anytime without affecting application code.
This independence from the underlying system call details is achieved by using a single style of event notification, in this case notification of operation completion.
To obtain a completion notification, the application code registers
completion functions with the
,
connection<>
and
connector<>
. There are several choices for doing this - you
can use a class that models a concept, a class that implements a
virtual base interface, or individual
acceptor<>
boost::function
notifications.
There is a Twisted tutorial on building a finger service, so I thought it would be nice to see how this shaped up when implemented with Giallo.
#include <boost/net/demultiplexer.hpp>
#include <boost/net/demultiplexer/impl/reactor_select_dispatcher.hpp>
int main(int, char**)
{
boost::net::demultiplexer<boost::net::demux::reactor_select_dispatcher> demux;
demux.run();
return 0;
}
This example runs a select reactor, which having no objects to wait on, will return immediatly. The select based reactor is one of Giallo's demultiplexers. You can use as many different demultiplexers as you require. The actual demultiplexers available depend on both the platform that you are using and the type of objects that you are adding. Some of the demultiplexers are portable.
To do something useful, we need to run as a server, which implies accepting incoming connections. We therefore add an acceptor.
#include <boost/net/demultiplexer.hpp>
#include <boost/net/demultiplexer/impl/reactor_select_dispatcher.hpp>
#include <boost/net/socket/acceptor.hpp>
#include <boost/net/socket/endpoint.hpp>
#include "boost/net/socket/ip4/address.hpp"
#include "boost/net/socket/ip4/protocol.hpp"
int main(int, char**)
{
boost::net::demultiplexer<> demux;
boost::net::socket::acceptor<> acceptor(demux);
acceptor.open(
boost::net::socket::make_endpoint(
boost::net::socket::ip4::tcp_protocol(),
oost::net::socket::ip4::address("127.0.0.1", 1079) ) );
demux.run();
return 0;
}
This starts an acceptor listening on port 1079 (finger normally runs on the reserverd port 79, the standard port for finger servers). Connections to 1079 will be accepted, but closed automatically on any input.
at this point the socket has called listen, but not accept.
To respond to an accepted connection we need to add an accept handler.
#include <boost/net/demultiplexer.hpp>
#include <boost/net/demultiplexer/impl/reactor_select_dispatcher.hpp>
#include <boost/net/socket/acceptor.hpp>
#include <boost/net/socket/endpoint.hpp>
#include "boost/net/socket/ip4/address.hpp"
#include "boost/net/socket/ip4/protocol.hpp"
#include <boost/function.hpp>
void on_accepted(boost::net::socket::socket& s,
boost::net::socket::any_address&)
{
s.close();
}
int main(int, char**)
{
boost::net::demultiplexer<> demux;
boost::net::socket::acceptor<> acceptor(demux);
acceptor.attach(boost::function(&on_accepted));
acceptor.open(
boost::net::socket::make_endpoint(
boost::net::socket::ip4::tcp_protocol(),
oost::net::socket::ip4::address("127.0.0.1", 1079) ) );
acceptor.accept();
demux.run();
return 0;
}
Here we respond to the event of beginning a connection by terminating it. To progress further it is going to be easiest to convert the above to something a little more object oriented. We do this by making the acceptor a memeber of a server class. Note that we have added an accept erro handler, and we now attach the class rather than just a single function.
#include <boost/net/demultiplexer.hpp>
#include <boost/net/demultiplexer/impl/reactor_select_dispatcher.hpp>
#include <boost/net/socket/acceptor.hpp>
#include <boost/net/socket/endpoint.hpp>
#include "boost/net/socket/ip4/address.hpp"
#include "boost/net/socket/ip4/protocol.hpp"
#include <boost/function.hpp>
class finger_server
{
public:
finger_server(boost::net::demultiplexer<>& demux)
: m_acceptor(demux)
{
m_acceptor.attach(this);
m_acceptor.open(
boost::net::socket::make_endpoint(
boost::net::socket::ip4::tcp_protocol(),
boost::net::socket::ip4::address("127.0.0.1", 1079) ) );
m_acceptor.accept();
}
void on_accepted(boost::net::socket::socket& s,
boost::net::socket::any_address&)
{
s.close();
m_acceptor.accept();
}
void on_acceptor_error(boost::net::acceptor_error err)
{
}
private:
boost::net::socket::acceptor<> m_acceptor;
};
int main(int, char**)
{
boost::net::demultiplexer<> demux;
finger_server server(demux);
demux.run();
return 0;
}
No we add a connection class that does something with the accepted connection.
#include <boost/net/demultiplexer.hpp>
#include <boost/net/demultiplexer/impl/reactor_select_dispatcher.hpp>
#include <boost/net/socket/acceptor.hpp>
#include <boost/net/socket/connection.hpp>
#include <boost/net/socket/endpoint.hpp>
#include "boost/net/socket/ip4/address.hpp"
#include "boost/net/socket/ip4/protocol.hpp"
#include <boost/function.hpp>
class finger_connection
{
public:
finger_connection(boost::net::socket::socket& s,
boost::net::demultiplexer<>& demux)
: m_connection(s, demux)
{
m_connection.attach(this);
m_connection.on_close_notification(
boost::bind(&finger_connection::on_finalise,this) );
m_connection.recv(m_buffer,100);
}
void on_received(int n, int /*err*/)
{
m_buffer[n]=0;
std::cerr << "finger: recevied request for " << m_buffer << std::endl;
m_connection.close();
}
void on_sent(int n, int /*err*/){}
void on_closed() {}
void on_connection_error(boost::net::connection_error){}
void on_finalise()
{
delete this;
}
private:
char m_buffer[100];
boost::net::socket::connection<> m_connection;
};
class finger_server
{
public:
finger_server(boost::net::demultiplexer<>& demux)
: m_acceptor(demux),
m_demultiplexer(demux)
{
m_acceptor.attach(this);
m_acceptor.open(
boost::net::socket::make_endpoint(
boost::net::socket::ip4::tcp_protocol(),
boost::net::socket::ip4::address("127.0.0.1", 1079) ) );
m_acceptor.accept();
}
void on_accepted(boost::net::socket::socket& s,
boost::net::socket::any_address&)
{
new finger_connection(s,m_demultiplexer);
m_acceptor.accept();
}
void on_acceptor_error(boost::net::acceptor_error err)
{
}
private:
boost::net::socket::acceptor<> m_acceptor;
boost::net::demultiplexer<>& m_demultiplexer;
};
int main(int, char**)
{
boost::net::demultiplexer<> demux;
finger_server server(demux);
demux.run();
return 0;
}
Copyright © 2004 Hugo Duncan |