ACE Proactor 實現 **Proactor 模式**(異步 I/O 完成通知),與 Reactor(同步事件通知)不同。UDP 無連接,無 Acceptor/Connector,直接用 ACE_Asynch_Read_Dgram/ACE_Asynch_Write_Dgram 綁定 ACE_SOCK_Dgram 並註冊完成處理器。
class Sender : public ACE_Handler {
ACE_SOCK_Dgram sock_;
ACE_Asynch_Write_Dgram writer_;
const char *compKey_ = "SenderKey", *act_ = "SenderAct";
public:
int open(const ACE_TCHAR *host, u_short port) {
sock_.open(ACE_INET_Addr::sap_any);
writer_.open(*this, sock_.get_handle(), compKey_, ACE_Proactor::instance());
// 構造兩塊數據:頭 + 體
ACE_Message_Block *hdr = new ACE_Message_Block(100);
hdr->copy("To be or not to be.", 20);
ACE_Message_Block *body = new ACE_Message_Block(100);
memset(body->wr_ptr(), 'X', 100); body->wr_ptr(100);
hdr->cont(body);
// 異步發送
ACE_INET_Addr dst(port, host);
size_t sent; int rc = writer_.send(hdr, sent, 0, dst, act_);
return (rc == -1) ? -1 : 0;
}
virtual void handle_write_dgram(const ACE_Asynch_Write_Dgram::Result &r) {
r.message_block()->release(); // 釋放鏈
// 可檢查 r.bytes_transferred(), r.success() 等
}
};
class Receiver : public ACE_Service_Handler {
ACE_SOCK_Dgram sock_;
ACE_Asynch_Read_Dgram reader_;
const char *compKey_ = "RecvKey", *act_ = "RecvAct";
public:
int open_addr(const ACE_INET_Addr &local) {
sock_.open(local);
reader_.open(*this, sock_.get_handle(), compKey_, ACE_Proactor::instance());
ACE_Message_Block *hdr = new ACE_Message_Block(1024); hdr->size(20);
ACE_Message_Block *body = new ACE_Message_Block(1024);
hdr->cont(body);
size_t recvd; int rc = reader_.recv(hdr, recvd, 0, PF_INET, act_);
return (rc == -1) ? -1 : 0;
}
virtual void handle_read_dgram(const ACE_Asynch_Read_Dgram::Result &r) {
if (r.success() && r.bytes_transferred()) {
for (auto mb = r.message_block(); mb; mb = mb->cont()) {
// mb->length() 有效長度,mb->rd_ptr() 數據指針
}
}
r.message_block()->release();
}
};
需求:每隔 interval 秒,讀取文件內容,發送到配置文件列出的多個 IP:Port。
class Broadcaster : public ACE_Handler, public ACE_Event_Handler {
ACE_SOCK_Dgram sock_;
ACE_Asynch_Write_Dgram writer_;
long timerId_;
int intervalSec_;
vector<string> targets_; // "ip:port"
string contentFile_;
public:
Broadcaster(int interval) : intervalSec_(interval) {}
int open(const ACE_TCHAR *localHost, u_short localPort) {
sock_.open(ACE_INET_Addr::sap_any);
writer_.open(*this, sock_.get_handle(), "BcastKey", ACE_Proactor::instance());
// 註冊定時器
reactor(ACE_Reactor::instance());
timerId_ = reactor()->schedule_timer(this, 0,
ACE_Time_Value(intervalSec_), ACE_Time_Value(intervalSec_));
return 0;
}
virtual int handle_timeout(const ACE_Time_Value&, const void*) {
// 讀取配置與內容
readTargets("targets.cfg"); // 每行 "ip port"
string content = readFile(contentFile_);
// 逐目標發送
for (auto &t : targets_) {
sendOne(t, content);
}
return 0;
}
void sendOne(const string& target, const string& msg) {
ACE_Message_Block *mb = new ACE_Message_Block(msg.size()+1);
mb->copy(msg.c_str(), msg.size()+1);
ACE_INET_Addr addr(target.c_str());
size_t sent; writer_.send(mb, sent, 0, addr, "BcastAct");
}
virtual void handle_write_dgram(const ACE_Asynch_Write_Dgram::Result &r) {
r.message_block()->release();
}
};
int ACE_TMAIN(int argc, ACE_TCHAR *argv[]) {
ACE_Proactor::close_singleton();
ACE_WIN32_Proactor *impl = new ACE_WIN32_Proactor(0, 1);
ACE_Proactor::instance(new ACE_Proactor(impl, 1), 1);
ACE_Reactor::instance()->register_handler(impl, impl->get_handle());
Broadcaster b(10); // 10 秒間隔
b.open(ACE_TEXT("0.0.0.0"), 0);
ACE_Reactor::instance()->run_event_loop(); // 永久運行
return 0;
}
# targets.cfg 192.168.1.100 5000 192.168.1.101 5000 # content.txt...data...
ACE Proactor UDP 異步通信核心在於:
1. ACE_Asynch_Read_Dgram/Write_Dgram 綁定 ACE_SOCK_Dgram 與完成處理器。
2. 數據塊鏈 (Message_Block::cont) 支持散佈/聚集讀寫。
3. 定時廣播結合 ACE_Event_Handler::handle_timeout + Reactor::schedule_timer。
4. 完成回調中**必須釋放 Message_Block 鏈**,否則洩漏。
此模型適用於高性能 UDP 服務器/客戶端、日誌廣播、心跳檢測等場景。