C++使用Muduo庫實(shí)現(xiàn)英譯漢功能
一、前言
在本文將會為大家介紹Muduo庫常用的一些接口,并借助這些接口來實(shí)現(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指針來進(jìn)行事件監(jiān)控,Option選項(xiàng)則是指明服務(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ù)器進(jìn)行事件監(jiān)控的,一旦調(diào)用loop( )函數(shù)就會一直死循環(huán)進(jì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()
②向連接的遠(yuǎn)端服務(wù)端發(fā)送消息——send()
1.4 TcpClient類基礎(chǔ)介紹
● TcpClient
TcpClient(EventLoop* loop,const InetAddress& serverAddr, const string& nameArg);
對于TcpClient的構(gòu)造需要傳遞loop指針進(jìn)行事件監(jiān)控,InetAddress來指明服務(wù)端的IP和port,nameArg則是指明TcpClient的命名
●void connect()
調(diào)用該函數(shù),TcpClient則會向已經(jīng)設(shè)置好的遠(yuǎn)端服務(wù)器進(jìn)行連接
●void disconnect()
調(diào)用該函數(shù),TcpClient則會取消與遠(yuǎn)端服務(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 類
因?yàn)?muduo 庫不管是服務(wù)端還是客?端都是異步操作, 對于客?端來說如果我們在連接還沒有完全建?成功的時候發(fā)送數(shù)據(jù),這是不被允許的。 因此我們可以使?內(nèi)置的CountDownLatch 類進(jìn)?同步控制。具體的思路就是給計數(shù)器count一個初值,比如說1,當(dāng)連接建立成功的時候,我們將該值減少為0,才進(jìn)行l(wèi)oop的事件監(jiān)控,否則就一直處于阻塞等待連接的狀態(tài),避免client還沒有建立連接成功,就進(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類基礎(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(),由于我們字典翻譯的請求間隔時間比較長,因此默認(rèn)緩沖區(qū)里的數(shù)據(jù)就是一次完整的翻譯請求,所以我們就使用retrieveAllAsString()接口將緩沖區(qū)的數(shù)據(jù)全部讀作為一次完整的請求
2. Muduo庫英譯漢服務(wù)
2.1 英譯漢TCP服務(wù)器
/*
實(shí)現(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庫實(shí)現(xiàn)英譯漢功能的詳細(xì)內(nèi)容,更多關(guān)于C++ Muduo英譯漢的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C++中關(guān)鍵字const的詳細(xì)說明和使用介紹(最全)
const在C/C++中是十分重要的,如果單純理解為“常量”那么你的格局就小了,今天在這里給大家介紹一下const在C++中具體詳細(xì)的用法,需要的朋友可以參考下2025-03-03
C++實(shí)現(xiàn)教務(wù)管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)教務(wù)管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-06-06
C++使用GDAL庫實(shí)現(xiàn)Tiff文件的讀取
這篇文章主要為大家詳細(xì)介紹了C++使用GDAL庫實(shí)現(xiàn)Tiff文件的讀取的相關(guān)知識,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-03-03
C++模擬實(shí)現(xiàn)STL容器vector的示例代碼
這篇文章主要為大家詳細(xì)介紹了C++如何模擬實(shí)現(xiàn)STL容器vector的相關(guān)資料,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)C++有一定幫助,需要的可以參考一下2022-11-11
關(guān)于c++編譯protobuf時提示LNK2001 無法解析的外部符號的問題
這篇文章主要介紹了關(guān)于c++編譯protobuf時提示LNK2001 無法解析的外部符號的問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-12-12
OpenCV實(shí)現(xiàn)相機(jī)標(biāo)定板
這篇文章主要為大家詳細(xì)介紹了OpenCV實(shí)現(xiàn)相機(jī)標(biāo)定板,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-04-04

