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& listenAddr,const string& nameArg,Option option = kNoReusePort); void setThreadNum(int numThreads); void start(); /// Called when a new connection is successfully created void setConnectionCallback(const ConnectionCallback& 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& 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 <muduo/net/> #include <muduo/net/> #include <muduo/net/> #include <muduo/net/> #include <muduo/net/> #include <iostream> #include <string> #include <unordered_map> class DicServer{ public: DicServer(int port) :_server(&_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(&DicServer::onConnection,this,std::placeholders::_1)); //Set the callback for the connection message _server.setMessageCallback(std::bind(&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 &conn) { if(conn->connected()) std::cout<<"Connection established!\n"; else std::cout<<"Disconnection!\n"; } void onMessage(const muduo::net::TcpConnectionPtr &conn,muduo::net::Buffer *buf,muduo::Timestamp) { static std::unordered_map<std::string,std::string> dict_map={ {"hello","Hello"}, {"world","world"}, {"worker","Working people"} }; std::string msg=buf->retrieveAllAsString(); std::string res; auto it=dict_map.find(msg); if(it != dict_map.end()) res=it->second; else res="Unknown word!"; conn->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 <muduo/net/> #include <muduo/net/> #include <muduo/net/> #include <muduo/net/> #include <muduo/net/> #include <iostream> #include <string> class DictClient{ public: DictClient(const std::string &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(&DictClient::onConnection,this,std::placeholders::_1)); //Set the callback for the connection message _client.setMessageCallback(std::bind(&DictClient::onMessage,this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3)); //Connect the server _client.connect(); _downlatch.wait(); } bool send(const std::string &msg) { if(_conn->connected() ==false) { std::cout<<"The connection has been disconnected, and the data has failed to be sent!\n"; return false; } _conn->send(msg); } private: void onConnection(const muduo::net::TcpConnectionPtr &conn) { if(conn->connected()) { std::cout<<"Connection established!\n"; _downlatch.countDown();//Count --, wake up blocking when it is 0 _conn=conn; } else { std::cout<<"Disconnection!\n"; _conn.reset(); } } void onMessage(const muduo::net::TcpConnectionPtr &conn,muduo::net::Buffer *buf,muduo::Timestamp) { std::string res = buf->retrieveAllAsString(); std::cout<< res <<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>>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!