关于拼写小助手的开发日记

---恢复内容开始---

# **我的Spellcorrect 开发文档**


相关配置文件及准备工作:

我的主要文件夹分为三个:分别为客户端,cppjieba分词库,离线部分及服务器部分

1560856582308

客户端部分:内部为客户端源码及运行程序

1560856552431

cppjieba分词库部分,就不赘述,请自行安装
离线部分:内部有中英文件夹放置索引及词典文件,还有配置文件及分词库,其余为代码

1560857073864

服务器部分:最为重要的配置文件及数据部分,头文件在include,实现文件在src里面

1560857034230


演示效果(中文):

启动时服务器:

1560857677039

客户端连入时时服务器:

1560857739202

输入“赵”

1560858117388

输入“周杰伦”

1560858201376

输入清华大学

1560858560147


演示效果(英语):

启动时服务器:

1560857677039

客户端连入时时服务器:

1560857739202

输入student:

1560858008297

输入spell:

1560858872540

输入computer:

1560859162357


代码部分:

离线部分:

![img](file:///C:\Users\dell\AppData\Local\Temp\ksohtml13180\wps1.jpg)

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;
}


在线部分:

![img](file:///C:\Users\dell\AppData\Local\Temp\ksohtml13180\wps2.jpg)

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 开发文档



相关配置文件及准备工作:

我的主要文件夹分为三个:分别为客户端,cppjieba分词库,离线部分及服务器部分

1560856582308

客户端部分:内部为客户端源码及运行程序

1560856552431

cppjieba分词库部分,就不赘述,请自行安装
离线部分:内部有中英文件夹放置索引及词典文件,还有配置文件及分词库,其余为代码

1560857073864

服务器部分:最为重要的配置文件及数据部分,头文件在include,实现文件在src里面

1560857034230


演示效果(中文):

启动时服务器:

1560857677039

客户端连入时时服务器:

1560857739202

输入“赵”

1560858117388

输入“周杰伦”

1560858201376

输入清华大学

1560858560147


演示效果(英语):

启动时服务器:

1560857677039

客户端连入时时服务器:

1560857739202

输入student:

1560858008297

输入spell:

1560858872540

输入computer:

1560859162357


代码部分:

离线部分:

![img](file:///C:\Users\dell\AppData\Local\Temp\ksohtml13180\wps1.jpg)

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;
}


在线部分:

![img](file:///C:\Users\dell\AppData\Local\Temp\ksohtml13180\wps2.jpg)

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)

posted @ 2019-06-25 17:48  大白白熊白白  阅读(411)  评论(0编辑  收藏  举报