SoFunction
Updated on 2025-05-06

C++ uses Muduo library to implement English-Chinese translation function

1. Preface

In this article, we will introduce some commonly used interfaces of the Muduo library, and use these interfaces to implement a simple version of the English-translated Chinese server and client. I hope it can help everyone deepen the use of the Muduo library! ! ! !

2. Text

Introduction to common library interfaces

1.1 Introduction to the basics of TcpServer

● TcpConnectionPtr

typedef std::shared_ptr<TcpConnection> TcpConnectionPtr;

TcpConnectionPtr belongs to the TcpConnection class, but when we write the server, we also need to accept the client connection. When the connection comes, the connection event callback function will handle the connection.

● ConnectionCallback

 typedef std::function<void (const TcpConnectionPtr&)> ConnectionCallback;

ConnectionCallback is a callback function for the server to handle connections. When a connection from the client comes, the function will be automatically called to handle connections.

● MessageCallback

 typedef std::function<void (const TcpConnectionPtr&, Buffer*,
 Timestamp)> MessageCallback;

MessageCallback is a callback function for the server to process connection messages. When a client sends a message, the function will be automatically called to process the message.

● InetAddress 

 class InetAddress : public muduo::copyable
 {
 public:
     InetAddress(StringArg ip, uint16_t port, bool ipv6 = false);
 };

The InetAddress field is related to the server settings. This field combines ip, port and ipv6 into a field. When we set up the server, we need to pass this field to indicate the server's IP address, port number and whether to use ipv6.

● TcpServer

 class TcpServer : noncopyable
 {
 public:
     enum Option
     {
         kNoReusePort,
         kReusePort,
     };
     
    TcpServer(EventLoop* loop,const InetAddress&amp; listenAddr,const string&amp;         
              nameArg,Option option = kNoReusePort);
 
    void setThreadNum(int numThreads);
    void start();
     
    /// Called when a new connection is successfully created    void setConnectionCallback(const ConnectionCallback&amp; cb { connectionCallback_ = cb; }
     
    ///The service processing callback function of the message--This is the function called when a new connection message is received    void setMessageCallback (const MessageCallback&amp; cb)
     { messageCallback_ = cb; }
 };

The TcpServer class is the main body to be used by our waiting dictionary server. In its constructor, we need to pass the InetAddress field to indicate the ip and port number; pass the EventLoop pointer for event monitoring, and the Option option indicates whether the server port is taken; the start function is to start the server; before starting the server, we also need to set up a callback function to establish a callback function and a message processing callback function.

1.2 EventLoop class

 class EventLoop : noncopyable
 {
 public:
 /// Loops forever.
 /// Must be called in the same thread as creation of the object.
 void loop();
 /// Quits loop.
 /// This is not 100% thread safe, if you call through a raw pointer,
 /// better to call through shared_ptr<EventLoop> for 100% safety.
 void quit();
 TimerId runAt(Timestamp time, TimerCallback cb);
 /// Runs callback after @c delay seconds.
 /// Safe to call from other threads.
 TimerId runAfter(double delay, TimerCallback cb);
 /// Runs callback every @c interval seconds.
 /// Safe to call from other threads.
 TimerId runEvery(double interval, TimerCallback cb);
 /// Cancels the timer.
 /// Safe to call from other threads.
 void cancel(TimerId timerId);
 private:
 std::atomic<bool> quit_;
 std::unique_ptr<Poller> poller_;
 mutable MutexLock mutex_;
 std::vector<Functor> pendingFunctors_ GUARDED_BY(mutex_);
 };

The EventLoop class helps our server to monitor events. Once the loop( ) function is called, it will continue to loop to the event monitoring state.

1.3 TcpConnection class

class TcpConnection : noncopyable,
 public std::enable_shared_from_this<TcpConnection>
 {
 public:
 /// Constructs a TcpConnection with a connected sockfd
 ///
 /// User should not create this object.
 TcpConnection(EventLoop* loop,
               const string& name,
               int sockfd,
               const InetAddress& localAddr,
               const InetAddress& peerAddr);
 bool connected() const { return state_ == kConnected; }
 bool disconnected() const { return state_ == kDisconnected; }
 void send(string&& message); // C++11
 void send(const void* message, int len);
 void send(const StringPiece& message);
 // void send(Buffer&& message); // C++11
 void send(Buffer* message);  // this one will swap data
 void shutdown(); // NOT thread safe, no simultaneous calling
 void setContext(const boost::any& context)
 { context_ = context; }
 const boost::any& getContext() const
 { return context_; }
 boost::any* getMutableContext()
 { return &context_; }
 void setConnectionCallback(const ConnectionCallback& cb)
 { connectionCallback_ = cb; }
 void setMessageCallback(const MessageCallback& cb)
 { messageCallback_ = cb; }
 private:
 enum StateE { kDisconnected, kConnecting, kConnected, kDisconnecting };
 EventLoop* loop_;
 ConnectionCallback connectionCallback_;
 MessageCallback messageCallback_;
 WriteCompleteCallback writeCompleteCallback_;
 boost::any context_;
 };

