目錄linux
---恢復內容開始---ios
個人主要文件夾分爲三個:分別爲客戶端,cppjieba分詞庫,離線部分及服務器部分c++
==啓動時服務器:==數據庫
==客戶端連入時時服務器:==編程
==輸入「趙」==json
==輸入「周杰倫」==數組
==輸入清華大學==緩存
==啓動時服務器:==安全
==客戶端連入時時服務器:==服務器
==輸入student:==
==輸入spell:==
==輸入computer:==
==Makefile:==
SRCS:=$(wildcard *.cc) OBJS:= $(patsubst %.cc, %.o, $(SRCS)) CXX:=g++ CXXFLAGS:= -w -g -std=c++11 $(addprefix -I, $(INC_DIR)) $(LIBS) -Wno-deprecated -I ../cppjieba/include/ -I ../cppjieba/deps EXE:=./main $(EXE):$(OBJS) $(CXX) -o $(EXE) $(OBJS) $(CXXFLAGS) clean: rm -rf $(EXE) rm -rf $(OBJS)
==Configuration:==
///======================================= /// File: Configuration.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-12 00:30:39 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __CONFIGURATION_H__ #define __CONFIGURATION_H__ #include "Nocopyable.h" #include <string> #include <map> using namespace std; class Configuration :public Noncopyable { public: Configuration(const string &filePath); string getEnglishDir() const {return _englishDir;} string getChineseDir() const {return _chineseDir;} private: string _filePath; string _englishDir; string _chineseDir; }; template<typename T> class Singleton { public: template<typename ...Args> static T* getInstance(Args ...args) { if(!_pInstance) _pInstance = new T(args...); return _pInstance; } static void destroy() { if(_pInstance) delete _pInstance; } private: Singleton(); ~Singleton(); static T *_pInstance; }; template<typename T> T * Singleton<T>::_pInstance = NULL; #endif
1 ///======================================= 2 /// File: Configuration.cc 3 /// Author: wtptorres(1584292712@qq.com) 4 /// Date: 2019-06-12 00:30:04 5 /// Dream: Don't forget your dreams! 6 /// ====================================== 7 8 9 #include "Configuration.h" 10 #include <utility> 11 #include <fstream> 12 #include <iostream> 13 using namespace std; 14 15 Configuration::Configuration(const string &filePath) 16 :_filePath(std::move(filePath)) 17 { 18 ifstream ifs(_filePath); 19 if(!ifs) 20 cout<<"file open error!"<<endl; 21 ifs>>_englishDir; 22 ifs>>_chineseDir; 23 ifs.close(); 24 }
///======================================= /// File: Nocopyable.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-12 00:24:36 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __NOCOPYABLE_H__ #define __NOCOPYABLE_H__ class Noncopyable { public: Noncopyable()=default; ~Noncopyable()=default; private: Noncopyable(const Noncopyable &rhs); Noncopyable &operator =(const Noncopyable &rhs); }; #endif
==DictProducer:==
///======================================= /// File: DictProducer.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-12 16:40:25 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __DICTPRODUCER_H__ #define __DICTPRODUCER_H__ #include "SplitTool.h" using namespace std; #include "Nocopyable.h" #include <memory> #include <string> #include <vector> #include <map> #include <utility> class DictProducer :public Noncopyable { public: DictProducer(const string,const string,const string &,SplitToolJieba *); ~DictProducer(){} void build_dict(); void build_cn_dict(); void store_dict(); vector<pair<string,int>>& getIndict(){return _indict;} private: void processEnglishWord(string &word); void processChineseWord(string &word);//除去中文的數字 void construct_indict(); string _englishDir; string _chineseDir; string _goleFilePath; vector<string> _englishFiles; vector<string> _chineseFiles; map<string,int> _dict; vector<pair<string,int>> _indict; shared_ptr<SplitToolJieba> _splitTool; }; #endif
///======================================= /// File: DictProducer.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-12 16:50:46 /// Dream: Don't forget your dreams! /// ====================================== #include "DictProducer.h" #include <cctype> #include <utility> #include <fstream> #include <iostream> #define FIRSTSIZE 10000 using namespace std; DictProducer::DictProducer(const string englishDir,const string chineseDir,const string &goleFilePath,SplitToolJieba *splitToolPtr) :_englishDir(englishDir) ,_chineseDir(chineseDir) ,_goleFilePath(goleFilePath) { _splitTool.reset(splitToolPtr); std::ifstream ifsEnglish(_englishDir); std::ifstream ifsChinese(_chineseDir); string filePath; if(!ifsEnglish || !ifsChinese){ cout<<"Dict file open error!"<<endl; } while(ifsEnglish>>filePath) { _englishFiles.push_back(filePath); } while(ifsChinese>>filePath) { _chineseFiles.push_back(filePath); } _indict.reserve(FIRSTSIZE); } void DictProducer::processEnglishWord(string &word) { auto cit =word.begin(); for(;cit!=word.end();++cit) { //去除標點符號或數字 if(!isalpha(*cit)){ word.erase(cit); --cit;//迭代器位置發生改變 }else if(isupper(*cit)){//將大寫字母改成小寫 *cit =tolower(*cit); } } } void DictProducer::processChineseWord(string &word) { auto cit =word.begin(); for(;cit!=word.end();++cit) { //去除數字 if(!isalnum(*cit)){ word.erase(cit); --cit; } } } void DictProducer::build_dict()//創建英文詞典 { for(auto &filePath:_englishFiles) { ifstream ifs(filePath); if(!ifs){ cout<<"English File open error!"<<endl; } string word; while(ifs>>word) { processEnglishWord(word); auto cit =_dict.find(word); if(word.size()>0 && cit ==_dict.end()){ _dict.insert(std::make_pair(word,1)); }else if(cit!=_dict.end()){ ++ cit ->second; } } } } void DictProducer::build_cn_dict() { vector<string>words; for(auto filePath:_chineseFiles) { ifstream ifs(filePath); if(!ifs){ cout<<"Chinese file open error!"<<endl; } string sentence; while(std::getline(ifs,sentence)) { _splitTool->Cut(sentence); } } vector<string>& results =_splitTool->getResult(); for(auto &res:results) { processChineseWord(res); auto cit =_dict.find(res); if(cit ==_dict.end()){ _dict.insert(std::make_pair(res,1)); }else{ ++ cit ->second; } } } void DictProducer::store_dict() { construct_indict(); ofstream ofs(_goleFilePath); if(!ofs) cout<<"Store_dict open file error!"<<endl; for(auto &mypair:_indict) { ofs<<mypair.first<<" "<<mypair.second<<endl; } ofs.close(); } void DictProducer::construct_indict() { for(auto dictpair:_dict){ _indict.push_back(dictpair); } }
==GetIndex:==
///======================================= /// File: GetIndex.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-12 08:52:04 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __GETINDEX_H__ #define __GETINDEX_H__ #include <string> #include <unordered_map> #include <set> #include <vector> #include <utility> #include <unordered_set> using namespace std; class GetIndex { public: GetIndex(const string &,const string &,const string &); ~GetIndex(){} void construct_index(); void store_index(); private: bool isEnglish(const string &rhs) const; vector<string>getOneCharacter(const string & word); string _sourceFilePath; string _goleFilePath; string _stopWordsFilePath; vector<pair<string,int>>_dict; unordered_set<string>_stopWords; unordered_map<string,set<int>>_index; }; #endif
///======================================= /// File: GetIndex.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-12 09:00:11 /// Dream: Don't forget your dreams! /// ====================================== #include "GetIndex.h" #include <fstream> #include <sstream> #include <iostream> using namespace std; GetIndex::GetIndex(const string & sourceFilePath,const string &goleFilePath,const string &stopWordsFilePath) :_sourceFilePath(std::move(sourceFilePath)) ,_goleFilePath(std::move(goleFilePath)) ,_stopWordsFilePath(std::move(stopWordsFilePath)) { ifstream ifs(_sourceFilePath); if(!ifs){ cout<<"GetIndex file open error!"<<endl; } string line; while(getline(ifs,line)) { istringstream iss(line); string key; int value; iss>>key>>value; _dict.push_back(std::make_pair(key,value)); } ifstream ifs1(_stopWordsFilePath); if(!ifs1){ cout<<"file open error!"<<endl; } string stopWord; while(ifs1>>stopWord,!ifs1.eof()) { _stopWords.insert(stopWord); } } vector<string> GetIndex::getOneCharacter(const string &word) { vector<string>tmp; auto cit =word.begin(); while(cit<word.end()) { if(224==(*cit &224)) { string oneCharacter; oneCharacter.append(cit,cit+3); tmp.push_back(oneCharacter); cit +=3; }else if(240==(*cit &240)){ string oneCharacter; oneCharacter.append(cit,cit+4); tmp.push_back(oneCharacter); cit +=4; }else break; } return tmp; } bool GetIndex::isEnglish(const string &rhs) const { char ch =*(rhs.begin()); if(ch<0) return false; return true; } #if 0 bool GetIndex::isEnglish(const string &rhs) const { char ch =*(rhs.begin()); if(ch<0){ return false; } return true; } #endif void GetIndex::construct_index() { for(size_t i=0;i!=_dict.size();++i) { string tmp=_dict[i].first; if(isEnglish(tmp)) { for(auto ch:tmp) { string charactor(1,ch); if(isalpha(ch)) { auto cit =_index.find(charactor); if(cit ==_index.end()) { set<int> smp; smp.insert(i); _index.insert(std::make_pair(charactor,smp)); }else{//已經存在了該字母的索引 cit->second.insert(i); } } } }else{//中文處理部分 vector<string> oneCharacterRally =getOneCharacter(tmp); for(auto oneCharacter:oneCharacterRally) {//stop_words中不存在該單詞,則加入索引中 if(_stopWords.find(oneCharacter)==_stopWords.end()){ auto it =_index.find(oneCharacter); if(it == _index.end()){ set<int>tmp; tmp.insert(i); _index.insert(std::make_pair(oneCharacter,tmp)); }else{ it->second.insert(i); } } } } } } void GetIndex::store_index() { //ofs存儲索引的內容 std::ofstream ofs(_goleFilePath); if(!ofs){ cout<<"file open error!"<<endl; return; } for(auto data:_index) { ofs<<data.first<<" "; for(auto linenum:data.second) { ofs<<linenum<<" "; } ofs<<endl; } ofs.close(); }
==SplitTool:==
///======================================= /// File: SplitTool.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-12 17:12:01 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __SPLITTOOL_H__ #define __SPLITTOOL_H__ #include "../cppjieba/include/cppjieba/Jieba.hpp"//須要本身將cppjieba安裝在項目目錄下 #include "Configuration.h" #include <string> #include <vector> using namespace std; using namespace cppjieba; class SplitToolJieba { public: SplitToolJieba(const string& dict_path,const string &model_path,const string &user_dict_path,const string & idfPath, const string &stopWordPath) :_jieba(dict_path,model_path,user_dict_path,idfPath,stopWordPath) {} ~SplitToolJieba(){} void Cut(const string & sentence) { vector<string>tmp; _jieba.Cut(sentence,tmp); _result.insert(_result.end(),tmp.begin(),tmp.end()); } vector<string> & getResult(){return _result;} private: vector<string> _result; cppjieba::Jieba _jieba; }; #endif
==main:==
///======================================= /// File: main.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-12 20:38:50 /// Dream: Don't forget your dreams! /// ====================================== #include "Configuration.h" #include "SplitTool.h" using namespace std; #include "DictProducer.h" #include "GetIndex.h" #include <iostream> #include <memory> const char * const DICT_PATH ="../cppjieba/dict/jieba.dict.utf8"; const char * const HMM_PATH ="../cppjieba/dict/hmm_model.utf8"; const char * const USER_DICT_PATH ="../cppjieba/dict/user.dict.utf8"; const char * const IDF_PATH ="../cppjieba/dict/idf.utf8"; const char * const STOP_WORD_PATH ="../cppjieba/dict/stop_words.utf8"; const string GOLE_DICT_PATH="../server/data/dict.txt"; const string GOLE_INDEX_PATH="../server/data/index.txt"; class SplitTool; int main(void) { Configuration *pconfig =Singleton<Configuration>::getInstance("configure.txt"); SplitToolJieba *ptool =new SplitToolJieba(DICT_PATH,HMM_PATH,USER_DICT_PATH,IDF_PATH,STOP_WORD_PATH); DictProducer mydictProducer(pconfig->getEnglishDir(),pconfig->getChineseDir(),GOLE_DICT_PATH,ptool); mydictProducer.build_dict();//創建英語詞典 mydictProducer.build_cn_dict();//創建中文詞典 mydictProducer.store_dict();//儲存詞典 GetIndex myindex(GOLE_DICT_PATH,GOLE_INDEX_PATH,"stop_words_zh.txt"); myindex.construct_index();//創建索引 myindex.store_index();//存儲索引 Singleton<Configuration>::destroy(); return 0; }
==ConFiguration:==
///======================================= /// File: ConFiguration.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-06 10:32:43 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __CONFIGURATION_H__ #define __CONFIGURATION_H__ #include "Noncopyable.h" #include <string> #include <map> #define CONFPATH "/home/wtp/spell/server/conf/configure.txt" using namespace std; namespace wd { class Configuration :public Noncopyable { public: Configuration(const string &filePath); ~Configuration()=default; string getDictDir() const; string getIndexDir() const; string getIp()const; string getCache() const; unsigned short getPort() const; private: string _filePath; map<string,string> _conf; }; }; template<typename T> class Singleton { public: template<typename ...Args> static T *getInstance(Args ...args) { if(!_pInstance) _pInstance=new T(args ...); return _pInstance; } static void destroy() { if(_pInstance) delete _pInstance; } private: Singleton(); ~Singleton(); static T *_pInstance; }; template<typename T> T *Singleton<T>::_pInstance =NULL; #endif
///======================================= /// File: ConFiguration.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 15:24:14 /// Dream: Don't forget your dreams! /// ====================================== #include "ConFiguration.h" #include <stdlib.h> #include <utility> #include <fstream> #include <iostream> using namespace std; using namespace wd; wd::Configuration::Configuration(const string & filePath) :_filePath(std::move(filePath)) { ifstream ifs(_filePath); if(!ifs){ cout<<"file open error!"<<endl; } string key,value; while(ifs>>key) { ifs>>value; _conf.insert(std::make_pair(key,value)); } ifs.close(); } string wd::Configuration::getDictDir() const { auto cit=_conf.find("mydict"); if(cit== _conf.end()) return ""; else return cit->second; } string wd::Configuration::getIndexDir() const { auto cit =_conf.find("myindex"); if(cit== _conf.end()) return ""; else return cit->second; } string wd::Configuration::getIp() const { auto cit =_conf.find("myip"); if(cit ==_conf.end()) return ""; else return cit->second; } unsigned short wd::Configuration::getPort() const { auto cit =_conf.find("myport"); if(cit==_conf.end()) return 0; else return atoi(cit->second.c_str()); } string wd::Configuration::getCache() const { auto cit =_conf.find("mycache"); if(cit ==_conf.end()) return ""; else return cit->second; }
==Acceptor:==
///======================================= /// File: Acceptor.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-05 23:47:05 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __WD_ACCEPTOR_H__ #define __WD_ACCEPTOR_H__ #include "Socket.h" #include "InetAddress.h" namespace wd { class Acceptor { public: Acceptor(int listenfd,const InetAddress & addr); void ready();//服務器監聽準備 int accept();//服務器接收新鏈接 int fd()const {return _listenSock.fd();} private: void setReuseAddr(bool on);//設置地址重用 void setReusePort(bool on);//設置端口重用 void bind();//綁定 void listen();//監聽 Socket _listenSock; InetAddress _addr; }; } #endif
///======================================= /// File: Acceptor.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-05 23:52:12 /// Dream: Don't forget your dreams! /// ====================================== #include <iostream> #include "Acceptor.h" #include "SocketUtil.h" namespace wd { Acceptor::Acceptor(int listenfd,const InetAddress & addr) :_listenSock(listenfd) ,_addr(addr) {} void Acceptor::ready() { setReuseAddr(true); setReusePort(true); bind(); listen(); } int Acceptor::accept() { int peerfd=::accept(_listenSock.fd(),NULL,NULL); if(-1==peerfd) { perror("accept error!"); } return peerfd; } void Acceptor::setReuseAddr(bool flag) { int on=(flag?1:0); if(::setsockopt(_listenSock.fd() ,SOL_SOCKET ,SO_REUSEADDR ,&on ,static_cast<socklen_t>(size_t(on)))==-1) { perror("setsockopt reuseaddr error!"); ::close(_listenSock.fd()); exit(EXIT_FAILURE); } } void Acceptor::setReusePort(bool flag) { #ifndef SO_REUSEPORT int on=(flag?1:0); if(::setsockopt(_listenSock.fd() ,SOL_SOCKET ,SO_REUSEADDR ,&on ,static_cast<socklen_t>(size_t(on)))==-1) { perror("setsockopt reuseport error!"); ::close(_listenSock.fd()); exit(EXIT_FAILURE); } #else if(flag) { fprintf(stderr,"SO_REUSEPORT is not supported!\n"); } #endif } void Acceptor::bind() { if(-1==::bind(_listenSock.fd() ,(const struct sockaddr*)_addr.getSockAddrPtr() ,sizeof(InetAddress))) { perror("bind error!"); ::close(_listenSock.fd()); exit(EXIT_FAILURE); } } void Acceptor::listen() { if(-1==::listen(_listenSock.fd(),10)) { perror("listen error!"); ::close(_listenSock.fd()); exit(EXIT_FAILURE); } } } #if 0 int main() { std::cout<<"Acceptor is correct!"<<std::endl; } #endif
==Condition.h:==
#ifndef __WD_CONDITION_H__ #define __WD_CONDITION_H__ #include "Noncopyable.h" #include "MutexLock.h" #include <pthread.h> namespace wd { class Condition :Noncopyable { public: Condition(MutexLock &mutex) :_mutex(mutex) {pthread_cond_init(&_cond,NULL);} ~Condition() {pthread_cond_destroy(&_cond);} void wait() {pthread_cond_wait(&_cond,_mutex.getMutexLockPtr());} void notify() {pthread_cond_signal(&_cond);} void notifyAll() {pthread_cond_broadcast(&_cond);} private: pthread_cond_t _cond; MutexLock & _mutex; }; } #endif
==Cache:==
///======================================= /// File: Cache.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-05 19:52:40 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __CACHE_H__ #define __CACHE_H__ #include <unordered_map> #include <string> using namespace std; namespace wd { class Cache { public: void addElement(string,string);//增長緩存信息 void readFromFile(string);//從文件中讀取信息 void writeToFile(string);//將信息寫入文件中 void update(const Cache&);//更新緩存消息 bool find(string querry);//從數據庫中找尋信息 string &operator[](string key); private: unordered_map<string,string>_hashTable;//採用hashTable進行緩存 }; }; #endif
///======================================= /// File: Cache.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-05 20:01:25 /// Dream: Don't forget your dreams! /// ====================================== #include "Cache.h" #include <fstream> #include <utility> #include <iostream> using namespace std; using namespace wd; void Cache::addElement(string querry,string result) { _hashTable[querry]=result; } void Cache::readFromFile(string filePath) { ifstream ifs(filePath); if(!ifs){ cout<<"Cache::read readFromFile file open error!"<<endl; return; } string querry,result; while(ifs>>querry,!ifs.eof()) { ifs>>result; _hashTable[querry]=result; } } #if 0 void Cache::writeToFile(string filePath) { ofstream ofs(filePath); if(!ofs){ cout<<""<<endl; return; } for(auto &mypair:_hashTable) { ofs<<mypair.first<<" "; ofs<<mypair.second<<endl; } } void Cache::update(const Cache & cache) { for(auto &mypair:cache._hashTable) { auto cit =_hashTable.find(mypair.first); if(cit==_hashTable.end()) { _hashTable.insert(std::move(mypair)); } } } #endif void Cache::writeToFile(string filePath) { ofstream ofs(filePath); if(!ofs){ cout<<"file write error!"<<endl; return; } for(auto &mypair:_hashTable) { ofs<<mypair.first<<" "; ofs<<mypair.second<<endl; } } void Cache::update(const Cache & cache) { for(auto &mypair:cache._hashTable) { auto cit =_hashTable.find(mypair.first); if(cit==_hashTable.end()) { _hashTable.insert(std::move(mypair)); } } } bool Cache::find(string querry) { auto cit =_hashTable.find(querry); if(cit==_hashTable.end()) return false; return true; } string &Cache::operator[](string key) { return _hashTable[key]; } #if 0 int main() { cout<<"cache is correct!"<<endl; } #endif
==CacheManger:==
///======================================= /// File: CacheManger.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-05 20:51:09 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __CACHEMANGER_H__ #define __CACHEMANGER_H__ #include "Cache.h" #include <vector> #define THREADNUM 4//線程數目設置爲4個,可自定義 using std::vector; namespace wd { class CacheManger { public: CacheManger(string filePath); void init(string);//建立緩存 Cache & getCache(size_t);//獲取某個緩存 void periodicUpdate();//定時更新全部緩存 private: string _cacheFilePath; vector<Cache>_cacheList; }; }; #endif
///======================================= /// File: CacheManger.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-05 20:56:50 /// Dream: Don't forget your dreams! /// ====================================== #include "CacheManger.h" #include <iostream> #include <fstream> #include <utility> #include <iostream> using namespace std; using namespace wd; CacheManger::CacheManger(string cacheFilePath) { init(cacheFilePath); } void CacheManger::init(string cacheFilePath) { _cacheFilePath=cacheFilePath; _cacheList.reserve(THREADNUM); Cache tmp; tmp.readFromFile(_cacheFilePath); for(size_t i=0;i!=THREADNUM;++i) { _cacheList.push_back(std::move(tmp)); } } Cache & CacheManger::getCache(size_t number) { return _cacheList[number]; } void CacheManger::periodicUpdate() { auto cit=_cacheList.begin(); Cache lastWrite=*(cit ++); for(;cit<_cacheList.end();++cit) { lastWrite.update(*cit); } for(cit=_cacheList.begin()+1;cit!=_cacheList.end();++cit) { (*cit).update(lastWrite); } lastWrite.writeToFile(_cacheFilePath); }
==EpollPoller:==
///======================================= /// File: EpollPoller.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-06 11:03:36 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __WD_EPOLLPOLLER_H__ #define __WD_EPOLLPOLLER_H__ #include "TcpConnection.h" #include "Noncopyable.h" #include "MutexLock.h" #include <sys/epoll.h> #include <vector> #include <map> #include <functional> namespace wd { class Acceptor; class EpollPoller :Noncopyable { public: typedef TcpConnection::TcpConnectionCallback EpollCallback; typedef std::function<void()> Functor; EpollPoller(Acceptor &acceptor); ~EpollPoller(); void loop(); void unloop(); void runInLoop(const Functor && cb); void doPendingFunctors(); void wakeup(); void setConnectionCallback(EpollCallback cb); void setMessageCallback(EpollCallback cb); void setCloseCallback(EpollCallback cb); private: void waitEpollfd(); void handleConnection(); void handleMessage(int peerfd); void handleRead(); Acceptor & _acceptor; int _epollfd; int _eventfd; int _listenfd; bool _isLooping; MutexLock _mutex; std::vector<Functor> _pendingFunctors; typedef std::vector<struct epoll_event>Eventlist; Eventlist _eventList; typedef std::map<int,TcpConnectionPtr> ConnectionMap; ConnectionMap _connMap; EpollCallback _onConnectionCb; EpollCallback _onMessageCb; EpollCallback _onCloseCb; }; } #endif
///======================================= /// File: EpollPoller.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 15:42:54 /// Dream: Don't forget your dreams! /// ====================================== #include "EpollPoller.h" #include "SocketUtil.h" #include "Acceptor.h" #include <assert.h> #include <iostream> using namespace std; namespace wd { EpollPoller::EpollPoller(Acceptor & acceptor) :_acceptor(acceptor) ,_epollfd(createEpollFd()) ,_eventfd(createEventFd()) ,_listenfd(_acceptor.fd()) ,_isLooping(false) ,_eventList(1024) { addEpollFdRead(_epollfd,_listenfd); addEpollFdRead(_epollfd,_eventfd); } EpollPoller::~EpollPoller() { ::close(_epollfd); } void EpollPoller::loop() { _isLooping=true; while(_isLooping) { waitEpollfd(); } } void EpollPoller::unloop() { if(_isLooping) _isLooping=false; } void EpollPoller::setConnectionCallback(EpollCallback cb) { _onConnectionCb=cb; } void EpollPoller::setMessageCallback(EpollCallback cb) { _onMessageCb=cb; } void EpollPoller::setCloseCallback(EpollCallback cb) { _onCloseCb=cb; } void EpollPoller::waitEpollfd() { int nready; do { nready =::epoll_wait(_epollfd,&(*_eventList.begin()),_eventList.size(),10000); }while(-1==nready && errno ==EINTR); if(-1==nready){ perror("epoll wait error!"); exit(EXIT_FAILURE); }else if(0==nready){ cout<<"epoll_wait timeout!"<<endl; }else{//擴容 if(nready==static_cast<int>(_eventList.size())){ _eventList.resize(_eventList.size()*2); } for(int idx=0;idx!=nready;++idx)//正宗羅老師循環體(TwT) { if(_eventList[idx].data.fd ==_listenfd) { if(_eventList[idx].events & EPOLLIN) { handleConnection(); } }else if(_eventList[idx].data.fd ==_eventfd){ handleRead(); cout<<">>doPendingFunctors()"<<endl; doPendingFunctors(); }else{ if(_eventList[idx].events & EPOLLIN){ handleMessage(_eventList[idx].data.fd); } } } } } void EpollPoller::handleConnection() { int peerfd=_acceptor.accept(); addEpollFdRead(_epollfd,peerfd); TcpConnectionPtr conn(new TcpConnection(peerfd,this)); conn->setConnectionCallback(_onConnectionCb); conn->setMessageCallback(_onMessageCb); conn->setCloseCallback(_onCloseCb); std::pair<ConnectionMap::iterator,bool>ret; ret=_connMap.insert(std::make_pair(peerfd,conn)); assert(ret.second ==true); (void)ret; conn->handleConnectionCallback(); } void EpollPoller::handleMessage(int peerfd) { bool isClosed=isConnectionClosed(peerfd); ConnectionMap::iterator it =_connMap.find(peerfd); assert(it!=_connMap.end()); if(isClosed) { it->second->handleCloseCallback(); delEpollReadFd(_epollfd,peerfd); _connMap.erase(it); }else{ it->second->handleMessageCallback(); } } void EpollPoller::runInLoop(const Functor && cb)//在計算線程中執行 { MutexLockGuard mlg(_mutex); _pendingFunctors.push_back(std::move(cb)); wakeup(); } void EpollPoller::doPendingFunctors() { std::vector<Functor>tmp; { MutexLockGuard mlg(_mutex); tmp.swap(_pendingFunctors); } for(auto & functor:tmp) { functor(); } } void EpollPoller::handleRead() { uint64_t howmany; int ret=::read(_eventfd,&howmany,sizeof(howmany)); if(ret !=sizeof(howmany)) { perror("read error!"); } } void EpollPoller::wakeup() { uint64_t one =1; int ret =::write(_eventfd,&one,sizeof(one)); if(ret!=sizeof(one)) { perror("write error!"); } } }
==InetAddress:==
///======================================= /// File: InetAddress.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-05 21:55:19 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __WD_INETADDRESS_H__ #define __WD_INETADDRESS_H__ #include <netinet/in.h> #include <string> namespace wd { class InetAddress { public: InetAddress(short port); InetAddress(const char *pIp,short port); InetAddress(const struct sockaddr_in & addr); std::string ip()const; unsigned short port() const; const struct sockaddr_in *getSockAddrPtr() const; private: struct sockaddr_in _addr; }; } #endif
///======================================= /// File: InetAddress.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 20:55:18 /// Dream: Don't forget your dreams! /// ====================================== #include "InetAddress.h" #include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <arpa/inet.h> #include <string.h> namespace wd { InetAddress::InetAddress(short port) { ::memset(&_addr,0,sizeof(_addr)); _addr.sin_family=AF_INET; _addr.sin_port=htons(port); _addr.sin_addr.s_addr=INADDR_ANY; } InetAddress::InetAddress(const char * pIp,short port) { ::memset(&_addr,0,sizeof(_addr)); _addr.sin_family=AF_INET; _addr.sin_port=htons(port); _addr.sin_addr.s_addr=inet_addr(pIp); } InetAddress::InetAddress(const struct sockaddr_in & addr) :_addr(addr) {} const struct sockaddr_in * InetAddress::getSockAddrPtr()const { return & _addr; } std::string InetAddress::ip()const { return std::string(inet_ntoa(_addr.sin_addr)); } unsigned short InetAddress::port() const { return ntohs(_addr.sin_port); } }
==MutexLock:==
#ifndef __WD_MUTEXLOCK_H__ #define __WD_MUTEXLOCK_H__ #include "Noncopyable.h" #include <pthread.h> namespace wd { class MutexLock :Noncopyable { public: MutexLock() {pthread_mutex_init(&_mutex,NULL);} ~MutexLock() {pthread_mutex_destroy(&_mutex);} void lock() {pthread_mutex_lock(&_mutex);} void unlock() {pthread_mutex_unlock(&_mutex);} pthread_mutex_t *getMutexLockPtr() {return &_mutex;} private: pthread_mutex_t _mutex; }; class MutexLockGuard//C++之父BS提出的RAII { public: MutexLockGuard(MutexLock &mutex) :_mutex(mutex) { _mutex.lock(); } ~MutexLockGuard() { _mutex.unlock(); } private: MutexLock &_mutex; }; } #endif
==Mydict:==
///======================================= /// File: Mydict.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-06 11:12:19 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __MYDICT_H__ #define __MYDICT_H__ #include <string> #include <vector> #include <map> #include <utility> #include <set> #include <fstream> #include <iostream> #include <sstream> using namespace std; namespace wd { struct MyResult { string _word; int _iFreq;//詞頻 int _iDist;//最小編輯距離 }; class Mydict { public: Mydict(const string dictDir,const string indexDir) { ifstream ifs1(dictDir),ifs2(indexDir); if(!ifs1||!ifs2) cout<<"Mydict open file error!"<<endl; string key; int value; ifs1>>value; _dict.push_back(std::make_pair(string(" "),value)); ifs1>>value; _dict.push_back(std::make_pair(string(" "),value)); while(ifs1>>key) { ifs1>>value; _dict.push_back(std::make_pair(key,value)); } string line; while(std::getline(ifs2,line)) { istringstream iss(line); string ikey; int ivalue; iss>>ikey; set<int> tmp; while(iss>>ivalue) { tmp.insert(ivalue); } _index.insert(std::make_pair(ikey,tmp)); } } vector<pair<string,int>> & getDict(){return _dict;} map<string ,set<int>> & getIndexTable(){return _index;} private: vector<pair<string,int>> _dict; map<string,set<int>> _index; }; } #endif
==MyTask:==
///======================================= /// File: MyTask.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-06 21:04:54 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __MYTASK_H__ #define __MYTASK_H__ #include "TcpConnection.h" #include "ConFiguration.h" #include "Mydict.h" #include "Cache.h" #include <string> #include <queue> using namespace std; class MyCompare { public: bool operator()(const wd::MyResult & lhs,const wd::MyResult &rhs) { if(lhs._iDist !=rhs._iDist) return lhs._iDist<rhs._iDist; else return lhs._iFreq>rhs._iFreq; } private: }; using Character =string; class MyTask { public: MyTask(const string &querry,const wd::TcpConnectionPtr conn) :_querry(std::move(querry)) ,_conn(conn) {} void execute(); private: void queryIndexTable();//查詢索引(四個索引) void statistic(set<int> &iset);//計算 int distance(const string & rhs);//計算最小編輯距離 bool response(wd::Cache & cache);//響應客戶端的請求 vector<Character>getOneCharacter(const string &word);//獲取字符數組 string _querry; wd::TcpConnectionPtr _conn; priority_queue<wd::MyResult,vector<wd::MyResult>,MyCompare> _resultQue; }; #endif
///======================================= /// File: MyTask.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 22:47:19 /// Dream: Don't forget your dreams! /// ====================================== #include "MyTask.h" #include "ConFiguration.h" #include "Mydict.h" #include "CacheManger.h" #include "json/json.h" #include <string.h> #include <algorithm> extern __thread int t_number; bool MyTask::response(wd::Cache &cache) { if(cache.find(_querry)) { _conn->sendInLoop(cache[_querry]); return true; } return false; } int MyTask::distance(const string &rhs) { vector<Character>querryCharacter =getOneCharacter(_querry); vector<Character>indexCharacter =getOneCharacter(rhs); int len1,len2; len1=querryCharacter.size(); len2=indexCharacter.size(); int edit[len1+1][len2+1]; int i,j; for(i=0;i<=len1;++i){ for(j=0;j<=len2;++j){ edit[i][j]=0; } } for(i=0;i<len1;++i){ edit[i][0]=i; } for(j=0;j<=len2;++j){ edit[0][j]=j; } for(i=1;i<len1;++i){ for(j=1;j<=len2;++j){ int cost =((querryCharacter[i-1]==indexCharacter[j-1])?0:1); int deletion =edit[i-1][j]+1; int insertion=edit[i][j-1]+1; int substitution=edit[i-1][j-1]+cost; edit[i][j]=std::min(deletion,std::min(insertion,substitution)); } } return edit[len1][len2]; } void MyTask::statistic(set<int> &iset) { vector<pair<string,int>>dict=(Singleton<wd::Mydict>::getInstance(Singleton<wd::Configuration>::getInstance(CONFPATH)->getDictDir(), Singleton<wd::Configuration>::getInstance(CONFPATH)->getIndexDir()))->getDict(); for(auto &idx:iset) { string key=dict[idx].first; int iDist =distance(key); if(iDist<=3) { wd::MyResult res; res._word=key; res._iDist=iDist; res._iFreq=dict[idx].second; _resultQue.push(res); } } } vector<Character>MyTask::getOneCharacter(const string & word) { auto cit =word.begin(); vector<Character> ret; while(cit<word.end()) { if(224==(*cit &224)){ Character oneCharacter; oneCharacter.append(cit,cit+3); ret.push_back(oneCharacter); cit =cit+3; }else if(240==(*cit &240)){ Character oneCharacter; oneCharacter.append(cit,cit+4); ret.push_back(oneCharacter); cit =cit+4; }else{ Character oneCharacter(1,*cit); ret.push_back(oneCharacter); cit ++; } } return ret; } void MyTask::queryIndexTable() { map<string,set<int>>index=(Singleton<wd::Mydict>::getInstance(Singleton<wd::Configuration>::getInstance(CONFPATH)->getDictDir(), Singleton<wd::Configuration>::getInstance(CONFPATH)->getIndexDir()))->getIndexTable(); vector<Character> oneCharacter=getOneCharacter(_querry); set<int>allRally; for(auto myCharacter:oneCharacter) { auto cit =index.find(myCharacter); if(cit!=index.end()) { for(auto &idx:cit->second) allRally.insert(idx); } } statistic(allRally); } void MyTask::execute() { wd::Cache &mycache =(Singleton<wd::CacheManger>::getInstance(Singleton<wd::Configuration>::getInstance(CONFPATH)->getCache()))->getCache(t_number); if(response(mycache)) return; else{ queryIndexTable(); Json::FastWriter writerinfo; Json::Value arrayObj; while(!_resultQue.empty()) { Json::Value new_item; new_item[""]=_resultQue.top()._word; _resultQue.pop(); arrayObj.append(new_item); } string strEmail=writerinfo.write(arrayObj); mycache.addElement(_querry,strEmail); _conn->sendInLoop(strEmail); } }
==Noncopyable:==
#ifndef __WD_NONCOPYABLE_H__ #define __WD_NONCOPYABLE_H__ namespace wd { class Noncopyable { protected: Noncopyable(){} ~Noncopyable(){} private: Noncopyable(const Noncopyable &); Noncopyable & operator=(const Noncopyable &); }; } #endif
==Socket:==
///======================================= /// File: Socket.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-05 21:46:26 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __WD_SOCKET_H__ #define __WD_SOCKET_H__ #include "Noncopyable.h" namespace wd { class InetAddress; class Socket :Noncopyable { public: Socket(int socket); Socket(); ~Socket(); void shutdownWrite(); int fd()const {return _sockfd;} void nonblock(); static InetAddress getLocalAddr(int socketfd); static InetAddress getPeerAddr(int sockfd); private: int _sockfd; }; } #endif
///======================================= /// File: Socket.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 20:38:20 /// Dream: Don't forget your dreams! /// ====================================== #include "Socket.h" #include "SocketUtil.h" #include "InetAddress.h" namespace wd { Socket::Socket(int sockfd) :_sockfd(sockfd) {} Socket::Socket() :_sockfd(createSocketFd()) {} Socket::~Socket() { ::close(_sockfd); } void Socket::nonblock() { setNonblock(_sockfd); } void Socket::shutdownWrite() { if(-1==::shutdown(_sockfd,SHUT_WR)){ perror("shutdown write error!"); } } InetAddress Socket::getLocalAddr(int sockfd) { struct sockaddr_in addr; socklen_t len=sizeof(sockaddr_in); if(-1==::getsockname(sockfd,(struct sockaddr *)&addr,&len)){ perror("getsockname error!"); } return InetAddress(addr); } InetAddress Socket::getPeerAddr(int sockfd) { struct sockaddr_in addr; socklen_t len=sizeof(sockaddr_in); if(-1==::getpeername(sockfd,(struct sockaddr *)&addr,&len)){ perror("getpeername error!"); } return InetAddress(addr); } }
==SocketIO:==
///======================================= /// File: SocketIO.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-06 17:10:23 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __SOCKETIO_H__ #define __SOCKETIO_H__ #include <stdio.h> namespace wd { class SocketIO { public: SocketIO(int sockfd); size_t readn(char *buf,size_t count); size_t writen(const char *buf,size_t count); size_t readline(char *buf,size_t max_len); private: size_t recv_peek(char *buf,size_t count); int _sockfd; }; } #endif
///======================================= /// File: SocketIO.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 21:56:34 /// Dream: Don't forget your dreams! /// ====================================== #include "SocketIO.h" #include "SocketUtil.h" namespace wd { SocketIO::SocketIO(int sockfd) :_sockfd(sockfd) {} size_t SocketIO::readn(char *buf,size_t count) { size_t nleft =count; char *pbuf=buf; while(nleft>0) { int nread =::read(_sockfd,pbuf,nleft); if(-1==nread) { if(errno ==EINTR) continue; return EXIT_FAILURE; }else if(0==nread){ break; } pbuf =pbuf+nread; nleft=nleft-nread; } return (count -nleft); } size_t SocketIO::writen(const char * buf,size_t count) { size_t nleft =count; const char *pbuf=buf; while(nleft >0) { int nwrite=::write(_sockfd,pbuf,nleft); if(-1==nwrite) { if(errno ==EINTR) continue; return EXIT_FAILURE; } nleft =nleft -nwrite; pbuf =pbuf +nwrite; } return (count -nleft); } size_t SocketIO::recv_peek(char *buf,size_t count) { int nread; do{ nread=::recv(_sockfd,buf,count,MSG_PEEK); }while(-1==nread && errno ==EINTR); return nread; } size_t SocketIO::readline(char *buf,size_t maxlen) { size_t nleft =maxlen-1; char *pbuf=buf; size_t total=0; while(nleft>0) { size_t nread =recv_peek(pbuf,nleft); if(nread<=0) return nread; for(size_t idx =0;idx!=nread;++idx){//檢查換行符/n if(pbuf[idx]=='\n'){ size_t nsize =idx +1; if(readn(pbuf,nsize)!=nsize) return EXIT_FAILURE; pbuf +=nsize; total +=nsize; *pbuf=0; return total; } } if(readn(pbuf,nread)!=nread) return EXIT_FAILURE; pbuf +=nread; nleft -=nread; total +=nread; } *pbuf=0; return maxlen-1; } }
==SockUtil(根據陳碩編寫的LINUX書上分開頭文件)==
///======================================= /// File: SocktUtil.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-05 22:01:30 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __WD_SOCKERUTIL_H__ #define __WD_SOCKERUTIL_H__ #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/eventfd.h> #include <sys/epoll.h> namespace wd { inline int createSocketFd() { int fd=::socket(AF_INET,SOCK_STREAM,0); if(-1==fd) { perror("socket create error!"); } return fd; } inline void setNonblock(int fd) { int flags=::fcntl(fd,F_GETFL,0); flags |= O_NONBLOCK; ::fcntl(fd,F_SETFL,flags); } inline int createEpollFd() { int efd=::epoll_create1(0); if(-1==efd) { perror("epoll create1 error!"); exit(EXIT_FAILURE); } return efd; } inline int createEventFd() { int evtfd=::eventfd(0,EFD_NONBLOCK|EFD_CLOEXEC); if(-1==evtfd) { perror("eventfd create error!"); } return evtfd; } inline void addEpollFdRead(int efd,int fd) { struct epoll_event ev; ev.data.fd=fd; ev.events=EPOLLIN; int ret=epoll_ctl(efd,EPOLL_CTL_ADD,fd,&ev); if(-1==ret) { perror("epoll ctl add error!"); exit(EXIT_FAILURE); } } inline void delEpollReadFd(int efd,int fd) { struct epoll_event ev; ev.data.fd=fd; int ret=epoll_ctl(efd,EPOLL_CTL_DEL,fd,&ev); if(-1==ret) { perror("epoll ctl delete error!"); exit(EXIT_FAILURE); } } inline size_t recvPeek(int sockfd,void *buf,size_t len) { int nread; do{ nread=::recv(sockfd,buf,len,MSG_PEEK); }while(nread==-1 && errno ==EINTR); return nread; } inline bool isConnectionClosed(int sockfd) { char buf[1024]; int nread=recvPeek(sockfd,buf,sizeof(buf)); if(-1==nread) { perror("recvPeek error!"); return true; } return (0==nread); } } #endif
==SpellCorrrectSever:==
///======================================= /// File: SpellCorrectServer.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-06 20:41:13 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __SPELLCORRECTSERVER_H__ #define __SPELLCORRECTSERVER_H__ #include "TcpServer.h" #include "Threadpool.h" using namespace wd; namespace wd { class SpellCorrectServer { public: SpellCorrectServer(const string & ip ,unsigned short port ,size_t threadNUM ,size_t queSize); void start(); private: void onConnection(const TcpConnectionPtr &); void onMessage(const TcpConnectionPtr &); void onClose(const TcpConnectionPtr &); TcpServer _tcpserver; Threadpool _threadpoll; }; }; #endif
///======================================= /// File: SpellCorrectServer.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 21:20:41 /// Dream: Don't forget your dreams! /// ====================================== #include "SpellCorrectServer.h" #include "MyTask.h" #include <stdio.h> #include <iostream> #include <string> #include <utility> #include <functional> using namespace std; void SpellCorrectServer::onConnection(const wd::TcpConnectionPtr & conn) { cout<<conn->toString()<<endl; conn->send("hello ,welcome to WTP Chat Server.\r\n"); } void SpellCorrectServer::onMessage(const wd::TcpConnectionPtr & conn) { string s(conn->receive()); MyTask task(s,conn); _threadpoll.addTask(std::bind(&MyTask::execute,&task)); cout<<">add task to threadpool"<<endl; } void SpellCorrectServer::onClose(const wd::TcpConnectionPtr &conn) { ::printf("%s close\n",conn->toString().c_str()); } SpellCorrectServer::SpellCorrectServer(const string & ip ,unsigned short port ,size_t threadNUM ,size_t queSize) :_tcpserver(ip,port) ,_threadpoll(threadNUM,queSize) {} void SpellCorrectServer::start() { _threadpoll.start(); _tcpserver.setConnectionCallback(std::bind(&SpellCorrectServer::onConnection,this,std::placeholders::_1)); _tcpserver.setMessageCallback(std::bind(&SpellCorrectServer::onMessage,this,std::placeholders::_1)); _tcpserver.setCloseCallback(std::bind(&SpellCorrectServer::onClose,this,std::placeholders::_1)); _tcpserver.start(); }
==TaskQue:==
#ifndef __WD_TASKQUEUE_H__ #define __WD_TASKQUEUE_H__ #include "MutexLock.h" #include "Condition.h" #include <queue> #include <functional> namespace wd { typedef std::function<void()>Task; class TaskQueue { public: TaskQueue(size_t queSize) :_queSize(queSize) ,_mutex() ,_notFull(_mutex) ,_notEmpty(_mutex) ,_flag(true) {} void push(Task &&task); Task pop(); bool empty()const { return _que.size()==0; } bool full()const {return _que.size()==_queSize;} void wakeup() { if(_flag) _flag=false; _notEmpty.notifyAll(); } private: size_t _queSize; std::queue<Task> _que; MutexLock _mutex; Condition _notFull; Condition _notEmpty; bool _flag; }; } #endif
#include "TaskQueue.h" using namespace wd; //生產者所在的線程 void TaskQueue::push(Task && task) { MutexLockGuard autoLock(_mutex); while(full()) { _notFull.wait(); } _que.push(std::move(task)); _notEmpty.notify(); } //消費者所在線程 Task TaskQueue::pop() { MutexLockGuard autoLock(_mutex); while(_flag && empty()) { _notEmpty.wait(); } if(_flag){ Task task=_que.front(); _que.pop(); _notFull.notify(); return task; }else{ return NULL; } } #if 0 Task TaskQueue::pop() { MutexLockGuard autoLock(_mutex); while(_flag && empty()) { _notEmpty.wait(); } if(_flag){ Task task =_que.front(); _que.pop(); _notFull.notify(); return task; }else{ return NULL; } } #endif
==TcpConnection:==
///======================================= /// File: TcpConnection.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-06 17:15:33 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __WD_TCPCONNECTION_H__ #define __WD_TCPCONNECTION_H__ #include "Noncopyable.h" #include "InetAddress.h" #include "Socket.h" #include "SocketIO.h" #include <string> #include <memory> #include <functional> namespace wd { class EpollPoller; class TcpConnection; typedef std::shared_ptr<TcpConnection> TcpConnectionPtr; class TcpConnection :Noncopyable ,public std::enable_shared_from_this<TcpConnection> { public: typedef std::function<void(const TcpConnectionPtr &)>TcpConnectionCallback; TcpConnection(int sockfd,EpollPoller *loop); ~TcpConnection(); std::string receive(); void send(const std::string &msg); void sendInLoop(const std::string &msg); void shutdown(); std::string toString(); void setConnectionCallback(TcpConnectionCallback cb); void setMessageCallback(TcpConnectionCallback cb); void setCloseCallback(TcpConnectionCallback cb); void handleConnectionCallback(); void handleMessageCallback(); void handleCloseCallback(); private: Socket _sockfd; SocketIO _sockIO; const InetAddress _localAddr; const InetAddress _peerAddr; bool _isShutdownWrite; EpollPoller * _loop; TcpConnectionCallback _onConnectionCb; TcpConnectionCallback _onMessageCb; TcpConnectionCallback _onCloseCb; }; } #endif
///======================================= /// File: TcpConnection.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 22:22:22 /// Dream: Don't forget your dreams! /// ====================================== #include "TcpConnection.h" #include "EpollPoller.h" #include <string.h> #include <stdio.h> namespace wd { TcpConnection::TcpConnection(int sockfd,EpollPoller * loop) :_sockfd(sockfd) ,_sockIO(sockfd) ,_localAddr(wd::Socket::getLocalAddr(sockfd)) ,_peerAddr(wd::Socket::getPeerAddr(sockfd)) ,_isShutdownWrite(false) ,_loop(loop) {_sockfd.nonblock();} TcpConnection::~TcpConnection() { if(!_isShutdownWrite) { _isShutdownWrite=true; shutdown(); } printf("~TcpConnection()\n"); } std::string TcpConnection::receive() { char buf[65536]; memset(buf,0,sizeof(buf)); size_t ret =_sockIO.readline(buf,sizeof(buf)); if(0==ret){ return std::string(); }else{ return std::string(buf); } } void TcpConnection::send(const std::string &msg) { size_t len=msg.size(); _sockIO.writen((const char *)&len,sizeof(int)); _sockIO.writen(msg.c_str(),len); } void TcpConnection::shutdown() { if(!_isShutdownWrite) _sockfd.shutdownWrite(); _isShutdownWrite=true; } std::string TcpConnection::toString() { char str[100]; snprintf(str,sizeof(str),"%s:%d->%s:%d" ,_localAddr.ip().c_str() ,_localAddr.port() ,_peerAddr.ip().c_str() ,_peerAddr.port()); return std::string(str); } void TcpConnection::setConnectionCallback(TcpConnectionCallback cb) { _onConnectionCb =cb; } void TcpConnection::setMessageCallback(TcpConnectionCallback cb) { _onMessageCb =cb; } void TcpConnection::setCloseCallback(TcpConnectionCallback cb) { _onCloseCb =cb; } void TcpConnection::handleConnectionCallback() { if(_onConnectionCb){ _onConnectionCb(shared_from_this()); } } void TcpConnection::handleMessageCallback() { if(_onMessageCb){ _onMessageCb(shared_from_this()); } } void TcpConnection::handleCloseCallback() { if(_onCloseCb){ _onCloseCb(shared_from_this()); } } void TcpConnection::sendInLoop(const std::string & msg) { _loop->runInLoop(std::bind(&TcpConnection::send,this,msg)); } }
==TcpServer:==
///======================================= /// File: TcpServer.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-06 20:15:21 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __WD_TCPSERVER_H__ #define __WD_TCPSERVER_H__ #include "Acceptor.h" #include "EpollPoller.h" #include <string> using std::string; namespace wd { class TcpServer { public: typedef EpollPoller::EpollCallback TcpServerCallback; TcpServer(const string & ip,unsigned short port); TcpServer(unsigned short port); void start(); void stop(); void setConnectionCallback(TcpServerCallback cb); void setMessageCallback(TcpServerCallback cb); void setCloseCallback(TcpServerCallback cb); private: Acceptor _acceptor; EpollPoller _poller; TcpServerCallback _connectionCallback; TcpServerCallback _messageCallback; TcpServerCallback _closeCallback; }; } #endif
///======================================= /// File: TcpServer.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 19:59:37 /// Dream: Don't forget your dreams! /// ====================================== #include "TcpServer.h" #include "InetAddress.h" #include "SocketUtil.h" #include <iostream> using namespace std; namespace wd { TcpServer::TcpServer(const string & ip,unsigned short port) :_acceptor(createSocketFd(),InetAddress(ip.c_str(),port)) ,_poller(_acceptor) {} void TcpServer::start() { _acceptor.ready(); _poller.setConnectionCallback(_connectionCallback); _poller.setMessageCallback(_messageCallback); _poller.setCloseCallback(_closeCallback); _poller.loop(); } void TcpServer::stop() { _poller.unloop(); } void TcpServer::setConnectionCallback(TcpServerCallback cb) {_connectionCallback=cb;} void TcpServer::setMessageCallback(TcpServerCallback cb) {_messageCallback=cb;} void TcpServer::setCloseCallback(TcpServerCallback cb) {_closeCallback=cb;} }
==Thread:==
#ifndef __WD_THREAD_H__ #define __WD_THREAD_H__ #include "Noncopyable.h" #include <pthread.h> #include <functional> using std::function; namespace wd { class Thread; struct ThreadPtr { int _number; Thread *_pthread; }; class Thread :Noncopyable { using ThreadCallback =function<void()>; public: Thread(ThreadCallback &&cb); ~Thread(); void start(int number); void join(); bool isRunning()const {return _isRunning;} private: static void * threadFunc(void *); pthread_t _pthid; bool _isRunning; ThreadCallback _cb; }; } #endif
#include "Thread.h" #include <iostream> using namespace std; using namespace wd; __thread int t_number;//將線程編號做爲線程存儲的標記 Thread::Thread(ThreadCallback && cb)//這裏的右值引用自己取決因而否有名字 :_pthid(0) ,_isRunning(false) ,_cb(std::move(cb)) { cout<<"Thread(cb)"<<endl; } void Thread::start(int number) { ThreadPtr *threadPtr=new ThreadPtr(); threadPtr->_number=number; threadPtr->_pthread=this; pthread_create(&_pthid,NULL,threadFunc,threadPtr); _isRunning=true; } void *Thread::threadFunc(void *arg) {//應用了線程存儲 ThreadPtr *threadPtr=static_cast<ThreadPtr*>(arg); Thread * pthread=threadPtr->_pthread; t_number=threadPtr->_number; if(pthread) pthread->_cb();//線程開始工做! delete threadPtr; //Thread * pthread =threadPtr->_pthread; return NULL; } #if 0 void *Thread::threadFunc(void *arg) { ThreadPtr *threadPtr =static_cast<ThreadPtr*>(arg); Thread * pthread =threadPtr->_pthread; t_number =threadPtr->_number; if(pthread) pthread->_cb(); delete threadPtr; return NULL; } #endif void Thread::join() { pthread_join(_pthid,NULL); _isRunning=false; } Thread::~Thread() { if(_isRunning) { pthread_detach(_pthid); _isRunning=false; } cout<<"~Thread()"<<endl; }
==Threadpool:==
#ifndef __WD_THREADPOLL_H__ #define __WD_THREADPOLL_H__ #include "TaskQueue.h" #include "Thread.h" #include <vector> #include <memory> #include <functional> using std::shared_ptr; using std::vector; namespace wd { class Threadpool { public: using Task=std::function<void()>; Threadpool(size_t threadNum,size_t queSize) :_threadNum(threadNum) ,_queSize(queSize) ,_taskQue(_queSize) ,_isExit(false) { _threads.reserve(_threadNum); } ~Threadpool(); void start(); void stop(); void addTask(Task && task); private: void threadFunc(); Task getTask(); size_t _threadNum; size_t _queSize; vector<shared_ptr<Thread>> _threads; TaskQueue _taskQue; bool _isExit; }; } #endif
#include "Threadpool.h" #include "Thread.h" #include <unistd.h> #include <iostream> using namespace std; using namespace wd; void Threadpool::start() { for(size_t idx=0;idx<_threadNum;++idx) { shared_ptr<Thread>pThread(new Thread(std::bind(&Threadpool::threadFunc,this))); _threads.push_back(std::move(pThread)); } int number=0; for(auto &pThread:_threads) { pThread->start(number); ++number; } } void Threadpool::stop()//爲了線程安全,將stop方法置於主線程中 { if(!_isExit) { while(!_taskQue.empty()){ ::sleep(1); cout<<"Threadpool sleep 1 second!"<<endl; } _isExit=true; cout<<"Threadpool ->stop:_isExit="<<_isExit<<endl; _taskQue.wakeup(); for(auto &pthread:_threads){ pthread->join(); } } } Threadpool::~Threadpool() { if(!_isExit){ stop(); } } void Threadpool::addTask(Task && task) { _taskQue.push(std::move(task)); } Task Threadpool::getTask() { return _taskQue.pop(); } void Threadpool::threadFunc() { while(!_isExit) { Task task=getTask(); if(task){ task(); } } }
==Timer:==
///======================================= /// File: Timer.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-06 20:00:45 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __WD_TIMER_H__ #define __WD_TIMER_H__ #include <functional> namespace wd { class Timer { public: using TimerCallback =std::function<void()>; Timer(int initailTime,int intervalTime,TimerCallback && cb); ~Timer(); void start(); void stop(); private: int _fd; int _initialTime; int _intervalTime; TimerCallback _cb; bool _isStarted; int createTimerFd(); void setTimerfd(int initialTime, int intervalTime); void handleRead(); }; } #endif
///======================================= /// File: Timer.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 20:09:14 /// Dream: Don't forget your dreams! /// ====================================== #include "Timer.h" #include <unistd.h> #include <errno.h> #include <poll.h> #include <sys/timerfd.h> #include <iostream> using namespace std; using namespace wd; Timer::Timer(int initialTime,int intervalTime,TimerCallback && cb) :_fd(createTimerFd()) ,_initialTime(initialTime) ,_intervalTime(intervalTime) ,_cb(std::move(cb)) ,_isStarted(false) {} void Timer::start() { struct pollfd pfd; pfd.fd=_fd; pfd.events=POLLIN; setTimerfd(_initialTime,_intervalTime);//開啓定時器 _isStarted=true; while(_isStarted){ int nready=::poll(&pfd,1,5000); if(-1==nready &&errno ==EINTR){ continue; }else if(-1==nready){ perror(">>>poll error!"); exit(EXIT_FAILURE); }else if(0==nready){ cout<<">>>poll timeout!"<<endl; }else{ if(pfd.revents & POLLIN){ handleRead();//先對定時器進行處理 if(_cb){ _cb();//再去執行回調任務 } } } } } void Timer::stop() { setTimerfd(0,0); if(_isStarted){ _isStarted=false; } } Timer::~Timer() { if(_isStarted){ stop(); } } int Timer::createTimerFd() { int fd=::timerfd_create(CLOCK_REALTIME,0); if(-1==fd){ perror(">>timerfd_create error!"); } return fd; } void Timer::setTimerfd(int initialTime,int intervalTime) { struct itimerspec value; value.it_value.tv_sec=initialTime; value.it_value.tv_nsec=0; value.it_interval.tv_sec=intervalTime; value.it_interval.tv_nsec=0; int ret=::timerfd_settime(_fd,0,&value,NULL); if(-1==ret){ perror(">>>timerfd_settime error!"); } } #if 0 void Timer::handleRead() { uint64_t howmany; int ret =::read(_fd,&howmany,sizeof(uint64_t)); if(ret!=sizeof(uint64_t)){ perror("read!"); } } #endif void Timer::handleRead() { uint64_t howmany;//爲一個64位 int ret=::read(_fd,&howmany,sizeof(uint64_t)); if(ret!=sizeof(uint64_t)){ perror(">>>read error!"); } }
==TimerThread:==
///======================================= /// File: TimerThread.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 17:12:51 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __WD_TIMERTHREAD_H__ #define __WD_TIMERTHREAD_H__ #include "Timer.h" #include "Thread.h" #include <functional> namespace wd { class TimerThread { public: using TimerCallback = std::function<void()>; TimerThread(int, int, TimerCallback && cb); ~TimerThread(); void start(); void stop(); private: Timer _timer; Thread _subThread; bool _isStarted; }; }//end of namespace wd #endif
///======================================= /// File: TimerThread.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 20:09:14 /// Dream: Don't forget your dreams! /// ====================================== #include "TimerThread.h" using namespace wd; TimerThread::TimerThread(int initialTime, int intervalTime, TimerCallback && cb) : _timer(initialTime, intervalTime, std::move(cb)) , _subThread(std::bind(&Timer::start, &_timer)) , _isStarted(false) {} void TimerThread::start() { _subThread.start(0); _isStarted = true; } void TimerThread::stop() { if(_isStarted) { _timer.stop(); _subThread.join(); _isStarted = false; } } TimerThread::~TimerThread() { if(_isStarted) stop(); }
==main:==
///======================================= /// File: main.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 21:09:32 /// Dream: Don't forget your dreams! /// ====================================== #include "SpellCorrectServer.h" #include "ConFiguration.h" #include "CacheManger.h" #include "TimerThread.h" #include <iostream> #include <functional> using namespace std; using namespace wd; int main() { wd::CacheManger *mycacheManger=Singleton<CacheManger>::getInstance(Singleton<Configuration> ::getInstance(CONFPATH)->getCache()); TimerThread timer(5,600,std::bind(&CacheManger::periodicUpdate,mycacheManger)); timer.start(); SpellCorrectServer myspell(Singleton<Configuration>::getInstance(CONFPATH)->getIp() ,Singleton<Configuration>::getInstance(CONFPATH)->getPort() ,4 ,10); myspell.start(); return 0; }
小結:(1)已經實現項目需求,中文和英文單詞都能查詢,通過測試,運行穩定,能輸出很多候選詞
(2)仍然存在少許bug,例如偶爾會發生段錯誤
(3)因爲時間問題,json讀出的數據key-value的key值沒有打印,用戶界面還將來得及優化
(4)陳碩的《linux多線程服務端編程》使用linux接口(timerfd),沒用posix接口(eventfd)
---恢復內容結束---
# 個人Spellcorrect 開發文檔
[TOC]
個人主要文件夾分爲三個:分別爲客戶端,cppjieba分詞庫,離線部分及服務器部分
==啓動時服務器:==
==客戶端連入時時服務器:==
==輸入「趙」==
==輸入「周杰倫」==
==輸入清華大學==
==啓動時服務器:==
==客戶端連入時時服務器:==
==輸入student:==
==輸入spell:==
==輸入computer:==
==Makefile:==
SRCS:=$(wildcard *.cc) OBJS:= $(patsubst %.cc, %.o, $(SRCS)) CXX:=g++ CXXFLAGS:= -w -g -std=c++11 $(addprefix -I, $(INC_DIR)) $(LIBS) -Wno-deprecated -I ../cppjieba/include/ -I ../cppjieba/deps EXE:=./main $(EXE):$(OBJS) $(CXX) -o $(EXE) $(OBJS) $(CXXFLAGS) clean: rm -rf $(EXE) rm -rf $(OBJS)
==Configuration:==
///======================================= /// File: Configuration.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-12 00:30:39 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __CONFIGURATION_H__ #define __CONFIGURATION_H__ #include "Nocopyable.h" #include <string> #include <map> using namespace std; class Configuration :public Noncopyable { public: Configuration(const string &filePath); string getEnglishDir() const {return _englishDir;} string getChineseDir() const {return _chineseDir;} private: string _filePath; string _englishDir; string _chineseDir; }; template<typename T> class Singleton { public: template<typename ...Args> static T* getInstance(Args ...args) { if(!_pInstance) _pInstance = new T(args...); return _pInstance; } static void destroy() { if(_pInstance) delete _pInstance; } private: Singleton(); ~Singleton(); static T *_pInstance; }; template<typename T> T * Singleton<T>::_pInstance = NULL; #endif
1 ///======================================= 2 /// File: Configuration.cc 3 /// Author: wtptorres(1584292712@qq.com) 4 /// Date: 2019-06-12 00:30:04 5 /// Dream: Don't forget your dreams! 6 /// ====================================== 7 8 9 #include "Configuration.h" 10 #include <utility> 11 #include <fstream> 12 #include <iostream> 13 using namespace std; 14 15 Configuration::Configuration(const string &filePath) 16 :_filePath(std::move(filePath)) 17 { 18 ifstream ifs(_filePath); 19 if(!ifs) 20 cout<<"file open error!"<<endl; 21 ifs>>_englishDir; 22 ifs>>_chineseDir; 23 ifs.close(); 24 }
///======================================= /// File: Nocopyable.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-12 00:24:36 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __NOCOPYABLE_H__ #define __NOCOPYABLE_H__ class Noncopyable { public: Noncopyable()=default; ~Noncopyable()=default; private: Noncopyable(const Noncopyable &rhs); Noncopyable &operator =(const Noncopyable &rhs); }; #endif
==DictProducer:==
///======================================= /// File: DictProducer.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-12 16:40:25 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __DICTPRODUCER_H__ #define __DICTPRODUCER_H__ #include "SplitTool.h" using namespace std; #include "Nocopyable.h" #include <memory> #include <string> #include <vector> #include <map> #include <utility> class DictProducer :public Noncopyable { public: DictProducer(const string,const string,const string &,SplitToolJieba *); ~DictProducer(){} void build_dict(); void build_cn_dict(); void store_dict(); vector<pair<string,int>>& getIndict(){return _indict;} private: void processEnglishWord(string &word); void processChineseWord(string &word);//除去中文的數字 void construct_indict(); string _englishDir; string _chineseDir; string _goleFilePath; vector<string> _englishFiles; vector<string> _chineseFiles; map<string,int> _dict; vector<pair<string,int>> _indict; shared_ptr<SplitToolJieba> _splitTool; }; #endif
///======================================= /// File: DictProducer.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-12 16:50:46 /// Dream: Don't forget your dreams! /// ====================================== #include "DictProducer.h" #include <cctype> #include <utility> #include <fstream> #include <iostream> #define FIRSTSIZE 10000 using namespace std; DictProducer::DictProducer(const string englishDir,const string chineseDir,const string &goleFilePath,SplitToolJieba *splitToolPtr) :_englishDir(englishDir) ,_chineseDir(chineseDir) ,_goleFilePath(goleFilePath) { _splitTool.reset(splitToolPtr); std::ifstream ifsEnglish(_englishDir); std::ifstream ifsChinese(_chineseDir); string filePath; if(!ifsEnglish || !ifsChinese){ cout<<"Dict file open error!"<<endl; } while(ifsEnglish>>filePath) { _englishFiles.push_back(filePath); } while(ifsChinese>>filePath) { _chineseFiles.push_back(filePath); } _indict.reserve(FIRSTSIZE); } void DictProducer::processEnglishWord(string &word) { auto cit =word.begin(); for(;cit!=word.end();++cit) { //去除標點符號或數字 if(!isalpha(*cit)){ word.erase(cit); --cit;//迭代器位置發生改變 }else if(isupper(*cit)){//將大寫字母改成小寫 *cit =tolower(*cit); } } } void DictProducer::processChineseWord(string &word) { auto cit =word.begin(); for(;cit!=word.end();++cit) { //去除數字 if(!isalnum(*cit)){ word.erase(cit); --cit; } } } void DictProducer::build_dict()//創建英文詞典 { for(auto &filePath:_englishFiles) { ifstream ifs(filePath); if(!ifs){ cout<<"English File open error!"<<endl; } string word; while(ifs>>word) { processEnglishWord(word); auto cit =_dict.find(word); if(word.size()>0 && cit ==_dict.end()){ _dict.insert(std::make_pair(word,1)); }else if(cit!=_dict.end()){ ++ cit ->second; } } } } void DictProducer::build_cn_dict() { vector<string>words; for(auto filePath:_chineseFiles) { ifstream ifs(filePath); if(!ifs){ cout<<"Chinese file open error!"<<endl; } string sentence; while(std::getline(ifs,sentence)) { _splitTool->Cut(sentence); } } vector<string>& results =_splitTool->getResult(); for(auto &res:results) { processChineseWord(res); auto cit =_dict.find(res); if(cit ==_dict.end()){ _dict.insert(std::make_pair(res,1)); }else{ ++ cit ->second; } } } void DictProducer::store_dict() { construct_indict(); ofstream ofs(_goleFilePath); if(!ofs) cout<<"Store_dict open file error!"<<endl; for(auto &mypair:_indict) { ofs<<mypair.first<<" "<<mypair.second<<endl; } ofs.close(); } void DictProducer::construct_indict() { for(auto dictpair:_dict){ _indict.push_back(dictpair); } }
==GetIndex:==
///======================================= /// File: GetIndex.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-12 08:52:04 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __GETINDEX_H__ #define __GETINDEX_H__ #include <string> #include <unordered_map> #include <set> #include <vector> #include <utility> #include <unordered_set> using namespace std; class GetIndex { public: GetIndex(const string &,const string &,const string &); ~GetIndex(){} void construct_index(); void store_index(); private: bool isEnglish(const string &rhs) const; vector<string>getOneCharacter(const string & word); string _sourceFilePath; string _goleFilePath; string _stopWordsFilePath; vector<pair<string,int>>_dict; unordered_set<string>_stopWords; unordered_map<string,set<int>>_index; }; #endif
///======================================= /// File: GetIndex.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-12 09:00:11 /// Dream: Don't forget your dreams! /// ====================================== #include "GetIndex.h" #include <fstream> #include <sstream> #include <iostream> using namespace std; GetIndex::GetIndex(const string & sourceFilePath,const string &goleFilePath,const string &stopWordsFilePath) :_sourceFilePath(std::move(sourceFilePath)) ,_goleFilePath(std::move(goleFilePath)) ,_stopWordsFilePath(std::move(stopWordsFilePath)) { ifstream ifs(_sourceFilePath); if(!ifs){ cout<<"GetIndex file open error!"<<endl; } string line; while(getline(ifs,line)) { istringstream iss(line); string key; int value; iss>>key>>value; _dict.push_back(std::make_pair(key,value)); } ifstream ifs1(_stopWordsFilePath); if(!ifs1){ cout<<"file open error!"<<endl; } string stopWord; while(ifs1>>stopWord,!ifs1.eof()) { _stopWords.insert(stopWord); } } vector<string> GetIndex::getOneCharacter(const string &word) { vector<string>tmp; auto cit =word.begin(); while(cit<word.end()) { if(224==(*cit &224)) { string oneCharacter; oneCharacter.append(cit,cit+3); tmp.push_back(oneCharacter); cit +=3; }else if(240==(*cit &240)){ string oneCharacter; oneCharacter.append(cit,cit+4); tmp.push_back(oneCharacter); cit +=4; }else break; } return tmp; } bool GetIndex::isEnglish(const string &rhs) const { char ch =*(rhs.begin()); if(ch<0) return false; return true; } #if 0 bool GetIndex::isEnglish(const string &rhs) const { char ch =*(rhs.begin()); if(ch<0){ return false; } return true; } #endif void GetIndex::construct_index() { for(size_t i=0;i!=_dict.size();++i) { string tmp=_dict[i].first; if(isEnglish(tmp)) { for(auto ch:tmp) { string charactor(1,ch); if(isalpha(ch)) { auto cit =_index.find(charactor); if(cit ==_index.end()) { set<int> smp; smp.insert(i); _index.insert(std::make_pair(charactor,smp)); }else{//已經存在了該字母的索引 cit->second.insert(i); } } } }else{//中文處理部分 vector<string> oneCharacterRally =getOneCharacter(tmp); for(auto oneCharacter:oneCharacterRally) {//stop_words中不存在該單詞,則加入索引中 if(_stopWords.find(oneCharacter)==_stopWords.end()){ auto it =_index.find(oneCharacter); if(it == _index.end()){ set<int>tmp; tmp.insert(i); _index.insert(std::make_pair(oneCharacter,tmp)); }else{ it->second.insert(i); } } } } } } void GetIndex::store_index() { //ofs存儲索引的內容 std::ofstream ofs(_goleFilePath); if(!ofs){ cout<<"file open error!"<<endl; return; } for(auto data:_index) { ofs<<data.first<<" "; for(auto linenum:data.second) { ofs<<linenum<<" "; } ofs<<endl; } ofs.close(); }
==SplitTool:==
///======================================= /// File: SplitTool.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-12 17:12:01 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __SPLITTOOL_H__ #define __SPLITTOOL_H__ #include "../cppjieba/include/cppjieba/Jieba.hpp"//須要本身將cppjieba安裝在項目目錄下 #include "Configuration.h" #include <string> #include <vector> using namespace std; using namespace cppjieba; class SplitToolJieba { public: SplitToolJieba(const string& dict_path,const string &model_path,const string &user_dict_path,const string & idfPath, const string &stopWordPath) :_jieba(dict_path,model_path,user_dict_path,idfPath,stopWordPath) {} ~SplitToolJieba(){} void Cut(const string & sentence) { vector<string>tmp; _jieba.Cut(sentence,tmp); _result.insert(_result.end(),tmp.begin(),tmp.end()); } vector<string> & getResult(){return _result;} private: vector<string> _result; cppjieba::Jieba _jieba; }; #endif
==main:==
///======================================= /// File: main.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-12 20:38:50 /// Dream: Don't forget your dreams! /// ====================================== #include "Configuration.h" #include "SplitTool.h" using namespace std; #include "DictProducer.h" #include "GetIndex.h" #include <iostream> #include <memory> const char * const DICT_PATH ="../cppjieba/dict/jieba.dict.utf8"; const char * const HMM_PATH ="../cppjieba/dict/hmm_model.utf8"; const char * const USER_DICT_PATH ="../cppjieba/dict/user.dict.utf8"; const char * const IDF_PATH ="../cppjieba/dict/idf.utf8"; const char * const STOP_WORD_PATH ="../cppjieba/dict/stop_words.utf8"; const string GOLE_DICT_PATH="../server/data/dict.txt"; const string GOLE_INDEX_PATH="../server/data/index.txt"; class SplitTool; int main(void) { Configuration *pconfig =Singleton<Configuration>::getInstance("configure.txt"); SplitToolJieba *ptool =new SplitToolJieba(DICT_PATH,HMM_PATH,USER_DICT_PATH,IDF_PATH,STOP_WORD_PATH); DictProducer mydictProducer(pconfig->getEnglishDir(),pconfig->getChineseDir(),GOLE_DICT_PATH,ptool); mydictProducer.build_dict();//創建英語詞典 mydictProducer.build_cn_dict();//創建中文詞典 mydictProducer.store_dict();//儲存詞典 GetIndex myindex(GOLE_DICT_PATH,GOLE_INDEX_PATH,"stop_words_zh.txt"); myindex.construct_index();//創建索引 myindex.store_index();//存儲索引 Singleton<Configuration>::destroy(); return 0; }
==ConFiguration:==
///======================================= /// File: ConFiguration.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-06 10:32:43 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __CONFIGURATION_H__ #define __CONFIGURATION_H__ #include "Noncopyable.h" #include <string> #include <map> #define CONFPATH "/home/wtp/spell/server/conf/configure.txt" using namespace std; namespace wd { class Configuration :public Noncopyable { public: Configuration(const string &filePath); ~Configuration()=default; string getDictDir() const; string getIndexDir() const; string getIp()const; string getCache() const; unsigned short getPort() const; private: string _filePath; map<string,string> _conf; }; }; template<typename T> class Singleton { public: template<typename ...Args> static T *getInstance(Args ...args) { if(!_pInstance) _pInstance=new T(args ...); return _pInstance; } static void destroy() { if(_pInstance) delete _pInstance; } private: Singleton(); ~Singleton(); static T *_pInstance; }; template<typename T> T *Singleton<T>::_pInstance =NULL; #endif
///======================================= /// File: ConFiguration.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 15:24:14 /// Dream: Don't forget your dreams! /// ====================================== #include "ConFiguration.h" #include <stdlib.h> #include <utility> #include <fstream> #include <iostream> using namespace std; using namespace wd; wd::Configuration::Configuration(const string & filePath) :_filePath(std::move(filePath)) { ifstream ifs(_filePath); if(!ifs){ cout<<"file open error!"<<endl; } string key,value; while(ifs>>key) { ifs>>value; _conf.insert(std::make_pair(key,value)); } ifs.close(); } string wd::Configuration::getDictDir() const { auto cit=_conf.find("mydict"); if(cit== _conf.end()) return ""; else return cit->second; } string wd::Configuration::getIndexDir() const { auto cit =_conf.find("myindex"); if(cit== _conf.end()) return ""; else return cit->second; } string wd::Configuration::getIp() const { auto cit =_conf.find("myip"); if(cit ==_conf.end()) return ""; else return cit->second; } unsigned short wd::Configuration::getPort() const { auto cit =_conf.find("myport"); if(cit==_conf.end()) return 0; else return atoi(cit->second.c_str()); } string wd::Configuration::getCache() const { auto cit =_conf.find("mycache"); if(cit ==_conf.end()) return ""; else return cit->second; }
==Acceptor:==
///======================================= /// File: Acceptor.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-05 23:47:05 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __WD_ACCEPTOR_H__ #define __WD_ACCEPTOR_H__ #include "Socket.h" #include "InetAddress.h" namespace wd { class Acceptor { public: Acceptor(int listenfd,const InetAddress & addr); void ready();//服務器監聽準備 int accept();//服務器接收新鏈接 int fd()const {return _listenSock.fd();} private: void setReuseAddr(bool on);//設置地址重用 void setReusePort(bool on);//設置端口重用 void bind();//綁定 void listen();//監聽 Socket _listenSock; InetAddress _addr; }; } #endif
///======================================= /// File: Acceptor.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-05 23:52:12 /// Dream: Don't forget your dreams! /// ====================================== #include <iostream> #include "Acceptor.h" #include "SocketUtil.h" namespace wd { Acceptor::Acceptor(int listenfd,const InetAddress & addr) :_listenSock(listenfd) ,_addr(addr) {} void Acceptor::ready() { setReuseAddr(true); setReusePort(true); bind(); listen(); } int Acceptor::accept() { int peerfd=::accept(_listenSock.fd(),NULL,NULL); if(-1==peerfd) { perror("accept error!"); } return peerfd; } void Acceptor::setReuseAddr(bool flag) { int on=(flag?1:0); if(::setsockopt(_listenSock.fd() ,SOL_SOCKET ,SO_REUSEADDR ,&on ,static_cast<socklen_t>(size_t(on)))==-1) { perror("setsockopt reuseaddr error!"); ::close(_listenSock.fd()); exit(EXIT_FAILURE); } } void Acceptor::setReusePort(bool flag) { #ifndef SO_REUSEPORT int on=(flag?1:0); if(::setsockopt(_listenSock.fd() ,SOL_SOCKET ,SO_REUSEADDR ,&on ,static_cast<socklen_t>(size_t(on)))==-1) { perror("setsockopt reuseport error!"); ::close(_listenSock.fd()); exit(EXIT_FAILURE); } #else if(flag) { fprintf(stderr,"SO_REUSEPORT is not supported!\n"); } #endif } void Acceptor::bind() { if(-1==::bind(_listenSock.fd() ,(const struct sockaddr*)_addr.getSockAddrPtr() ,sizeof(InetAddress))) { perror("bind error!"); ::close(_listenSock.fd()); exit(EXIT_FAILURE); } } void Acceptor::listen() { if(-1==::listen(_listenSock.fd(),10)) { perror("listen error!"); ::close(_listenSock.fd()); exit(EXIT_FAILURE); } } } #if 0 int main() { std::cout<<"Acceptor is correct!"<<std::endl; } #endif
==Condition.h:==
#ifndef __WD_CONDITION_H__ #define __WD_CONDITION_H__ #include "Noncopyable.h" #include "MutexLock.h" #include <pthread.h> namespace wd { class Condition :Noncopyable { public: Condition(MutexLock &mutex) :_mutex(mutex) {pthread_cond_init(&_cond,NULL);} ~Condition() {pthread_cond_destroy(&_cond);} void wait() {pthread_cond_wait(&_cond,_mutex.getMutexLockPtr());} void notify() {pthread_cond_signal(&_cond);} void notifyAll() {pthread_cond_broadcast(&_cond);} private: pthread_cond_t _cond; MutexLock & _mutex; }; } #endif
==Cache:==
///======================================= /// File: Cache.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-05 19:52:40 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __CACHE_H__ #define __CACHE_H__ #include <unordered_map> #include <string> using namespace std; namespace wd { class Cache { public: void addElement(string,string);//增長緩存信息 void readFromFile(string);//從文件中讀取信息 void writeToFile(string);//將信息寫入文件中 void update(const Cache&);//更新緩存消息 bool find(string querry);//從數據庫中找尋信息 string &operator[](string key); private: unordered_map<string,string>_hashTable;//採用hashTable進行緩存 }; }; #endif
///======================================= /// File: Cache.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-05 20:01:25 /// Dream: Don't forget your dreams! /// ====================================== #include "Cache.h" #include <fstream> #include <utility> #include <iostream> using namespace std; using namespace wd; void Cache::addElement(string querry,string result) { _hashTable[querry]=result; } void Cache::readFromFile(string filePath) { ifstream ifs(filePath); if(!ifs){ cout<<"Cache::read readFromFile file open error!"<<endl; return; } string querry,result; while(ifs>>querry,!ifs.eof()) { ifs>>result; _hashTable[querry]=result; } } #if 0 void Cache::writeToFile(string filePath) { ofstream ofs(filePath); if(!ofs){ cout<<""<<endl; return; } for(auto &mypair:_hashTable) { ofs<<mypair.first<<" "; ofs<<mypair.second<<endl; } } void Cache::update(const Cache & cache) { for(auto &mypair:cache._hashTable) { auto cit =_hashTable.find(mypair.first); if(cit==_hashTable.end()) { _hashTable.insert(std::move(mypair)); } } } #endif void Cache::writeToFile(string filePath) { ofstream ofs(filePath); if(!ofs){ cout<<"file write error!"<<endl; return; } for(auto &mypair:_hashTable) { ofs<<mypair.first<<" "; ofs<<mypair.second<<endl; } } void Cache::update(const Cache & cache) { for(auto &mypair:cache._hashTable) { auto cit =_hashTable.find(mypair.first); if(cit==_hashTable.end()) { _hashTable.insert(std::move(mypair)); } } } bool Cache::find(string querry) { auto cit =_hashTable.find(querry); if(cit==_hashTable.end()) return false; return true; } string &Cache::operator[](string key) { return _hashTable[key]; } #if 0 int main() { cout<<"cache is correct!"<<endl; } #endif
==CacheManger:==
///======================================= /// File: CacheManger.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-05 20:51:09 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __CACHEMANGER_H__ #define __CACHEMANGER_H__ #include "Cache.h" #include <vector> #define THREADNUM 4//線程數目設置爲4個,可自定義 using std::vector; namespace wd { class CacheManger { public: CacheManger(string filePath); void init(string);//建立緩存 Cache & getCache(size_t);//獲取某個緩存 void periodicUpdate();//定時更新全部緩存 private: string _cacheFilePath; vector<Cache>_cacheList; }; }; #endif
///======================================= /// File: CacheManger.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-05 20:56:50 /// Dream: Don't forget your dreams! /// ====================================== #include "CacheManger.h" #include <iostream> #include <fstream> #include <utility> #include <iostream> using namespace std; using namespace wd; CacheManger::CacheManger(string cacheFilePath) { init(cacheFilePath); } void CacheManger::init(string cacheFilePath) { _cacheFilePath=cacheFilePath; _cacheList.reserve(THREADNUM); Cache tmp; tmp.readFromFile(_cacheFilePath); for(size_t i=0;i!=THREADNUM;++i) { _cacheList.push_back(std::move(tmp)); } } Cache & CacheManger::getCache(size_t number) { return _cacheList[number]; } void CacheManger::periodicUpdate() { auto cit=_cacheList.begin(); Cache lastWrite=*(cit ++); for(;cit<_cacheList.end();++cit) { lastWrite.update(*cit); } for(cit=_cacheList.begin()+1;cit!=_cacheList.end();++cit) { (*cit).update(lastWrite); } lastWrite.writeToFile(_cacheFilePath); }
==EpollPoller:==
///======================================= /// File: EpollPoller.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-06 11:03:36 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __WD_EPOLLPOLLER_H__ #define __WD_EPOLLPOLLER_H__ #include "TcpConnection.h" #include "Noncopyable.h" #include "MutexLock.h" #include <sys/epoll.h> #include <vector> #include <map> #include <functional> namespace wd { class Acceptor; class EpollPoller :Noncopyable { public: typedef TcpConnection::TcpConnectionCallback EpollCallback; typedef std::function<void()> Functor; EpollPoller(Acceptor &acceptor); ~EpollPoller(); void loop(); void unloop(); void runInLoop(const Functor && cb); void doPendingFunctors(); void wakeup(); void setConnectionCallback(EpollCallback cb); void setMessageCallback(EpollCallback cb); void setCloseCallback(EpollCallback cb); private: void waitEpollfd(); void handleConnection(); void handleMessage(int peerfd); void handleRead(); Acceptor & _acceptor; int _epollfd; int _eventfd; int _listenfd; bool _isLooping; MutexLock _mutex; std::vector<Functor> _pendingFunctors; typedef std::vector<struct epoll_event>Eventlist; Eventlist _eventList; typedef std::map<int,TcpConnectionPtr> ConnectionMap; ConnectionMap _connMap; EpollCallback _onConnectionCb; EpollCallback _onMessageCb; EpollCallback _onCloseCb; }; } #endif
///======================================= /// File: EpollPoller.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 15:42:54 /// Dream: Don't forget your dreams! /// ====================================== #include "EpollPoller.h" #include "SocketUtil.h" #include "Acceptor.h" #include <assert.h> #include <iostream> using namespace std; namespace wd { EpollPoller::EpollPoller(Acceptor & acceptor) :_acceptor(acceptor) ,_epollfd(createEpollFd()) ,_eventfd(createEventFd()) ,_listenfd(_acceptor.fd()) ,_isLooping(false) ,_eventList(1024) { addEpollFdRead(_epollfd,_listenfd); addEpollFdRead(_epollfd,_eventfd); } EpollPoller::~EpollPoller() { ::close(_epollfd); } void EpollPoller::loop() { _isLooping=true; while(_isLooping) { waitEpollfd(); } } void EpollPoller::unloop() { if(_isLooping) _isLooping=false; } void EpollPoller::setConnectionCallback(EpollCallback cb) { _onConnectionCb=cb; } void EpollPoller::setMessageCallback(EpollCallback cb) { _onMessageCb=cb; } void EpollPoller::setCloseCallback(EpollCallback cb) { _onCloseCb=cb; } void EpollPoller::waitEpollfd() { int nready; do { nready =::epoll_wait(_epollfd,&(*_eventList.begin()),_eventList.size(),10000); }while(-1==nready && errno ==EINTR); if(-1==nready){ perror("epoll wait error!"); exit(EXIT_FAILURE); }else if(0==nready){ cout<<"epoll_wait timeout!"<<endl; }else{//擴容 if(nready==static_cast<int>(_eventList.size())){ _eventList.resize(_eventList.size()*2); } for(int idx=0;idx!=nready;++idx)//正宗羅老師循環體(TwT) { if(_eventList[idx].data.fd ==_listenfd) { if(_eventList[idx].events & EPOLLIN) { handleConnection(); } }else if(_eventList[idx].data.fd ==_eventfd){ handleRead(); cout<<">>doPendingFunctors()"<<endl; doPendingFunctors(); }else{ if(_eventList[idx].events & EPOLLIN){ handleMessage(_eventList[idx].data.fd); } } } } } void EpollPoller::handleConnection() { int peerfd=_acceptor.accept(); addEpollFdRead(_epollfd,peerfd); TcpConnectionPtr conn(new TcpConnection(peerfd,this)); conn->setConnectionCallback(_onConnectionCb); conn->setMessageCallback(_onMessageCb); conn->setCloseCallback(_onCloseCb); std::pair<ConnectionMap::iterator,bool>ret; ret=_connMap.insert(std::make_pair(peerfd,conn)); assert(ret.second ==true); (void)ret; conn->handleConnectionCallback(); } void EpollPoller::handleMessage(int peerfd) { bool isClosed=isConnectionClosed(peerfd); ConnectionMap::iterator it =_connMap.find(peerfd); assert(it!=_connMap.end()); if(isClosed) { it->second->handleCloseCallback(); delEpollReadFd(_epollfd,peerfd); _connMap.erase(it); }else{ it->second->handleMessageCallback(); } } void EpollPoller::runInLoop(const Functor && cb)//在計算線程中執行 { MutexLockGuard mlg(_mutex); _pendingFunctors.push_back(std::move(cb)); wakeup(); } void EpollPoller::doPendingFunctors() { std::vector<Functor>tmp; { MutexLockGuard mlg(_mutex); tmp.swap(_pendingFunctors); } for(auto & functor:tmp) { functor(); } } void EpollPoller::handleRead() { uint64_t howmany; int ret=::read(_eventfd,&howmany,sizeof(howmany)); if(ret !=sizeof(howmany)) { perror("read error!"); } } void EpollPoller::wakeup() { uint64_t one =1; int ret =::write(_eventfd,&one,sizeof(one)); if(ret!=sizeof(one)) { perror("write error!"); } } }
==InetAddress:==
///======================================= /// File: InetAddress.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-05 21:55:19 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __WD_INETADDRESS_H__ #define __WD_INETADDRESS_H__ #include <netinet/in.h> #include <string> namespace wd { class InetAddress { public: InetAddress(short port); InetAddress(const char *pIp,short port); InetAddress(const struct sockaddr_in & addr); std::string ip()const; unsigned short port() const; const struct sockaddr_in *getSockAddrPtr() const; private: struct sockaddr_in _addr; }; } #endif
///======================================= /// File: InetAddress.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 20:55:18 /// Dream: Don't forget your dreams! /// ====================================== #include "InetAddress.h" #include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <arpa/inet.h> #include <string.h> namespace wd { InetAddress::InetAddress(short port) { ::memset(&_addr,0,sizeof(_addr)); _addr.sin_family=AF_INET; _addr.sin_port=htons(port); _addr.sin_addr.s_addr=INADDR_ANY; } InetAddress::InetAddress(const char * pIp,short port) { ::memset(&_addr,0,sizeof(_addr)); _addr.sin_family=AF_INET; _addr.sin_port=htons(port); _addr.sin_addr.s_addr=inet_addr(pIp); } InetAddress::InetAddress(const struct sockaddr_in & addr) :_addr(addr) {} const struct sockaddr_in * InetAddress::getSockAddrPtr()const { return & _addr; } std::string InetAddress::ip()const { return std::string(inet_ntoa(_addr.sin_addr)); } unsigned short InetAddress::port() const { return ntohs(_addr.sin_port); } }
==MutexLock:==
#ifndef __WD_MUTEXLOCK_H__ #define __WD_MUTEXLOCK_H__ #include "Noncopyable.h" #include <pthread.h> namespace wd { class MutexLock :Noncopyable { public: MutexLock() {pthread_mutex_init(&_mutex,NULL);} ~MutexLock() {pthread_mutex_destroy(&_mutex);} void lock() {pthread_mutex_lock(&_mutex);} void unlock() {pthread_mutex_unlock(&_mutex);} pthread_mutex_t *getMutexLockPtr() {return &_mutex;} private: pthread_mutex_t _mutex; }; class MutexLockGuard//C++之父BS提出的RAII { public: MutexLockGuard(MutexLock &mutex) :_mutex(mutex) { _mutex.lock(); } ~MutexLockGuard() { _mutex.unlock(); } private: MutexLock &_mutex; }; } #endif
==Mydict:==
///======================================= /// File: Mydict.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-06 11:12:19 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __MYDICT_H__ #define __MYDICT_H__ #include <string> #include <vector> #include <map> #include <utility> #include <set> #include <fstream> #include <iostream> #include <sstream> using namespace std; namespace wd { struct MyResult { string _word; int _iFreq;//詞頻 int _iDist;//最小編輯距離 }; class Mydict { public: Mydict(const string dictDir,const string indexDir) { ifstream ifs1(dictDir),ifs2(indexDir); if(!ifs1||!ifs2) cout<<"Mydict open file error!"<<endl; string key; int value; ifs1>>value; _dict.push_back(std::make_pair(string(" "),value)); ifs1>>value; _dict.push_back(std::make_pair(string(" "),value)); while(ifs1>>key) { ifs1>>value; _dict.push_back(std::make_pair(key,value)); } string line; while(std::getline(ifs2,line)) { istringstream iss(line); string ikey; int ivalue; iss>>ikey; set<int> tmp; while(iss>>ivalue) { tmp.insert(ivalue); } _index.insert(std::make_pair(ikey,tmp)); } } vector<pair<string,int>> & getDict(){return _dict;} map<string ,set<int>> & getIndexTable(){return _index;} private: vector<pair<string,int>> _dict; map<string,set<int>> _index; }; } #endif
==MyTask:==
///======================================= /// File: MyTask.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-06 21:04:54 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __MYTASK_H__ #define __MYTASK_H__ #include "TcpConnection.h" #include "ConFiguration.h" #include "Mydict.h" #include "Cache.h" #include <string> #include <queue> using namespace std; class MyCompare { public: bool operator()(const wd::MyResult & lhs,const wd::MyResult &rhs) { if(lhs._iDist !=rhs._iDist) return lhs._iDist<rhs._iDist; else return lhs._iFreq>rhs._iFreq; } private: }; using Character =string; class MyTask { public: MyTask(const string &querry,const wd::TcpConnectionPtr conn) :_querry(std::move(querry)) ,_conn(conn) {} void execute(); private: void queryIndexTable();//查詢索引(四個索引) void statistic(set<int> &iset);//計算 int distance(const string & rhs);//計算最小編輯距離 bool response(wd::Cache & cache);//響應客戶端的請求 vector<Character>getOneCharacter(const string &word);//獲取字符數組 string _querry; wd::TcpConnectionPtr _conn; priority_queue<wd::MyResult,vector<wd::MyResult>,MyCompare> _resultQue; }; #endif
///======================================= /// File: MyTask.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 22:47:19 /// Dream: Don't forget your dreams! /// ====================================== #include "MyTask.h" #include "ConFiguration.h" #include "Mydict.h" #include "CacheManger.h" #include "json/json.h" #include <string.h> #include <algorithm> extern __thread int t_number; bool MyTask::response(wd::Cache &cache) { if(cache.find(_querry)) { _conn->sendInLoop(cache[_querry]); return true; } return false; } int MyTask::distance(const string &rhs) { vector<Character>querryCharacter =getOneCharacter(_querry); vector<Character>indexCharacter =getOneCharacter(rhs); int len1,len2; len1=querryCharacter.size(); len2=indexCharacter.size(); int edit[len1+1][len2+1]; int i,j; for(i=0;i<=len1;++i){ for(j=0;j<=len2;++j){ edit[i][j]=0; } } for(i=0;i<len1;++i){ edit[i][0]=i; } for(j=0;j<=len2;++j){ edit[0][j]=j; } for(i=1;i<len1;++i){ for(j=1;j<=len2;++j){ int cost =((querryCharacter[i-1]==indexCharacter[j-1])?0:1); int deletion =edit[i-1][j]+1; int insertion=edit[i][j-1]+1; int substitution=edit[i-1][j-1]+cost; edit[i][j]=std::min(deletion,std::min(insertion,substitution)); } } return edit[len1][len2]; } void MyTask::statistic(set<int> &iset) { vector<pair<string,int>>dict=(Singleton<wd::Mydict>::getInstance(Singleton<wd::Configuration>::getInstance(CONFPATH)->getDictDir(), Singleton<wd::Configuration>::getInstance(CONFPATH)->getIndexDir()))->getDict(); for(auto &idx:iset) { string key=dict[idx].first; int iDist =distance(key); if(iDist<=3) { wd::MyResult res; res._word=key; res._iDist=iDist; res._iFreq=dict[idx].second; _resultQue.push(res); } } } vector<Character>MyTask::getOneCharacter(const string & word) { auto cit =word.begin(); vector<Character> ret; while(cit<word.end()) { if(224==(*cit &224)){ Character oneCharacter; oneCharacter.append(cit,cit+3); ret.push_back(oneCharacter); cit =cit+3; }else if(240==(*cit &240)){ Character oneCharacter; oneCharacter.append(cit,cit+4); ret.push_back(oneCharacter); cit =cit+4; }else{ Character oneCharacter(1,*cit); ret.push_back(oneCharacter); cit ++; } } return ret; } void MyTask::queryIndexTable() { map<string,set<int>>index=(Singleton<wd::Mydict>::getInstance(Singleton<wd::Configuration>::getInstance(CONFPATH)->getDictDir(), Singleton<wd::Configuration>::getInstance(CONFPATH)->getIndexDir()))->getIndexTable(); vector<Character> oneCharacter=getOneCharacter(_querry); set<int>allRally; for(auto myCharacter:oneCharacter) { auto cit =index.find(myCharacter); if(cit!=index.end()) { for(auto &idx:cit->second) allRally.insert(idx); } } statistic(allRally); } void MyTask::execute() { wd::Cache &mycache =(Singleton<wd::CacheManger>::getInstance(Singleton<wd::Configuration>::getInstance(CONFPATH)->getCache()))->getCache(t_number); if(response(mycache)) return; else{ queryIndexTable(); Json::FastWriter writerinfo; Json::Value arrayObj; while(!_resultQue.empty()) { Json::Value new_item; new_item[""]=_resultQue.top()._word; _resultQue.pop(); arrayObj.append(new_item); } string strEmail=writerinfo.write(arrayObj); mycache.addElement(_querry,strEmail); _conn->sendInLoop(strEmail); } }
==Noncopyable:==
#ifndef __WD_NONCOPYABLE_H__ #define __WD_NONCOPYABLE_H__ namespace wd { class Noncopyable { protected: Noncopyable(){} ~Noncopyable(){} private: Noncopyable(const Noncopyable &); Noncopyable & operator=(const Noncopyable &); }; } #endif
==Socket:==
///======================================= /// File: Socket.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-05 21:46:26 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __WD_SOCKET_H__ #define __WD_SOCKET_H__ #include "Noncopyable.h" namespace wd { class InetAddress; class Socket :Noncopyable { public: Socket(int socket); Socket(); ~Socket(); void shutdownWrite(); int fd()const {return _sockfd;} void nonblock(); static InetAddress getLocalAddr(int socketfd); static InetAddress getPeerAddr(int sockfd); private: int _sockfd; }; } #endif
///======================================= /// File: Socket.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 20:38:20 /// Dream: Don't forget your dreams! /// ====================================== #include "Socket.h" #include "SocketUtil.h" #include "InetAddress.h" namespace wd { Socket::Socket(int sockfd) :_sockfd(sockfd) {} Socket::Socket() :_sockfd(createSocketFd()) {} Socket::~Socket() { ::close(_sockfd); } void Socket::nonblock() { setNonblock(_sockfd); } void Socket::shutdownWrite() { if(-1==::shutdown(_sockfd,SHUT_WR)){ perror("shutdown write error!"); } } InetAddress Socket::getLocalAddr(int sockfd) { struct sockaddr_in addr; socklen_t len=sizeof(sockaddr_in); if(-1==::getsockname(sockfd,(struct sockaddr *)&addr,&len)){ perror("getsockname error!"); } return InetAddress(addr); } InetAddress Socket::getPeerAddr(int sockfd) { struct sockaddr_in addr; socklen_t len=sizeof(sockaddr_in); if(-1==::getpeername(sockfd,(struct sockaddr *)&addr,&len)){ perror("getpeername error!"); } return InetAddress(addr); } }
==SocketIO:==
///======================================= /// File: SocketIO.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-06 17:10:23 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __SOCKETIO_H__ #define __SOCKETIO_H__ #include <stdio.h> namespace wd { class SocketIO { public: SocketIO(int sockfd); size_t readn(char *buf,size_t count); size_t writen(const char *buf,size_t count); size_t readline(char *buf,size_t max_len); private: size_t recv_peek(char *buf,size_t count); int _sockfd; }; } #endif
///======================================= /// File: SocketIO.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 21:56:34 /// Dream: Don't forget your dreams! /// ====================================== #include "SocketIO.h" #include "SocketUtil.h" namespace wd { SocketIO::SocketIO(int sockfd) :_sockfd(sockfd) {} size_t SocketIO::readn(char *buf,size_t count) { size_t nleft =count; char *pbuf=buf; while(nleft>0) { int nread =::read(_sockfd,pbuf,nleft); if(-1==nread) { if(errno ==EINTR) continue; return EXIT_FAILURE; }else if(0==nread){ break; } pbuf =pbuf+nread; nleft=nleft-nread; } return (count -nleft); } size_t SocketIO::writen(const char * buf,size_t count) { size_t nleft =count; const char *pbuf=buf; while(nleft >0) { int nwrite=::write(_sockfd,pbuf,nleft); if(-1==nwrite) { if(errno ==EINTR) continue; return EXIT_FAILURE; } nleft =nleft -nwrite; pbuf =pbuf +nwrite; } return (count -nleft); } size_t SocketIO::recv_peek(char *buf,size_t count) { int nread; do{ nread=::recv(_sockfd,buf,count,MSG_PEEK); }while(-1==nread && errno ==EINTR); return nread; } size_t SocketIO::readline(char *buf,size_t maxlen) { size_t nleft =maxlen-1; char *pbuf=buf; size_t total=0; while(nleft>0) { size_t nread =recv_peek(pbuf,nleft); if(nread<=0) return nread; for(size_t idx =0;idx!=nread;++idx){//檢查換行符/n if(pbuf[idx]=='\n'){ size_t nsize =idx +1; if(readn(pbuf,nsize)!=nsize) return EXIT_FAILURE; pbuf +=nsize; total +=nsize; *pbuf=0; return total; } } if(readn(pbuf,nread)!=nread) return EXIT_FAILURE; pbuf +=nread; nleft -=nread; total +=nread; } *pbuf=0; return maxlen-1; } }
==SockUtil(根據陳碩編寫的LINUX書上分開頭文件)==
///======================================= /// File: SocktUtil.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-05 22:01:30 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __WD_SOCKERUTIL_H__ #define __WD_SOCKERUTIL_H__ #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/eventfd.h> #include <sys/epoll.h> namespace wd { inline int createSocketFd() { int fd=::socket(AF_INET,SOCK_STREAM,0); if(-1==fd) { perror("socket create error!"); } return fd; } inline void setNonblock(int fd) { int flags=::fcntl(fd,F_GETFL,0); flags |= O_NONBLOCK; ::fcntl(fd,F_SETFL,flags); } inline int createEpollFd() { int efd=::epoll_create1(0); if(-1==efd) { perror("epoll create1 error!"); exit(EXIT_FAILURE); } return efd; } inline int createEventFd() { int evtfd=::eventfd(0,EFD_NONBLOCK|EFD_CLOEXEC); if(-1==evtfd) { perror("eventfd create error!"); } return evtfd; } inline void addEpollFdRead(int efd,int fd) { struct epoll_event ev; ev.data.fd=fd; ev.events=EPOLLIN; int ret=epoll_ctl(efd,EPOLL_CTL_ADD,fd,&ev); if(-1==ret) { perror("epoll ctl add error!"); exit(EXIT_FAILURE); } } inline void delEpollReadFd(int efd,int fd) { struct epoll_event ev; ev.data.fd=fd; int ret=epoll_ctl(efd,EPOLL_CTL_DEL,fd,&ev); if(-1==ret) { perror("epoll ctl delete error!"); exit(EXIT_FAILURE); } } inline size_t recvPeek(int sockfd,void *buf,size_t len) { int nread; do{ nread=::recv(sockfd,buf,len,MSG_PEEK); }while(nread==-1 && errno ==EINTR); return nread; } inline bool isConnectionClosed(int sockfd) { char buf[1024]; int nread=recvPeek(sockfd,buf,sizeof(buf)); if(-1==nread) { perror("recvPeek error!"); return true; } return (0==nread); } } #endif
==SpellCorrrectSever:==
///======================================= /// File: SpellCorrectServer.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-06 20:41:13 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __SPELLCORRECTSERVER_H__ #define __SPELLCORRECTSERVER_H__ #include "TcpServer.h" #include "Threadpool.h" using namespace wd; namespace wd { class SpellCorrectServer { public: SpellCorrectServer(const string & ip ,unsigned short port ,size_t threadNUM ,size_t queSize); void start(); private: void onConnection(const TcpConnectionPtr &); void onMessage(const TcpConnectionPtr &); void onClose(const TcpConnectionPtr &); TcpServer _tcpserver; Threadpool _threadpoll; }; }; #endif
///======================================= /// File: SpellCorrectServer.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 21:20:41 /// Dream: Don't forget your dreams! /// ====================================== #include "SpellCorrectServer.h" #include "MyTask.h" #include <stdio.h> #include <iostream> #include <string> #include <utility> #include <functional> using namespace std; void SpellCorrectServer::onConnection(const wd::TcpConnectionPtr & conn) { cout<<conn->toString()<<endl; conn->send("hello ,welcome to WTP Chat Server.\r\n"); } void SpellCorrectServer::onMessage(const wd::TcpConnectionPtr & conn) { string s(conn->receive()); MyTask task(s,conn); _threadpoll.addTask(std::bind(&MyTask::execute,&task)); cout<<">add task to threadpool"<<endl; } void SpellCorrectServer::onClose(const wd::TcpConnectionPtr &conn) { ::printf("%s close\n",conn->toString().c_str()); } SpellCorrectServer::SpellCorrectServer(const string & ip ,unsigned short port ,size_t threadNUM ,size_t queSize) :_tcpserver(ip,port) ,_threadpoll(threadNUM,queSize) {} void SpellCorrectServer::start() { _threadpoll.start(); _tcpserver.setConnectionCallback(std::bind(&SpellCorrectServer::onConnection,this,std::placeholders::_1)); _tcpserver.setMessageCallback(std::bind(&SpellCorrectServer::onMessage,this,std::placeholders::_1)); _tcpserver.setCloseCallback(std::bind(&SpellCorrectServer::onClose,this,std::placeholders::_1)); _tcpserver.start(); }
==TaskQue:==
#ifndef __WD_TASKQUEUE_H__ #define __WD_TASKQUEUE_H__ #include "MutexLock.h" #include "Condition.h" #include <queue> #include <functional> namespace wd { typedef std::function<void()>Task; class TaskQueue { public: TaskQueue(size_t queSize) :_queSize(queSize) ,_mutex() ,_notFull(_mutex) ,_notEmpty(_mutex) ,_flag(true) {} void push(Task &&task); Task pop(); bool empty()const { return _que.size()==0; } bool full()const {return _que.size()==_queSize;} void wakeup() { if(_flag) _flag=false; _notEmpty.notifyAll(); } private: size_t _queSize; std::queue<Task> _que; MutexLock _mutex; Condition _notFull; Condition _notEmpty; bool _flag; }; } #endif
#include "TaskQueue.h" using namespace wd; //生產者所在的線程 void TaskQueue::push(Task && task) { MutexLockGuard autoLock(_mutex); while(full()) { _notFull.wait(); } _que.push(std::move(task)); _notEmpty.notify(); } //消費者所在線程 Task TaskQueue::pop() { MutexLockGuard autoLock(_mutex); while(_flag && empty()) { _notEmpty.wait(); } if(_flag){ Task task=_que.front(); _que.pop(); _notFull.notify(); return task; }else{ return NULL; } } #if 0 Task TaskQueue::pop() { MutexLockGuard autoLock(_mutex); while(_flag && empty()) { _notEmpty.wait(); } if(_flag){ Task task =_que.front(); _que.pop(); _notFull.notify(); return task; }else{ return NULL; } } #endif
==TcpConnection:==
///======================================= /// File: TcpConnection.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-06 17:15:33 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __WD_TCPCONNECTION_H__ #define __WD_TCPCONNECTION_H__ #include "Noncopyable.h" #include "InetAddress.h" #include "Socket.h" #include "SocketIO.h" #include <string> #include <memory> #include <functional> namespace wd { class EpollPoller; class TcpConnection; typedef std::shared_ptr<TcpConnection> TcpConnectionPtr; class TcpConnection :Noncopyable ,public std::enable_shared_from_this<TcpConnection> { public: typedef std::function<void(const TcpConnectionPtr &)>TcpConnectionCallback; TcpConnection(int sockfd,EpollPoller *loop); ~TcpConnection(); std::string receive(); void send(const std::string &msg); void sendInLoop(const std::string &msg); void shutdown(); std::string toString(); void setConnectionCallback(TcpConnectionCallback cb); void setMessageCallback(TcpConnectionCallback cb); void setCloseCallback(TcpConnectionCallback cb); void handleConnectionCallback(); void handleMessageCallback(); void handleCloseCallback(); private: Socket _sockfd; SocketIO _sockIO; const InetAddress _localAddr; const InetAddress _peerAddr; bool _isShutdownWrite; EpollPoller * _loop; TcpConnectionCallback _onConnectionCb; TcpConnectionCallback _onMessageCb; TcpConnectionCallback _onCloseCb; }; } #endif
///======================================= /// File: TcpConnection.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 22:22:22 /// Dream: Don't forget your dreams! /// ====================================== #include "TcpConnection.h" #include "EpollPoller.h" #include <string.h> #include <stdio.h> namespace wd { TcpConnection::TcpConnection(int sockfd,EpollPoller * loop) :_sockfd(sockfd) ,_sockIO(sockfd) ,_localAddr(wd::Socket::getLocalAddr(sockfd)) ,_peerAddr(wd::Socket::getPeerAddr(sockfd)) ,_isShutdownWrite(false) ,_loop(loop) {_sockfd.nonblock();} TcpConnection::~TcpConnection() { if(!_isShutdownWrite) { _isShutdownWrite=true; shutdown(); } printf("~TcpConnection()\n"); } std::string TcpConnection::receive() { char buf[65536]; memset(buf,0,sizeof(buf)); size_t ret =_sockIO.readline(buf,sizeof(buf)); if(0==ret){ return std::string(); }else{ return std::string(buf); } } void TcpConnection::send(const std::string &msg) { size_t len=msg.size(); _sockIO.writen((const char *)&len,sizeof(int)); _sockIO.writen(msg.c_str(),len); } void TcpConnection::shutdown() { if(!_isShutdownWrite) _sockfd.shutdownWrite(); _isShutdownWrite=true; } std::string TcpConnection::toString() { char str[100]; snprintf(str,sizeof(str),"%s:%d->%s:%d" ,_localAddr.ip().c_str() ,_localAddr.port() ,_peerAddr.ip().c_str() ,_peerAddr.port()); return std::string(str); } void TcpConnection::setConnectionCallback(TcpConnectionCallback cb) { _onConnectionCb =cb; } void TcpConnection::setMessageCallback(TcpConnectionCallback cb) { _onMessageCb =cb; } void TcpConnection::setCloseCallback(TcpConnectionCallback cb) { _onCloseCb =cb; } void TcpConnection::handleConnectionCallback() { if(_onConnectionCb){ _onConnectionCb(shared_from_this()); } } void TcpConnection::handleMessageCallback() { if(_onMessageCb){ _onMessageCb(shared_from_this()); } } void TcpConnection::handleCloseCallback() { if(_onCloseCb){ _onCloseCb(shared_from_this()); } } void TcpConnection::sendInLoop(const std::string & msg) { _loop->runInLoop(std::bind(&TcpConnection::send,this,msg)); } }
==TcpServer:==
///======================================= /// File: TcpServer.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-06 20:15:21 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __WD_TCPSERVER_H__ #define __WD_TCPSERVER_H__ #include "Acceptor.h" #include "EpollPoller.h" #include <string> using std::string; namespace wd { class TcpServer { public: typedef EpollPoller::EpollCallback TcpServerCallback; TcpServer(const string & ip,unsigned short port); TcpServer(unsigned short port); void start(); void stop(); void setConnectionCallback(TcpServerCallback cb); void setMessageCallback(TcpServerCallback cb); void setCloseCallback(TcpServerCallback cb); private: Acceptor _acceptor; EpollPoller _poller; TcpServerCallback _connectionCallback; TcpServerCallback _messageCallback; TcpServerCallback _closeCallback; }; } #endif
///======================================= /// File: TcpServer.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 19:59:37 /// Dream: Don't forget your dreams! /// ====================================== #include "TcpServer.h" #include "InetAddress.h" #include "SocketUtil.h" #include <iostream> using namespace std; namespace wd { TcpServer::TcpServer(const string & ip,unsigned short port) :_acceptor(createSocketFd(),InetAddress(ip.c_str(),port)) ,_poller(_acceptor) {} void TcpServer::start() { _acceptor.ready(); _poller.setConnectionCallback(_connectionCallback); _poller.setMessageCallback(_messageCallback); _poller.setCloseCallback(_closeCallback); _poller.loop(); } void TcpServer::stop() { _poller.unloop(); } void TcpServer::setConnectionCallback(TcpServerCallback cb) {_connectionCallback=cb;} void TcpServer::setMessageCallback(TcpServerCallback cb) {_messageCallback=cb;} void TcpServer::setCloseCallback(TcpServerCallback cb) {_closeCallback=cb;} }
==Thread:==
#ifndef __WD_THREAD_H__ #define __WD_THREAD_H__ #include "Noncopyable.h" #include <pthread.h> #include <functional> using std::function; namespace wd { class Thread; struct ThreadPtr { int _number; Thread *_pthread; }; class Thread :Noncopyable { using ThreadCallback =function<void()>; public: Thread(ThreadCallback &&cb); ~Thread(); void start(int number); void join(); bool isRunning()const {return _isRunning;} private: static void * threadFunc(void *); pthread_t _pthid; bool _isRunning; ThreadCallback _cb; }; } #endif
#include "Thread.h" #include <iostream> using namespace std; using namespace wd; __thread int t_number;//將線程編號做爲線程存儲的標記 Thread::Thread(ThreadCallback && cb)//這裏的右值引用自己取決因而否有名字 :_pthid(0) ,_isRunning(false) ,_cb(std::move(cb)) { cout<<"Thread(cb)"<<endl; } void Thread::start(int number) { ThreadPtr *threadPtr=new ThreadPtr(); threadPtr->_number=number; threadPtr->_pthread=this; pthread_create(&_pthid,NULL,threadFunc,threadPtr); _isRunning=true; } void *Thread::threadFunc(void *arg) {//應用了線程存儲 ThreadPtr *threadPtr=static_cast<ThreadPtr*>(arg); Thread * pthread=threadPtr->_pthread; t_number=threadPtr->_number; if(pthread) pthread->_cb();//線程開始工做! delete threadPtr; //Thread * pthread =threadPtr->_pthread; return NULL; } #if 0 void *Thread::threadFunc(void *arg) { ThreadPtr *threadPtr =static_cast<ThreadPtr*>(arg); Thread * pthread =threadPtr->_pthread; t_number =threadPtr->_number; if(pthread) pthread->_cb(); delete threadPtr; return NULL; } #endif void Thread::join() { pthread_join(_pthid,NULL); _isRunning=false; } Thread::~Thread() { if(_isRunning) { pthread_detach(_pthid); _isRunning=false; } cout<<"~Thread()"<<endl; }
==Threadpool:==
#ifndef __WD_THREADPOLL_H__ #define __WD_THREADPOLL_H__ #include "TaskQueue.h" #include "Thread.h" #include <vector> #include <memory> #include <functional> using std::shared_ptr; using std::vector; namespace wd { class Threadpool { public: using Task=std::function<void()>; Threadpool(size_t threadNum,size_t queSize) :_threadNum(threadNum) ,_queSize(queSize) ,_taskQue(_queSize) ,_isExit(false) { _threads.reserve(_threadNum); } ~Threadpool(); void start(); void stop(); void addTask(Task && task); private: void threadFunc(); Task getTask(); size_t _threadNum; size_t _queSize; vector<shared_ptr<Thread>> _threads; TaskQueue _taskQue; bool _isExit; }; } #endif
#include "Threadpool.h" #include "Thread.h" #include <unistd.h> #include <iostream> using namespace std; using namespace wd; void Threadpool::start() { for(size_t idx=0;idx<_threadNum;++idx) { shared_ptr<Thread>pThread(new Thread(std::bind(&Threadpool::threadFunc,this))); _threads.push_back(std::move(pThread)); } int number=0; for(auto &pThread:_threads) { pThread->start(number); ++number; } } void Threadpool::stop()//爲了線程安全,將stop方法置於主線程中 { if(!_isExit) { while(!_taskQue.empty()){ ::sleep(1); cout<<"Threadpool sleep 1 second!"<<endl; } _isExit=true; cout<<"Threadpool ->stop:_isExit="<<_isExit<<endl; _taskQue.wakeup(); for(auto &pthread:_threads){ pthread->join(); } } } Threadpool::~Threadpool() { if(!_isExit){ stop(); } } void Threadpool::addTask(Task && task) { _taskQue.push(std::move(task)); } Task Threadpool::getTask() { return _taskQue.pop(); } void Threadpool::threadFunc() { while(!_isExit) { Task task=getTask(); if(task){ task(); } } }
==Timer:==
///======================================= /// File: Timer.h /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-06 20:00:45 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __WD_TIMER_H__ #define __WD_TIMER_H__ #include <functional> namespace wd { class Timer { public: using TimerCallback =std::function<void()>; Timer(int initailTime,int intervalTime,TimerCallback && cb); ~Timer(); void start(); void stop(); private: int _fd; int _initialTime; int _intervalTime; TimerCallback _cb; bool _isStarted; int createTimerFd(); void setTimerfd(int initialTime, int intervalTime); void handleRead(); }; } #endif
///======================================= /// File: Timer.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 20:09:14 /// Dream: Don't forget your dreams! /// ====================================== #include "Timer.h" #include <unistd.h> #include <errno.h> #include <poll.h> #include <sys/timerfd.h> #include <iostream> using namespace std; using namespace wd; Timer::Timer(int initialTime,int intervalTime,TimerCallback && cb) :_fd(createTimerFd()) ,_initialTime(initialTime) ,_intervalTime(intervalTime) ,_cb(std::move(cb)) ,_isStarted(false) {} void Timer::start() { struct pollfd pfd; pfd.fd=_fd; pfd.events=POLLIN; setTimerfd(_initialTime,_intervalTime);//開啓定時器 _isStarted=true; while(_isStarted){ int nready=::poll(&pfd,1,5000); if(-1==nready &&errno ==EINTR){ continue; }else if(-1==nready){ perror(">>>poll error!"); exit(EXIT_FAILURE); }else if(0==nready){ cout<<">>>poll timeout!"<<endl; }else{ if(pfd.revents & POLLIN){ handleRead();//先對定時器進行處理 if(_cb){ _cb();//再去執行回調任務 } } } } } void Timer::stop() { setTimerfd(0,0); if(_isStarted){ _isStarted=false; } } Timer::~Timer() { if(_isStarted){ stop(); } } int Timer::createTimerFd() { int fd=::timerfd_create(CLOCK_REALTIME,0); if(-1==fd){ perror(">>timerfd_create error!"); } return fd; } void Timer::setTimerfd(int initialTime,int intervalTime) { struct itimerspec value; value.it_value.tv_sec=initialTime; value.it_value.tv_nsec=0; value.it_interval.tv_sec=intervalTime; value.it_interval.tv_nsec=0; int ret=::timerfd_settime(_fd,0,&value,NULL); if(-1==ret){ perror(">>>timerfd_settime error!"); } } #if 0 void Timer::handleRead() { uint64_t howmany; int ret =::read(_fd,&howmany,sizeof(uint64_t)); if(ret!=sizeof(uint64_t)){ perror("read!"); } } #endif void Timer::handleRead() { uint64_t howmany;//爲一個64位 int ret=::read(_fd,&howmany,sizeof(uint64_t)); if(ret!=sizeof(uint64_t)){ perror(">>>read error!"); } }
==TimerThread:==
///======================================= /// File: TimerThread.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 17:12:51 /// Dream: Don't forget your dreams! /// ====================================== #ifndef __WD_TIMERTHREAD_H__ #define __WD_TIMERTHREAD_H__ #include "Timer.h" #include "Thread.h" #include <functional> namespace wd { class TimerThread { public: using TimerCallback = std::function<void()>; TimerThread(int, int, TimerCallback && cb); ~TimerThread(); void start(); void stop(); private: Timer _timer; Thread _subThread; bool _isStarted; }; }//end of namespace wd #endif
///======================================= /// File: TimerThread.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 20:09:14 /// Dream: Don't forget your dreams! /// ====================================== #include "TimerThread.h" using namespace wd; TimerThread::TimerThread(int initialTime, int intervalTime, TimerCallback && cb) : _timer(initialTime, intervalTime, std::move(cb)) , _subThread(std::bind(&Timer::start, &_timer)) , _isStarted(false) {} void TimerThread::start() { _subThread.start(0); _isStarted = true; } void TimerThread::stop() { if(_isStarted) { _timer.stop(); _subThread.join(); _isStarted = false; } } TimerThread::~TimerThread() { if(_isStarted) stop(); }
==main:==
///======================================= /// File: main.cc /// Author: wtptorres(1584292712@qq.com) /// Date: 2019-06-07 21:09:32 /// Dream: Don't forget your dreams! /// ====================================== #include "SpellCorrectServer.h" #include "ConFiguration.h" #include "CacheManger.h" #include "TimerThread.h" #include <iostream> #include <functional> using namespace std; using namespace wd; int main() { wd::CacheManger *mycacheManger=Singleton<CacheManger>::getInstance(Singleton<Configuration> ::getInstance(CONFPATH)->getCache()); TimerThread timer(5,600,std::bind(&CacheManger::periodicUpdate,mycacheManger)); timer.start(); SpellCorrectServer myspell(Singleton<Configuration>::getInstance(CONFPATH)->getIp() ,Singleton<Configuration>::getInstance(CONFPATH)->getPort() ,4 ,10); myspell.start(); return 0; }
小結:(1)已經實現項目需求,中文和英文單詞都能查詢,通過測試,運行穩定,能輸出很多候選詞
(2)仍然存在少許bug,例如偶爾會發生段錯誤
(3)因爲時間問題,json讀出的數據key-value的key值沒有打印,用戶界面還將來得及優化
(4)陳碩的《linux多線程服務端編程》使用linux接口(timerfd),沒用posix接口(eventfd)