Python Twisted 是一款非常好的網絡庫,它也采用 Reactor 作為網絡編程的基本模型,所以從使 用上與 muduo 頗有相似之處。(當然,muduo 沒有 deferreds)Finger 是 twisted 文檔的一個經典 例子,本文展示如何用 muduo 來實現最簡單的 finger 服務端。限於篇幅,只實現 finger01~07。代 碼位於 examples/twisted/finger 。
1 拒絕連接
什麼都不做,程序空等。 finger01.cc
1: #include
2:
3: using namespace muduo;
4: using namespace muduo::net;
5:
6: int main()
7: {
8: EventLoop loop;
9: loop.loop();
10: }
2 接受新連接
在 1079 端口偵聽新連接 ,接受連接之後什麼都不做,程序空等。muduo 會自動丟棄收到的數據。finger02.cc
1: #include
2: #include
3:
4: using namespace muduo;
5: using namespace muduo::net;
6:
7: int main()
8: {
9: EventLoop loop;
10: TcpServer server(&loop, InetAddress(1079), "Finger");
11: server.start();
12: loop.loop();
13: }
3 主動斷開連接
接受新連接之後主動斷開。finger03.cc
以下省略頭文件和 namespace。
1: void onConnection(const TcpConnectionPtr& conn)
2: {
3: if (conn->connected())
4: {
5: conn->shutdown ();
6: }
7: }
8:
9: int main()
10: {
11: EventLoop loop;
12: TcpServer server(&loop, InetAddress(1079), "Finger");
13: server.setConnectionCallback(onConnection);
14: server.start();
15: loop.loop();
16: }
4 讀取用戶名,然後斷開連接
如果讀到一行以 /r/n 結尾的消息,就斷開連接。finger04.cc
注意這段代碼有安全問 題,如果惡意客戶端不斷發送數據而不換行,會撐爆服務端的內存。另外,Buffer::findCRLF() 是線 性查找,如果客戶端每次發一個字節,服務端的時間復雜度為 O(N^2),會消耗 CPU 資源。
1: void onMessage(const TcpConnectionPtr& conn,
2: Buffer* buf,
3: Timestamp receiveTime)
4: {
5: if (buf->findCRLF())
6: {
7: conn->shutdown();
8: }
9: }
10:
11: int main()
12: {
13: EventLoop loop;
14: TcpServer server(&loop, InetAddress(1079), "Finger");
15: server.setMessageCallback (onMessage);
16: server.start();
17: loop.loop();
18: }
5. 讀取 用戶名、輸出錯誤信息、然後斷開連接
如果讀到一行以 /r/n 結尾的消息,就發送一條出錯信 息,然後斷開連接。finger05.cc
安全問題同上。
1: void onMessage(const TcpConnectionPtr& conn,
2: Buffer* buf,
3: Timestamp receiveTime)
4: {
5: if (buf->findCRLF())
6: {
7: conn->send("No such user/r/n");
8: conn->shutdown();
9: }
10: }
11:
12: int main()
13: {
14: EventLoop loop;
15: TcpServer server(&loop, InetAddress(1079), "Finger");
16: server.setMessageCallback(onMessage);
17: server.start();
18: loop.loop();
19: }
6. 從空的 UserMap 裡查找用戶
從一行消息中拿到用戶名(第 22 行),在 UserMap 裡查找,然後返回結果。 finger06.cc
安全問題同上。
1: typedef std::map UserMap;
2: UserMap users;
3:
4: string getUser(const string& user)
5: {
6: string result = "No such user";
7: UserMap::iterator it = users.find (user);
8: if (it != users.end())
9: {
10: result = it- >second;
11: }
12: return result;
13: }
14:
15: void onMessage(const TcpConnectionPtr& conn,
16: Buffer* buf,
17: Timestamp receiveTime)
18: {
19: const char* crlf = buf->findCRLF ();
20: if (crlf)
21: {
22: string user(buf->peek(), crlf);
23: conn->send(getUser(user) + "/r/n");
24: buf->retrieveUntil(crlf + 2);
25: conn->shutdown();
26: }
27: }
28:
29: int main()
30: {
31: EventLoop loop;
32: TcpServer server(&loop, InetAddress(1079), "Finger");
33: server.setMessageCallback(onMessage);
34: server.start();
35: loop.loop ();
36: }
7. 往 UserMap 裡添加一個用戶
與前面幾乎完全一樣,只多了第 31 行。finger07.cc
1: typedef std::map UserMap;
2: UserMap users;
3:
4: string getUser(const string& user)
5: {
6: string result = "No such user";
7: UserMap::iterator it = users.find(user);
8: if (it != users.end())
9: {
10: result = it->second;
11: }
12: return result;
13: }
14:
15: void onMessage(const TcpConnectionPtr& conn,
16: Buffer* buf,
17: Timestamp receiveTime)
18: {
19: const char* crlf = buf->findCRLF();
20: if (crlf)
21: {
22: string user(buf->peek(), crlf);
23: conn->send (getUser(user) + "/r/n");
24: buf->retrieveUntil(crlf + 2);
25: conn->shutdown();
26: }
27: }
28:
29: int main()
30: {
31: users["schen"] = "Happy and well";
32: EventLoop loop;
33: TcpServer server(&loop, InetAddress (1079), "Finger");
34: server.setMessageCallback(onMessage);
35: server.start();
36: loop.loop();
37: }
以上就是全部內容,可以用 telnet 扮演客戶端來測試我們的簡單 finger 服務端。
Telnet 測試
在一個命令行窗口運行
$ ./bin/twisted_finger07
另一個命令行運行
$ telnet localhost 1079
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
muduo
No such user
Connection closed by foreign host.
再試一次
$ telnet localhost 1079
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
schen
Happy and well
Connection closed by foreign host.
冒煙測試過關。
查看本欄目