使用Boost.Asio写的多线程TCP转发代理服务器

http://www.cppblog.com/archiveman/archive/2010/03/05/108971.html

应用场景是这样的:

客户端和服务器在不同的网段内,它们之间不能直接通过TCP连接,但是有一台机器(暂时称为转发器)有双网卡,两块网卡分别在客户端和服务器端的网段内,这样转发器就能分别和客户端即服务器建立连接,并来回传输数据。

设计思路是这样的:

当客户端连接到转发器后,转发器马上建立一条到服务器之间的连接,与服务器端的连接建立后,就同时异步地从客户端和服务器端接收数据到两个缓冲区中,一旦任何一方有数据接收,就通过另外一条连接将数据发送到另一方,发送完毕后又开始新一轮的数据接收。如果在接收数据的过程中有任何一方出现错误,就将取消另外一条连接的异步调用,这样整个连接就会关闭。

其中用到了Boost库的以下特性:

1.Asio的异步IO调用

2.多线程

3.share_ptr的自动指针管理

遗留的一些问题:

由于采用了多线程,为了保险起见,我将每个回调函数都用strand包裹起来,在各回调函数没有使用共享资源的情况下并不必要,因此在这方面可以优化下
 1  /*
 2   * =====================================================================================
 3   *
 4   * Filename: xproxy_main.cpp
 5   *
 6   * Description:
 7   *
 8   * Version: 1.0
 9   * Created: 2009年11月26日 15时10分29秒
10   * Revision: none
11   * Compiler: gcc
12   *
13   * Author: David Fang (A free programmer), qi_fd@163.com
14   * Company: nocompany
15   *
16   * =====================================================================================
17    */
18 
19  #include  < iostream >
20  #include  < string >
21  #include  < boost / asio.hpp >
22  #include  " xproxy_server.hpp "
23 
24  int  main( int  argc,  char *  argv[])
25  {
26       try
27      {
28           if ( 5   !=  argc)
29          {
30              std::cerr << " Usage: xproxy <local port> <server ip> <server_port> <[thread size>\n " ;
31              std::cerr << " local port: local port used to accept login client\n " ;
32              std::cerr << " server ip: analysing server address, ip string in decimal dot format\n " ;
33              std::cerr << " server port: analysing server port, an unsigned short value\n " ;
34              std::cerr << " thread size: number of threads to running xproxy server\n " ;
35               return   1 ;
36          }
37          xproxy_server srv(atoi(argv[ 1 ]), argv[ 2 ], atoi(argv[ 3 ]), atoi(argv[ 4 ]));
38 
39          srv.run();
40      }
41       catch (std::exception &  e)
42      {
43          std::cerr << " exception:  " << e.what() << " \n " ;
44      }
45 
46       return   0 ;
47  }
 1  /*
 2   * =====================================================================================
 3   *
 4   * Filename: xproxy_server.hpp
 5   *
 6   * Description:
 7   *
 8   * Version: 1.0
 9   * Created: 2009年11月26日 15时12分01秒
10   * Revision: none
11   * Compiler: gcc
12   *
13   * Author: David Fang (A free programmer), qi_fd@163.com
14   * Company: nocompany
15   *
16   * =====================================================================================
17    */
18  #ifndef XPROXY_SERVER_HPP
19  #define  XPROXY_SERVER_HPP
20 
21  #include  < string >
22 
23  #include  < boost / asio.hpp >
24  #include  < boost / noncopyable.hpp >
25  #include  < boost / shared_ptr.hpp >
26  #include  " xproxy_connection.hpp "
27 
28  using  boost::asio::ip::tcp;
29 
30  class  xproxy_server: private  boost::noncopyable
31  {
32  public :
33 
34       // construction of xproxy_server, which takes the destination machine(analysing server)'s
35 
36       // address and port(ipv4) as arguments
37 
38       explicit  xproxy_server(unsigned  short  local_port,  const  std:: string &  ana_address, unsigned  short  ana_port,
39              std::size_t thread_pool_size  =   1 );
40      
41       // Run the server's io_service loop
42 
43       void  run();
44 
45       // Stop the server
46 
47       void  stop();
48  private :
49       // Handle the completion of an asynchronous accept from the login client
50 
51       void  handle_accept( const  boost::system::error_code &  e);
52 
53       // The number of threads that will call io_service::run()
54 
55      std::size_t thread_pool_size_;
56 
57       // The io_service used to perform asynchronous operations.
58 
59      boost::asio::io_service io_service_;
60 
61       // Acceptor used to listen for incoming proxy connectins
62 
63      boost::asio::ip::tcp::acceptor acceptor_;
64 
65       // Local endpoint corresponding to the login client
66 
67      tcp::endpoint local_endpoint_;
68 
69       // The endpoint to analysing server
70 
71      tcp::endpoint analysing_server_endpoint_;
72 
73       // The next connectin to be accepted.
74 
75      xproxy_connection_ptr new_connection_;
76  };
77 
78  #endif
 1  /*
 2   * =====================================================================================
 3   *
 4   * Filename: xproxy_server.cpp
 5   *
 6   * Description:
 7   *
 8   * Version: 1.0
 9   * Created: 2009年11月26日 15时12分07秒
10   * Revision: none
11   * Compiler: gcc
12   *
13   * Author: David Fang (A free programmer), qi_fd@163.com
14   * Company: nocompany
15   *
16   * =====================================================================================
17    */
18 
19  #include  " xproxy_server.hpp "
20  #include  < boost / thread.hpp >
21  #include  < boost / bind.hpp >
22  #include  < boost / shared_ptr.hpp >
23  #include  < vector >
24 
25  xproxy_server::xproxy_server(unsigned  short  local_port,
26           const  std:: string &  ana_address,
27          unsigned  short  ana_port,
28          std::size_t thread_pool_size)
29      :thread_pool_size_(thread_pool_size),
30      acceptor_(io_service_),
31      local_endpoint_(tcp::v4(), local_port),
32      analysing_server_endpoint_(boost::asio::ip::address::from_string(ana_address), ana_port),
33      new_connection_( new  xproxy_connection(io_service_, analysing_server_endpoint_))
34  {
35      acceptor_.open(local_endpoint_.protocol());
36      acceptor_.set_option(tcp::acceptor::reuse_address( true ));
37      acceptor_.bind(local_endpoint_);
38      acceptor_.listen();
39      acceptor_.async_accept(new_connection_ -> login_clt_sock(),
40              boost::bind( & xproxy_server::handle_accept,  this ,
41                  boost::asio::placeholders::error));
42  }
43 
44  void  xproxy_server::run()
45  {
46      std::vector < boost::shared_ptr < boost::thread >   >  threads;
47       for (std::size_t i  =   0 ; i  <  thread_pool_size_;  ++ i)
48      {
49          boost::shared_ptr < boost::thread >  thread( new  boost::thread(
50              boost::bind( & boost::asio::io_service::run,  & io_service_)));
51          threads.push_back(thread);
52      }
53 
54       for (std::size_t i  =   0 ; i  <  threads.size();  ++ i)
55      {
56          threads[i] -> join();
57      }
58  }
59 
60  void  xproxy_server::stop()
61  {
62      io_service_.stop();
63  }
64 
65  void  xproxy_server::handle_accept( const  boost::system::error_code &  e)
66  {
67       if ( ! e)
68      {
69          new_connection_ -> start();
70          new_connection_.reset( new  xproxy_connection(io_service_,
71              analysing_server_endpoint_));
72 
73          acceptor_.async_accept(new_connection_ -> login_clt_sock(),
74              boost::bind( & xproxy_server::handle_accept,  this ,
75                  boost::asio::placeholders::error));
76      }
77  }
 1  /*
 2   * =====================================================================================
 3   *
 4   * Filename: xproxy_connection.hpp
 5   *
 6   * Description:
 7   *
 8   * Version: 1.0
 9   * Created: 2009年11月26日 15时11分04秒
10   * Revision: none
11   * Compiler: gcc
12   *
13   * Author: David Fang (A free programmer), qi_fd@163.com
14   * Company: nocompany
15   *
16   * =====================================================================================
17    */
18  #ifndef XPROXY_CONNECTION_HPP
19  #define  XPROXY_CONNECTION_HPP
20 
21  #include  < boost / asio.hpp >
22  #include  < boost / array.hpp >
23  #include  < boost / noncopyable.hpp >
24  #include  < boost / shared_ptr.hpp >
25  #include  < boost / enable_shared_from_this.hpp >
26 
27  using  boost::asio::ip::tcp;
28 
29  class  xproxy_connection: public  boost::enable_shared_from_this < xproxy_connection > ,
30       private  boost::noncopyable
31  {
32  public :
33       // Contruct a connection with the given io_service, the analysing server address and port
34 
35       explicit  xproxy_connection(boost::asio::io_service &  io_service,
36              tcp::endpoint &  ana_endpoint);
37 
38       ~ xproxy_connection();
39 
40       // Start the asyncronous connection to analysing server
41 
42       void  start();
43 
44      tcp::socket &  login_clt_sock();
45 
46  private :
47       // Handle completion of connection to analysing server
48 
49       void  handle_connect_to_ana_server( const  boost::system::error_code &  e);
50 
51       // Handle completion of login client socket read
52 
53       void  handle_login_clt_sock_read( const  boost::system::error_code &  e,
54              std::size_t bytes_transferred);
55 
56       // Handle completion of analysing server socket write
57 
58       void  handle_ana_srv_sock_write( const  boost::system::error_code &  e);
59 
60       // Handle completion of analysing server socket read
61 
62       void  handle_ana_srv_sock_read( const  boost::system::error_code &  e,
63              std::size_t bytes_transferred);
64 
65       // Handle completion of login client socket write
66 
67       void  handle_login_clt_sock_write( const  boost::system::error_code &  e);
68 
69       // Strand to ensure the connection's handles are not called concurrently
70 
71      boost::asio::io_service::strand strand_;
72 
73       // analysing server endpoint
74 
75      tcp::endpoint ana_endpoint_;
76 
77       // socket to the flex login client
78 
79      tcp::socket login_clt_sock_;
80 
81       // socket to analysing server
82 
83      tcp::socket ana_srv_sock_;
84 
85       // buffer used to recieve data from the login client
86 
87      boost::array < char 1024 >  clt_buffer_;
88      
89       // buffer used to recieve data from the analysing server
90 
91      boost::array < char 1024 >  srv_buffer_;
92  };
93 
94  typedef boost::shared_ptr < xproxy_connection >  xproxy_connection_ptr;
95 
96  #endif
  1  /*
  2   * =====================================================================================
  3   *
  4   * Filename: xproxy_connection.cpp
  5   *
  6   * Description:
  7   *
  8   * Version: 1.0
  9   * Created: 2009年11月26日 15时12分33秒
 10   * Revision: none
 11   * Compiler: gcc
 12   *
 13   * Author: David Fang (A free programmer), qi_fd@163.com
 14   * Company: nocompany
 15   *
 16   * =====================================================================================
 17    */
 18 
 19  #include  " xproxy_connection.hpp "
 20  #include  < vector >
 21  #include  < iostream >
 22  #include  < boost / bind.hpp >
 23 
 24  xproxy_connection::xproxy_connection(boost::asio::io_service &  io_service,
 25      tcp::endpoint &  ana_endpoint)
 26      :strand_(io_service),
 27      ana_endpoint_(ana_endpoint),
 28      login_clt_sock_(io_service),
 29      ana_srv_sock_(io_service)
 30  {
 31      std::cout << " new connection construct\n " ;
 32  }
 33 
 34  xproxy_connection:: ~ xproxy_connection()
 35  {
 36      std::cout << " connection destruct\n " ;
 37  }
 38 
 39  tcp::socket &  xproxy_connection::login_clt_sock()
 40  {
 41       return  login_clt_sock_;
 42  }
 43          
 44  void  xproxy_connection::start()
 45  {
 46      std::cout << " connection start to connect to analysing server\n " ;
 47      ana_srv_sock_.async_connect(ana_endpoint_,
 48          strand_.wrap(boost::bind( & xproxy_connection::handle_connect_to_ana_server,
 49              shared_from_this(), boost::asio::placeholders::error)));
 50  }
 51 
 52  void  xproxy_connection::handle_connect_to_ana_server( const  boost::system::error_code &  e)
 53  {
 54       if ( ! e)
 55      {
 56          std::cout << " connect to analysing server succeed, "
 57               << " now start to receive data from both sides\n " ;
 58 
 59          login_clt_sock_.async_read_some(boost::asio::buffer(clt_buffer_),
 60                  strand_.wrap(
 61                      boost::bind( & xproxy_connection::handle_login_clt_sock_read,
 62                          shared_from_this(), boost::asio::placeholders::error,
 63                          boost::asio::placeholders::bytes_transferred)));
 64 
 65          ana_srv_sock_.async_read_some(boost::asio::buffer(srv_buffer_),
 66                  strand_.wrap(
 67                      boost::bind( & xproxy_connection::handle_ana_srv_sock_read,
 68                          shared_from_this(), boost::asio::placeholders::error,
 69                          boost::asio::placeholders::bytes_transferred)));
 70 
 71      }
 72  }
 73 
 74  void  xproxy_connection::handle_login_clt_sock_read
 75      ( const  boost::system::error_code &  e, std::size_t bytes_transferred)
 76  {
 77       if ( ! e)
 78      {
 79          std::cout << " data read from login client:\n " ;
 80          std::cout.write(clt_buffer_.data(), bytes_transferred);
 81          std::cout << " \nnow send it to analysing server\n " ;
 82          boost::asio::async_write(ana_srv_sock_,
 83                  boost::asio::buffer(clt_buffer_.data(), bytes_transferred),
 84                  strand_.wrap(boost::bind(
 85                           & xproxy_connection::handle_ana_srv_sock_write,
 86                          shared_from_this(), boost::asio::placeholders::error)));
 87      }
 88       else
 89      {
 90          std::cout << " read data from login client error,  "
 91               << " now need to shutdown this connection\n " ;
 92          ana_srv_sock_.cancel();
 93      }
 94  }
 95 
 96  void  xproxy_connection::handle_ana_srv_sock_write( const  boost::system::error_code &  e)
 97  {
 98       if ( ! e)
 99      {
100          std::cout << " data send to analysing server complete,  "
101               << " now start to receive data from login client again\n " ;
102          login_clt_sock_.async_read_some(boost::asio::buffer(clt_buffer_),
103                  strand_.wrap(
104                      boost::bind( & xproxy_connection::handle_login_clt_sock_read,
105                          shared_from_this(), boost::asio::placeholders::error,
106                          boost::asio::placeholders::bytes_transferred)));
107      }
108  }
109 
110  void  xproxy_connection::handle_ana_srv_sock_read(
111           const  boost::system::error_code &  e,
112          std::size_t bytes_transferred)
113  {
114       if ( ! e)
115      {
116          std::cout << " data read from analysing server:\n " ;
117          std::cout.write(srv_buffer_.data(), bytes_transferred);
118          std::cout << " \nnow send it to login client\n " ;
119          boost::asio::async_write(login_clt_sock_,
120                  boost::asio::buffer(srv_buffer_.data(), bytes_transferred),
121                  strand_.wrap(
122                      boost::bind( & xproxy_connection::handle_login_clt_sock_write,
123                          shared_from_this(), boost::asio::placeholders::error)));
124      }
125       else
126      {
127          std::cout << " read data from analysing server error,  "
128               << " now need to shutdown this connection\n " ;
129          login_clt_sock_.cancel();
130      }
131  }
132 
133  void  xproxy_connection::handle_login_clt_sock_write( const  boost::system::error_code &  e)
134  {
135       if ( ! e)
136      {
137          std::cout << " data send to login client complete,  "
138               << " now start to receive data from analysing server again\n " ;
139          ana_srv_sock_.async_read_some(boost::asio::buffer(srv_buffer_),
140                  strand_.wrap(
141                      boost::bind( & xproxy_connection::handle_ana_srv_sock_read,
142                          shared_from_this(), boost::asio::placeholders::error,
143                          boost::asio::placeholders::bytes_transferred)));
144      }
145  }
 1  BOOST_INC =/ home / done / dev_lib / boost_1_38_0 /
 2  BOOST_LIB =/ home / done / dev_lib / boostlibs /
 3  LIB_THREAD = $(BOOST_LIB)libboost_thread - gcc42 - mt - s - 1_38.a
 4  LIB_SYSTEM = $(BOOST_LIB)libboost_system - gcc42 - mt - s - 1_38.a
 5  SYS_INC =/ usr / include /
 6  CPP_INC =/ usr / include / c ++/ 4.2 /
 7  default :xproxy_main.o xproxy_server.o xproxy_connection.o
 8      g ++   - o xproxy xproxy_main.o xproxy_server.o xproxy_connection.o $(LIB_THREAD) $(LIB_SYSTEM)  - lpthread
 9  xproxy_main.o:xproxy_main.cpp xproxy_server.hpp
