discard
Discard 恐怕算是最簡單的長連接 TCP 應用層協議,它只需要關注“三個半事件”中的“消息/數據到達”事件,事件處理函數如下:
1: void DiscardServer::onMessage(const muduo::net::TcpConnectionPtr& conn,
2: muduo::net::Buffer* buf,
3: muduo::Timestamp time)
4: {
5: string msg(buf->retrieveAsString()); // 取回讀到的全部數據
6: LOG_INFO << conn->name() << " discards " << msg.size() << " bytes at " << time.toString();
7: }剩下的都是例行公事的代碼:定義一個 DiscardServer class,以 TcpServer 為成員。 1: #ifndef MUDUO_EXAMPLES_SIMPLE_DISCARD_DISCARD_H 2: #define MUDUO_EXAMPLES_SIMPLE_DISCARD_DISCARD_H 3: 4: #include 5: 6: // RFC 863 7: class DiscardServer
8: {
9: public:
10: DiscardServer(muduo::net::EventLoop* loop,
11: const muduo::net::InetAddress& listenAddr);
12:
13: void start();
14:
15: private:
16: void onConnection(const muduo::net::TcpConnectionPtr& conn);
17:
18: void onMessage(const muduo::net::TcpConnectionPtr& conn,
19: muduo::net::Buffer* buf,
20: muduo::Timestamp time);
21:
22: muduo::net::EventLoop* loop_;
23: muduo::net::TcpServer server_;
24: };
25:
26: #endif // MUDUO_EXAMPLES_SIMPLE_DISCARD_DISCARD_H注冊回調函數
1: DiscardServer::DiscardServer(muduo::net::EventLoop* loop,
2: const muduo::net::InetAddress& listenAddr)
3: : loop_(loop),
4: server_(loop, listenAddr, "DiscardServer")
5: {
6: server_.setConnectionCallback(
7: boost::bind(&DiscardServer::onConnection, this, _1));
8: server_.setMessageCallback(
9: boost::bind(&DiscardServer::onMessage, this, _1, _2, _3));
10: }
11:
12: void DiscardServer::start()
13: {
14: server_.start();
15: }
處理連接與數據事件
1: void DiscardServer::onConnection(const muduo::net::TcpConnectionPtr& conn)
2: {
3: LOG_INFO << "DiscardServer - " << conn->peerAddress().toHostPort() << " -> "
4: << conn->localAddress().toHostPort() << " is "
5: << (conn->connected() ? "UP" : "DOWN");
6: }
7:
8: void DiscardServer::onMessage(const muduo::net::TcpConnectionPtr& conn,
9: muduo::net::Buffer* buf,
10: muduo::Timestamp time)
11: {
12: string msg(buf->retrieveAsString());
13: LOG_INFO << conn->name() << " discards " << msg.size() << " bytes at " << time.toString();
14: }
在 main() 裡用 EventLoop 讓整個程序轉起來
1: #include "discard.h"
2:
3: #include
4: #include
5:
6: using namespace muduo;
7: using namespace muduo::net;
8:
9: int main()
10: {
11: LOG_INFO << "pid = " << getpid();
12: EventLoop loop;
13: InetAddress listenAddr(2009);
14: DiscardServer server(&loop, listenAddr);
15: server.start();
16: loop.loop();
17: }daytime
Daytime 是短連接協議,在發送完當前時間後,由服務端主動斷開連接。它只需要關注“三個半事件”中的“連接已建立”事件,事件處理函數如下:
1: void DaytimeServer::onConnection(const muduo::net::TcpConnectionPtr& conn)
2: {
3: LOG_INFO << "DaytimeServer - " << conn->peerAddress().toHostPort() << " -> "
4: << conn->localAddress().toHostPort() << " is "
5: << (conn->connected() ? "UP" : "DOWN");
6: if (conn->connected()) 7: { 8: conn->send(Timestamp::now().toFormattedString() + " "); // 發送時間字符串 9: conn->shutdown(); // 主動斷開連接 10: } 11: }剩下的都是例行公事的代碼,為節省篇幅,此處從略,請閱讀 muduo/examples/simple/daytime。
用 netcat 扮演客戶端,運行結果如下:
$ nc 127.0.0.1 2013
2011-02-02 03:31:26.622647 # 服務器返回的時間字符串
time
Time 協議與 daytime 極為類似,只不過它返回的不是日期時間字符串,而是一個 32-bit 整數,表示從 1970-01-01 00:00:00Z 到現在的秒數。當然,這個協議有“2038 年問題”。服務端只需要關注“三個半事件”中的“連接已建立”事件,事件處理函數如下:
1: void TimeServer::onConnection(const muduo::net::TcpConnectionPtr& conn) 2: { 3: LOG_INFO << "TimeServer - " << conn->peerAddress().toHostPort() << " -> " 4: << conn->localAddress().toHostPort() << " is " 5: << (conn->connected() ? "UP" : "DOWN"); 6: if (conn->connected()) 7: { 8: int32_t now = sockets::hostToNetwork32(static_cast<int>(::time(NULL))); 9: conn->send(&now, sizeof now); // 發送 4 個字節 10: conn->shutdown(); // 主動斷開連接 11: } 12: }剩下的都是例行公事的代碼,為節省篇幅,此處從略,請閱讀 muduo/examples/simple/time。
用 netcat 扮