C++使用Muduo庫(kù)實(shí)現(xiàn)英譯漢功能
一、前言
在本文將會(huì)為大家介紹Muduo庫(kù)常用的一些接口,并借助這些接口來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單版的英譯漢服務(wù)器和客戶(hù)端,希望能夠幫助大家加深對(duì)Muduo庫(kù)的使用?。。?!
二、正文
1.Muduo庫(kù)常見(jiàn)接口介紹
1.1 TcpServer類(lèi)基礎(chǔ)介紹
● TcpConnectionPtr
typedef std::shared_ptr<TcpConnection> TcpConnectionPtr;
TcpConnectionPtr屬于TcpConnection類(lèi),但是我們?cè)诰帉?xiě)服務(wù)器的時(shí)候也需要接受客戶(hù)端的連接,當(dāng)連接到來(lái)的時(shí)候,由連接事件的回調(diào)函數(shù)來(lái)處理連接
● ConnectionCallback
typedef std::function<void (const TcpConnectionPtr&)> ConnectionCallback;
ConnectionCallback是服務(wù)器處理連接事情的回調(diào)函數(shù),當(dāng)有來(lái)自客戶(hù)端的連接到來(lái)時(shí),就會(huì)自動(dòng)調(diào)用該函數(shù)來(lái)處理連接
● MessageCallback
typedef std::function<void (const TcpConnectionPtr&, Buffer*, Timestamp)> MessageCallback;
MessageCallback是服務(wù)器處理連接消息的回調(diào)函數(shù),當(dāng)客戶(hù)端傳來(lái)消息時(shí),就會(huì)自動(dòng)調(diào)用該函數(shù)來(lái)處理消息
● InetAddress
class InetAddress : public muduo::copyable { public: InetAddress(StringArg ip, uint16_t port, bool ipv6 = false); };
InetAddress 字段與服務(wù)器的設(shè)置有關(guān),該字段將ip,port與ipv6合并成為一個(gè)字段,當(dāng)我們?cè)O(shè)置服務(wù)器的時(shí)候就需要傳遞該字段,來(lái)指明服務(wù)器的ip地址,端口號(hào)和是否采取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)?個(gè)新連接建?成功的時(shí)候被調(diào)? void setConnectionCallback(const ConnectionCallback& cb { connectionCallback_ = cb; } ///消息的業(yè)務(wù)處理回調(diào)函數(shù)--這是收到新連接消息的時(shí)候被調(diào)?的函數(shù) void setMessageCallback (const MessageCallback& cb) { messageCallback_ = cb; } };
TcpServer類(lèi)則是我們等會(huì)字典服務(wù)器要使用的主體,在其構(gòu)造函數(shù)中我們要傳遞InetAddress字段,表明ip和端口號(hào);傳遞EventLoop指針來(lái)進(jìn)行事件監(jiān)控,Option選項(xiàng)則是指明服務(wù)器端口是否服用;start函數(shù)則是啟動(dòng)服務(wù)器;在啟動(dòng)服務(wù)器之前,我們還需要設(shè)置連接建立回調(diào)函數(shù)和消息處理的回調(diào)函數(shù)
1.2 EventLoop類(lèi)
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類(lèi)是幫助我們服務(wù)器進(jìn)行事件監(jiān)控的,一旦調(diào)用loop( )函數(shù)就會(huì)一直死循環(huán)進(jìn)入事件監(jiān)控的狀態(tài)
1.3 TcpConnection類(lèi)
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)的類(lèi)常用函數(shù)的有:
①判斷當(dāng)前的連接情況——connected() / disconnected()
②向連接的遠(yuǎn)端服務(wù)端發(fā)送消息——send()
1.4 TcpClient類(lèi)基礎(chǔ)介紹
● TcpClient
TcpClient(EventLoop* loop,const InetAddress& serverAddr, const string& nameArg);
對(duì)于TcpClient的構(gòu)造需要傳遞loop指針進(jìn)行事件監(jiān)控,InetAddress來(lái)指明服務(wù)端的IP和port,nameArg則是指明TcpClient的命名
●void connect()
調(diào)用該函數(shù),TcpClient則會(huì)向已經(jīng)設(shè)置好的遠(yuǎn)端服務(wù)器進(jìn)行連接
●void disconnect()
調(diào)用該函數(shù),TcpClient則會(huì)取消與遠(yuǎn)端服務(wù)器的連接
●void setConnectionCallback(ConnectionCallback cb)
/// 連接服務(wù)器成功時(shí)的回調(diào)函數(shù) void setConnectionCallback(ConnectionCallback cb) { connectionCallback_ = std::move(cb); }
●void setMessageCallback(MessageCallback cb)
/// 收到服務(wù)器發(fā)送的消息時(shí)的回調(diào)函數(shù) void setMessageCallback(MessageCallback cb) { messageCallback_ = std::move(cb); }
1.5 CountDownLatch 類(lèi)
因?yàn)?muduo 庫(kù)不管是服務(wù)端還是客?端都是異步操作, 對(duì)于客?端來(lái)說(shuō)如果我們?cè)谶B接還沒(méi)有完全建?成功的時(shí)候發(fā)送數(shù)據(jù),這是不被允許的。 因此我們可以使?內(nèi)置的CountDownLatch 類(lèi)進(jìn)?同步控制。具體的思路就是給計(jì)數(shù)器count一個(gè)初值,比如說(shuō)1,當(dāng)連接建立成功的時(shí)候,我們將該值減少為0,才進(jìn)行l(wèi)oop的事件監(jiān)控,否則就一直處于阻塞等待連接的狀態(tài),避免client還沒(méi)有建立連接成功,就進(jìn)入事件的監(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類(lèi)基礎(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類(lèi)中,我們這次用到的接口是retrieveAllAsString(),由于我們字典翻譯的請(qǐng)求間隔時(shí)間比較長(zhǎng),因此默認(rèn)緩沖區(qū)里的數(shù)據(jù)就是一次完整的翻譯請(qǐng)求,所以我們就使用retrieveAllAsString()接口將緩沖區(qū)的數(shù)據(jù)全部讀作為一次完整的請(qǐng)求
2. Muduo庫(kù)英譯漢服務(wù)
2.1 英譯漢TCP服務(wù)器
/* 實(shí)現(xiàn)一個(gè)翻譯服務(wù)器,客戶(hù)端發(fā)送過(guò)來(lái)一個(gè)英語(yǔ)單詞,返回一個(gè)漢語(yǔ)詞語(yǔ) */ #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(); //先開(kāi)始監(jiān)聽(tīng) _baseloop.loop(); //再開(kāi)始死循環(huán)事件監(jiān)控 } private: void onConnection(const muduo::net::TcpConnectionPtr &conn) { if(conn->connected()) std::cout<<"連接建立!\n"; else std::cout<<"連接斷開(kāi)!\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 英譯漢客戶(hù)端
#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) //初始化計(jì)數(shù)器為1,只有為0時(shí)才會(huì)喚醒 ,_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)斷開(kāi),發(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();//計(jì)數(shù)--,為0時(shí)喚醒阻塞 _conn=conn; } else { std::cout<<"連接斷開(kāi)!\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:指明鏈接的庫(kù)
三、結(jié)語(yǔ)
以上就是C++使用Muduo庫(kù)實(shí)現(xiàn)英譯漢功能的詳細(xì)內(nèi)容,更多關(guān)于C++ Muduo英譯漢的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C++中關(guān)鍵字const的詳細(xì)說(shuō)明和使用介紹(最全)
const在C/C++中是十分重要的,如果單純理解為“常量”那么你的格局就小了,今天在這里給大家介紹一下const在C++中具體詳細(xì)的用法,需要的朋友可以參考下2025-03-03C++實(shí)現(xiàn)教務(wù)管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)教務(wù)管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06C++使用GDAL庫(kù)實(shí)現(xiàn)Tiff文件的讀取
這篇文章主要為大家詳細(xì)介紹了C++使用GDAL庫(kù)實(shí)現(xiàn)Tiff文件的讀取的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-03-03C++模擬實(shí)現(xiàn)STL容器vector的示例代碼
這篇文章主要為大家詳細(xì)介紹了C++如何模擬實(shí)現(xiàn)STL容器vector的相關(guān)資料,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C++有一定幫助,需要的可以參考一下2022-11-11用C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單掃雷小游戲
這篇文章主要為大家詳細(xì)介紹了用C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單掃雷小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07關(guān)于c++編譯protobuf時(shí)提示LNK2001 無(wú)法解析的外部符號(hào)的問(wèn)題
這篇文章主要介紹了關(guān)于c++編譯protobuf時(shí)提示LNK2001 無(wú)法解析的外部符號(hào)的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12OpenCV實(shí)現(xiàn)相機(jī)標(biāo)定板
這篇文章主要為大家詳細(xì)介紹了OpenCV實(shí)現(xiàn)相機(jī)標(biāo)定板,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-04-04