Common functions of TcpConnection related to connections are:

①Judge the current connection situation—connected() / disconnected()

②Send a message to the connected remote server—send()

1.4 Introduction to the basics of TcpClient class

● TcpClient

 TcpClient(EventLoop* loop,const InetAddress& serverAddr,
 const string& nameArg);

For the TcpClient construction, you need to pass a loop pointer for event monitoring. InetAddress indicates the IP and port of the server, and nameArg indicates the name of TcpClient.

●void connect()

Call this function, TcpClient will connect to the remote server that has been set.

●void disconnect()

Call this function, TcpClient will cancel the connection to the remote server

 ●void setConnectionCallback(ConnectionCallback cb)

/// Callback function when the server is connected successfully 
void setConnectionCallback(ConnectionCallback cb)
 { connectionCallback_ = std::move(cb); }

 ●void setMessageCallback(MessageCallback cb)

 /// Callback function when receiving a message sent by the server 
void setMessageCallback(MessageCallback cb)
 { messageCallback_ = std::move(cb); }

1.5 CountDownLatch Class

Because the muduo library is asynchronously operated by both the server and the client, if we send data when the connection has not been fully established, this is not allowed. Therefore, we can use the built-in CountDownLatch class for synchronization control. The specific idea is to give the counter count an initial value, such as 1. When the connection is successfully established, we reduce the value to 0 before loop event monitoring is carried out. Otherwise, we will be in a state of blocking and waiting for the connection to avoid the client entering event monitoring before the connection has been established successfully. This is illogical.

 class CountDownLatch : noncopyable
 {
 public:
     explicit CountDownLatch(int count);
     void wait(){
         MutexLockGuard lock(mutex_);
         while (count_ > 0)
         {
             condition_.wait();
         }
     }
 
     void countDown(){
         MutexLockGuard lock(mutex_);--count_;
         if (count_ == 0)
         {
             condition_.notifyAll();
         }
     }
     int getCount() const;
 private:
     mutable MutexLock mutex_;
     Condition condition_ GUARDED_BY(mutex_);
     int count_ GUARDED_BY(mutex_);
 };

1.6 Introduction to the basics of the Buffer class

class Buffer : public muduo::copyable
 {
 public:
 static const size_t kCheapPrepend = 8;
 static const size_t kInitialSize = 1024;
 explicit Buffer(size_t initialSize = kInitialSize)
     : buffer_(kCheapPrepend + initialSize),
     readerIndex_(kCheapPrepend),
     writerIndex_(kCheapPrepend);
 void swap(Buffer& rhs)
 size_t readableBytes() const
 size_t writableBytes() const
 const char* peek() const
 const char* findEOL() const
 const char* findEOL(const char* start) const
 void retrieve(size_t len)
 void retrieveInt64()
 void retrieveInt32()
 void retrieveInt16()
 void retrieveInt8()
 string retrieveAllAsString()
 string retrieveAsString(size_t len)
 void append(const StringPiece& str)
 void append(const char* /*restrict*/ data, size_t len)
 void append(const void* /*restrict*/ data, size_t len)
 char* beginWrite()
 const char* beginWrite() const
 void hasWritten(size_t len)
 void appendInt64(int64_t x)
 void appendInt32(int32_t x)
 void appendInt16(int16_t x)
 void appendInt8(int8_t x)
 int64_t readInt64()
 int32_t readInt32()
 int16_t readInt16()
 int8_t readInt8()
 int64_t peekInt64() const
 int32_t peekInt32() const
 int16_t peekInt16() const
 int8_t peekInt8() const
 void prependInt64(int64_t x)
 void prependInt32(int32_t x)
 void prependInt16(int16_t x)
 void prependInt8(int8_t x)
 void prepend(const void* /*restrict*/ data, size_t len)
 private:
 std::vector<char> buffer_;
 size_t readerIndex_;
 size_t writerIndex_;
 static const char kCRLF[];
 };

In the Buffer class, the interface we use this time is retrieveAllAsString(). Since the request interval for our dictionary translation is relatively long, the data in the default buffer is a complete translation request. Therefore, we use the retrieveAllAsString() interface to read all the data in the buffer as a complete request.

2. Muduo library English-Chinese translation service

2.1 English-translated Chinese TCP server

/*
     Implement a translation server, the client sends an English word and returns a Chinese word
 */
 
 
