C++使用Muduo庫實現(xiàn)英譯漢功能
一、前言
在本文將會為大家介紹Muduo庫常用的一些接口,并借助這些接口來實現(xiàn)一個簡單版的英譯漢服務(wù)器和客戶端,希望能夠幫助大家加深對Muduo庫的使用!?。?!
二、正文
1.Muduo庫常見接口介紹
1.1 TcpServer類基礎(chǔ)介紹
● TcpConnectionPtr
typedef std::shared_ptr<TcpConnection> TcpConnectionPtr;
TcpConnectionPtr屬于TcpConnection類,但是我們在編寫服務(wù)器的時候也需要接受客戶端的連接,當(dāng)連接到來的時候,由連接事件的回調(diào)函數(shù)來處理連接
● ConnectionCallback
typedef std::function<void (const TcpConnectionPtr&)> ConnectionCallback;
ConnectionCallback是服務(wù)器處理連接事情的回調(diào)函數(shù),當(dāng)有來自客戶端的連接到來時,就會自動調(diào)用該函數(shù)來處理連接
● MessageCallback
typedef std::function<void (const TcpConnectionPtr&, Buffer*, Timestamp)> MessageCallback;
MessageCallback是服務(wù)器處理連接消息的回調(diào)函數(shù),當(dāng)客戶端傳來消息時,就會自動調(diào)用該函數(shù)來處理消息
● InetAddress
class InetAddress : public muduo::copyable { public: InetAddress(StringArg ip, uint16_t port, bool ipv6 = false); };
InetAddress 字段與服務(wù)器的設(shè)置有關(guān),該字段將ip,port與ipv6合并成為一個字段,當(dāng)我們設(shè)置服務(wù)器的時候就需要傳遞該字段,來指明服務(wù)器的ip地址,端口號和是否采取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(); /// 當(dāng)?個新連接建?成功的時候被調(diào)? void setConnectionCallback(const ConnectionCallback& cb { connectionCallback_ = cb; } ///消息的業(yè)務(wù)處理回調(diào)函數(shù)--這是收到新連接消息的時候被調(diào)?的函數(shù) void setMessageCallback (const MessageCallback& cb) { messageCallback_ = cb; } };
TcpServer類則是我們等會字典服務(wù)器要使用的主體,在其構(gòu)造函數(shù)中我們要傳遞InetAddress字段,表明ip和端口號;傳遞EventLoop指針來進行事件監(jiān)控,Option選項則是指明服務(wù)器端口是否服用;start函數(shù)則是啟動服務(wù)器;在啟動服務(wù)器之前,我們還需要設(shè)置連接建立回調(diào)函數(shù)和消息處理的回調(diào)函數(shù)
1.2 EventLoop類
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_); };
EventLoop類是幫助我們服務(wù)器進行事件監(jiān)控的,一旦調(diào)用loop( )函數(shù)就會一直死循環(huán)進入事件監(jiān)控的狀態(tài)
1.3 TcpConnection類
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_; };
在TcpConnection與連接相關(guān)的類常用函數(shù)的有:
①判斷當(dāng)前的連接情況——connected() / disconnected()
②向連接的遠端服務(wù)端發(fā)送消息——send()
1.4 TcpClient類基礎(chǔ)介紹
● TcpClient
TcpClient(EventLoop* loop,const InetAddress& serverAddr, const string& nameArg);
對于TcpClient的構(gòu)造需要傳遞loop指針進行事件監(jiān)控,InetAddress來指明服務(wù)端的IP和port,nameArg則是指明TcpClient的命名
●void connect()
調(diào)用該函數(shù),TcpClient則會向已經(jīng)設(shè)置好的遠端服務(wù)器進行連接
●void disconnect()
調(diào)用該函數(shù),TcpClient則會取消與遠端服務(wù)器的連接
●void setConnectionCallback(ConnectionCallback cb)
/// 連接服務(wù)器成功時的回調(diào)函數(shù) void setConnectionCallback(ConnectionCallback cb) { connectionCallback_ = std::move(cb); }
●void setMessageCallback(MessageCallback cb)
/// 收到服務(wù)器發(fā)送的消息時的回調(diào)函數(shù) void setMessageCallback(MessageCallback cb) { messageCallback_ = std::move(cb); }
1.5 CountDownLatch 類
因為 muduo 庫不管是服務(wù)端還是客?端都是異步操作, 對于客?端來說如果我們在連接還沒有完全建?成功的時候發(fā)送數(shù)據(jù),這是不被允許的。 因此我們可以使?內(nèi)置的CountDownLatch 類進?同步控制。具體的思路就是給計數(shù)器count一個初值,比如說1,當(dāng)連接建立成功的時候,我們將該值減少為0,才進行l(wèi)oop的事件監(jiān)控,否則就一直處于阻塞等待連接的狀態(tài),避免client還沒有建立連接成功,就進入事件的監(jiān)控,這是不符合邏輯的。
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 Buffer類基礎(chǔ)介紹
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[]; };
在Buffer類中,我們這次用到的接口是retrieveAllAsString(),由于我們字典翻譯的請求間隔時間比較長,因此默認緩沖區(qū)里的數(shù)據(jù)就是一次完整的翻譯請求,所以我們就使用retrieveAllAsString()接口將緩沖區(qū)的數(shù)據(jù)全部讀作為一次完整的請求
2. Muduo庫英譯漢服務(wù)
2.1 英譯漢TCP服務(wù)器
/* 實現(xiàn)一個翻譯服務(wù)器,客戶端發(fā)送過來一個英語單詞,返回一個漢語詞語 */ #include <muduo/net/TcpServer.h> #include <muduo/net/EventLoop.h> #include <muduo/net/TcpConnection.h> #include <muduo/net/TcpClient.h> #include <muduo/net/Buffer.h> #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) { //設(shè)置連接事件(連接建立/管理)的回調(diào) _server.setConnectionCallback(std::bind(&DicServer::onConnection,this,std::placeholders::_1)); //設(shè)置連接消息的回調(diào) _server.setMessageCallback(std::bind(&DicServer::onMessage,this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3)); } void start() { _server.start(); //先開始監(jiān)聽 _baseloop.loop(); //再開始死循環(huán)事件監(jiān)控 } private: void onConnection(const muduo::net::TcpConnectionPtr &conn) { if(conn->connected()) std::cout<<"連接建立!\n"; else std::cout<<"連接斷開!\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","你好"}, {"world","世界"}, {"worker","打工人"} }; std::string msg=buf->retrieveAllAsString(); std::string res; auto it=dict_map.find(msg); if(it != dict_map.end()) res=it->second; else res="未知單詞!"; conn->send(res); } public: muduo::net::EventLoop _baseloop; muduo::net::TcpServer _server; }; int main() { DicServer server(9090); server.start(); return 0; }
2.2 英譯漢客戶端
#include <muduo/net/TcpClient.h> #include <muduo/net/EventLoop.h> #include <muduo/net/EventLoopThread.h> #include <muduo/net/TcpClient.h> #include <muduo/net/Buffer.h> #include <iostream> #include <string> class DictClient{ public: DictClient(const std::string &sip,int sport) :_baseloop(_loopthrad.startLoop()) ,_downlatch(1) //初始化計數(shù)器為1,只有為0時才會喚醒 ,_client(_baseloop,muduo::net::InetAddress(sip,sport),"DicClient") { //設(shè)置連接事件(連接建立/管理)的回調(diào) _client.setConnectionCallback(std::bind(&DictClient::onConnection,this,std::placeholders::_1)); //設(shè)置連接消息的回調(diào) _client.setMessageCallback(std::bind(&DictClient::onMessage,this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3)); //連接服務(wù)器 _client.connect(); _downlatch.wait(); } bool send(const std::string &msg) { if(_conn->connected() ==false) { std::cout<<"連接已經(jīng)斷開,發(fā)送數(shù)據(jù)失??!\n"; return false; } _conn->send(msg); } private: void onConnection(const muduo::net::TcpConnectionPtr &conn) { if(conn->connected()) { std::cout<<"連接建立!\n"; _downlatch.countDown();//計數(shù)--,為0時喚醒阻塞 _conn=conn; } else { std::cout<<"連接斷開!\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; client.send(msg); } return 0; }
2.3 makefile文件
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: server.cpp g++ $(CFLAG) $^ -o $@ $(LFLAG) client: client.cpp g++ $(CFLAG) $^ -o $@ $(LFLAG)
CFLAG:處理文件中包含的頭文件
LFLAG:指明鏈接的庫
三、結(jié)語
以上就是C++使用Muduo庫實現(xiàn)英譯漢功能的詳細內(nèi)容,更多關(guān)于C++ Muduo英譯漢的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C++中關(guān)鍵字const的詳細說明和使用介紹(最全)
const在C/C++中是十分重要的,如果單純理解為“常量”那么你的格局就小了,今天在這里給大家介紹一下const在C++中具體詳細的用法,需要的朋友可以參考下2025-03-03關(guān)于c++編譯protobuf時提示LNK2001 無法解析的外部符號的問題
這篇文章主要介紹了關(guān)于c++編譯protobuf時提示LNK2001 無法解析的外部符號的問題,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-12-12