Boost.Asio基礎(二)

套接字 Sockets

Boost.Asio有三種類型的Socket類:ip::tcp,ip::udp和ip::icmp,三者都是可擴展的。你可以創建自己的Socket類,雖然做起來稍微複雜了點。假如你真的要這麼做,可以參考boost/asio/ip/tcp.hpp,boost/asio/ip/udp.hpp和boost/asio/ip/icmp.hpp。它們都是很小的類,在內部使用typedef關鍵字。
你可以把ip::tcp,ip::udp和ip::icmp類,作爲一個佔位符;可以用下面的形式來訪問類的和類的方法:

  • ip::tcp::socket, ip::tcp::acceptor, ip::tcp::endpoint, ip::tcp::resolver, ip::tcp::iostream
  • ip::udp::socket, ip::udp::endpoint, ip::udp::resolver
  • ip::icmp::socket, ip::icmp::endpoint, ip::icmp::resolver

相應的socket類創建一個對應的套接字。在io_service實例構造的時候,你需要傳入這個socket:

io_service service;
ip::udp::socket sock(service);
sock.set_option(ip::udp::socket::reuse_address(true));

每一個socket的名字都由typedef而來:

  • ip::tcp::socket = basic_stream_socket
  • ip::udp::socket = basic_stream_socket
  • ip::icmp::socket = basic_stream_socket

同步錯誤代碼(Synchronous error codes)

所有的同步函數都有例外情況,它們會拋出異常或者返回一個錯誤代碼,例如下列代碼:

sync_func(arg1, arg2 ... argN); //拋出異常
boost::system::error_code ec;
sync_func(arg1 arg2, ... , argN, ec); //返回錯誤代碼

在後面,會遇到很多同步函數。爲了保持簡潔,後面會忽略返回錯誤代碼的例外情況。

Socket成員函數

這些函數被分爲幾個組。並不是每個種類的socket都能訪問所有這些成員函數。本節的最後,會有一張表列出哪些成員是隸屬於何種socket類。
需要注意的是,所有的異步函數都是立即返回的,而同步版本的函數,只在操作完成之後才返回。

連接相關的類

有些函數用於連接或者綁定socket,斷開連接,查詢連接是否有效:

  • assign(protocol, socket):它給socket實例賦予原始套接字(原生)。使用它來處理一些遺留系統(這些系統中套接字通常是已經創建過了的)。
  • open(protocol):用給定的IP協議(v4或者v6)打開一個socket。主要用於UDP/ICMP socket,或者是用於服務器端socket。
  • bind(endpoint):綁定到指定的地址。
  • connect(endpoint):同步連接到指定的地址。
  • async_connect(endpoint):異步地連接到指定的地址。
  • is_open():socket是否是打開的。
  • close():關閉套接字。任何在此socket的異步操作都會被取消掉,並以error::operation_aborted錯誤代碼完成。
  • shutdown(type_of_shutdown):禁用send,receive操作。
  • cancel():取消socket上的所有異步操作。所有在此socket上的異步操作都會被立即完成,並以error::operation_aborted錯誤代碼返回。
    下面是例子:
ip::tcp::endpoint ep(ip::address::from_string("127.0.0.1"), 80);
ip::tcp::socket sock(service);
sock.open(ip::tcp::v4());
sock.connect(ep);
sock.write_some(buffer("GET /index.html\r\n"));
char buff[1204];
sock.read_some(buffer(buff, 1024));
sock.shutdown(ip::tcp::socket::shutdown_receive);
sock.close();

讀/寫函數

讀寫函數在socket上進行I/O操作。
對於異步函數,handler是一個回調函數,形如void handler(const boost::system::error_code& e, size_t bytes)。

  • async_receive(buffer, [flags], handler):在socket上開始異步的recevie操作。
  • async_read_some(buffer, handler):和async_receive作用相同。
  • async_receive_from(buffer, endpoint [,flags], handler:在指定的endpoint上開始異步的receive操作。
  • async_send(buffer [, flags], handler):將緩衝區中的數據異步的發送出去。
  • async_write_some(buffer, handler):和async_send相同。
  • async_send_to(buffer, endpoint, handler):在指定的endpoint上開始異步的發送操作。
  • receive(buffer [, flags]):同步接受數據到buffer,將阻塞,知道數據接收完成,或者出錯。
  • read_some(buffer):和receive相同。
  • receive_from(buffer, endpoint [, flags]):從給定的endpoint接收數據,將阻塞,知道數據接收完成,或者出錯。
  • send(buffer [, flags]):同步的發送緩衝區中的數據,將阻塞,知道數據發送完成,或者出錯。
  • write_some(buffer):和send相同。
  • send_to(buffer, endpoint [, flags]):同步地將數據發送給指定endpoint。將阻塞,知道數據發送完成,或者出錯。
  • available():返回在不阻塞的情況下,可以從socket中讀取出多少字節。

這裏簡單討論下緩衝區。默認的flags參數是0,也可以混合下面的值:

  • ip::socket_type::socket::message_peek:這個flag表示,只在緩衝區中檢索數據。它可以返回消息,但是下一次讀時,會重新讀取這條數據。
  • ip::socket_type::socket::message_out_of_band:這個標誌表示處理帶外數據(OBB)。OBB數據比普通的數據更重要。對OBB數據的討論超出了本書的範圍。
  • ip::socket_type::socket::message_end_of_record:Windows下不支持。

大多數時候我們都使用message_peek,例子如下:

char buff[1024];
sock.receive(buffer(buff), ip::tcp::socket::message_peek);
memset(buff, 1024, 0);
//重新讀取上次讀取過的數據
sock.receive(buffer(buff));

下面的例子演示了同步和異步的區別:

  • 例子1,在tcp socket上同步的寫和讀:
ip::tcp::endpoint ep(ip::address::from_string("127.0.0.1", 80);
ip::tcp::socke sock(service);
sock.connect(ep);
sock.write_some(buffer("GET /index.html\r\n");
std::cout<< "有效字節數: "<< sock.available() <<std::endl;
char buff[512];
size_t read = sock.read_some(buffer(buff));
  • 例子2,在UDP socket上異步讀和寫:
ip::udp::socket sock(service);
sock.open(ip::udp::v4());
ip::udp::endpoint receiver_ep("xxx.xxx.xxx.xxx", 80);
sock.send_to(buffer("testing\n"), receiver_ep);
char buff[512];
ip::udp::endpoint sender_ep;
sock.receive_from(buffer(buff), sender_ep);
  • 例子3,從UDP服務器socket中異步讀取:
using namespace boost::asio;
io_service service;
ip::udp::socket sock(service);
boost::asio::ip::udp::endpoint sender_ep;
char buff[512];

void on_read(const boost::system::error_code& err, std::size_t read_bytes) 
{
    std::cout<<"read "<< read_bytes << std::endl;
    sock.async_receive_from(buffer(buff), sender_ep, on_read);
}

int main(int argc, char** argv)
{
    ip::udp::endpoint ep(ip::address::from_string("127.0.0.1"), 8001);
    sock.open(ep.protocol());
    sock.set_option(boost::asio::ip::udp::socket::reuse_address(true));
    sock.bind(ep);
    sock.async_receive_from(buffer(buff, 512), sender_ep, on_read);
    service.run();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章