10      g ++   - - I$(SYS_INC)  - I$(BOOST_INC)  - I$(CPP_INC) xproxy_main.cpp
11  xproxy_server.o:xproxy_server.cpp xproxy_connection.hpp
12      g ++   - - I$(SYS_INC)  - I$(BOOST_INC)  - I$(CPP_INC) xproxy_server.cpp
13  xproxy_connection.o:xproxy_connection.cpp xproxy_connection.hpp
14      g ++   - - I$(SYS_INC)  - I$(BOOST_INC)  - I$(CPP_INC) xproxy_connection.cpp
15  clean:
16      rm  * .o xproxy  2 >/ dev / null

Feedback

# re: 使用Boost.Asio写的多线程TCP转发代理服务器  回复  更多评论  

2010-03-06 10:12 by zuhd
奇怪为什么有这样的需求?为什么不用udp,udp可以穿越NAT

# re: 使用Boost.Asio写的多线程TCP转发代理服务器  回复  更多评论  

2010-03-06 12:24 by David Fang
嘿嘿,这个是安全项目的内幕,为了保护背后的网络。

# re: 使用Boost.Asio写的多线程TCP转发代理服务器  回复  更多评论  

2010-03-07 11:22 by ziding
若A发送一段数据到proxy之后,连接断掉了,proxy是不是否会把之前收到的内容发给后面的服务器b?要是不发,是不是不太合适?

