//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
;
}