#include &lt;muduo/net/&gt;
#include &lt;muduo/net/&gt;
#include &lt;muduo/net/&gt;
#include &lt;muduo/net/&gt;
#include &lt;muduo/net/&gt;
#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;unordered_map&gt;
 
 
class DicServer{
public:
    DicServer(int port)
        :_server(&amp;_baseloop,
        muduo::net::InetAddress("0.0.0.0",port),
        "DicServer",muduo::net::TcpServer::Option::kReusePort)
    {
        //Set the callback for the connection event (connection establishment/management)        _server.setConnectionCallback(std::bind(&amp;DicServer::onConnection,this,std::placeholders::_1));
        //Set the callback for the connection message        _server.setMessageCallback(std::bind(&amp;DicServer::onMessage,this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3));
 
    }
 
    void start()
    {
        _server.start();    //Start monitoring first        _baseloop.loop();   //Start the dead cycle event monitoring again    }
private:
    void onConnection(const muduo::net::TcpConnectionPtr &amp;conn)
    {
        if(conn-&gt;connected())
            std::cout&lt;&lt;"Connection established!\n";
        else
            std::cout&lt;&lt;"Disconnection!\n";
    }
 
    void onMessage(const muduo::net::TcpConnectionPtr &amp;conn,muduo::net::Buffer *buf,muduo::Timestamp)
    {
        static std::unordered_map&lt;std::string,std::string&gt; dict_map={
            {"hello","Hello"},
            {"world","world"},
            {"worker","Working people"}
        };
        std::string msg=buf-&gt;retrieveAllAsString();
        std::string res;
        auto it=dict_map.find(msg);
        if(it != dict_map.end())
            res=it-&gt;second;
        else    
            res="Unknown word!";
        
        conn-&gt;send(res);
    }
 
public:
    muduo::net::EventLoop _baseloop;
    muduo::net::TcpServer _server;
 
};
 
int main()
{
    DicServer server(9090);
    ();
    return 0;
}

2.2 English-Chinese translation client

#include &lt;muduo/net/&gt;
#include &lt;muduo/net/&gt;
#include &lt;muduo/net/&gt;
#include &lt;muduo/net/&gt;
#include &lt;muduo/net/&gt;
#include &lt;iostream&gt;
#include &lt;string&gt;
 
 
class DictClient{
public:
    DictClient(const std::string &amp;sip,int sport)
        :_baseloop(_loopthrad.startLoop())
        ,_downlatch(1) //Initialize the counter to 1, and will wake up only if it is 0        ,_client(_baseloop,muduo::net::InetAddress(sip,sport),"DicClient")
    {
        //Set the callback for connection event (connection establishment/management)        _client.setConnectionCallback(std::bind(&amp;DictClient::onConnection,this,std::placeholders::_1));
        //Set the callback for the connection message        _client.setMessageCallback(std::bind(&amp;DictClient::onMessage,this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3));
        
        //Connect the server        _client.connect();
        _downlatch.wait();
    }
 
    bool send(const std::string &amp;msg)
    {
        if(_conn-&gt;connected() ==false)
        {
            std::cout&lt;&lt;"The connection has been disconnected, and the data has failed to be sent!\n";
            return false;
        }
        _conn-&gt;send(msg);
    }
private:
    void onConnection(const muduo::net::TcpConnectionPtr &amp;conn)
    {
        if(conn-&gt;connected())
        {
            std::cout&lt;&lt;"Connection established!\n";
            _downlatch.countDown();//Count --, wake up blocking when it is 0            _conn=conn;
        }
        else
        {
            std::cout&lt;&lt;"Disconnection!\n";
            _conn.reset();
        }
    }
 
    void onMessage(const muduo::net::TcpConnectionPtr &amp;conn,muduo::net::Buffer *buf,muduo::Timestamp)
    {
        std::string res = buf-&gt;retrieveAllAsString();
        std::cout&lt;&lt; res &lt;&lt;std::endl;
    }
 
 
private:
    muduo::net::TcpConnectionPtr _conn;
    muduo::CountDownLatch _downlatch;
    muduo::net::EventLoopThread _loopthrad;
    muduo::net::EventLoop *_baseloop;
    muduo::net::TcpClient _client;
 
};
 
 
int main()
{
    DictClient client("127.0.0.1",9090);
    while(1)
    {
        std::string msg;
        std::cin&gt;&gt;msg;
        (msg);
    }
    return 0;
}

2.3 makefile file

CFLAG= -std=c++11 -I ../../../../build/release-install-cpp11/include/
LFLAG= -L../../../../build/release-install-cpp11/lib  -lmuduo_net -lmuduo_base -pthread
 
all: server client
server: 
	g++  $(CFLAG) $^ -o $@ $(LFLAG)
client: 
	g++  $(CFLAG) $^ -o $@ $(LFLAG)

CFLAG: Process the header files contained in the file

LFLAG: The library that specifies the link

3. Conclusion

The above is the detailed content of C++ using the Muduo library to implement the English-Chinese translation function. For more information about C++ Muduo's English-Chinese translation, please pay attention to my other related articles!