muduo庫的簡單使用-echo服務的編寫


muduo庫的簡單使用

muduo是一個基於事件驅動的非阻塞網絡庫,采用C++和Boost庫編寫。
它的使用方法很簡單,參考這篇文章:TCP網絡編程本質論

里面有這么幾句:

我認為,TCP 網絡編程最本質的是處理三個半事件:

連接的建立,包括服務端接受 (accept) 新連接和客戶端成功發起 (connect) 連接。
連接的斷開,包括主動斷開 (close 或 shutdown) 和被動斷開 (read 返回 0)。
消息到達,文件描述符可讀。這是最為重要的一個事件,對它的處理方式決定了網絡編程的風格(阻塞還是非阻塞,如何處理分包,應用層的緩沖如何設計等等)。
消息發送完畢,這算半個。對於低流量的服務,可以不必關心這個事件;另外,這里“發送完畢”是指將數據寫入操作系統的緩沖區,將由 TCP 協議棧負責數據的發送與重傳,不代表對方已經收到數據。

所以,使用muduo庫只需編寫上面幾處相關的邏輯即可。像套接字建立、epoll輪詢這種例行公事的代碼,我們不必再編寫。

下面我們實現echo服務器,echo的核心邏輯只有一個,那就是將收到的信息回顯給對方,所以這里我們只需關心消息到達這個事件即可。

代碼如下:


#include <muduo/base/Logging.h>
#include <muduo/base/Timestamp.h>
#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/TcpConnection.h>

using namespace muduo;
using namespace muduo::net;

void onConnection(const TcpConnectionPtr &conn)
{
    LOG_INFO << "EchoServer - " << conn->peerAddress().toIpPort() << " -> "
             << conn->localAddress().toIpPort() << " is "
             << (conn->connected() ? "UP" : "DOWN");
}

void onMessage(const TcpConnectionPtr &conn,
               Buffer *buf,
               Timestamp time)
{
    muduo::string msg(buf->retrieveAllAsString());
    LOG_INFO << conn->name() << " echo " << msg.size() << " bytes, "
                     << "data received at " << time.toString();
    conn->send(msg);
}

int main(int argc, const char *argv[])
{
    EventLoop loop;
    InetAddress addr("127.0.0.1", 8988);
    TcpServer server(&loop, addr, "echo");
    server.setConnectionCallback(&onConnection);
    server.setMessageCallback(&onMessage);
    server.start();
    loop.loop();
    return 0;
}

使用下列命令編譯:

g++ -o echo echo.cc -lmuduo_net -lmuduo_base -lpthread

客戶端采用netcat即可:

echo "hello" | nc localhost 8988

基於對象的使用方法

上面的使用方式是采用了全局函數,我們還可以將echo服務器封裝成一個類:


#include <muduo/net/TcpServer.h>
#include <muduo/base/Logging.h>
#include <boost/bind.hpp>
#include <muduo/net/EventLoop.h>

class EchoServer
{
 public:
  EchoServer(muduo::net::EventLoop* loop,
             const muduo::net::InetAddress& listenAddr);

  void start();  // calls server_.start();

 private:
  void onConnection(const muduo::net::TcpConnectionPtr& conn);

  void onMessage(const muduo::net::TcpConnectionPtr& conn,
                 muduo::net::Buffer* buf,
                 muduo::Timestamp time);

  muduo::net::TcpServer server_;
};

EchoServer::EchoServer(muduo::net::EventLoop* loop,
                       const muduo::net::InetAddress& listenAddr)
  : server_(loop, listenAddr, "EchoServer")
{
  server_.setConnectionCallback(
      boost::bind(&EchoServer::onConnection, this, _1));
  server_.setMessageCallback(
      boost::bind(&EchoServer::onMessage, this, _1, _2, _3));
}

void EchoServer::start()
{
  server_.start();
}

void EchoServer::onConnection(const muduo::net::TcpConnectionPtr& conn)
{
  LOG_INFO << "EchoServer - " << conn->peerAddress().toIpPort() << " -> "
           << conn->localAddress().toIpPort() << " is "
           << (conn->connected() ? "UP" : "DOWN");
}

void EchoServer::onMessage(const muduo::net::TcpConnectionPtr& conn,
                           muduo::net::Buffer* buf,
                           muduo::Timestamp time)
{
  // 接收到所有的消息,然后回顯
  muduo::string msg(buf->retrieveAllAsString());
  LOG_INFO << conn->name() << " echo " << msg.size() << " bytes, "
           << "data received at " << time.toString();
  conn->send(msg);
}


int main()
{
  LOG_INFO << "pid = " << getpid();
  muduo::net::EventLoop loop;
  muduo::net::InetAddress listenAddr(2007);
  EchoServer server(&loop, listenAddr);
  server.start();
  loop.loop();
}

后面陸續分析一些復雜的示例。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM