Muduo网络编程示例之一:五个简单 TCP 协议
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/易做图/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/易做图/time。
用 netcat 扮
补充:软件开发 , C语言 ,