async_tcp_echo_server.cpp
阿新 • • 發佈:2018-12-30
//echo伺服器是一個非常簡單的服務,並且在實際中沒有太多用處
//但echo服務相對在網路除錯程式時,可能存在用處,本文是boost.asio
//的示例程式,經過“簡單C++”註解版本,出於學習的目的,註解的
//過程可以加深對asio的理解,同時也加深了對網路程式的理解,相關
//基本概念的理解
#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
//作為一個簡單的session,它只是把一個資訊發出去
//或者接受一個資訊,它實現上只是一個簡單做這些事,
//並沒有維護其它資訊或結構,作為現實應用的一個session可能需要維護的資訊很多
class session
{
public:
session(boost::asio::io_service& io_service)
: socket_(io_service)
{
}
tcp::socket& socket()
{
return socket_;
}
void start()
{
socket_.async_read_some(boost::asio::buffer(data_, max_length) ,
boost::bind(&session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void handle_read(const boost::system::error_code& error,
size_t bytes_transferred)
{
if (!error)
{
boost::asio ::async_write(socket_,
boost::asio::buffer(data_, bytes_transferred),
boost::bind(&session::handle_write, this,
boost::asio::placeholders::error));
}
else
{
delete this;
}
}
void handle_write(const boost::system::error_code& error)
{
if (!error)
{
socket_.async_read_some(boost::asio::buffer(data_, max_length),
boost::bind(&session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
delete this;
}
}
private:
//一個session為需要一個socket?一個網路連線session需要什麼樣的語義?這一點決定
//一個session需要一個socket,它代表該session與連線的進行的通訊道路。
tcp::socket socket_;
enum { max_length = 1024 };
char data_[max_length];
};
//一個伺服器的典型設計,它等待一個客戶連線
//當有一個客戶連線了,它會建立一個session,然後具體的與客戶之間的交流就交給session了
//當把交流任務交給session後,它繼續去等待其它客戶的連線
class server
{
public:
server(boost::asio::io_service& io_service, short port)
: io_service_(io_service),
acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
{
//一啟動這一個物件,它就開始接受客戶的連線
//或者監聽客戶連線
session* new_session = new session(io_service_);
acceptor_.async_accept(new_session->socket(),
boost::bind(&server::handle_accept, this, new_session,
boost::asio::placeholders::error));
}
void handle_accept(session* new_session,
const boost::system::error_code& error)
{
if (!error)
{
new_session->start();
new_session = new session(io_service_);
//接受一個連線需要指出在那個socket上接受
//所以自然需要一個socket引數
acceptor_.async_accept(new_session->socket(),
boost::bind(&server::handle_accept, this, new_session,
boost::asio::placeholders::error));
}
else
{
delete new_session;
}
}
private:
boost::asio::io_service& io_service_;
//等待客戶連線在asio中,類accecptor已經做好了,
//作為asio使用者只需要簡單指定埠號和IO Service就可以了
//後者是asio的結構要求的,前者是應用本身的需要
tcp::acceptor acceptor_;
};
int main(int argc, char* argv[])
{
try
{
if (argc != 2)
{
std::cerr << "Usage: async_tcp_echo_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();
}
//這裡看出來,asio可能沒有丟擲非std::exception異常
//或者asio定製的異常都繼承自std::exception,作為一個異常處理構架
//我們應該使用std::exception
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
//但echo服務相對在網路除錯程式時,可能存在用處,本文是boost.asio
//的示例程式,經過“簡單C++”註解版本,出於學習的目的,註解的
//過程可以加深對asio的理解,同時也加深了對網路程式的理解,相關
//基本概念的理解
#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
//作為一個簡單的session,它只是把一個資訊發出去
//或者接受一個資訊,它實現上只是一個簡單做這些事,
//並沒有維護其它資訊或結構,作為現實應用的一個session可能需要維護的資訊很多
class session
{
public:
session(boost::asio::io_service& io_service)
: socket_(io_service)
{
}
tcp::socket& socket()
{
return socket_;
}
void start()
{
socket_.async_read_some(boost::asio::buffer(data_, max_length)
boost::bind(&session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void handle_read(const boost::system::error_code& error,
size_t bytes_transferred)
{
if (!error)
{
boost::asio
boost::asio::buffer(data_, bytes_transferred),
boost::bind(&session::handle_write, this,
boost::asio::placeholders::error));
}
else
{
delete this;
}
}
void handle_write(const boost::system::error_code& error)
{
if (!error)
{
socket_.async_read_some(boost::asio::buffer(data_, max_length),
boost::bind(&session::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
delete this;
}
}
private:
//一個session為需要一個socket?一個網路連線session需要什麼樣的語義?這一點決定
//一個session需要一個socket,它代表該session與連線的進行的通訊道路。
tcp::socket socket_;
enum { max_length = 1024 };
char data_[max_length];
};
//一個伺服器的典型設計,它等待一個客戶連線
//當有一個客戶連線了,它會建立一個session,然後具體的與客戶之間的交流就交給session了
//當把交流任務交給session後,它繼續去等待其它客戶的連線
class server
{
public:
server(boost::asio::io_service& io_service, short port)
: io_service_(io_service),
acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
{
//一啟動這一個物件,它就開始接受客戶的連線
//或者監聽客戶連線
session* new_session = new session(io_service_);
acceptor_.async_accept(new_session->socket(),
boost::bind(&server::handle_accept, this, new_session,
boost::asio::placeholders::error));
}
void handle_accept(session* new_session,
const boost::system::error_code& error)
{
if (!error)
{
new_session->start();
new_session = new session(io_service_);
//接受一個連線需要指出在那個socket上接受
//所以自然需要一個socket引數
acceptor_.async_accept(new_session->socket(),
boost::bind(&server::handle_accept, this, new_session,
boost::asio::placeholders::error));
}
else
{
delete new_session;
}
}
private:
boost::asio::io_service& io_service_;
//等待客戶連線在asio中,類accecptor已經做好了,
//作為asio使用者只需要簡單指定埠號和IO Service就可以了
//後者是asio的結構要求的,前者是應用本身的需要
tcp::acceptor acceptor_;
};
int main(int argc, char* argv[])
{
try
{
if (argc != 2)
{
std::cerr << "Usage: async_tcp_echo_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();
}
//這裡看出來,asio可能沒有丟擲非std::exception異常
//或者asio定製的異常都繼承自std::exception,作為一個異常處理構架
//我們應該使用std::exception
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}