boost.asio

来源:互联网 发布:水手怕水 知乎 编辑:程序博客网 时间:2024/05/16 15:48
Asio学习1: TCP客户端:对准时间 解析
   #include <iostream>
#include <boost/array.hpp>
#include <boost/asio.hpp>
//本程序的目的是访问一个时间同步服务器,我们需要用户指定一个服务器(如time-a.nist.gov),用IP亦可. 

using boost::asio::ip::tcp;

int main(int argc, char* argv[])
{
  try
  {
    if (argc != 2)
    {
      std::cerr << "Usage: client <host>" << std::endl;
      return 1;
    }

    //用asio进行网络连接至少需要一个boost::asio::io_service对象 
     boost::asio::io_service io_service;

     /*
      我们需要把在命令行参数中指定的服务器转换为TCP上的节点.
      完成这项工作需要boost::asio::ip::tcp::resolver对象 
     
*/


    tcp::resolver resolver(io_service);
    /*
    一个resolver对象查询一个参数,并将其转换为TCP上节点的列表.
    这里我们把argv[1]中的sever的名字和要查询字串daytime关联. 
    
*/


    tcp::resolver::query query(argv[1], "daytime");
    /*
    节点列表可以用 boost::asio::ip::tcp::resolver::iterator 来进行迭代.
    iterator默认的构造函数生成一个end iterator. 
    
*/


    tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
    tcp::resolver::iterator end;
    /*
    现在我们建立一个连接的sockert,由于获得节点既有IPv4也有IPv6的.
    所以,我们需要依次尝试他们直到找到一个可以正常工作的.这步使得我们的程序独立于IP版本 
    
*/


    tcp::socket socket(io_service);
    boost::asio::error error = boost::asio::error::host_not_found;
    while (error && endpoint_iterator != end)
    {
      socket.close();
      socket.connect(*endpoint_iterator++, boost::asio::assign_error(error));
    }

    if (error)
      throw error;
     /*
     连接完成,我们需要做的是读取daytime服务器的响应. 
     我们用boost::array来保存得到的数据,boost::asio::buffer()会自动根据array的大小暂停工作,
     来防止缓冲溢出.除了使用boost::array,也可以使用char [] 或std::vector. 
     
*/


    for (;;)
    {
      boost::array<char, 128> buf;
      boost::asio::error error;

      size_t len = socket.read_some(
          boost::asio::buffer(buf), boost::asio::assign_error(error));
     /*
       当服务器关闭连接时,boost::asio::ip::tcp::socket::read_some()会用boost::asio::error::eof标志完成, 
       这时我们应该退出读取循环了. 
      
*/


      if (error == boost::asio::error::eof)
        break// Connection closed cleanly by peer.
      else if (error)
        throw error; // Some other error.

      std::cout.write(buf.data(), len);
    }


  }

  catch (std::exception& e)
  {
    std::cerr << e.what() << std::endl;
  }

}

注:下面这一段如果看起来有点麻烦的话可以写简单些,就让其只解析ipv4类型地址,端口号为13,只连接一次

    tcp::resolver::query query(argv[1], "daytime");
    tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
    tcp::resolver::iterator end;

    tcp::socket socket(io_service);
    boost::asio::error error = boost::asio::error::host_not_found;
    while (error && endpoint_iterator != end)
    {
      socket.close();
      socket.connect(*endpoint_iterator, boost::asio::assign_error(error));
    }

    if (error)
      throw error;

简单点的:

    //域名解析,只将域名解析为ipv4地址
    tcp::resolver::query query(tcp::v4(),argv[1], "13");
    tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
    //只连接一次
    tcp::socket socket(io_service);
    boost::asio::error error = boost::asio::error::host_not_found;    
    socket.connect(*endpoint_iterator, boost::asio::assign_error(error));   
    if (error)
      throw error;  

下面是用winsock api(阻塞模式) 所写的代码,可以比较一下

#include <iostream>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")

int main(int argc, char* argv[])
{
    if(argc<2)
    {
        std::cout << "usage: tcp_datatime hostname(time-a.nist.gov) " << std::endl;
        return -1;
    }
    WSADATA wsaData;
    if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0)
    {
        std::cout << " lib error ";
        return -1;
    }

    SOCKET cliSocket;
    cliSocket = socket(AF_INET, SOCK_STREAM,0);


    SOCKADDR_IN addr;
    memset(&addr,0, sizeof(addr));
    addr.sin_port = htons(13);
    addr.sin_family = AF_INET;
    if( (addr.sin_addr.s_addr = inet_addr(argv[1])) == INADDR_NONE)
    {
        hostent * hostent;
        hostent  = gethostbyname(argv[1]);
        if(hostent == NULL)
        {
            std::cout << " can't resolve host! " ;
            return -1;
        }
        memcpy(&addr.sin_addr,hostent->h_addr_list[0],4);
    }
    
    if( connect(cliSocket, (sockaddr*)&addr,sizeof(sockaddr)) != 0)
    {
        std::cout << "connect error ";
        return -1;
    }
    
    char buf[100];
    int recvSize = recv(cliSocket, buf, sizeof(buf), 0);
    buf[recvSize] = 0;
    std::cout << buf << std::endl;
    return 0;
}
Asio学习2: TCP服务器端:对准时间 解析
#include <ctime>
#include <iostream>
#include <string>
#include <boost/asio.hpp>

using boost::asio::ip::tcp;

std::string make_daytime_string()
{
    using namespace std;
    time_t now = time(0);
    return ctime(&now);
}

int _tmain(int argc, _TCHAR* argv[])
{
    try
    {
        boost::asio::io_service io_service;
        //新建一个asio::ip::tcp::acceptor对象来监听新的连接.我们监听TCP端口13,IP版本为V4

        /*
        *以下构造函数相当于以下步骤
        * basic_socket_acceptor<tcp> acceptor(io_service);
        * acceptor.open(tcp::v4());
        * acceptor.bind(tcp::endpoint(13));
        * acceptor.listen(0);//default 
        
*/

        tcp::acceptor acceptor(io_service,tcp::endpoint(tcp::v4(), 13));
        //basic_endpoint(const Protocol& protocol, unsigned short port_num)
        
//此构造函数一般作为服务器接受连接使用,ip地址即为INADDR_ANY

        
//这是一个iterative server,也就是说同一时间只能处理一个连接.
        
//建立一个socket来表示一个和客户端的连接, 然后等待客户端的连接
        for(;;)
        {
            tcp::socket socket(io_service);
            acceptor.accept(socket);
            std::string message = make_daytime_string();
            boost::asio::write(socket,boost::asio::buffer(message),
                boost::asio::transfer_all(),boost::asio::ignore_error());
        }        

    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;        
    }
    return 0;
}

下面是winsock api 所写:

#include <iostream>
#include <string>
#include <ctime>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")

std::string make_daytime_string()
{
    using namespace std;
    time_t now = time(0);
    return ctime(&now);
}


int main(int argc, char* argv[])
{
    WSADATA wsaData;
    if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0)
    {
        std::cout << " lib error  ";
        return -1;
    }

    SOCKET listenSocket;
    if((listenSocket = socket(AF_INET, SOCK_STREAM,0)) == INVALID_SOCKET)
    {
        std::cout << "socket error ";
        return -1;
    }

    SOCKADDR_IN addr;
    memset(&addr,0, sizeof(addr));    
    addr.sin_family = AF_INET;
    addr.sin_port = htons(13);
    addr.sin_addr.s_addr = htonl(ADDR_ANY);
    if(bind(listenSocket,(sockaddr*)&addr,sizeof(addr)) == SOCKET_ERROR)
    {
        std::cout << "bind error ";
    }
    listen(listenSocket,5);
    for(;;)
    {
        SOCKET socket = accept(listenSocket,0,0);
        std::string timeStr = make_daytime_string();
        send(socket,timeStr.c_str(),timeStr.length(),0);
        closesocket(socket);
    }  
      
}
Asio学习3: 异步Tcp服务器端(Datetime)
#include <ctime>
#include 
<iostream>
#include 
<boost/bind.hpp>
#include 
<boost/shared_ptr.hpp>
#include 
<boost/enable_shared_from_this.hpp>
#include 
<boost/asio.hpp>

using boost::asio::ip::tcp;

std::
string make_daytime_string()
{
    
using namespace std;
    time_t now 
= time(0);
    
return ctime(&now);
}

/*
 从enable_shared_from_this 派生的类,
 成员函数shared_from_this返回shared_ptr

 tcp_connection类管理新连接的socket,连接后发送时间字符串至客户端
*/
class tcp_connection
    : 
public boost::enable_shared_from_this<tcp_connection>
{
public:
    typedef boost::shared_ptr
<tcp_connection> pointer;

    
static pointer create(boost::asio::io_service& io_service)
    {
        
return pointer(new tcp_connection(io_service));
    }

    tcp::socket
& socket()
    {
        
return socket_;
    }

    
void start()
    {
        message_ 
= make_daytime_string();
        
/*
         *向新连接socket异步写数据
         *注意bind的用法(可以查看有关资料),这里是绑定类成员函数
         *第一个参数是类成员函数地址,第二个是该类变量指针或智能指针或类变量
         *后面是传递给类成员函数的各个参数,有几个就传递几个
         
*/
        boost::asio::async_write(socket_, boost::asio::buffer(message_),
            boost::bind(
&tcp_connection::handle_write,shared_from_this(),
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
    }
private:
    tcp_connection(boost::asio::io_service
& io_service)
        : socket_(io_service)
    {
    }
    
void handle_write(const boost::asio::error&/*error*/,
        size_t
/*bytes_transferfed*/)
    {
    }
    tcp::socket socket_;
    std::
string message_;
};


class tcp_server
{
public:
    tcp_server(boost::asio::io_service
& io)
        : acceptor_(io, tcp::endpoint(tcp::v4(),
13))
    {
        start_accept();
    }
private:
    
void start_accept()
    {
        
//创建新tcp_connection对象,成员变量socket_将会作为acceptor的参数
        tcp_connection::pointer new_connection =
            tcp_connection::create(acceptor_.io_service());

        
//等待接受新连接
        acceptor_.async_accept(new_connection->socket(),
            boost::bind(
&tcp_server::handle_accept,this,
            new_connection,boost::asio::placeholders::error));

    }

    
/*
     *当async_accept接受新连接完成后呼叫handle_accept
     *我们在这个函数中响应客户请求,并等待下个连接
     
*/
    
void handle_accept(tcp_connection::pointer new_connection,
        boost::asio::error
&error)
    {
        
if(!error)
        {
            new_connection
->start();
            start_accept();
        }

    }
private:
    
/*
    /// TCP socket 类型.
    typedef basic_stream_socket<tcp> socket;
    /// TCP acceptor 类型.
    typedef basic_socket_acceptor<tcp> acceptor;
    
*/
    tcp::acceptor acceptor_;
};

/*
    io_service 类为异步i/o对象的用户提供核心 i/o功能(在windows2000以上环境使用完成端口)
    如: 
        boost::asio::ip::tcp::socket
        boost::asio::ip::tcp::acceptor
        boost::asio::ip::udp::socket
        boost::asio::deadline_timer
*/
int _tmain(int argc, _TCHAR* argv[])
{
    
try{
        boost::asio::io_service io;
        tcp_server server(io);
        io.run();
    }
    
catch(std::exception& e)
    {
        std::cerr 
<< e.what() << std::endl;
    }
    
return 0;
}