用ACE開發網路通訊程式

2021-04-23 05:31:37 字數 4405 閱讀 7720

該程式將演示如何將乙個簡單結構序列化後傳送到網路上,如何從網路上接收到資料後反序列化回結構。

首先使用ace_sock_connector::connect連線某個伺服器(使用ip位址和埠號),該伺服器上使用ace_sock_acceptor::accept等待外部的連線請求。

ace_inet_addr類進行管理socket通訊使用的ip位址和埠號。

當連線建立的時候,連線者和等待者都初始化乙個傳輸者用於通訊。

下面就是連線者如何連線本機的7777埠的服務程式**:

#include

using namespace std;

#include "ace/inet_addr.h"

#include "ace/sock_stream.h"

#include "ace/sock_connector.h"

int main(void)

}如果連線成功,connect方法返回0,如果連線失敗,返回-1,執行緒專有的errno變數將被設定對應的錯誤碼,你可以通過strerror函式獲取錯誤資訊描述字串。ace不使用異常報錯,原因之一是早些時候異常並不被所有的c++編譯器支援,原因之二是異常對效能仍然有影響,作為高效能底層庫ace仍然採用了c風格進行錯誤處理。但是你仍然可以在自己的應用邏輯中使用異常,並不會和ace發生衝突。

下面是等待者的示例:

#include

using namespace std;

#include "ace/inet_addr.h"

#include "ace/sock_stream.h"

#include "ace/sock_acceptor.h"

int main(void)

ace_sock_stream stream;

if(acceptor.accept(stream)==-1)

}注意,ace_sock_acceptor::accept和ace_sock_connector::connect方法都可以接收乙個ace_time_value*引數。該引數缺省直為null,就像上面的兩個示例,表示除非建立連線,否則不會返回;如果我們建立ace_time_value time(0,0)物件作為引數,則表示方法不會阻塞,如果不能立刻建立連線,就返回-1,並且errno為ewouldblock;如果我們建立ace_time_value time(5,0)物件作為引數,就表示方法會最多等待5秒鐘,如果5秒鐘內還沒有建立連線,就返回-1,並且errno為etime.

ace_sock_acceptor物件沒有狀態,因此多執行緒可以在不鎖定的情況下共享該物件。

通常資料傳輸的過程是將物件中的資料按照某種格式序列化成連續的位元組流,然後傳送到網路上,當另一端接收到位元組流後,按照此格式反序列化成物件。

當連線建立好後,通訊雙方都有兩個可以傳送和接收資料的ace_sock_stream物件。該物件提供了傳送和接收的方法。send_n/recv_n用於傳送和接收確定數量的位元組流,如果沒有傳送或者接收完,該方法將阻塞。而send/recv就不保證這一點,可能實際傳送或者接收的資料比引數指定的少,該方法不會阻塞,而是返回實際傳送或者接收的資料大小。send/recv方法實際是從父類ace_sock_io繼承而來的。

網路傳輸的一種高效的方法是集中寫和分散讀。不同緩衝區的資料沒有必要拷貝到一起,就可以直接按照次序一次型的傳送出去。從網路另一端收到後,有可以分散的寫到不同的緩衝區中。這就避免了資料複製的開銷。ace_sock_stream的方法recvv_n/sendv_n方法就提供了這個機制。我們後面的示例將嚴實這個方法的使用。

如果我們使用tcp/ip協議傳送資料,tcp/ip協議有乙個nagle演算法。該演算法將快取小資料,減少網路傳送的次數,從而避免過多通訊的開銷。在某些情況下,我們需要關閉該演算法,讓我們的資料能夠立刻傳送出去。ace_sock_stream的set_option方法使用引數tcp_nodelay可以關閉這個演算法。另乙個方法是當我們使用sendv_n方法時,也會強制資料立刻傳送。

下面的示例將乙個結構shmrecord初始化,並序列化到ace_outputcdr物件中。然後使用sendv_n方法將資料發出。

#include

using namespace std;

#include "ace/inet_addr.h"

#include "ace/sock_stream.h"

#include "ace/sock_connector.h"

#include "ace/cdr_stream.h"

class shmrecord

ace_uint16 type_;

ace_uint32 offset_;

void* pdata_;

ace_uint32 datalength_;

size_t size() const

~shmrecord()

};int operator<<(ace_outputcdr & cdr,shmrecord const& record)

int operator>>(ace_inputcdr & cdr,shmrecord & record)

int main(void)

shmrecord record;

record.type_=1;

record.offset_=2;

record.pdata_=new char[4]();

record.datalength_=4;

strcpy(static_cast(record.pdata_),"hih");

const size_t size=record.size()+ace_cdr::max_alignment;

ace_outputcdr payload(size);

payload<

//create cdr header for this data

ace_outputcdr header(ace_cdr::max_alignment+8);

headeriovec iov[2];

iov[0].iov_base=header.begin()->rd_ptr();

iov[0].iov_len=8;

iov[1].iov_base=payload.begin()->rd_ptr();

iov[1].iov_len=size;

stream.sendv_n(iov,2);

coutace提供了ace_outputcdr和ace_inputcdr類,是針對網路程式經常遇到的將物件資料序列化到位元組流和從位元組流中反序列化到物件的情況。你可以提供自己的operator《和operator>>操作,就像上面的例子一樣。

這種方式和支援標準c++流的方式是一樣的。那麼,為什麼不直接使用標準c++流呢?因為ace所支援的平台很多,有些編譯器不支援標準c++流。並且據我個人的體驗,標準c++流在記憶體管理上是封裝的,你不可能通過公有方法獲得內部關裡的緩衝區的指標,除非自己定義自己的派生類,這並不容易。還有乙個原因是不同編譯器和不同的硬體使用了不同的位元組對齊方式(大尾數法和小尾數法)。使用ace的cdr類就可以保證各種環境下都能使用,因為它在內部使用了corba公共資料表示的格式。

對於基本的數值型別,各個平台也有可能有長度的差異,比如int究竟是16,32還是64。所以這裡使用了ace提供的基本數值型別,比如ace_uint32。

在這個示例程式裡,我們實際上建立了兩個ace_outputcdr物件,乙個用來表示資料頭,乙個存發實際結構中的資料。資料頭中前4個位元組存放了乙個布林值,表示本機的位元組順序,後面四個位元組表示第二個物件的實際長度。

因此,接收資料時首先接收固定長度的頭物件,取得位元組順序標誌後,調整位元組順序,然後獲取實際長度,根據該長度接收第二個ace_outputcdr物件存放的實際資料。

下面的例子演示了如何接收傳送來的資料。

int main(void)

ace_sock_stream stream;

if(acceptor.accept(stream)==-1)

auto_ptr

spblock(new ace_message_block(ace_default_cdr_bufsize));

ace_cdr::mb_align(spblock.get());

if(stream.recv_n(spblock->wr_ptr(),8)==8)//receive the header of cdr}}

ace_message_block類用來管理資料,內部有乙個指向ace_data_block物件的指標,ace_data_block類管理實際的緩衝區資料。這種設計允許多個ace_message_block物件共享同乙個ace_data_block物件,對於效率的提高很有幫助。多個ace_message_block物件可以組成乙個鍊錶(雙向或者單向)。

在上面的例子中,我們 建立了乙個預設大小的ace_message_block物件,然後將接收的資料寫入ace_data_block的緩衝區中,並且移動寫指標的位置。ace_inputcdr通過和ace_message_block物件關聯來讀取緩衝區的資料。

用ACE開發網路通訊程式

該程式將演示如何將乙個簡單結構序列化後傳送到網路上,如何從網路上接收到資料後反序列化回結構。建立連線 首先使用ace sock connector connect連線某個伺服器 使用ip位址和埠號 該伺服器上使用ace sock acceptor accept等待外部的連線請求。ace inet a...

Winsock開發網路通訊程式的經典入門

對於許多初學者來說,網路通訊程式的開發,普遍的乙個現象就是覺得難以入手。許多概念,諸如 同步 sync 非同步 async 阻塞 block 非阻塞 unblock 等,初學者往往迷惑不清,只知其所以而不知起所以然。同步方式指的是傳送方不等接收方響應,便接著發下個資料報的通訊方式 而非同步指傳送方發...

Winsock開發網路通訊程式的經典入門

對於許多初學者來說,網路通訊程式的開發,普遍的 乙個現象就是覺得難以入手。許多概念,諸如 同步 sync 非同步 async 阻塞 block 非阻塞 unblock 等,初學者往往迷惑不清,只知其所以而不知起所以然。同步方式指的是傳送方不等接收方響應,便接著發下 個資料報的通訊方式 而非同步指傳送...