关于拼写小助手的开发日记
2019-08-16 07:42:14来源:博客园 阅读 ()
关于拼写小助手的开发日记
目录
- 我的Spellcorrect 开发文档
- 相关配置文件及准备工作:
- 演示效果(中文):
- 演示效果(英语):
- 代码部分:
- 相关配置文件及准备工作:
- 演示效果(中文):
- 演示效果(英语):
- 代码部分:
---恢复内容开始---
我的Spellcorrect 开发文档
相关配置文件及准备工作:
我的主要文件夹分为三个:分别为客户端,cppjieba分词库,离线部分及服务器部分
客户端部分:内部为客户端源码及运行程序
cppjieba分词库部分,就不赘述,请自行安装
离线部分:内部有中英文件夹放置索引及词典文件,还有配置文件及分词库,其余为代码
服务器部分:最为重要的配置文件及数据部分,头文件在include,实现文件在src里面
演示效果(中文):
==启动时服务器:==
==客户端连入时时服务器:==
==输入“赵”==
==输入“周杰伦”==
==输入清华大学==
演示效果(英语):
==启动时服务器:==
==客户端连入时时服务器:==
==输入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分词库,离线部分及服务器部分
客户端部分:内部为客户端源码及运行程序
cppjieba分词库部分,就不赘述,请自行安装
离线部分:内部有中英文件夹放置索引及词典文件,还有配置文件及分词库,其余为代码
服务器部分:最为重要的配置文件及数据部分,头文件在include,实现文件在src里面
演示效果(中文):
==启动时服务器:==
==客户端连入时时服务器:==
==输入“赵”==
==输入“周杰伦”==
==输入清华大学==
演示效果(英语):
==启动时服务器:==
==客户端连入时时服务器:==
==输入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)
原文链接:https://www.cnblogs.com/wtptorres/p/11084174.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
下一篇:递归(五):递归图形
- 关于各种不同开发语言之间数据加密方法(DES,RSA等)的互通的 2020-06-07
- 关于使用ffmpeg的一些牢骚 2020-05-08
- 关于有趣的windows.h 2020-03-09
- 关于C/C++的各种优化 2020-02-06
- 关于C/C++的各种优化 2020-01-20
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash