http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-
started-with-boostasio?pg=8

7. Networking basics: connectors and acceptors (TCP)
我们来学习boost的TCP网络编程。之前的篇章已经介绍了网络系统框架。我们只需要学习网络API函数即可

我们首先学习如何同步的连接主机。我们的代码作为客户端运行,使用tcp::socket对象.tcp::socket对象针对不同协议有不同的socket类型.我们需要确认使用正确的对象。当我们连接一个远端主机
,我们需要获得远端的地址。为了达到这个目标,我们使用tcp::resolver。

#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string> boost::mutex global_stream_lock; void WorkerThread( boost::shared_ptr< boost::asio::io_service > io_service )
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Thread Start" << std::endl;
global_stream_lock.unlock(); while( true )
{
try
{
boost::system::error_code ec;
io_service->run( ec );
if( ec )
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Error: " << ec << std::endl;
global_stream_lock.unlock();
}
break;
}
catch( std::exception & ex )
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Exception: " << ex.what() << std::endl;
global_stream_lock.unlock();
}
} global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Thread Finish" << std::endl;
global_stream_lock.unlock();
} int main( int argc, char * argv[] )
{
boost::shared_ptr< boost::asio::io_service > io_service(
new boost::asio::io_service
);
boost::shared_ptr< boost::asio::io_service::work > work(
new boost::asio::io_service::work( *io_service )
);
boost::shared_ptr< boost::asio::io_service::strand > strand(
new boost::asio::io_service::strand( *io_service )
); global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Press [return] to exit." << std::endl;
global_stream_lock.unlock(); boost::thread_group worker_threads;
for( int x = 0; x < 2; ++x )
{
worker_threads.create_thread( boost::bind( &WorkerThread, io_service ) );
} boost::asio::ip::tcp::socket sock( *io_service ); try
{
boost::asio::ip::tcp::resolver resolver( *io_service );
boost::asio::ip::tcp::resolver::query query(
"www.google.com",
boost::lexical_cast< std::string >( 80 )
);
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve( query );
boost::asio::ip::tcp::endpoint endpoint = *iterator; global_stream_lock.lock();
std::cout << "Connecting to: " << endpoint << std::endl;
global_stream_lock.unlock(); sock.connect( endpoint );
}
catch( std::exception & ex )
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Exception: " << ex.what() << std::endl;
global_stream_lock.unlock();
} std::cin.get(); boost::system::error_code ec;
sock.shutdown( boost::asio::ip::tcp::socket::shutdown_both, ec );
sock.close( ec ); io_service->stop(); worker_threads.join_all(); return 0;
}

  

这个例子简单的开启了一个连接。程序将返回它实际尝试连接的端口和IP。如果我们开启一个命令提示窗口运行 "netstat -n",我们会看见这个程序的TCP连接
例子中我们使用query对象去重用这段代码。代码更适用于数字而不是字符串,所以我们使用函数将端口从数字转化为字符串.

有时候我们可能需要异步的去连接一个远程主机.例如GUI程序通过一个按钮开启连接,但是我们不希望GUI界面在连接完成之前就冻结住。boost::asio提供了一个异步连接方式。
使用bind shared_ptr。

#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string> boost::mutex global_stream_lock; void WorkerThread( boost::shared_ptr< boost::asio::io_service > io_service )
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Thread Start" << std::endl;
global_stream_lock.unlock(); while( true )
{
try
{
boost::system::error_code ec;
io_service->run( ec );
if( ec )
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Error: " << ec << std::endl;
global_stream_lock.unlock();
}
break;
}
catch( std::exception & ex )
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Exception: " << ex.what() << std::endl;
global_stream_lock.unlock();
}
} global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Thread Finish" << std::endl;
global_stream_lock.unlock();
} void OnConnect( const boost::system::error_code & ec, boost::shared_ptr< boost::asio::ip::tcp::socket > sock )
{
if( ec )
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Error: " << ec << std::endl;
global_stream_lock.unlock();
}
else
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Connected!" << std::endl;
global_stream_lock.unlock();
}
} int main( int argc, char * argv[] )
{
boost::shared_ptr< boost::asio::io_service > io_service(
new boost::asio::io_service
);
boost::shared_ptr< boost::asio::io_service::work > work(
new boost::asio::io_service::work( *io_service )
);
boost::shared_ptr< boost::asio::io_service::strand > strand(
new boost::asio::io_service::strand( *io_service )
); global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Press [return] to exit." << std::endl;
global_stream_lock.unlock(); boost::thread_group worker_threads;
for( int x = 0; x < 2; ++x )
{
worker_threads.create_thread( boost::bind( &WorkerThread, io_service ) );
} boost::shared_ptr< boost::asio::ip::tcp::socket > sock(
new boost::asio::ip::tcp::socket( *io_service )
); try
{
boost::asio::ip::tcp::resolver resolver( *io_service );
boost::asio::ip::tcp::resolver::query query(
"www.google.com",
boost::lexical_cast< std::string >( 80 )
);
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve( query );
boost::asio::ip::tcp::endpoint endpoint = *iterator; global_stream_lock.lock();
std::cout << "Connecting to: " << endpoint << std::endl;
global_stream_lock.unlock(); sock->async_connect( endpoint, boost::bind( OnConnect, _1, sock ) );
}
catch( std::exception & ex )
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Exception: " << ex.what() << std::endl;
global_stream_lock.unlock();
} std::cin.get(); boost::system::error_code ec;
sock->shutdown( boost::asio::ip::tcp::socket::shutdown_both, ec );
sock->close( ec ); io_service->stop(); worker_threads.join_all(); return 0;
}

  

如果想传递boost::asio对象,我们一般使用shared_ptr智能指针.因为大多数对象是不能拷贝的non-copyable,并且我们确定对象在等待调用期间依然有效。
我们使用bind设置我们的自定义处理程序。
最后一个例子我们异步连接远端地址

#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string> boost::mutex global_stream_lock; void WorkerThread( boost::shared_ptr< boost::asio::io_service > io_service )
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Thread Start" << std::endl;
global_stream_lock.unlock(); while( true )
{
try
{
boost::system::error_code ec;
io_service->run( ec );
if( ec )
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Error: " << ec << std::endl;
global_stream_lock.unlock();
}
break;
}
catch( std::exception & ex )
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Exception: " << ex.what() << std::endl;
global_stream_lock.unlock();
}
} global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Thread Finish" << std::endl;
global_stream_lock.unlock();
} void OnAccept( const boost::system::error_code & ec, boost::shared_ptr< boost::asio::ip::tcp::socket > sock )
{
if( ec )
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Error: " << ec << std::endl;
global_stream_lock.unlock();
}
else
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Accepted!" << std::endl;
global_stream_lock.unlock();
}
} int main( int argc, char * argv[] )
{
boost::shared_ptr< boost::asio::io_service > io_service(
new boost::asio::io_service
);
boost::shared_ptr< boost::asio::io_service::work > work(
new boost::asio::io_service::work( *io_service )
);
boost::shared_ptr< boost::asio::io_service::strand > strand(
new boost::asio::io_service::strand( *io_service )
); global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Press [return] to exit." << std::endl;
global_stream_lock.unlock(); boost::thread_group worker_threads;
for( int x = 0; x < 2; ++x )
{
worker_threads.create_thread( boost::bind( &WorkerThread, io_service ) );
} boost::shared_ptr< boost::asio::ip::tcp::acceptor > acceptor(
new boost::asio::ip::tcp::acceptor( *io_service )
);
boost::shared_ptr< boost::asio::ip::tcp::socket > sock(
new boost::asio::ip::tcp::socket( *io_service )
); try
{
boost::asio::ip::tcp::resolver resolver( *io_service );
boost::asio::ip::tcp::resolver::query query(
"127.0.0.1",
boost::lexical_cast< std::string >( 7777 )
);
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve( query );
acceptor->open( endpoint.protocol() );
acceptor->set_option( boost::asio::ip::tcp::acceptor::reuse_address( false ) );
acceptor->bind( endpoint );
acceptor->listen( boost::asio::socket_base::max_connections );
acceptor->async_accept( *sock, boost::bind( OnAccept, _1, sock ) ); global_stream_lock.lock();
std::cout << "Listening on: " << endpoint << std::endl;
global_stream_lock.unlock();
}
catch( std::exception & ex )
{
global_stream_lock.lock();
std::cout << "[" << boost::this_thread::get_id()
<< "] Exception: " << ex.what() << std::endl;
global_stream_lock.unlock();
} std::cin.get(); boost::system::error_code ec;
acceptor->close( ec ); sock->shutdown( boost::asio::ip::tcp::socket::shutdown_both, ec );
sock->close( ec ); io_service->stop(); worker_threads.join_all(); return 0;
}

  

这个例子与上一个例子很类似。事实上仅仅有一点点改变。之前提到过,asio库是一个很优秀的库。我们学习他的一些组件,就能理解它的其他组件。
在端口7777上运行上面这段代码,我们可以从命令行窗口运行命令"telnet localhost 7777",开启一个到服务器的连接来激发代码中的 OnAccept函数

