summaryrefslogtreecommitdiff
path: root/doc/html/boost_asio/example/porthopper/server.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'doc/html/boost_asio/example/porthopper/server.cpp')
-rwxr-xr-xdoc/html/boost_asio/example/porthopper/server.cpp187
1 files changed, 187 insertions, 0 deletions
diff --git a/doc/html/boost_asio/example/porthopper/server.cpp b/doc/html/boost_asio/example/porthopper/server.cpp
new file mode 100755
index 0000000000..0703bddff9
--- /dev/null
+++ b/doc/html/boost_asio/example/porthopper/server.cpp
@@ -0,0 +1,187 @@
+//
+// server.cpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include <boost/asio.hpp>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <cmath>
+#include <cstdlib>
+#include <exception>
+#include <iostream>
+#include <set>
+#include "protocol.hpp"
+
+using boost::asio::ip::tcp;
+using boost::asio::ip::udp;
+
+typedef boost::shared_ptr<tcp::socket> tcp_socket_ptr;
+typedef boost::shared_ptr<boost::asio::deadline_timer> timer_ptr;
+typedef boost::shared_ptr<control_request> control_request_ptr;
+
+class server
+{
+public:
+ // Construct the server to wait for incoming control connections.
+ server(boost::asio::io_service& io_service, unsigned short port)
+ : acceptor_(io_service, tcp::endpoint(tcp::v4(), port)),
+ timer_(io_service),
+ udp_socket_(io_service, udp::endpoint(udp::v4(), 0)),
+ next_frame_number_(1)
+ {
+ // Start waiting for a new control connection.
+ tcp_socket_ptr new_socket(new tcp::socket(acceptor_.get_io_service()));
+ acceptor_.async_accept(*new_socket,
+ boost::bind(&server::handle_accept, this,
+ boost::asio::placeholders::error, new_socket));
+
+ // Start the timer used to generate outgoing frames.
+ timer_.expires_from_now(boost::posix_time::milliseconds(100));
+ timer_.async_wait(boost::bind(&server::handle_timer, this));
+ }
+
+ // Handle a new control connection.
+ void handle_accept(const boost::system::error_code& ec, tcp_socket_ptr socket)
+ {
+ if (!ec)
+ {
+ // Start receiving control requests on the connection.
+ control_request_ptr request(new control_request);
+ boost::asio::async_read(*socket, request->to_buffers(),
+ boost::bind(&server::handle_control_request, this,
+ boost::asio::placeholders::error, socket, request));
+ }
+
+ // Start waiting for a new control connection.
+ tcp_socket_ptr new_socket(new tcp::socket(acceptor_.get_io_service()));
+ acceptor_.async_accept(*new_socket,
+ boost::bind(&server::handle_accept, this,
+ boost::asio::placeholders::error, new_socket));
+ }
+
+ // Handle a new control request.
+ void handle_control_request(const boost::system::error_code& ec,
+ tcp_socket_ptr socket, control_request_ptr request)
+ {
+ if (!ec)
+ {
+ // Delay handling of the control request to simulate network latency.
+ timer_ptr delay_timer(
+ new boost::asio::deadline_timer(acceptor_.get_io_service()));
+ delay_timer->expires_from_now(boost::posix_time::seconds(2));
+ delay_timer->async_wait(
+ boost::bind(&server::handle_control_request_timer, this,
+ socket, request, delay_timer));
+ }
+ }
+
+ void handle_control_request_timer(tcp_socket_ptr socket,
+ control_request_ptr request, timer_ptr /*delay_timer*/)
+ {
+ // Determine what address this client is connected from, since
+ // subscriptions must be stored on the server as a complete endpoint, not
+ // just a port. We use the non-throwing overload of remote_endpoint() since
+ // it may fail if the socket is no longer connected.
+ boost::system::error_code ec;
+ tcp::endpoint remote_endpoint = socket->remote_endpoint(ec);
+ if (!ec)
+ {
+ // Remove old port subscription, if any.
+ if (unsigned short old_port = request->old_port())
+ {
+ udp::endpoint old_endpoint(remote_endpoint.address(), old_port);
+ subscribers_.erase(old_endpoint);
+ std::cout << "Removing subscription " << old_endpoint << std::endl;
+ }
+
+ // Add new port subscription, if any.
+ if (unsigned short new_port = request->new_port())
+ {
+ udp::endpoint new_endpoint(remote_endpoint.address(), new_port);
+ subscribers_.insert(new_endpoint);
+ std::cout << "Adding subscription " << new_endpoint << std::endl;
+ }
+ }
+
+ // Wait for next control request on this connection.
+ boost::asio::async_read(*socket, request->to_buffers(),
+ boost::bind(&server::handle_control_request, this,
+ boost::asio::placeholders::error, socket, request));
+ }
+
+ // Every time the timer fires we will generate a new frame and send it to all
+ // subscribers.
+ void handle_timer()
+ {
+ // Generate payload.
+ double x = next_frame_number_ * 0.2;
+ double y = std::sin(x);
+ int char_index = static_cast<int>((y + 1.0) * (frame::payload_size / 2));
+ std::string payload;
+ for (int i = 0; i < frame::payload_size; ++i)
+ payload += (i == char_index ? '*' : '.');
+
+ // Create the frame to be sent to all subscribers.
+ frame f(next_frame_number_++, payload);
+
+ // Send frame to all subscribers. We can use synchronous calls here since
+ // UDP send operations typically do not block.
+ std::set<udp::endpoint>::iterator j;
+ for (j = subscribers_.begin(); j != subscribers_.end(); ++j)
+ {
+ boost::system::error_code ec;
+ udp_socket_.send_to(f.to_buffers(), *j, 0, ec);
+ }
+
+ // Wait for next timeout.
+ timer_.expires_from_now(boost::posix_time::milliseconds(100));
+ timer_.async_wait(boost::bind(&server::handle_timer, this));
+ }
+
+private:
+ // The acceptor used to accept incoming control connections.
+ tcp::acceptor acceptor_;
+
+ // The timer used for generating data.
+ boost::asio::deadline_timer timer_;
+
+ // The socket used to send data to subscribers.
+ udp::socket udp_socket_;
+
+ // The next frame number.
+ unsigned long next_frame_number_;
+
+ // The set of endpoints that are subscribed.
+ std::set<udp::endpoint> subscribers_;
+};
+
+int main(int argc, char* argv[])
+{
+ try
+ {
+ if (argc != 2)
+ {
+ std::cerr << "Usage: server <port>\n";
+ return 1;
+ }
+
+ boost::asio::io_service io_service;
+
+ using namespace std; // For atoi.
+ server s(io_service, atoi(argv[1]));
+
+ io_service.run();
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << "Exception: " << e.what() << std::endl;
+ }
+
+ return 0;
+}