C++使用Muduo库实现英译汉功能
目录
- 一、前言
- 二、正文
- 1.Muduo库常见接口介绍
- 1.1 TcpServer类基础介绍
- 1.2 EventLoop类
- 1.3 TcpConnection类
- 1.4 TcpClient类基础介绍
- 1.5 CountDownLatch 类
- 1.6 Buffer类基础介绍
- 2. Muduo库英译汉服务
- 2.1 英译汉TCP服务器
- 2.2 英译汉客户端
- 2.3 makefile文件
- 三、结语
一、前言
在本文将会为大家介绍Muduo库常用的一些接口,并借助这些接口来实现一个简单版的英译汉服务器和客户端,希望能够帮助大家加深对Muduo库的使用!!!!
二、正文
1.Muduo库常见接口介绍
1.1 TcpServer类基础介绍
● TcpConnectionPtr
typedef std::shared_ptr<TcpConnection> TcpConnectionPtr;
TcpConnectionPtr属于TcpConnection类,但是我们在编写服务器的时候也需要接受客户端的连接,当连接到来的时候,由连接事件的回调函数来处理连接
● ConnectionCallback
typedef std::function<void (const TcpConnectionPtr&)> ConnectionCallback;
ConnectionCallback是服务器处理连接事情的回调函数,当有来自客户端的连接到来时,就会自动调用该函数来处理连接
● MessageCallback
typedef std::function<void (const TcpConnectionPtr&, Buffer*, Timestamp)> MessageCallback;
MessageCallback是服务器处理连接消息的回调函数,当客户端传来消息时,就会自动调用该函数来处理消息
● InetAddress
class InetAddress : public muduo::copyable { public: InetAddress(StringArg ip, uint16_t port, bool ipv6 = false); };
InetAddress 字段与服务器的设置有关,该字段将ip,port与ipv6合并成为一个字段,当我们设置服务器的时候就需要传递该字段,来指明服务器的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(); /// 当⼀个新连接建⽴成功的时候被调⽤ void setConnectionCallback(const ConnectionCallback& cb { connectionCallback_ = cb; } ///消息的业务处理回调函数--这是收到新连接消息的时候被调⽤的函数 void setMessageCallback (const MessageCallback& cb) { messageCallback_ = cb; } };
TcpServer类则是我们等会字典服务器要使用的主体,在其构造函数中我们要传递InetAddress字段,表明ip和端口号;传递EventLoop指针来进行事件监控,Option选项则是指明服务器端口是否服用;start函数则是启动服务器;在启动服务器之前,我们还需要设置连接建立回调函数和消息处理的回调函数
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); www.devze.com/// 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类是帮助我们服务器进行事件监控的,一旦调用loop( )函数就会一直死循环进入事件监控的状态
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与连接相关的类常用函数的有:
①判断当前的连接情况——connected() / disconnected()
②向连接的远端服务端发送消息——send()
1.4 TcpClient类基础介绍
● TcpClient
TcpClient(EventLoop* loop,const InetAddress&ahttp://www.devze.commp; serverAddr, const string& nameArg);
对于TcpClient的构造需要传递loop指针进行事件监控,InetAddress来指明服务端的IP和port,nameArg则是指明TcpClient的命名
●void connect()
调用该函数,TcpClient则会向已经设置好的远端服务器进行连接
●void disconnect()
调用该函数,TcpClient则会取消与远端服务器的连接
●void setConnectionCallback(ConnectionCallback cb)
/// 连接服务器成功时的回调函数 void setConnectionCallback(ConnectionCallback cb) { connectionCallback_ = std::move(cb); }
●void setMessageCallback(MessageCallback cb)
/// 收到服务器发送的消息时的回调函数 void setMessageCallback(MessageCallback cb) { messageCallback_ = std::move(cb); }
1.5 CountDownLatch 类
因为 muduo 库不管是服务端还是客⼾端都是异步操作, 对于客⼾端来说如果我们在连接还没有完全建⽴成功的时候发送数据,这是不被允许的。 因此我们可以使⽤内置的CountDownLatch 类进⾏同步控制。具体的思路就是给计数器count一个初值,比如说1,当连接建立成功的时候,我们将该值减少为0,才进行loop的事件监控,否则就一直处于阻塞等待连接的状态,避免client还没有建立连接成功,就进入事件的监控,这是不符合逻辑的。
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类基础介绍
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(),由于我们字典翻译的请求间隔时间比较长,因此默认缓冲区里的数据就是一次完整的翻译请求,所以我们就使用retrieveAllAsString()接口将缓冲区的数据全部读作为一次完整的请求
2. Muduo库英译汉服务
2.1 英译汉TCP服务器
/* 实现一个翻译服务器,客户端发送过来一个英语单词,返回一个汉语词语 */ #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) { //设置连接事件(连接建立/管理)的回调 _server.setConnectionCallback(std::bind(&DicServer::onConnection,this,std::placeholders::_1)); //设置连接消息的回调 _server.setMessageCallback(std::bind(&DicServer::onMessage,this,std::placeholders::glEJhQu_1,std::placeholders::_2,std::placeholders::_3)); } void start() { _server.start(); //先开始监听 _baseloop.loop(); //再开始死循环事件监控 } 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) //初始化计数器为1,只有为0时才会唤醒 ,_client(_baseloop,muduo::net::InetAddress(sip,sport),"DicClient") { //设置连接事件(连接建立/管理)的回调 _client.setConnectionCallback(std::bind(&DictClient::onConnection,this,std::placeholders::_1)); //设置连接消息的回调 _client.setMessageCallback(std::bind(&DictClient::onMessage,this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3)); //连接服务器 _client.connect(); _downlatch.wait(); } bool send(const std::string &msg) { if(_conn->connected() ==false) { std::cout<<"连接已经断开,发送数据失败!\n"; retu编程客栈rn false; } _conn->send(msg); } private: void onConnection(const muduo::net::TcpConnectionPtr &conn) { if(conn->connected()) { std::cout<<"连接建立!\n"; _downlatch.countDown();//计数--,为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:指明链接的库
三、结语
以上就是C++使用Muduo库实现英译汉功能的详细内容,更多关于C++ Muduo英译汉的资料请关注编程客栈(www.devze.com)其它相关文章!
精彩评论