然而服务器将不能再接收更多的连接,这是因为我们仅仅只呼叫了async_accept一次并且只有一个socket 对象。稍后我们将处理服务器的设计策略。我们仅仅只是需要开启核心API。
例子中,我们使用错误变量来确认没有异常发生。
讨论完基本的连接和接收。下章节将讨论socket的读写

boost asio 学习(七) 网络基础 连接器和接收器(TCP示例)的更多相关文章

  1. boost asio 学习(八) 网络基础 二进制写发送和接收

    http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting- started-with-boostasio?pg=9 8. Net ...

  2. boost asio 学习(一)io_service的基础

    原文  http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting- started-with-boostasio/ 编译环境 b ...

  3. BOOST ASIO 学习专贴

    本文已于20170903更新完毕,所有boost asio 代码均为本人手抄.编译器为vs2013,并且所有代码已经上传,本文下方可下载源码 为了学习boost asio库,我是从boost的官方bo ...

  4. boost asio 学习(九) boost::asio 网络封装

    http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting- started-with-boostasio?pg=10 9. A ...

  5. boost asio 学习(六) 定时器

    http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting- started-with-boostasio?pg=7 6 定时器 ...

  6. boost asio 学习(三)post与dispatch

    http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with-boostasio?pg=4 本章节为io_ ...

  7. boost::asio 学习草稿

    http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with-boostasio/ 可以多个线程拥有io_ ...

  8. boost::asio 学习

    安装 下载-解压 指定安装目录 ./bootstrap.sh --prefix=/usr/local/boost_1_68_0 查看所有必须要编译才能使用的库 ./b2 --show-librarie ...

  9. boost asio 学习(五) 错误处理

    http://www.gamedev.net/blog/950/entry-2249317-a-guide-to-getting-started-with-boostasio?pg=6 5. Erro ...

随机推荐

  1. Java单列模式

    设计模式 单列模式的定义和作用 目的:使得类的一个对象成为该类系统中的唯一实列: 定义:一个类有且仅有一个实例,并且自行实列化向整个系统提供?: 单列模式分为 恶汉式  (在创建对象的时候就直接初始化 ...

  2. jsp 进度条

    <html>  <head>  <title>进度条</title>  <style type="text/css">  ...

  3. 分布式CAP定理,为什么不能同时满足三个特性?

    在弄清楚这个问题之前,我们先了解一下什么是分布式的CAP定理. 根据百度百科的定义,CAP定理又称CAP原则,指的是在一个分布式系统中,Consistency(一致性). Availability(可 ...

  4. 当通过Nuget包管理器获取还原组时,出现 提示 “xxxxx”已拥有为“xxxxx”定义的依赖项

    当通过Nuget包管理器获取还原组件时,出现  提示 “xxxxx”已拥有为“xxxxx”定义的依赖项 时 解决方法: 工具---扩展和更新,把Nuget包管理器卸载后,重启VS,再安装,现打开VS项 ...

  5. 关于javabean

    [javabean定义]定义:JavaBeans是Java语言中可以重复使用的软件组件,实质上是一种特殊的Java类.特点是可序列化,提供无参构造器,提供getter方法和setter方法访问对象的属 ...

  6. Java 虚拟机面试题全面解析(干货)

    Java 虚拟机面试题全面解析(干货) JDK 是什么 JRE 是什么 Java历史版本的特性 Java Version SE 50 Java Version SE 6 Java Version SE ...

  7. gentoo 工具命令

    查看具体某个命令来源于哪个软件包,使用 equery,比如说查找 lsusb 来源于哪个包,可以用 equery belongs lsusb

  8. Ubuntu 14.03 安装mysql

    Ubuntu下安装MySQL及开启远程访问 2017年02月07日 一.Ubuntu上安装MySQL非常简单只需要几条命令就可以完成. sudo apt-get install mysql-serve ...

  9. postgresql批量备份和恢复数据表

    备份数据库:pg_dump -h localhost -U root demo02 > /home/arno/dumps/demo02.bak 恢复数据库:psql -h localhost - ...

  10. SQL 中的语法顺序与执行顺序

    FROM : HOME SQL 是一种声明式语言 SQL 语言是为计算机声明了一个你想从原始数据中获得什么样的结果的一个范例,而不是告诉计算机如何能够得到结果. SQL 语言声明的是结果集的属性,计算 ...