# re: 使用Boost.Asio写的多线程TCP转发代理服务器  回复  更多评论  

2010-03-07 22:09 by David Fang
A(我理解是客户端)发送的数据被xproxy_connection收到后,会调用handle_login_clt_sock_read,它将客户端发来的数据到服务器,这时如果A和代理间的连接掉了不影响数据发到服务器。当之前从客户端收到的数据从代理发到服务器完毕后,handle_ana_srv_sock_write被调用,代理又开始从客户端接收数据,这才发现客户端关闭连接了,异步调用的处理函数handle_login_clt_sock_read会得到一个错误,然后就撤销与服务器连接的socket的所有请求,而本身和客户端连接的socket有没有新的调用,因此整个连接会被释放,应该还算比较合理吧。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Boost.Asio是一个开源的跨平台网络编程库,它可以用于构建高效的异步I/O应用程序。以下是一些关于Boost.Asio的学习资源: 1. Boost.Asio官方文档:Boost.Asio的官方文档提供了详细的介绍和使用指南,包括教程、参考文档和示例代码。文档链接:https://www.boost.org/doc/libs/1_77_0/doc/html/boost_asio.html。 2. Boost.Asio学习指南:这是一篇由Boost.Asio的核心开发者编的学习指南,它介绍了Boost.Asio的基本概念和使用方法,并提供了一些示例代码。指南链接:https://think-async.com/Asio/asio-1.18.1/doc/asio/overview/core.html。 3. Boost.Asio教程:这是一系列由Boost.Asio社区成员编的教程,涵盖了从基础到高级的内容。教程链接:https://github.com/chriskohlhoff/asio/tree/master/asio/doc/tutorial。 4. Boost.Asio实战:这是一本关于使用Boost.Asio构建网络应用的书籍,它详细介绍了Boost.Asio使用方法和实践经验,并提供了大量示例代码。书籍链接:https://www.oreilly.com/library/view/boostasio-c/9781785283079/。 希望这些资源能够帮助您学习和掌握Boost.Asio。 ### 回答2: boost.asio是一个基于C++的网络编程库,为开发人员提供了一套强大而灵活的工具来实现异步网络通信。 该库的教程涵盖了boost.asio的核心概念、基本用法和高级功能。首先,教程介绍了异步编程的概念,以及为什么应该使用异步编程来处理网络通信。然后,它讲解了boost.asio的核心组件,例如IoService、Socket和Buffer,以及如何使用它们进行网络连接和数据传输。 教程还会指导开发人员如何使用boost.asio处理不同类型的网络协议,例如TCP/IP和UDP。开发人员将学习如何创建服务器和客户端,并使用boost.asio的异步操作来处理连接和数据传输。教程还会介绍一些常见的网络编程任务,例如并发服务器和多线程编程,以及如何使用boost.asio来解决这些问题。 除了基本内容外,教程还涵盖了boost.asio的高级功能,例如SSL加密、定时器和信号处理。开发人员将学习如何使用SSL加密来保护网络通信,以及如何使用定时器来处理超时和延迟。此外,教程还会介绍如何使用信号处理来处理中断和异常情况。 总的来说,boost.asio教程为开发人员提供了一个全面的参考资料,帮助他们掌握这个强大的网络编程库。无论是初学者还是有经验的开发人员,都可以从中学习到如何使用boost.asio来构建高效可靠的网络应用程序。 ### 回答3: boost.asio是一个用于异步I/O操作的C++库。它提供了一个面向对象的接口,可以用于处理网络编程、文件I/O和串口通信等操作。boost.asio的设计目标是高效和可扩展性。 boost.asio教程是一个系统介绍boost.asio库的学习材料。该教程通常包含以下内容: 1. 引言:介绍boost.asio库的作用和特性。解释为什么选择boost.asio而不是其他库。 2. 环境配置:指导读者如何安装和配置boost.asio库。包括下载和安装boost库、配置编译器和连接器等步骤。 3. 基本概念:介绍boost.asio库的基本概念和术语。例如,异步操作、回调函数、handler等。 4. 网络编程:教授如何使用boost.asio库进行网络编程。包括创建Socket对象、建立连接、发送和接收数据等操作。 5. 文件I/O:介绍如何使用boost.asio库进行文件读操作。教授如何打开文件、读取和入数据等。 6. 串口通信:介绍如何使用boost.asio库进行串口通信。教授如何打开串口、发送和接收数据等。 7. 高级主题:介绍一些高级主题,例如多线程编程、定时器、SSL加密等。这些主题可以帮助读者更深入地理解和使用boost.asio库。 通过学习boost.asio教程,读者可以学会使用boost.asio库进行异步I/O操作。他们可以编高性能的网络应用程序、文件处理程序和串口通信程序。同时,他们还能够了解到一些高级主题,从而扩展他们的技能和知识。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值