1. 程式人生 > >boost.asio系列——socket程式設計

boost.asio系列——socket程式設計

asio的主要用途還是用於socket程式設計,本文就以一個tcp的daytimer服務為例簡單的演示一下如何實現同步和非同步的tcp socket程式設計。

客戶端

客戶端的程式碼如下:

    #include <iostream>
    #include <boost/array.hpp>
    #include <boost/asio.hpp>

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

    int main(int argccharargv[])
    {
        try
        {
            boost::asio::io_service io_service;
            tcp::endpoint end_point(boost::asio::ip::address::from_string("127.0.0.1"), 3200);

            

tcp::socketsocket(io_service);
            socket.
connect(end_point);

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

                size_t len = socket.
read_some(boost::asio::buffer(buf), error);

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

                std::cout.write(buf.data(), len);
            }
        }
        catch (std::exception& e)
        {
            std::cerr << e.what() << std::endl;
        }

        return 0;
    }

主要流程如下:

  1. 通過tcp::socket類定義一個tcp client物件socket
  2. 通過connect函式連線伺服器,開啟socket連線。
  3. 通過read_some函式來讀資料

另外,還可以通過write_some來寫資料,通過close來關閉socket連線(這裡是通過釋放socket物件隱式釋放連線)。

伺服器

伺服器程式碼如下:

    #include <ctime>
    #include <iostream>
    #include <string>
    #include <boost/asio.hpp>

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

    int main()
    {
        try
        {
            asio::io_service io_service;
            tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 3200));

            for (;;)
            {
                tcp::socket socket(io_service);
                acceptor.accept(socket);

                time_t now = time(0);
                std::string message = ctime(&now);

                system::error_code ignored_error;
                socket.write_some(asio::buffer(message), ignored_error);
            }
        }
        catch (std::exception& e)
        {
            std::cerr << e.what() << std::endl;
        }

        return 0;
    }

主要流程如下:

  1. 通過tcp::acceptor建立一個tcp server物件,並繫結埠(也可以不在構造器中自動繫結,而通過bind函式手動繫結)
  2. 通過accept函式獲取遠端連線
  3. 通過遠端連線的write_some函式將資料發往客戶端

非同步伺服器

前面的伺服器是同步版本,在大併發的場景下一般需要用到非同步socket。伺服器的非同步版本如下:

    #include <ctime>
    #include <iostream>
    #include <string>
    #include <memory>
    #include <functional>
    #include <boost/asio.hpp>

    using boost::asio::ip::tcp;
    using namespace std;

    void process_client(shared_ptr<tcp::socketclient)
    {
        time_t now = time(0);
        
shared_ptr<string> message(new string(ctime(&now)));

        auto callback = [=](const boost::system::error_codeerr ,size_t size)
        {
            if ((int)size == message->length())
                cout << "write completed" << endl;
        };

        client->
async_send(boost::asio::buffer(*message), callback);
    }

    typedef function<void (const boost::system::error_code&)> accept_callback;
    void start_accept(tcp::acceptorserver)
    {
        
shared_ptr<tcp::socket> client(new tcp::socket(server.get_io_service()));
        accept_callback callback = [&server, client](const boost::system::error_codeerror)
            {
                if (!error)
                    process_client(client);

                start_accept(server);
            };

        server.
async_accept(*client, callback);
    }

    int main()
    {
        try
        {
            boost::asio::io_service io_service;
            tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 3200));
            start_accept(acceptor);
            io_service.run();
        }
        catch (std::exception& e)
        {
            std::cerr << e.what() << std::endl;
        }
        return 0;
    }

這個非同步版本的邏輯倒不是很複雜,基本上和.net中傳統的非同步socket相似,不過需要注意的是,由於c++中記憶體需要自己管理,而asio框架也沒有提供任何管理機制,因此需要注意async_accept、async_send等函式的引數生命週期,切記不能在裡面傳入棧變數的引用。如果是堆變數,需要確保釋放,本例中我是通過share_ptr來實現的自動釋放。

更多的示例請參看asio官方文件