Asio實現TCP套接字通信


1. boost::asio介紹:
       (1)Boost.Asio是一個跨平台的、主要用於網絡和其他一些底層輸入/輸出編程的C++庫。Boost.Asio在網絡通信抽象了IO概念,可以用它進行同步或者異步的IO網絡編程。Boost.Asio可以在大多數操作系統上使用,能同時支持數千個並發的連接。
       (2)Asio可以進行異步網絡編程,其采用前攝器模式實現異步IO,不需要多線程和鎖機制(避免了競爭和死鎖)。它內部封裝了select、kqueue、poll/epoll、overlappedIO等機制。
       (3)io_service是asio庫的異步處理處理機制(類似epoll),它負責與操作系統交互,通過調用其run()函數來等待所有的異步操作完成,並為每一個異步操作調用其handler回調函數。它必須先初始化,
       (4)Asio工作在同步模式:程序發起IO操作請求,隨即向IO_service提交請求,由IO_service將請求轉交給內核,之后阻塞等待IO操作完成。IO操作完成后由內核通知IO_service,IO_service將結果交給程序。
              Asio工作在異步模式:程序發起IO操作請求,隨即向IO_service提交請求,由IO_service將請求轉發給內核,同時注冊handler回調函數,之后立即返回。IO_service的run函數將等待IO操作完成,完成后從內核取回結果並調用handler函數。    
 
2. boost::asio有關網絡通信的API
(1)IP地址類:
  • p::address(v4_or_v6_address):把一個ipv4或者ipv6地址轉換成ip::address
  • ip::address::from_string(str):根據一個IPv4地址(.隔開)或者一個IPv6地址(十六進制)創建一個地址。
  • ip::address::to_string() :返回這個地址的字符串。
(2)端點類:
  • endpoint(protocol, port):創建可以接受新連接的Server端點。
  • endpoint(addr, port):創建一個連接到某個地址和端口的Client端點。
(3)套接字類:
  socket類可以創建一個相應的socket,而且總是在構造的時候傳入io_service實例:
io_service ios;
ip::tcp::socket sock(ios);
(4)socket類的常用方法:
TCP連接相關
  • open(protocol):用給定的IP協議(v4或者v6)打開一個socket。主要用在UDP客戶端 或者 服務端socket
  • bind(endpoint):將套接字綁定到一個地址和端口
  • connect(endpoint):Client用同步的方式連接到Server
  • async_connect(endpoint, handler):Client用異步的方式連接到Server,連接成功后,調用handler回調函數。
  • close():這個函數用來關閉套接字。
TCP讀寫相關
  • async_read_some(buffer,handler):從套接字異步接收數據。接收完成后,調用handler回調函數。
  • async_write_some(buffer, handler):異步發送緩沖區數據到套接字。發送完成后,調用handler回調函數。
  • read_some(buffer):同步地從所給的緩沖區讀取數據。在讀完所有數據或者錯誤出現之前,這個函數都是阻塞的。
  • write_some(buffer):同步地發送緩沖區的數據。在所有數據發送成功或者出現錯誤之前,這個函數都是阻塞的。
其他方法
  • local_endpoint():這個方法返回套接字本地連接的地址。
  • remote_endpoint():這個方法返回套接字連接到的遠程地址。
  • non_blocking():如果套接字是非阻塞的,這個方法返回true,否則false。
( ps:為了使socket和緩沖區(read或者write)在整個異步操作的生命周期中一直活動,需要采取特殊的防護措施。連接類需要繼承自enabled_shared_from_this,然后在內部保存它需要的緩沖區,而且每次異步調用都要傳遞一個智能指針給this操作。)
 
3. 使用boost::asio實現TCP客戶端和服務器端:
(1)Server端:
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/asio.hpp>
#include <boost/asio/placeholders.hpp>
#include <boost/system/error_code.hpp>
#include <boost/bind/bind.hpp>
#include "stdafx.h"

using namespace boost::asio;
using namespace std;
typedef boost::shared_ptr<ip::tcp::socket> sock_ptr;

class server
{
private:
    io_service m_io;
    ip::tcp::acceptor m_acceptor;

public:
    server() : m_acceptor(m_io, ip::tcp::endpoint(ip::tcp::v4(), 6688))
    { accept(); }

    void run(){ m_io.run();}

    void accept()
    {
        sock_ptr sock(new ip::tcp::socket(m_io));
        m_acceptor.async_accept(*sock, boost::bind(&server::accept_handler, this, boost::asio::placeholders::error, sock));
    }

    void accept_handler(const boost::system::error_code& ec, sock_ptr sock)
    {
        if (ec)
        { 
            return; 
        }
        cout<<"Client:";
        cout<<sock->remote_endpoint().address()<<endl;
        sock->async_write_some(buffer("hello asio"), boost::bind(&server::write_handler, this, boost::asio::placeholders::error));
        // 發送完畢后繼續監聽,否則io_service將認為沒有事件處理而結束運行 
        accept();
}

    void write_handler(const boost::system::error_code&ec)
    {
        cout<<"send msg complete"<<endl;
    }
};

int main()
{
    try
    {
        cout<<"Server start."<<endl;
        server srv;
        srv.run();
    }
    catch (std::exception &e)
    {
        cout<<e.what()<<endl;
    }
    return 0;
}
 
(2)Client端:
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/asio.hpp>
#include <boost/asio/placeholders.hpp>
#include <boost/system/error_code.hpp>
#include <boost/bind/bind.hpp>
#include "stdafx.h"

using namespace boost::asio;
using namespace std;

typedef boost::shared_ptr<ip::tcp::socket> sock_ptr;
typedef vector<char> buffer_type;

class client
{

private:
    io_service m_io;
    buffer_type m_buf;
    ip::tcp::endpoint m_ep;
public:
    client(): m_buf(100, 0),  m_ep(ip::address::from_string("127.0.0.1"), 6688)
    { start(); }

    void run()
    { m_io.run();}

    void start()
    {
        sock_ptr sock(new ip::tcp::socket(m_io));
        sock->async_connect(m_ep, boost::bind(&client::conn_handler, this, boost::asio::placeholders::error,     sock));
    }

    void conn_handler(const boost::system::error_code&ec, ip::tcp::socket sock)
    {
        if (ec)
        {return;}
        cout<<"Receive from "<<sock->remote_endpoint().address()<<": "<<endl;
        sock->async_read_some(buffer(m_buf), boost::bind(&client::read_handler, this, boost::asio::placeholders::error, sock));
    }

    void read_handler(const boost::system::error_code&ec, ip::tcp::socket sock)
    {
        if (ec)
        {return;}
        sock->async_read_some(buffer(m_buf), boost::bind(&client::read_handler, this, boost::asio::placeholders::error, sock));
        cout<<&m_buf[0]<<endl;
    }
};

int main()
{
    try
    {
        cout<<"Client start."<<endl;
        client cli;
        cli.run();
    }
    catch (std::exception &e)
    {
        cout<<e.what()<<endl;
    }
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM