欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-05-15 14:29:50
恢复内容开始 我的Spellcorrect 开发文档 [TOC] 相关配置文件及准备工作: 我的主要文件夹分为三个:分别为客户端,cppjieba分词库,离线部分及服务器部分 客户端部分:内部为客户端源码及运行程序 cppjieba分词库部分,就不赘述,请自行安装 离线部分:内部有中英文件夹放置索引 ......

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

我的spellcorrect 开发文档



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

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

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

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

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

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

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

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

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


演示效果(中文):

==启动时服务器:==

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

==客户端连入时时服务器:==

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

==输入“赵”==

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

==输入“周杰伦”==

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

==输入清华大学==

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


演示效果(英语):

==启动时服务器:==

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

==客户端连入时时服务器:==

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

==输入student:==

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

==输入spell:==

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

==输入computer:==

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


代码部分:

离线部分:

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

==makefile:==

srcs:=$(wildcard *.cc)
objs:= $(patsubst %.cc, %.o, $(srcs))

cxx:=g++

cxxflags:= -w -g -std=c++11 $(addprefix -i, $(inc_dir)) $(libs) -wno-deprecated -i ../cppjieba/include/ -i ../cppjieba/deps

exe:=./main

$(exe):$(objs)
        $(cxx) -o $(exe) $(objs) $(cxxflags)

clean:
        rm -rf $(exe)
            rm -rf $(objs)

==configuration:==

///=======================================
/// file:    configuration.h
/// author:  wtptorres(1584292712@qq.com)
/// date:    2019-06-12 00:30:39
/// dream:   don't forget your dreams!
/// ======================================

#ifndef __configuration_h__
#define __configuration_h__
#include "nocopyable.h"
#include <string>
#include <map>
using namespace std;

class configuration
:public noncopyable
{
public:
    configuration(const string &filepath);
    string getenglishdir() const {return _englishdir;}
    string getchinesedir() const {return _chinesedir;}
private:
    string _filepath;
    string _englishdir;
    string _chinesedir;
};
template<typename t>
class singleton
{
public:
    template<typename ...args>
    static t* getinstance(args ...args)
    {
        if(!_pinstance)
            _pinstance = new t(args...);
        return _pinstance;
    }
    static void destroy()
    {
        if(_pinstance)
            delete _pinstance;
    }
private:
    singleton();
    ~singleton();
    static t *_pinstance;                    
};
template<typename t>
t * singleton<t>::_pinstance = null;
#endif
  1  ///=======================================
  2  /// file:    configuration.cc
  3  /// author:  wtptorres(1584292712@qq.com)
  4  /// date:    2019-06-12 00:30:04
  5  /// dream:   don't forget your dreams!
  6  /// ======================================
  7 
  8                                     
  9 #include "configuration.h"
 10 #include <utility>
 11 #include <fstream>
 12 #include <iostream>
 13 using namespace std;
 14 
 15 configuration::configuration(const string &filepath)
 16 :_filepath(std::move(filepath))
 17 {
 18     ifstream ifs(_filepath);
 19     if(!ifs)
 20         cout<<"file open error!"<<endl;
 21     ifs>>_englishdir;
 22     ifs>>_chinesedir;
 23     ifs.close();
 24 }
 ///=======================================
 /// file:    nocopyable.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-12 00:24:36
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __nocopyable_h__
#define __nocopyable_h__
class noncopyable
{
public:
    noncopyable()=default;
    ~noncopyable()=default;
private:
    noncopyable(const noncopyable &rhs);
    noncopyable &operator =(const noncopyable &rhs);
};
#endif

==dictproducer:==

 ///=======================================
 /// file:    dictproducer.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-12 16:40:25
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __dictproducer_h__
#define __dictproducer_h__
#include "splittool.h"
using namespace std;
#include "nocopyable.h"
#include <memory>
#include <string>
#include <vector>
#include <map>
#include <utility>


class dictproducer
:public noncopyable
{
public:
    dictproducer(const string,const string,const string &,splittooljieba *);
    ~dictproducer(){}
    void build_dict();
    void build_cn_dict();
    void store_dict();
    vector<pair<string,int>>& getindict(){return _indict;}
private:
    void processenglishword(string &word);
    void processchineseword(string &word);//除去中文的数字
    void construct_indict();
    string _englishdir;
    string _chinesedir;
    string _golefilepath;
    vector<string> _englishfiles;
    vector<string> _chinesefiles;
    map<string,int> _dict;
    vector<pair<string,int>> _indict;
    shared_ptr<splittooljieba> _splittool;
};
#endif
 ///=======================================
 /// file:    dictproducer.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-12 16:50:46
 /// dream:   don't forget your dreams!
 /// ======================================


#include "dictproducer.h"
#include <cctype>
#include <utility>
#include <fstream>
#include <iostream>
#define firstsize 10000
using namespace std;

dictproducer::dictproducer(const string englishdir,const string chinesedir,const string &golefilepath,splittooljieba *splittoolptr)
    :_englishdir(englishdir)
    ,_chinesedir(chinesedir)
    ,_golefilepath(golefilepath)
{
    _splittool.reset(splittoolptr);
    std::ifstream ifsenglish(_englishdir);
    std::ifstream ifschinese(_chinesedir);
    string filepath;
    if(!ifsenglish || !ifschinese){
        cout<<"dict file open error!"<<endl;
    }
    while(ifsenglish>>filepath)
    {
        _englishfiles.push_back(filepath);
    }
    while(ifschinese>>filepath)
    {
        _chinesefiles.push_back(filepath);
    }
    _indict.reserve(firstsize);
}

void dictproducer::processenglishword(string &word)
{
    auto cit =word.begin();
    for(;cit!=word.end();++cit)
    {   //去除标点符号或数字
        if(!isalpha(*cit)){
            word.erase(cit);
            --cit;//迭代器位置发生改变
        }else if(isupper(*cit)){//将大写字母改为小写
            *cit =tolower(*cit);
        }
    }
}

void dictproducer::processchineseword(string &word)
{
    auto cit =word.begin();
    for(;cit!=word.end();++cit)
    {   //去除数字
        if(!isalnum(*cit)){
            word.erase(cit);
            --cit;
        }
    }
}

void dictproducer::build_dict()//建立英文词典
{
    for(auto &filepath:_englishfiles)
    {
        ifstream ifs(filepath);
        if(!ifs){
            cout<<"english file open error!"<<endl;
        }
        string word;
        while(ifs>>word)
        {
            processenglishword(word);
            auto cit =_dict.find(word);
            if(word.size()>0 && cit ==_dict.end()){
                _dict.insert(std::make_pair(word,1));
            }else if(cit!=_dict.end()){
                ++ cit ->second;
            }
        }
    }
}


void dictproducer::build_cn_dict()
{
    vector<string>words;
    for(auto filepath:_chinesefiles)
    {
        ifstream ifs(filepath);
        if(!ifs){
            cout<<"chinese file open error!"<<endl;
        }
        string sentence;
        while(std::getline(ifs,sentence))
        {
            _splittool->cut(sentence);
        }
    }
    vector<string>& results =_splittool->getresult();
    for(auto &res:results)
    {
        processchineseword(res);
        auto cit =_dict.find(res);
        if(cit ==_dict.end()){
            _dict.insert(std::make_pair(res,1));
        }else{
            ++ cit ->second;
        }
    }
}

void dictproducer::store_dict()
{
    construct_indict();
    ofstream ofs(_golefilepath);
    if(!ofs)
        cout<<"store_dict open file error!"<<endl;
    for(auto &mypair:_indict)
    {
        ofs<<mypair.first<<" "<<mypair.second<<endl;
    }
    ofs.close();
}

void dictproducer::construct_indict()
{
    for(auto dictpair:_dict){
        _indict.push_back(dictpair);
    }
}

==getindex:==

 ///=======================================
 /// file:    getindex.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-12 08:52:04
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __getindex_h__
#define __getindex_h__
#include <string>
#include <unordered_map>
#include <set>
#include <vector>
#include <utility>
#include <unordered_set>
using namespace std;

class getindex
{
public:
    getindex(const string &,const string &,const string &);
    ~getindex(){}
    void construct_index();
    void store_index();
private:
    bool isenglish(const string &rhs) const;
    vector<string>getonecharacter(const string & word);
    string _sourcefilepath;
    string _golefilepath;
    string _stopwordsfilepath;
    vector<pair<string,int>>_dict;
    unordered_set<string>_stopwords;
    unordered_map<string,set<int>>_index;
};
#endif
 ///=======================================
 /// file:    getindex.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-12 09:00:11
 /// dream:   don't forget your dreams!
 /// ======================================


#include "getindex.h"
#include <fstream>
#include <sstream>
#include <iostream>
using namespace std;

getindex::getindex(const string & sourcefilepath,const string &golefilepath,const string &stopwordsfilepath)
:_sourcefilepath(std::move(sourcefilepath))
,_golefilepath(std::move(golefilepath))
,_stopwordsfilepath(std::move(stopwordsfilepath))
{
    ifstream ifs(_sourcefilepath);
    if(!ifs){
        cout<<"getindex file open error!"<<endl;
    }
    string line;
    while(getline(ifs,line))
    {
        istringstream iss(line);
        string key;
        int value;
        iss>>key>>value;
        _dict.push_back(std::make_pair(key,value));
    }
    ifstream ifs1(_stopwordsfilepath);
    if(!ifs1){
        cout<<"file open error!"<<endl;
    }
    string stopword;
    while(ifs1>>stopword,!ifs1.eof())
    {
        _stopwords.insert(stopword);
    }
}

vector<string> getindex::getonecharacter(const string &word)
{
    vector<string>tmp;
    auto cit =word.begin();
    while(cit<word.end())
    {
        if(224==(*cit &224))
        {
            string onecharacter;
            onecharacter.append(cit,cit+3);
            tmp.push_back(onecharacter);
            cit +=3;
        }else if(240==(*cit &240)){
            string onecharacter;
            onecharacter.append(cit,cit+4);
            tmp.push_back(onecharacter);
            cit +=4;
        }else
            break;
    }
    return tmp;
}
             
bool getindex::isenglish(const string &rhs) const
{
    char ch =*(rhs.begin());
    if(ch<0)
        return false;
    return true;
}
#if 0
bool getindex::isenglish(const string &rhs) const
{
    char ch =*(rhs.begin());
    if(ch<0){
        return false;
    }
    return true;
}
#endif
void getindex::construct_index()
{
    for(size_t i=0;i!=_dict.size();++i)
    {
        string tmp=_dict[i].first;
        if(isenglish(tmp))
        {
            for(auto ch:tmp)
            {
                string charactor(1,ch);
                if(isalpha(ch))
                {
                    auto cit =_index.find(charactor);
                    if(cit ==_index.end())
                    {
                        set<int> smp;
                        smp.insert(i);
                        _index.insert(std::make_pair(charactor,smp));
                    }else{//已经存在了该字母的索引
                        cit->second.insert(i);
                    }
                }
            }
        }else{//中文处理部分
            vector<string> onecharacterrally =getonecharacter(tmp);
            for(auto onecharacter:onecharacterrally)
            {//stop_words中不存在该单词,则加入索引中
                if(_stopwords.find(onecharacter)==_stopwords.end()){
                    auto it =_index.find(onecharacter);
                    if(it == _index.end()){
                        set<int>tmp;
                        tmp.insert(i);
                        _index.insert(std::make_pair(onecharacter,tmp));
                    }else{
                        it->second.insert(i);
                    }
                }
            }
        }
    }
}

void getindex::store_index()
{   
    //ofs存储索引的内容
    std::ofstream ofs(_golefilepath);
    if(!ofs){
        cout<<"file open error!"<<endl;
        return;
    }
    for(auto data:_index)
    {
        ofs<<data.first<<" ";
        for(auto linenum:data.second)
        {
            ofs<<linenum<<" ";
        }
        ofs<<endl;
    }
    ofs.close();
}

==splittool:==

 ///=======================================
 /// file:    splittool.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-12 17:12:01
 /// dream:   don't forget your dreams!
 /// ======================================


#ifndef __splittool_h__
#define __splittool_h__
#include "../cppjieba/include/cppjieba/jieba.hpp"//需要自己将cppjieba安装在项目目录下
#include "configuration.h"
#include <string>
#include <vector>
using namespace std;
using namespace cppjieba;
class splittooljieba
{
public:
    splittooljieba(const string& dict_path,const string &model_path,const string &user_dict_path,const string & idfpath, const string &stopwordpath)
    :_jieba(dict_path,model_path,user_dict_path,idfpath,stopwordpath)
    {}
    ~splittooljieba(){}
    void cut(const string & sentence)
    {
        vector<string>tmp;
        _jieba.cut(sentence,tmp);
        _result.insert(_result.end(),tmp.begin(),tmp.end());
    }
    vector<string> & getresult(){return _result;}
private:
    vector<string> _result;
    cppjieba::jieba _jieba;
};
#endif

==main:==

 ///=======================================
 /// file:    main.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-12 20:38:50
 /// dream:   don't forget your dreams!
 /// ======================================


#include "configuration.h"
#include "splittool.h"
using namespace std;
#include "dictproducer.h"
#include "getindex.h"
#include <iostream>
#include <memory>
const char * const dict_path ="../cppjieba/dict/jieba.dict.utf8";
const char * const hmm_path ="../cppjieba/dict/hmm_model.utf8";
const char * const user_dict_path ="../cppjieba/dict/user.dict.utf8";
const char * const idf_path ="../cppjieba/dict/idf.utf8";
const char * const stop_word_path ="../cppjieba/dict/stop_words.utf8";
const string gole_dict_path="../server/data/dict.txt";
const string gole_index_path="../server/data/index.txt";

class splittool;
int main(void)
{
    configuration *pconfig =singleton<configuration>::getinstance("configure.txt");
    splittooljieba *ptool =new splittooljieba(dict_path,hmm_path,user_dict_path,idf_path,stop_word_path);
    dictproducer mydictproducer(pconfig->getenglishdir(),pconfig->getchinesedir(),gole_dict_path,ptool);
    mydictproducer.build_dict();//建立英语词典
    mydictproducer.build_cn_dict();//建立中文词典
    mydictproducer.store_dict();//储存词典
    getindex myindex(gole_dict_path,gole_index_path,"stop_words_zh.txt");
    myindex.construct_index();//建立索引
    myindex.store_index();//存储索引
    singleton<configuration>::destroy();
    return 0;
}

在线部分:

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

==configuration:==

 ///=======================================
 /// file:    configuration.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-06 10:32:43
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __configuration_h__
#define __configuration_h__
#include "noncopyable.h"
#include <string>
#include <map>
#define confpath "/home/wtp/spell/server/conf/configure.txt"
using namespace std;

namespace wd
{
    class configuration
    :public noncopyable
    {
    public:
        configuration(const string &filepath);
        ~configuration()=default;
        string getdictdir() const;
        string getindexdir() const;
        string getip()const;
        string getcache() const;
        unsigned short getport() const;

    private:
        string _filepath;
        map<string,string> _conf;
    };
};

template<typename t>
class singleton
{
public:
    template<typename ...args>
    static t *getinstance(args ...args)
    {
        if(!_pinstance)
            _pinstance=new t(args ...);
        return _pinstance;
    }

    static void destroy()
    {
        if(_pinstance)
            delete _pinstance;
    }
private:
    singleton();
    ~singleton();
    static t *_pinstance;
};

template<typename t>
t *singleton<t>::_pinstance =null;
#endif
 ///=======================================
 /// file:    configuration.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 15:24:14
 /// dream:   don't forget your dreams!
 /// ======================================

#include "configuration.h"
#include <stdlib.h>
#include <utility>
#include <fstream>
#include <iostream>
using namespace std;
using namespace wd;

wd::configuration::configuration(const string & filepath)
:_filepath(std::move(filepath))
{
    ifstream ifs(_filepath);
    if(!ifs){
        cout<<"file open error!"<<endl;
    }
    string key,value;
    while(ifs>>key)
    {
        ifs>>value;
        _conf.insert(std::make_pair(key,value));
    }
    ifs.close();
}

string wd::configuration::getdictdir() const
{
    auto cit=_conf.find("mydict");
    if(cit== _conf.end())
        return "";
    else
        return cit->second;
}

string wd::configuration::getindexdir() const
{
    auto cit =_conf.find("myindex");
    if(cit== _conf.end())
        return "";
    else 
        return cit->second;
}

string wd::configuration::getip() const
{
    auto cit =_conf.find("myip");
    if(cit ==_conf.end())
        return "";
    else
        return cit->second;
}

unsigned short wd::configuration::getport() const
{
    auto cit =_conf.find("myport");
    if(cit==_conf.end())
        return 0;
    else
        return atoi(cit->second.c_str());
}

string wd::configuration::getcache() const
{
    auto cit =_conf.find("mycache");
    if(cit ==_conf.end())
        return "";
    else
        return cit->second;
}
             
 

==acceptor:==

 ///=======================================
 /// file:    acceptor.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-05 23:47:05
 /// dream:   don't forget your dreams!
 /// ======================================
 
#ifndef  __wd_acceptor_h__
#define  __wd_acceptor_h__

#include "socket.h"
#include "inetaddress.h"

namespace wd
{
    class acceptor
    {
    public:
        acceptor(int listenfd,const inetaddress & addr);
        void ready();//服务器监听准备
        int accept();//服务器接收新连接
        int fd()const {return _listensock.fd();}
    private:
        void setreuseaddr(bool on);//设置地址重用
        void setreuseport(bool on);//设置端口重用
        void bind();//绑定
        void listen();//监听
        socket _listensock;
        inetaddress _addr;
    };
}

#endif
 ///=======================================
 /// file:    acceptor.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-05 23:52:12
 /// dream:   don't forget your dreams!
 /// ======================================
#include <iostream>
#include "acceptor.h"
#include "socketutil.h"

namespace wd
{
acceptor::acceptor(int listenfd,const inetaddress & addr)
:_listensock(listenfd)
,_addr(addr)
{}

void acceptor::ready()
{
    setreuseaddr(true);
    setreuseport(true);
    bind();
    listen();
}
int acceptor::accept()
{
    int peerfd=::accept(_listensock.fd(),null,null);
    if(-1==peerfd)
    {
        perror("accept error!");
    }
    return peerfd;
}
void acceptor::setreuseaddr(bool flag)
{
    int on=(flag?1:0);
    if(::setsockopt(_listensock.fd()
                    ,sol_socket
                    ,so_reuseaddr
                    ,&on
                    ,static_cast<socklen_t>(size_t(on)))==-1)
    {
        perror("setsockopt reuseaddr error!");
        ::close(_listensock.fd());
        exit(exit_failure);
    }
}

void acceptor::setreuseport(bool flag)
{
#ifndef so_reuseport
    int on=(flag?1:0);
    if(::setsockopt(_listensock.fd()
                    ,sol_socket
                    ,so_reuseaddr
                    ,&on
                    ,static_cast<socklen_t>(size_t(on)))==-1)
    {
        perror("setsockopt reuseport error!");
        ::close(_listensock.fd());
        exit(exit_failure);
    }
#else
    if(flag)
    {
        fprintf(stderr,"so_reuseport is not supported!\n");
    }
#endif
}

void acceptor::bind()
{
    if(-1==::bind(_listensock.fd()
                  ,(const struct sockaddr*)_addr.getsockaddrptr()
                  ,sizeof(inetaddress)))
    {
        perror("bind error!");
        ::close(_listensock.fd());
        exit(exit_failure);
    }
}
void acceptor::listen()
{
    if(-1==::listen(_listensock.fd(),10))
    {
        perror("listen error!");
        ::close(_listensock.fd());
        exit(exit_failure);
    }
}

}
#if 0
int main()
{
    std::cout<<"acceptor is correct!"<<std::endl;
}
#endif

==condition.h:==

#ifndef __wd_condition_h__
#define __wd_condition_h__

#include "noncopyable.h"
#include "mutexlock.h"
#include <pthread.h>

namespace wd
{
    class condition
    :noncopyable
    {
    public:
        condition(mutexlock &mutex)
        :_mutex(mutex)
        {pthread_cond_init(&_cond,null);}
    
        ~condition()
        {pthread_cond_destroy(&_cond);}
    
        void wait()
        {pthread_cond_wait(&_cond,_mutex.getmutexlockptr());}
    
        void notify()
        {pthread_cond_signal(&_cond);}
    
        void notifyall()
        {pthread_cond_broadcast(&_cond);}
    private:
        pthread_cond_t _cond;
        mutexlock & _mutex;
    };
}
#endif

==cache:==

 ///=======================================
 /// file:    cache.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-05 19:52:40
 /// dream:   don't forget your dreams!
 /// ======================================
 
#ifndef __cache_h__
#define __cache_h__
#include <unordered_map>
#include <string>
using namespace std;
namespace wd
{
    class cache
    {
    public:
        void addelement(string,string);//增加缓存信息
        void readfromfile(string);//从文件中读取信息
        void writetofile(string);//将信息写入文件中
        void update(const cache&);//更新缓存消息
        bool find(string querry);//从数据库中找寻信息
        string &operator[](string key);
    private:
        unordered_map<string,string>_hashtable;//采用hashtable进行缓存
    };
};
#endif
 ///=======================================
 /// file:    cache.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-05 20:01:25
 /// dream:   don't forget your dreams!
 /// ======================================
#include "cache.h"
#include <fstream>
#include <utility>
#include <iostream>
using namespace std;
using namespace wd;

void cache::addelement(string querry,string result)
{
    _hashtable[querry]=result;
}

void cache::readfromfile(string filepath)
{
    ifstream ifs(filepath);
    if(!ifs){
        cout<<"cache::read readfromfile file open error!"<<endl;
        return;
    }
    string querry,result;
    while(ifs>>querry,!ifs.eof())
    {
        ifs>>result;
        _hashtable[querry]=result;
    }
}
#if 0
void cache::writetofile(string filepath)
{
    ofstream ofs(filepath);
    if(!ofs){
        cout<<""<<endl;
        return;
    }
    for(auto &mypair:_hashtable)
    {
        ofs<<mypair.first<<" ";
        ofs<<mypair.second<<endl;
    }
}

void cache::update(const cache & cache)
{   
    for(auto &mypair:cache._hashtable)
    {
        auto cit =_hashtable.find(mypair.first);
        if(cit==_hashtable.end())
        {
            _hashtable.insert(std::move(mypair));
        }
    }
}
#endif

void cache::writetofile(string filepath)
{
    ofstream ofs(filepath);
    if(!ofs){
        cout<<"file write error!"<<endl;
        return;
    }
    for(auto &mypair:_hashtable)
    {
        ofs<<mypair.first<<" ";
        ofs<<mypair.second<<endl;
    }
}

void cache::update(const cache & cache)
{
    for(auto &mypair:cache._hashtable)
    {
        auto cit =_hashtable.find(mypair.first);
        if(cit==_hashtable.end())
        {
            _hashtable.insert(std::move(mypair));
        }
    }
}

bool cache::find(string querry)
{
    auto cit =_hashtable.find(querry);
    if(cit==_hashtable.end())
        return false;
    return true;
}

string &cache::operator[](string key)
{
    return _hashtable[key];
}

#if 0
int main()
{
    cout<<"cache is correct!"<<endl;
}
#endif

==cachemanger:==

 ///=======================================
 /// file:    cachemanger.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-05 20:51:09
 /// dream:   don't forget your dreams!
 /// ======================================
 
#ifndef __cachemanger_h__
#define __cachemanger_h__
#include "cache.h"
#include <vector>
#define threadnum 4//线程数目设置为4个,可自定义

using std::vector;
namespace wd
{
    class cachemanger
    {
    public:
        cachemanger(string filepath);
        void init(string);//创建缓存
        cache & getcache(size_t);//获取某个缓存
        void periodicupdate();//定时更新所有缓存
    private:
        string _cachefilepath;
        vector<cache>_cachelist;
    };
};

#endif
 ///=======================================
 /// file:    cachemanger.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-05 20:56:50
 /// dream:   don't forget your dreams!
 /// ======================================
#include "cachemanger.h"
#include <iostream>
#include <fstream>
#include <utility>
#include <iostream>
using namespace std;
using namespace wd;

cachemanger::cachemanger(string cachefilepath)
{
    init(cachefilepath);
}
             
void cachemanger::init(string cachefilepath)
{
    _cachefilepath=cachefilepath;
    _cachelist.reserve(threadnum);
    cache tmp;
    tmp.readfromfile(_cachefilepath);
    for(size_t i=0;i!=threadnum;++i)
    {
        _cachelist.push_back(std::move(tmp));
    }
}

cache & cachemanger::getcache(size_t number)
{
    return _cachelist[number];
}

void cachemanger::periodicupdate()
{
    auto cit=_cachelist.begin();
    cache lastwrite=*(cit ++);
    for(;cit<_cachelist.end();++cit)
    {
        lastwrite.update(*cit);
    }
    for(cit=_cachelist.begin()+1;cit!=_cachelist.end();++cit)
    {
        (*cit).update(lastwrite);
    }
    lastwrite.writetofile(_cachefilepath);
}

==epollpoller:==

 ///=======================================
 /// file:    epollpoller.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-06 11:03:36
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __wd_epollpoller_h__
#define __wd_epollpoller_h__

#include "tcpconnection.h"
#include "noncopyable.h"
#include "mutexlock.h"
#include <sys/epoll.h>
#include <vector>
#include <map>
#include <functional>

namespace wd
{
    class acceptor;
    class epollpoller
    :noncopyable
    {
    public:
        typedef tcpconnection::tcpconnectioncallback epollcallback;
        typedef  std::function<void()> functor;
        epollpoller(acceptor &acceptor);
        ~epollpoller();
    
        void loop();
        void unloop();
        void runinloop(const functor && cb);
        void dopendingfunctors();
        void wakeup();
    
        void setconnectioncallback(epollcallback cb);
        void setmessagecallback(epollcallback cb);
        void setclosecallback(epollcallback cb);
    private:
        void waitepollfd();
        void handleconnection();
        void handlemessage(int peerfd);
        void handleread();
    
        acceptor & _acceptor;
        int _epollfd;
        int _eventfd;
        int _listenfd;
        bool _islooping;
    
        mutexlock _mutex;
        std::vector<functor> _pendingfunctors;
    
        typedef std::vector<struct epoll_event>eventlist;
        eventlist _eventlist;
    
        typedef std::map<int,tcpconnectionptr> connectionmap;
        connectionmap _connmap;
        epollcallback _onconnectioncb;
        epollcallback _onmessagecb;
        epollcallback _onclosecb;
    };
}
#endif
 ///=======================================
 /// file:    epollpoller.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 15:42:54
 /// dream:   don't forget your dreams!
 /// ======================================

#include "epollpoller.h"
#include "socketutil.h"
#include "acceptor.h"
#include <assert.h>
#include <iostream>
using namespace std;

namespace wd
{
    epollpoller::epollpoller(acceptor & acceptor)
    :_acceptor(acceptor)
    ,_epollfd(createepollfd())
    ,_eventfd(createeventfd())
    ,_listenfd(_acceptor.fd())
    ,_islooping(false)
    ,_eventlist(1024)
    {
        addepollfdread(_epollfd,_listenfd);
        addepollfdread(_epollfd,_eventfd);

    }
    
    epollpoller::~epollpoller()
    {
        ::close(_epollfd);
    }
    
    void epollpoller::loop()
    {
        _islooping=true;
        while(_islooping)
        {
            waitepollfd();
        }
    }

    void epollpoller::unloop()
    {
        if(_islooping)
            _islooping=false;
    }

    void epollpoller::setconnectioncallback(epollcallback cb)
    {
        _onconnectioncb=cb;
    }
    
    void epollpoller::setmessagecallback(epollcallback cb)
    {
        _onmessagecb=cb;
    }
    
    void epollpoller::setclosecallback(epollcallback cb)
    {
        _onclosecb=cb;
    }
    void epollpoller::waitepollfd()
    {
        int nready;
        do
        {
            nready =::epoll_wait(_epollfd,&(*_eventlist.begin()),_eventlist.size(),10000);
                
        }while(-1==nready && errno ==eintr);

        if(-1==nready){
            perror("epoll wait error!");
            exit(exit_failure);
        }else if(0==nready){
            cout<<"epoll_wait timeout!"<<endl;
        }else{//扩容
            if(nready==static_cast<int>(_eventlist.size())){
                _eventlist.resize(_eventlist.size()*2);
            }

            for(int idx=0;idx!=nready;++idx)//正宗罗老师循环体(twt)
            {
                if(_eventlist[idx].data.fd ==_listenfd)
                {
                    if(_eventlist[idx].events & epollin)
                    {
                        handleconnection();
                    }
                }else if(_eventlist[idx].data.fd ==_eventfd){
                    handleread();
                    cout<<">>dopendingfunctors()"<<endl;
                    dopendingfunctors();
                }else{
                    if(_eventlist[idx].events & epollin){
                        handlemessage(_eventlist[idx].data.fd);
                    }
                }
            }
        }
    }

    void epollpoller::handleconnection()
    {
        int peerfd=_acceptor.accept();
        addepollfdread(_epollfd,peerfd);
        tcpconnectionptr conn(new tcpconnection(peerfd,this));
        conn->setconnectioncallback(_onconnectioncb);
        conn->setmessagecallback(_onmessagecb);
        conn->setclosecallback(_onclosecb);
        std::pair<connectionmap::iterator,bool>ret;
        ret=_connmap.insert(std::make_pair(peerfd,conn));
        assert(ret.second ==true);
        (void)ret;
        conn->handleconnectioncallback();
    }

    void epollpoller::handlemessage(int peerfd)
    {
        bool isclosed=isconnectionclosed(peerfd);
        connectionmap::iterator it =_connmap.find(peerfd);
        assert(it!=_connmap.end());

        if(isclosed)
        {
            it->second->handleclosecallback();
            delepollreadfd(_epollfd,peerfd);
            _connmap.erase(it);
        }else{
            it->second->handlemessagecallback();
        }
    }
    
    void epollpoller::runinloop(const functor && cb)//在计算线程中执行
    {
        mutexlockguard mlg(_mutex);
        _pendingfunctors.push_back(std::move(cb));
        wakeup();
    }

    void epollpoller::dopendingfunctors()
    {
        std::vector<functor>tmp;
        {
            mutexlockguard mlg(_mutex);
            tmp.swap(_pendingfunctors);
        }
        for(auto & functor:tmp)
        {
            functor();
        }
    }

    void epollpoller::handleread()
    {
        uint64_t howmany;
        int ret=::read(_eventfd,&howmany,sizeof(howmany));
        if(ret !=sizeof(howmany))
        {
            perror("read error!");
        }
    }

    void epollpoller::wakeup()
    {
        uint64_t one =1;
        int ret =::write(_eventfd,&one,sizeof(one));
        if(ret!=sizeof(one))
        {
            perror("write error!");
        }
    }
}
 

==inetaddress:==

 ///=======================================
 /// file:    inetaddress.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-05 21:55:19
 /// dream:   don't forget your dreams!
 /// ======================================
#ifndef __wd_inetaddress_h__
#define __wd_inetaddress_h__
#include <netinet/in.h>
#include <string>
namespace wd
{
    class inetaddress
    {
    public:
        inetaddress(short port);
        inetaddress(const char *pip,short port);
        inetaddress(const struct sockaddr_in & addr);
        std::string ip()const;
        unsigned short port() const;
        const struct sockaddr_in *getsockaddrptr() const;
    private:
        struct sockaddr_in _addr;
    };
}
#endif
 ///=======================================
 /// file:    inetaddress.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 20:55:18
 /// dream:   don't forget your dreams!
 /// ======================================

#include "inetaddress.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>

namespace wd
{
inetaddress::inetaddress(short port)
{
    ::memset(&_addr,0,sizeof(_addr));
    _addr.sin_family=af_inet;
    _addr.sin_port=htons(port);
    _addr.sin_addr.s_addr=inaddr_any;
}

inetaddress::inetaddress(const char * pip,short port)
{
    ::memset(&_addr,0,sizeof(_addr));
    _addr.sin_family=af_inet;
    _addr.sin_port=htons(port);
    _addr.sin_addr.s_addr=inet_addr(pip);
}

inetaddress::inetaddress(const struct sockaddr_in & addr)
:_addr(addr)
{}

const struct sockaddr_in * inetaddress::getsockaddrptr()const
{
    return & _addr;
}

std::string inetaddress::ip()const
{
    return std::string(inet_ntoa(_addr.sin_addr));
}

unsigned short inetaddress::port() const
{
    return ntohs(_addr.sin_port);
}

}

==mutexlock:==

#ifndef  __wd_mutexlock_h__
#define  __wd_mutexlock_h__

#include "noncopyable.h"
#include <pthread.h>

namespace wd
{
    class mutexlock
    :noncopyable
    {
    public:
        mutexlock()
        {pthread_mutex_init(&_mutex,null);}
        ~mutexlock()
        {pthread_mutex_destroy(&_mutex);}
        void lock()
        {pthread_mutex_lock(&_mutex);}
        void unlock()
        {pthread_mutex_unlock(&_mutex);}
        pthread_mutex_t *getmutexlockptr()
        {return &_mutex;}
    private:
        pthread_mutex_t _mutex;
};

class mutexlockguard//c++之父bs提出的raii
{
public:
    mutexlockguard(mutexlock &mutex)
    :_mutex(mutex)
    {
        _mutex.lock();
    }
    ~mutexlockguard()
    {
        _mutex.unlock();
    }
private:
    mutexlock &_mutex;
};
}
#endif

==mydict:==

 ///=======================================
 /// file:    mydict.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-06 11:12:19
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __mydict_h__
#define __mydict_h__
#include <string>
#include <vector>
#include <map>
#include <utility>
#include <set>
#include <fstream>
#include <iostream>
#include <sstream>
using namespace std;
namespace wd
{
    struct myresult
    {
        string _word;
        int _ifreq;//词频
        int _idist;//最小编辑距离
    };
    
    class mydict
    {
    public:
        mydict(const string dictdir,const string indexdir)
        {
            ifstream ifs1(dictdir),ifs2(indexdir);
            if(!ifs1||!ifs2)
                cout<<"mydict open file error!"<<endl;
            string key;
            int value;
            ifs1>>value;
            _dict.push_back(std::make_pair(string(" "),value));
            ifs1>>value;
            _dict.push_back(std::make_pair(string(" "),value));
            while(ifs1>>key)
            {
                ifs1>>value;
                _dict.push_back(std::make_pair(key,value));
            }
            string line;
            while(std::getline(ifs2,line))
            {
                istringstream iss(line);
                string ikey;
                int ivalue;
                iss>>ikey;
                set<int> tmp;
                while(iss>>ivalue)
                {
                    tmp.insert(ivalue);
                }
                _index.insert(std::make_pair(ikey,tmp));
            }
        }

        vector<pair<string,int>> & getdict(){return _dict;}

        map<string ,set<int>> & getindextable(){return _index;}

    private:
        vector<pair<string,int>> _dict;
        map<string,set<int>> _index;
    };
}
#endif

==mytask:==

 ///=======================================
 /// file:    mytask.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-06 21:04:54
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __mytask_h__
#define __mytask_h__
#include "tcpconnection.h"
#include "configuration.h"
#include "mydict.h"
#include "cache.h"
#include <string>
#include <queue>

using namespace std;

class mycompare
{
public:
    bool operator()(const wd::myresult & lhs,const wd::myresult &rhs)
    {
        if(lhs._idist !=rhs._idist)
            return lhs._idist<rhs._idist;
        else
            return lhs._ifreq>rhs._ifreq;
    }
private:
};

using character =string;

class mytask
{
public:
    mytask(const string &querry,const wd::tcpconnectionptr conn)
    :_querry(std::move(querry))
    ,_conn(conn)
    {}
    void execute();
private:
    void queryindextable();//查询索引(四个索引)
    void statistic(set<int> &iset);//计算
    int distance(const string & rhs);//计算最小编辑距离
    bool response(wd::cache & cache);//响应客户端的请求
    vector<character>getonecharacter(const string &word);//获取字符数组
    string _querry;
    wd::tcpconnectionptr _conn;
    priority_queue<wd::myresult,vector<wd::myresult>,mycompare> _resultque;
};
#endif
 ///=======================================
 /// file:    mytask.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 22:47:19
 /// dream:   don't forget your dreams!
 /// ======================================

#include "mytask.h"
#include "configuration.h"
#include "mydict.h"
#include "cachemanger.h"
#include "json/json.h"
#include <string.h>
#include <algorithm>
extern __thread int t_number;

bool mytask::response(wd::cache &cache)
{
    if(cache.find(_querry))
    {
        _conn->sendinloop(cache[_querry]);
        return true;
    }
    return false;
}

int mytask::distance(const string &rhs)
{
    vector<character>querrycharacter =getonecharacter(_querry);
    vector<character>indexcharacter =getonecharacter(rhs);

    int len1,len2;
    len1=querrycharacter.size();
    len2=indexcharacter.size();
    int edit[len1+1][len2+1];
    int i,j;
    for(i=0;i<=len1;++i){
        for(j=0;j<=len2;++j){
            edit[i][j]=0;
        }
    }
    for(i=0;i<len1;++i){
        edit[i][0]=i;
    }
    for(j=0;j<=len2;++j){
        edit[0][j]=j;
    }
    for(i=1;i<len1;++i){
        for(j=1;j<=len2;++j){
            int cost =((querrycharacter[i-1]==indexcharacter[j-1])?0:1);
            int deletion =edit[i-1][j]+1;
            int insertion=edit[i][j-1]+1;
            int substitution=edit[i-1][j-1]+cost;
            edit[i][j]=std::min(deletion,std::min(insertion,substitution));
        }
    }
    return edit[len1][len2];
}

void mytask::statistic(set<int> &iset)
{
    vector<pair<string,int>>dict=(singleton<wd::mydict>::getinstance(singleton<wd::configuration>::getinstance(confpath)->getdictdir(),
                                                                     singleton<wd::configuration>::getinstance(confpath)->getindexdir()))->getdict();

    for(auto &idx:iset)
    {
        string key=dict[idx].first;
        int idist =distance(key);
        if(idist<=3)
        {
            wd::myresult res;
            res._word=key;
            res._idist=idist;
            res._ifreq=dict[idx].second;
            _resultque.push(res);
        }
    }
}

vector<character>mytask::getonecharacter(const string & word)
{
    auto cit =word.begin();
    vector<character> ret;
    while(cit<word.end())
    {
        if(224==(*cit &224)){
            character onecharacter;
            onecharacter.append(cit,cit+3);
            ret.push_back(onecharacter);
            cit =cit+3;
        }else if(240==(*cit &240)){
            character onecharacter;
            onecharacter.append(cit,cit+4);
            ret.push_back(onecharacter);
            cit =cit+4;
        }else{
            character onecharacter(1,*cit);
            ret.push_back(onecharacter);
            cit ++;
        }
    }
    return ret;
}

void mytask::queryindextable()
{
    map<string,set<int>>index=(singleton<wd::mydict>::getinstance(singleton<wd::configuration>::getinstance(confpath)->getdictdir(),
                                                                  singleton<wd::configuration>::getinstance(confpath)->getindexdir()))->getindextable();

    vector<character> onecharacter=getonecharacter(_querry);
    set<int>allrally;
    for(auto mycharacter:onecharacter)
    {
        auto cit =index.find(mycharacter);
        if(cit!=index.end())
        {
            for(auto &idx:cit->second)
                allrally.insert(idx);
        }
    }
    statistic(allrally);
}

void mytask::execute()
{
    wd::cache &mycache =(singleton<wd::cachemanger>::getinstance(singleton<wd::configuration>::getinstance(confpath)->getcache()))->getcache(t_number);
    if(response(mycache))
        return;
    else{
        queryindextable();
        json::fastwriter writerinfo;
        json::value arrayobj;
        while(!_resultque.empty())
        {
            json::value new_item;
            new_item[""]=_resultque.top()._word;
            _resultque.pop();
            arrayobj.append(new_item);
        }
        string stremail=writerinfo.write(arrayobj);
        mycache.addelement(_querry,stremail);
        _conn->sendinloop(stremail);
    }
}

==noncopyable:==

#ifndef __wd_noncopyable_h__
#define __wd_noncopyable_h__

namespace  wd
{
    class noncopyable
    {
    protected:
        noncopyable(){}
        ~noncopyable(){}
    private:
        noncopyable(const noncopyable &);
        noncopyable & operator=(const noncopyable &);
    
    };
}
#endif

==socket:==

 ///=======================================
 /// file:    socket.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-05 21:46:26
 /// dream:   don't forget your dreams!
 /// ======================================
 
#ifndef __wd_socket_h__
#define __wd_socket_h__
#include "noncopyable.h"
namespace wd
{
    class inetaddress;
    class socket
    :noncopyable
    {
    public:
        socket(int socket);
        socket();
        ~socket();
    
        void shutdownwrite();
        int fd()const {return _sockfd;}
        void nonblock();
        static inetaddress getlocaladdr(int socketfd);
        static inetaddress getpeeraddr(int sockfd);
    private:
        int _sockfd;
    };
}
#endif
 
 ///=======================================
 /// file:    socket.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 20:38:20
 /// dream:   don't forget your dreams!
 /// ======================================

#include "socket.h"
#include "socketutil.h"
#include "inetaddress.h"

namespace wd
{
socket::socket(int sockfd)
:_sockfd(sockfd)
{}

socket::socket()
:_sockfd(createsocketfd())
{}

socket::~socket()
{
    ::close(_sockfd);
}

void socket::nonblock()
{
    setnonblock(_sockfd);
}

void socket::shutdownwrite()
{
    if(-1==::shutdown(_sockfd,shut_wr)){
        perror("shutdown write error!");
    }
}

inetaddress socket::getlocaladdr(int sockfd)
{
    struct sockaddr_in addr;
    socklen_t len=sizeof(sockaddr_in);
    if(-1==::getsockname(sockfd,(struct sockaddr *)&addr,&len)){
        perror("getsockname error!");
    }
    return inetaddress(addr);
}

inetaddress socket::getpeeraddr(int sockfd)
{
    struct sockaddr_in addr;
    socklen_t len=sizeof(sockaddr_in);
    if(-1==::getpeername(sockfd,(struct sockaddr *)&addr,&len)){
        perror("getpeername error!");
    }
    return inetaddress(addr);
    
}

}

==socketio:==

 ///=======================================
 /// file:    socketio.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-06 17:10:23
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __socketio_h__
#define __socketio_h__
#include <stdio.h>

namespace wd
{
    class socketio
    {
    public:
        socketio(int sockfd);
        size_t readn(char *buf,size_t count);
        size_t writen(const char *buf,size_t count);
        size_t readline(char *buf,size_t max_len);
    private:
        size_t recv_peek(char *buf,size_t count);
        int _sockfd;
    };
}
#endif
 ///=======================================
 /// file:    socketio.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 21:56:34
 /// dream:   don't forget your dreams!
 /// ======================================

#include "socketio.h"
#include "socketutil.h"
namespace wd
{
socketio::socketio(int sockfd)
:_sockfd(sockfd)
{}

size_t socketio::readn(char *buf,size_t count)
{
    size_t nleft =count;
    char *pbuf=buf;
    while(nleft>0)
    {
        int nread =::read(_sockfd,pbuf,nleft);
        if(-1==nread)
        {
            if(errno ==eintr)
                continue;
            return exit_failure;
        }else if(0==nread){
            break;
        }
        pbuf =pbuf+nread;
        nleft=nleft-nread;
    }
    return (count -nleft);
}

size_t socketio::writen(const char * buf,size_t count)
{
    size_t nleft =count;
    const char *pbuf=buf;
    while(nleft >0)
    {
        int nwrite=::write(_sockfd,pbuf,nleft);
        if(-1==nwrite)
        {
            if(errno ==eintr)
                continue;
            return exit_failure;
        }
        nleft =nleft -nwrite;
        pbuf =pbuf +nwrite;
    }
    return (count -nleft);
}
size_t socketio::recv_peek(char *buf,size_t count)
{
    int nread;
    do{
        nread=::recv(_sockfd,buf,count,msg_peek);
    }while(-1==nread && errno ==eintr);
    return nread;
}

size_t socketio::readline(char *buf,size_t maxlen)
{
    size_t nleft =maxlen-1;
    char *pbuf=buf;
    size_t total=0;
    while(nleft>0)
    {
        size_t nread =recv_peek(pbuf,nleft);
        if(nread<=0)
            return nread;

        for(size_t idx =0;idx!=nread;++idx){//检查换行符/n
            if(pbuf[idx]=='\n'){
                size_t nsize =idx +1;
                if(readn(pbuf,nsize)!=nsize)
                    return exit_failure;
                pbuf +=nsize;
                total +=nsize;
                *pbuf=0;
                return total;
            }
        }
        if(readn(pbuf,nread)!=nread)
            return exit_failure;
        pbuf +=nread;
        nleft -=nread;
        total +=nread;
    }
    *pbuf=0;
    return maxlen-1;
}

}

==sockutil(根据陈硕编写的linux书上分开头文件)==

 ///=======================================
 /// file:    socktutil.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-05 22:01:30
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __wd_sockerutil_h__
#define __wd_sockerutil_h__
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/eventfd.h>
#include <sys/epoll.h>
namespace wd
{
    inline int createsocketfd()
    {
        int fd=::socket(af_inet,sock_stream,0);
        if(-1==fd)
        {
            perror("socket create error!");
        }
        return fd;
    }
    
    inline void setnonblock(int fd)
    {
        int flags=::fcntl(fd,f_getfl,0);
        flags |= o_nonblock;
        ::fcntl(fd,f_setfl,flags);
    }
    
    inline int createepollfd()
    {
        int efd=::epoll_create1(0);
        if(-1==efd)
        {
            perror("epoll create1 error!");
            exit(exit_failure);
        }
        return efd;
    }
    
    inline int createeventfd()
    {
        int evtfd=::eventfd(0,efd_nonblock|efd_cloexec);
        if(-1==evtfd)
        {
            perror("eventfd create error!");
        }
        return evtfd;
    }
    inline void addepollfdread(int efd,int fd)
    {
        struct epoll_event ev;
        ev.data.fd=fd;
        ev.events=epollin;
        int ret=epoll_ctl(efd,epoll_ctl_add,fd,&ev);
        if(-1==ret)
        {
            perror("epoll ctl add error!");
            exit(exit_failure);
        }
    }
    inline void delepollreadfd(int efd,int fd)
    {
        struct epoll_event ev;
        ev.data.fd=fd;
        int ret=epoll_ctl(efd,epoll_ctl_del,fd,&ev);
        if(-1==ret)
        {
            perror("epoll ctl delete error!");
            exit(exit_failure);
        }
    }
    
    inline size_t recvpeek(int sockfd,void *buf,size_t len)
    {
        int nread;
        do{
            nread=::recv(sockfd,buf,len,msg_peek);
        }while(nread==-1 && errno ==eintr);
        return nread;
    }
    
    inline bool isconnectionclosed(int sockfd)
    {
        char buf[1024];
        int nread=recvpeek(sockfd,buf,sizeof(buf));
        if(-1==nread)
        {
            perror("recvpeek error!");
            return true;
        }
        return (0==nread);
    }
}
#endif

==spellcorrrectsever:==

 ///=======================================
 /// file:    spellcorrectserver.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-06 20:41:13
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __spellcorrectserver_h__
#define __spellcorrectserver_h__
#include "tcpserver.h"
#include "threadpool.h"

using namespace wd;
namespace wd
{
    class spellcorrectserver
    {
    public:
        spellcorrectserver(const string & ip
                           ,unsigned short port
                           ,size_t threadnum
                           ,size_t quesize);
        void start();
    private:
        void onconnection(const tcpconnectionptr &);
        void onmessage(const tcpconnectionptr &);
        void onclose(const tcpconnectionptr &);
        tcpserver _tcpserver;
        threadpool _threadpoll;
    };
};
#endif
 ///=======================================
 /// file:    spellcorrectserver.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 21:20:41
 /// dream:   don't forget your dreams!
 /// ======================================

#include "spellcorrectserver.h"
#include "mytask.h"
#include <stdio.h>
#include <iostream>
#include <string>
#include <utility>
#include <functional>
using namespace std;

void spellcorrectserver::onconnection(const wd::tcpconnectionptr & conn)
{
    cout<<conn->tostring()<<endl;
    conn->send("hello ,welcome to wtp chat server.\r\n");
}

void spellcorrectserver::onmessage(const wd::tcpconnectionptr & conn)
{
    string s(conn->receive());
    mytask task(s,conn);
    _threadpoll.addtask(std::bind(&mytask::execute,&task));
    cout<<">add task to threadpool"<<endl;
}

void spellcorrectserver::onclose(const wd::tcpconnectionptr &conn)
{
    ::printf("%s close\n",conn->tostring().c_str());
}

spellcorrectserver::spellcorrectserver(const string & ip
                                       ,unsigned short port
                                       ,size_t threadnum
                                       ,size_t quesize)
:_tcpserver(ip,port)
,_threadpoll(threadnum,quesize)
{}

void spellcorrectserver::start()
{
    _threadpoll.start();
    _tcpserver.setconnectioncallback(std::bind(&spellcorrectserver::onconnection,this,std::placeholders::_1));
    _tcpserver.setmessagecallback(std::bind(&spellcorrectserver::onmessage,this,std::placeholders::_1));
    _tcpserver.setclosecallback(std::bind(&spellcorrectserver::onclose,this,std::placeholders::_1));
    _tcpserver.start();
}

==taskque:==

#ifndef __wd_taskqueue_h__
#define __wd_taskqueue_h__

#include "mutexlock.h"
#include "condition.h"
#include <queue>
#include <functional>

namespace wd
{
    typedef std::function<void()>task;
    
    class taskqueue
    {
    public:
        taskqueue(size_t quesize)
        :_quesize(quesize)
        ,_mutex()
        ,_notfull(_mutex)
        ,_notempty(_mutex)
        ,_flag(true)
        {}
    
        void push(task &&task);
        task pop();
        bool empty()const
        {
            return _que.size()==0;
        }
        bool full()const
        {return _que.size()==_quesize;}
        void wakeup()
        {   
            if(_flag)
                _flag=false;
            _notempty.notifyall();
        }
    private:
        size_t _quesize;
        std::queue<task> _que;
        mutexlock _mutex;
        condition _notfull;
        condition _notempty;
        bool _flag;
    };
}
#endif
#include "taskqueue.h"

using namespace wd;
//生产者所在的线程
void taskqueue::push(task && task)
{
    mutexlockguard autolock(_mutex);
    while(full())
    {
        _notfull.wait();
    }
    _que.push(std::move(task));
    _notempty.notify();
}

//消费者所在线程
task taskqueue::pop()
{
    mutexlockguard autolock(_mutex);
    while(_flag && empty())
    {
        _notempty.wait();
    }
    if(_flag){
        task task=_que.front();
        _que.pop();
        _notfull.notify();
        return task;
    }else{
        return null;
    }
}
#if 0
task taskqueue::pop()
{
    mutexlockguard autolock(_mutex);
    while(_flag && empty())
    {
        _notempty.wait();
    }
    if(_flag){
        task task =_que.front();
        _que.pop();
        _notfull.notify();
        return task;
    }else{
        return null;
    }
}
#endif

==tcpconnection:==

 ///=======================================
 /// file:    tcpconnection.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-06 17:15:33
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __wd_tcpconnection_h__
#define __wd_tcpconnection_h__

#include "noncopyable.h"
#include "inetaddress.h"
#include "socket.h"
#include "socketio.h"

#include <string>
#include <memory>
#include <functional>
namespace wd
{
    class epollpoller;
    class tcpconnection;
    typedef std::shared_ptr<tcpconnection> tcpconnectionptr;

    class tcpconnection
    :noncopyable
    ,public std::enable_shared_from_this<tcpconnection>
    {
    public:
        typedef std::function<void(const tcpconnectionptr &)>tcpconnectioncallback;
        tcpconnection(int sockfd,epollpoller *loop);
        ~tcpconnection();

        std::string receive();
        void send(const std::string &msg);
        void sendinloop(const std::string &msg);
        void shutdown();

        std::string tostring();
        void setconnectioncallback(tcpconnectioncallback cb);
        void setmessagecallback(tcpconnectioncallback cb);
        void setclosecallback(tcpconnectioncallback cb);

        void handleconnectioncallback();
        void handlemessagecallback();
        void handleclosecallback();
    private:
        socket _sockfd;
        socketio _sockio;
        const inetaddress _localaddr;
        const inetaddress _peeraddr;
        bool _isshutdownwrite;
        epollpoller * _loop;
        tcpconnectioncallback _onconnectioncb;
        tcpconnectioncallback _onmessagecb;
        tcpconnectioncallback _onclosecb;

    };
}
#endif
 ///=======================================
 /// file:    tcpconnection.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 22:22:22
 /// dream:   don't forget your dreams!
 /// ======================================

#include "tcpconnection.h"
#include "epollpoller.h"
#include <string.h>
#include <stdio.h>

namespace wd
{
tcpconnection::tcpconnection(int sockfd,epollpoller * loop)
:_sockfd(sockfd)
,_sockio(sockfd)
,_localaddr(wd::socket::getlocaladdr(sockfd))
,_peeraddr(wd::socket::getpeeraddr(sockfd))
,_isshutdownwrite(false)
,_loop(loop)
{_sockfd.nonblock();}

tcpconnection::~tcpconnection()
{
    if(!_isshutdownwrite)
    {
        _isshutdownwrite=true;
        shutdown();
    }
    printf("~tcpconnection()\n");
}

std::string tcpconnection::receive()
{
    char buf[65536];
    memset(buf,0,sizeof(buf));
    size_t ret =_sockio.readline(buf,sizeof(buf));
    if(0==ret){
        return std::string();
    }else{
        return std::string(buf);
    }
}

void tcpconnection::send(const std::string &msg)
{
    size_t len=msg.size();
    _sockio.writen((const char *)&len,sizeof(int));
    _sockio.writen(msg.c_str(),len);
}

void tcpconnection::shutdown()
{
    if(!_isshutdownwrite)
        _sockfd.shutdownwrite();
    _isshutdownwrite=true;
}

std::string tcpconnection::tostring()
{
    char str[100];
    snprintf(str,sizeof(str),"%s:%d->%s:%d"
             ,_localaddr.ip().c_str()
             ,_localaddr.port()
             ,_peeraddr.ip().c_str()
             ,_peeraddr.port());
    return std::string(str);
}

void tcpconnection::setconnectioncallback(tcpconnectioncallback cb)
{
    _onconnectioncb =cb;
}
void tcpconnection::setmessagecallback(tcpconnectioncallback cb)
{
    _onmessagecb =cb;
}
void tcpconnection::setclosecallback(tcpconnectioncallback cb)
{
    _onclosecb =cb;
}

void tcpconnection::handleconnectioncallback()
{
    if(_onconnectioncb){
        _onconnectioncb(shared_from_this());
    }
}
void tcpconnection::handlemessagecallback()
{
    if(_onmessagecb){
        _onmessagecb(shared_from_this());
    }
}
void tcpconnection::handleclosecallback()
{
    if(_onclosecb){
        _onclosecb(shared_from_this());
    }
}

void tcpconnection::sendinloop(const std::string & msg)
{
    _loop->runinloop(std::bind(&tcpconnection::send,this,msg));
}

}

==tcpserver:==

 ///=======================================
 /// file:    tcpserver.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-06 20:15:21
 /// dream:   don't forget your dreams!
 /// ======================================
 
#ifndef __wd_tcpserver_h__
#define __wd_tcpserver_h__

#include "acceptor.h"
#include "epollpoller.h"
#include <string>

using std::string;
namespace wd
{
    class tcpserver
    {
    public:
        typedef epollpoller::epollcallback tcpservercallback;
        tcpserver(const string & ip,unsigned short port);
        tcpserver(unsigned short port);

        void start();
        void stop();
        void setconnectioncallback(tcpservercallback cb);
        void setmessagecallback(tcpservercallback cb);
        void setclosecallback(tcpservercallback cb);

    private:
        acceptor _acceptor;
        epollpoller _poller;

        tcpservercallback _connectioncallback;
        tcpservercallback _messagecallback;
        tcpservercallback _closecallback;
    };
}
#endif
 ///=======================================
 /// file:    tcpserver.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 19:59:37
 /// dream:   don't forget your dreams!
 /// ======================================

#include "tcpserver.h"
#include "inetaddress.h"
#include "socketutil.h"
#include <iostream>
using namespace std;
namespace wd
{
    tcpserver::tcpserver(const string & ip,unsigned short port)
    :_acceptor(createsocketfd(),inetaddress(ip.c_str(),port))
    ,_poller(_acceptor)
    {}

    void tcpserver::start()
    {
        _acceptor.ready();
        _poller.setconnectioncallback(_connectioncallback);
        _poller.setmessagecallback(_messagecallback);
        _poller.setclosecallback(_closecallback);
        _poller.loop();
    }

    void tcpserver::stop()
    {
        _poller.unloop();
    }

    void tcpserver::setconnectioncallback(tcpservercallback cb)
    {_connectioncallback=cb;}

    void tcpserver::setmessagecallback(tcpservercallback cb)
    {_messagecallback=cb;}

    void tcpserver::setclosecallback(tcpservercallback cb)
    {_closecallback=cb;}
}

==thread:==

#ifndef  __wd_thread_h__
#define  __wd_thread_h__

#include "noncopyable.h"
#include <pthread.h>
#include <functional>
using std::function;
namespace wd
{
    class thread;
    struct threadptr
    {
        int _number;
        thread *_pthread;
    };
    class thread
    :noncopyable
    {
        using threadcallback =function<void()>;
    public:
        thread(threadcallback &&cb);
        ~thread();
    
        void start(int number);
        void join();
    
        bool isrunning()const {return _isrunning;}
    
    private:
        static void * threadfunc(void *);
        pthread_t _pthid;
        bool _isrunning;
        threadcallback _cb;
    };
}
#endif
#include "thread.h"
#include <iostream>
using namespace std;
using namespace wd;

__thread int t_number;//将线程编号作为线程存储的标记

thread::thread(threadcallback && cb)//这里的右值引用本身取决于是否有名字
:_pthid(0)
,_isrunning(false)
,_cb(std::move(cb))
{
    cout<<"thread(cb)"<<endl;
}

void thread::start(int number)
{
    threadptr *threadptr=new threadptr();
    threadptr->_number=number;
    threadptr->_pthread=this;
    pthread_create(&_pthid,null,threadfunc,threadptr);
    _isrunning=true;
}

void *thread::threadfunc(void *arg)
{//应用了线程存储
    threadptr *threadptr=static_cast<threadptr*>(arg);
    thread * pthread=threadptr->_pthread;
    t_number=threadptr->_number;
    if(pthread)
        pthread->_cb();//线程开始工作!
    delete threadptr;
    //thread * pthread =threadptr->_pthread;
    return null;
}
#if 0
void *thread::threadfunc(void *arg)
{
    threadptr *threadptr =static_cast<threadptr*>(arg);
    thread * pthread =threadptr->_pthread;
    t_number =threadptr->_number;
    if(pthread)
        pthread->_cb();
    delete threadptr;
    return null;
}
#endif
void thread::join()
{
    pthread_join(_pthid,null);
    _isrunning=false;
}

thread::~thread()
{
    if(_isrunning)
    {
        pthread_detach(_pthid);
        _isrunning=false;
    }
    cout<<"~thread()"<<endl;
}

==threadpool:==

#ifndef __wd_threadpoll_h__
#define __wd_threadpoll_h__
#include "taskqueue.h"
#include "thread.h"
#include <vector>
#include <memory>
#include <functional>
using std::shared_ptr;
using std::vector;
namespace  wd
{
    class threadpool
    {
    public:
        using task=std::function<void()>;
    
        threadpool(size_t threadnum,size_t quesize)
        :_threadnum(threadnum)
        ,_quesize(quesize)
        ,_taskque(_quesize)
        ,_isexit(false)
        {
            _threads.reserve(_threadnum);
        }
        
        ~threadpool();
    
        void start();
        void stop();
        void addtask(task && task);
    
    private:
        void threadfunc();
        task gettask();
        size_t _threadnum;
        size_t _quesize;
        vector<shared_ptr<thread>> _threads;
        taskqueue _taskque;
        bool _isexit;
    };
}
#endif
#include "threadpool.h"
#include "thread.h"
#include <unistd.h>
#include <iostream>

using namespace std;
using namespace wd;

void threadpool::start()
{
    for(size_t idx=0;idx<_threadnum;++idx)
    {
        shared_ptr<thread>pthread(new thread(std::bind(&threadpool::threadfunc,this)));
        _threads.push_back(std::move(pthread));
    }
    int number=0;
    for(auto &pthread:_threads)
    {
        pthread->start(number);
        ++number;
    }
}
void threadpool::stop()//为了线程安全,将stop方法置于主线程中
{
    if(!_isexit)
    {
        while(!_taskque.empty()){
            ::sleep(1);
            cout<<"threadpool sleep 1 second!"<<endl;
        }
        _isexit=true;
        cout<<"threadpool ->stop:_isexit="<<_isexit<<endl;
        _taskque.wakeup();
        for(auto &pthread:_threads){
            pthread->join();
        }
    }
}

threadpool::~threadpool()
{
    if(!_isexit){
        stop();
    }
}
void threadpool::addtask(task && task)
{
    _taskque.push(std::move(task));
}

task threadpool::gettask()
{
    return _taskque.pop();
}

void threadpool::threadfunc()
{
    while(!_isexit)
    {
        task task=gettask();
        if(task){
            task();
        }
    }
}

==timer:==

 ///=======================================
 /// file:    timer.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-06 20:00:45
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __wd_timer_h__
#define __wd_timer_h__
#include <functional>

namespace wd
{
    class timer
    {
    public:
        using timercallback =std::function<void()>;
        timer(int initailtime,int intervaltime,timercallback && cb);
        ~timer();
        void start();
        void stop();
    private:
        int _fd;
        int _initialtime;
        int _intervaltime;
        timercallback _cb;
        bool _isstarted;
        int createtimerfd();
        void settimerfd(int initialtime, int intervaltime);
        void handleread();  
    };
}
#endif
 ///=======================================
 /// file:    timer.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 20:09:14
 /// dream:   don't forget your dreams!
 /// ======================================

#include "timer.h"
#include <unistd.h>
#include <errno.h>
#include <poll.h>
#include <sys/timerfd.h>
#include <iostream>
using namespace std;
using namespace wd;

timer::timer(int initialtime,int intervaltime,timercallback && cb)
:_fd(createtimerfd())
,_initialtime(initialtime)
,_intervaltime(intervaltime)
,_cb(std::move(cb))
,_isstarted(false)
{}

void timer::start()
{
    struct pollfd pfd;
    pfd.fd=_fd;
    pfd.events=pollin;
    settimerfd(_initialtime,_intervaltime);//开启定时器
    _isstarted=true;
    while(_isstarted){
        int nready=::poll(&pfd,1,5000);
        if(-1==nready &&errno ==eintr){
            continue;
        }else if(-1==nready){
            perror(">>>poll error!");
            exit(exit_failure);
        }else if(0==nready){
            cout<<">>>poll timeout!"<<endl;
        }else{
            if(pfd.revents & pollin){
                handleread();//先对定时器进行处理
                if(_cb){
                    _cb();//再去执行回调任务
                }
            }
        }
    }
}

void timer::stop()
{
    settimerfd(0,0);
    if(_isstarted){
        _isstarted=false;
    }
}

timer::~timer()
{
    if(_isstarted){
        stop();
    }
}

int timer::createtimerfd()
{
    int fd=::timerfd_create(clock_realtime,0);
    if(-1==fd){
        perror(">>timerfd_create error!");
    }
    return fd;
}

void timer::settimerfd(int initialtime,int intervaltime)
{
    struct itimerspec value;
    value.it_value.tv_sec=initialtime;
    value.it_value.tv_nsec=0;
    value.it_interval.tv_sec=intervaltime;
    value.it_interval.tv_nsec=0;
    int ret=::timerfd_settime(_fd,0,&value,null);
    if(-1==ret){
        perror(">>>timerfd_settime error!");
    }
}
#if 0
void timer::handleread()
{
    uint64_t howmany;
    int ret =::read(_fd,&howmany,sizeof(uint64_t));
    if(ret!=sizeof(uint64_t)){
        perror("read!");
    }
}
#endif


void timer::handleread()
{
    uint64_t howmany;//为一个64位
    int ret=::read(_fd,&howmany,sizeof(uint64_t));
    if(ret!=sizeof(uint64_t)){
        perror(">>>read error!");
    }
}

==timerthread:==

 ///=======================================
 /// file:    timerthread.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 17:12:51
 /// dream:   don't forget your dreams!
 /// ======================================
#ifndef __wd_timerthread_h__
#define __wd_timerthread_h__

#include "timer.h"
#include "thread.h"

#include <functional>

namespace wd
{
    
class timerthread
{
public:
    using timercallback = std::function<void()>;
    timerthread(int, int, timercallback && cb);
    ~timerthread();

    void start();
    void stop();


private:
    timer _timer;
    thread _subthread;
    bool _isstarted;
};
}//end of namespace wd

#endif
 ///=======================================
 /// file:    timerthread.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 20:09:14
 /// dream:   don't forget your dreams!
 /// ======================================
#include "timerthread.h"


using namespace wd;

timerthread::timerthread(int initialtime, int intervaltime, timercallback && cb)
: _timer(initialtime, intervaltime, std::move(cb))
, _subthread(std::bind(&timer::start, &_timer))
, _isstarted(false)
{}

void timerthread::start()
{
    _subthread.start(0);
    _isstarted = true;
}

void timerthread::stop()
{
    if(_isstarted) {
        _timer.stop();
        _subthread.join();
        _isstarted = false;
    }
}

timerthread::~timerthread()
{
    if(_isstarted)
        stop();
}

==main:==

 ///=======================================
 /// file:    main.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 21:09:32
 /// dream:   don't forget your dreams!
 /// ======================================

#include "spellcorrectserver.h"
#include "configuration.h"
#include "cachemanger.h"
#include "timerthread.h"
#include <iostream>
#include <functional>
using namespace std;
using namespace wd;

int main()
{
    wd::cachemanger *mycachemanger=singleton<cachemanger>::getinstance(singleton<configuration>
                                                         ::getinstance(confpath)->getcache());
    timerthread timer(5,600,std::bind(&cachemanger::periodicupdate,mycachemanger));
    timer.start();
    spellcorrectserver myspell(singleton<configuration>::getinstance(confpath)->getip()
                               ,singleton<configuration>::getinstance(confpath)->getport()
                               ,4
                               ,10);
    myspell.start();
    return 0;
}

小结:(1)已经实现项目需求,中文和英文单词都能查询,经过测试,运行稳定,能输出不少候选词

(2)仍然存在少量bug,例如偶尔会发生段错误

(3)由于时间问题,json读出的数据key-value的key值没有打印,用户界面还未来得及优化

(4)陈硕的《linux多线程服务端编程》使用linux接口(timerfd),没用posix接口(eventfd)

---恢复内容结束---

# 我的spellcorrect 开发文档


[toc]


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

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

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

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

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

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

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

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

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


演示效果(中文):

==启动时服务器:==

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

==客户端连入时时服务器:==

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

==输入“赵”==

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

==输入“周杰伦”==

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

==输入清华大学==

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


演示效果(英语):

==启动时服务器:==

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

==客户端连入时时服务器:==

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

==输入student:==

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

==输入spell:==

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

==输入computer:==

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


代码部分:

离线部分:

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

==makefile:==

srcs:=$(wildcard *.cc)
objs:= $(patsubst %.cc, %.o, $(srcs))

cxx:=g++

cxxflags:= -w -g -std=c++11 $(addprefix -i, $(inc_dir)) $(libs) -wno-deprecated -i ../cppjieba/include/ -i ../cppjieba/deps

exe:=./main

$(exe):$(objs)
        $(cxx) -o $(exe) $(objs) $(cxxflags)

clean:
        rm -rf $(exe)
            rm -rf $(objs)

==configuration:==

///=======================================
/// file:    configuration.h
/// author:  wtptorres(1584292712@qq.com)
/// date:    2019-06-12 00:30:39
/// dream:   don't forget your dreams!
/// ======================================

#ifndef __configuration_h__
#define __configuration_h__
#include "nocopyable.h"
#include <string>
#include <map>
using namespace std;

class configuration
:public noncopyable
{
public:
    configuration(const string &filepath);
    string getenglishdir() const {return _englishdir;}
    string getchinesedir() const {return _chinesedir;}
private:
    string _filepath;
    string _englishdir;
    string _chinesedir;
};
template<typename t>
class singleton
{
public:
    template<typename ...args>
    static t* getinstance(args ...args)
    {
        if(!_pinstance)
            _pinstance = new t(args...);
        return _pinstance;
    }
    static void destroy()
    {
        if(_pinstance)
            delete _pinstance;
    }
private:
    singleton();
    ~singleton();
    static t *_pinstance;                    
};
template<typename t>
t * singleton<t>::_pinstance = null;
#endif
  1  ///=======================================
  2  /// file:    configuration.cc
  3  /// author:  wtptorres(1584292712@qq.com)
  4  /// date:    2019-06-12 00:30:04
  5  /// dream:   don't forget your dreams!
  6  /// ======================================
  7 
  8                                     
  9 #include "configuration.h"
 10 #include <utility>
 11 #include <fstream>
 12 #include <iostream>
 13 using namespace std;
 14 
 15 configuration::configuration(const string &filepath)
 16 :_filepath(std::move(filepath))
 17 {
 18     ifstream ifs(_filepath);
 19     if(!ifs)
 20         cout<<"file open error!"<<endl;
 21     ifs>>_englishdir;
 22     ifs>>_chinesedir;
 23     ifs.close();
 24 }
 ///=======================================
 /// file:    nocopyable.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-12 00:24:36
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __nocopyable_h__
#define __nocopyable_h__
class noncopyable
{
public:
    noncopyable()=default;
    ~noncopyable()=default;
private:
    noncopyable(const noncopyable &rhs);
    noncopyable &operator =(const noncopyable &rhs);
};
#endif

==dictproducer:==

 ///=======================================
 /// file:    dictproducer.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-12 16:40:25
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __dictproducer_h__
#define __dictproducer_h__
#include "splittool.h"
using namespace std;
#include "nocopyable.h"
#include <memory>
#include <string>
#include <vector>
#include <map>
#include <utility>


class dictproducer
:public noncopyable
{
public:
    dictproducer(const string,const string,const string &,splittooljieba *);
    ~dictproducer(){}
    void build_dict();
    void build_cn_dict();
    void store_dict();
    vector<pair<string,int>>& getindict(){return _indict;}
private:
    void processenglishword(string &word);
    void processchineseword(string &word);//除去中文的数字
    void construct_indict();
    string _englishdir;
    string _chinesedir;
    string _golefilepath;
    vector<string> _englishfiles;
    vector<string> _chinesefiles;
    map<string,int> _dict;
    vector<pair<string,int>> _indict;
    shared_ptr<splittooljieba> _splittool;
};
#endif
 ///=======================================
 /// file:    dictproducer.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-12 16:50:46
 /// dream:   don't forget your dreams!
 /// ======================================


#include "dictproducer.h"
#include <cctype>
#include <utility>
#include <fstream>
#include <iostream>
#define firstsize 10000
using namespace std;

dictproducer::dictproducer(const string englishdir,const string chinesedir,const string &golefilepath,splittooljieba *splittoolptr)
    :_englishdir(englishdir)
    ,_chinesedir(chinesedir)
    ,_golefilepath(golefilepath)
{
    _splittool.reset(splittoolptr);
    std::ifstream ifsenglish(_englishdir);
    std::ifstream ifschinese(_chinesedir);
    string filepath;
    if(!ifsenglish || !ifschinese){
        cout<<"dict file open error!"<<endl;
    }
    while(ifsenglish>>filepath)
    {
        _englishfiles.push_back(filepath);
    }
    while(ifschinese>>filepath)
    {
        _chinesefiles.push_back(filepath);
    }
    _indict.reserve(firstsize);
}

void dictproducer::processenglishword(string &word)
{
    auto cit =word.begin();
    for(;cit!=word.end();++cit)
    {   //去除标点符号或数字
        if(!isalpha(*cit)){
            word.erase(cit);
            --cit;//迭代器位置发生改变
        }else if(isupper(*cit)){//将大写字母改为小写
            *cit =tolower(*cit);
        }
    }
}

void dictproducer::processchineseword(string &word)
{
    auto cit =word.begin();
    for(;cit!=word.end();++cit)
    {   //去除数字
        if(!isalnum(*cit)){
            word.erase(cit);
            --cit;
        }
    }
}

void dictproducer::build_dict()//建立英文词典
{
    for(auto &filepath:_englishfiles)
    {
        ifstream ifs(filepath);
        if(!ifs){
            cout<<"english file open error!"<<endl;
        }
        string word;
        while(ifs>>word)
        {
            processenglishword(word);
            auto cit =_dict.find(word);
            if(word.size()>0 && cit ==_dict.end()){
                _dict.insert(std::make_pair(word,1));
            }else if(cit!=_dict.end()){
                ++ cit ->second;
            }
        }
    }
}


void dictproducer::build_cn_dict()
{
    vector<string>words;
    for(auto filepath:_chinesefiles)
    {
        ifstream ifs(filepath);
        if(!ifs){
            cout<<"chinese file open error!"<<endl;
        }
        string sentence;
        while(std::getline(ifs,sentence))
        {
            _splittool->cut(sentence);
        }
    }
    vector<string>& results =_splittool->getresult();
    for(auto &res:results)
    {
        processchineseword(res);
        auto cit =_dict.find(res);
        if(cit ==_dict.end()){
            _dict.insert(std::make_pair(res,1));
        }else{
            ++ cit ->second;
        }
    }
}

void dictproducer::store_dict()
{
    construct_indict();
    ofstream ofs(_golefilepath);
    if(!ofs)
        cout<<"store_dict open file error!"<<endl;
    for(auto &mypair:_indict)
    {
        ofs<<mypair.first<<" "<<mypair.second<<endl;
    }
    ofs.close();
}

void dictproducer::construct_indict()
{
    for(auto dictpair:_dict){
        _indict.push_back(dictpair);
    }
}

==getindex:==

 ///=======================================
 /// file:    getindex.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-12 08:52:04
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __getindex_h__
#define __getindex_h__
#include <string>
#include <unordered_map>
#include <set>
#include <vector>
#include <utility>
#include <unordered_set>
using namespace std;

class getindex
{
public:
    getindex(const string &,const string &,const string &);
    ~getindex(){}
    void construct_index();
    void store_index();
private:
    bool isenglish(const string &rhs) const;
    vector<string>getonecharacter(const string & word);
    string _sourcefilepath;
    string _golefilepath;
    string _stopwordsfilepath;
    vector<pair<string,int>>_dict;
    unordered_set<string>_stopwords;
    unordered_map<string,set<int>>_index;
};
#endif
 ///=======================================
 /// file:    getindex.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-12 09:00:11
 /// dream:   don't forget your dreams!
 /// ======================================


#include "getindex.h"
#include <fstream>
#include <sstream>
#include <iostream>
using namespace std;

getindex::getindex(const string & sourcefilepath,const string &golefilepath,const string &stopwordsfilepath)
:_sourcefilepath(std::move(sourcefilepath))
,_golefilepath(std::move(golefilepath))
,_stopwordsfilepath(std::move(stopwordsfilepath))
{
    ifstream ifs(_sourcefilepath);
    if(!ifs){
        cout<<"getindex file open error!"<<endl;
    }
    string line;
    while(getline(ifs,line))
    {
        istringstream iss(line);
        string key;
        int value;
        iss>>key>>value;
        _dict.push_back(std::make_pair(key,value));
    }
    ifstream ifs1(_stopwordsfilepath);
    if(!ifs1){
        cout<<"file open error!"<<endl;
    }
    string stopword;
    while(ifs1>>stopword,!ifs1.eof())
    {
        _stopwords.insert(stopword);
    }
}

vector<string> getindex::getonecharacter(const string &word)
{
    vector<string>tmp;
    auto cit =word.begin();
    while(cit<word.end())
    {
        if(224==(*cit &224))
        {
            string onecharacter;
            onecharacter.append(cit,cit+3);
            tmp.push_back(onecharacter);
            cit +=3;
        }else if(240==(*cit &240)){
            string onecharacter;
            onecharacter.append(cit,cit+4);
            tmp.push_back(onecharacter);
            cit +=4;
        }else
            break;
    }
    return tmp;
}
             
bool getindex::isenglish(const string &rhs) const
{
    char ch =*(rhs.begin());
    if(ch<0)
        return false;
    return true;
}
#if 0
bool getindex::isenglish(const string &rhs) const
{
    char ch =*(rhs.begin());
    if(ch<0){
        return false;
    }
    return true;
}
#endif
void getindex::construct_index()
{
    for(size_t i=0;i!=_dict.size();++i)
    {
        string tmp=_dict[i].first;
        if(isenglish(tmp))
        {
            for(auto ch:tmp)
            {
                string charactor(1,ch);
                if(isalpha(ch))
                {
                    auto cit =_index.find(charactor);
                    if(cit ==_index.end())
                    {
                        set<int> smp;
                        smp.insert(i);
                        _index.insert(std::make_pair(charactor,smp));
                    }else{//已经存在了该字母的索引
                        cit->second.insert(i);
                    }
                }
            }
        }else{//中文处理部分
            vector<string> onecharacterrally =getonecharacter(tmp);
            for(auto onecharacter:onecharacterrally)
            {//stop_words中不存在该单词,则加入索引中
                if(_stopwords.find(onecharacter)==_stopwords.end()){
                    auto it =_index.find(onecharacter);
                    if(it == _index.end()){
                        set<int>tmp;
                        tmp.insert(i);
                        _index.insert(std::make_pair(onecharacter,tmp));
                    }else{
                        it->second.insert(i);
                    }
                }
            }
        }
    }
}

void getindex::store_index()
{   
    //ofs存储索引的内容
    std::ofstream ofs(_golefilepath);
    if(!ofs){
        cout<<"file open error!"<<endl;
        return;
    }
    for(auto data:_index)
    {
        ofs<<data.first<<" ";
        for(auto linenum:data.second)
        {
            ofs<<linenum<<" ";
        }
        ofs<<endl;
    }
    ofs.close();
}

==splittool:==

 ///=======================================
 /// file:    splittool.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-12 17:12:01
 /// dream:   don't forget your dreams!
 /// ======================================


#ifndef __splittool_h__
#define __splittool_h__
#include "../cppjieba/include/cppjieba/jieba.hpp"//需要自己将cppjieba安装在项目目录下
#include "configuration.h"
#include <string>
#include <vector>
using namespace std;
using namespace cppjieba;
class splittooljieba
{
public:
    splittooljieba(const string& dict_path,const string &model_path,const string &user_dict_path,const string & idfpath, const string &stopwordpath)
    :_jieba(dict_path,model_path,user_dict_path,idfpath,stopwordpath)
    {}
    ~splittooljieba(){}
    void cut(const string & sentence)
    {
        vector<string>tmp;
        _jieba.cut(sentence,tmp);
        _result.insert(_result.end(),tmp.begin(),tmp.end());
    }
    vector<string> & getresult(){return _result;}
private:
    vector<string> _result;
    cppjieba::jieba _jieba;
};
#endif

==main:==

 ///=======================================
 /// file:    main.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-12 20:38:50
 /// dream:   don't forget your dreams!
 /// ======================================


#include "configuration.h"
#include "splittool.h"
using namespace std;
#include "dictproducer.h"
#include "getindex.h"
#include <iostream>
#include <memory>
const char * const dict_path ="../cppjieba/dict/jieba.dict.utf8";
const char * const hmm_path ="../cppjieba/dict/hmm_model.utf8";
const char * const user_dict_path ="../cppjieba/dict/user.dict.utf8";
const char * const idf_path ="../cppjieba/dict/idf.utf8";
const char * const stop_word_path ="../cppjieba/dict/stop_words.utf8";
const string gole_dict_path="../server/data/dict.txt";
const string gole_index_path="../server/data/index.txt";

class splittool;
int main(void)
{
    configuration *pconfig =singleton<configuration>::getinstance("configure.txt");
    splittooljieba *ptool =new splittooljieba(dict_path,hmm_path,user_dict_path,idf_path,stop_word_path);
    dictproducer mydictproducer(pconfig->getenglishdir(),pconfig->getchinesedir(),gole_dict_path,ptool);
    mydictproducer.build_dict();//建立英语词典
    mydictproducer.build_cn_dict();//建立中文词典
    mydictproducer.store_dict();//储存词典
    getindex myindex(gole_dict_path,gole_index_path,"stop_words_zh.txt");
    myindex.construct_index();//建立索引
    myindex.store_index();//存储索引
    singleton<configuration>::destroy();
    return 0;
}

在线部分:

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

==configuration:==

 ///=======================================
 /// file:    configuration.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-06 10:32:43
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __configuration_h__
#define __configuration_h__
#include "noncopyable.h"
#include <string>
#include <map>
#define confpath "/home/wtp/spell/server/conf/configure.txt"
using namespace std;

namespace wd
{
    class configuration
    :public noncopyable
    {
    public:
        configuration(const string &filepath);
        ~configuration()=default;
        string getdictdir() const;
        string getindexdir() const;
        string getip()const;
        string getcache() const;
        unsigned short getport() const;

    private:
        string _filepath;
        map<string,string> _conf;
    };
};

template<typename t>
class singleton
{
public:
    template<typename ...args>
    static t *getinstance(args ...args)
    {
        if(!_pinstance)
            _pinstance=new t(args ...);
        return _pinstance;
    }

    static void destroy()
    {
        if(_pinstance)
            delete _pinstance;
    }
private:
    singleton();
    ~singleton();
    static t *_pinstance;
};

template<typename t>
t *singleton<t>::_pinstance =null;
#endif
 ///=======================================
 /// file:    configuration.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 15:24:14
 /// dream:   don't forget your dreams!
 /// ======================================

#include "configuration.h"
#include <stdlib.h>
#include <utility>
#include <fstream>
#include <iostream>
using namespace std;
using namespace wd;

wd::configuration::configuration(const string & filepath)
:_filepath(std::move(filepath))
{
    ifstream ifs(_filepath);
    if(!ifs){
        cout<<"file open error!"<<endl;
    }
    string key,value;
    while(ifs>>key)
    {
        ifs>>value;
        _conf.insert(std::make_pair(key,value));
    }
    ifs.close();
}

string wd::configuration::getdictdir() const
{
    auto cit=_conf.find("mydict");
    if(cit== _conf.end())
        return "";
    else
        return cit->second;
}

string wd::configuration::getindexdir() const
{
    auto cit =_conf.find("myindex");
    if(cit== _conf.end())
        return "";
    else 
        return cit->second;
}

string wd::configuration::getip() const
{
    auto cit =_conf.find("myip");
    if(cit ==_conf.end())
        return "";
    else
        return cit->second;
}

unsigned short wd::configuration::getport() const
{
    auto cit =_conf.find("myport");
    if(cit==_conf.end())
        return 0;
    else
        return atoi(cit->second.c_str());
}

string wd::configuration::getcache() const
{
    auto cit =_conf.find("mycache");
    if(cit ==_conf.end())
        return "";
    else
        return cit->second;
}
             
 

==acceptor:==

 ///=======================================
 /// file:    acceptor.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-05 23:47:05
 /// dream:   don't forget your dreams!
 /// ======================================
 
#ifndef  __wd_acceptor_h__
#define  __wd_acceptor_h__

#include "socket.h"
#include "inetaddress.h"

namespace wd
{
    class acceptor
    {
    public:
        acceptor(int listenfd,const inetaddress & addr);
        void ready();//服务器监听准备
        int accept();//服务器接收新连接
        int fd()const {return _listensock.fd();}
    private:
        void setreuseaddr(bool on);//设置地址重用
        void setreuseport(bool on);//设置端口重用
        void bind();//绑定
        void listen();//监听
        socket _listensock;
        inetaddress _addr;
    };
}

#endif
 ///=======================================
 /// file:    acceptor.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-05 23:52:12
 /// dream:   don't forget your dreams!
 /// ======================================
#include <iostream>
#include "acceptor.h"
#include "socketutil.h"

namespace wd
{
acceptor::acceptor(int listenfd,const inetaddress & addr)
:_listensock(listenfd)
,_addr(addr)
{}

void acceptor::ready()
{
    setreuseaddr(true);
    setreuseport(true);
    bind();
    listen();
}
int acceptor::accept()
{
    int peerfd=::accept(_listensock.fd(),null,null);
    if(-1==peerfd)
    {
        perror("accept error!");
    }
    return peerfd;
}
void acceptor::setreuseaddr(bool flag)
{
    int on=(flag?1:0);
    if(::setsockopt(_listensock.fd()
                    ,sol_socket
                    ,so_reuseaddr
                    ,&on
                    ,static_cast<socklen_t>(size_t(on)))==-1)
    {
        perror("setsockopt reuseaddr error!");
        ::close(_listensock.fd());
        exit(exit_failure);
    }
}

void acceptor::setreuseport(bool flag)
{
#ifndef so_reuseport
    int on=(flag?1:0);
    if(::setsockopt(_listensock.fd()
                    ,sol_socket
                    ,so_reuseaddr
                    ,&on
                    ,static_cast<socklen_t>(size_t(on)))==-1)
    {
        perror("setsockopt reuseport error!");
        ::close(_listensock.fd());
        exit(exit_failure);
    }
#else
    if(flag)
    {
        fprintf(stderr,"so_reuseport is not supported!\n");
    }
#endif
}

void acceptor::bind()
{
    if(-1==::bind(_listensock.fd()
                  ,(const struct sockaddr*)_addr.getsockaddrptr()
                  ,sizeof(inetaddress)))
    {
        perror("bind error!");
        ::close(_listensock.fd());
        exit(exit_failure);
    }
}
void acceptor::listen()
{
    if(-1==::listen(_listensock.fd(),10))
    {
        perror("listen error!");
        ::close(_listensock.fd());
        exit(exit_failure);
    }
}

}
#if 0
int main()
{
    std::cout<<"acceptor is correct!"<<std::endl;
}
#endif

==condition.h:==

#ifndef __wd_condition_h__
#define __wd_condition_h__

#include "noncopyable.h"
#include "mutexlock.h"
#include <pthread.h>

namespace wd
{
    class condition
    :noncopyable
    {
    public:
        condition(mutexlock &mutex)
        :_mutex(mutex)
        {pthread_cond_init(&_cond,null);}
    
        ~condition()
        {pthread_cond_destroy(&_cond);}
    
        void wait()
        {pthread_cond_wait(&_cond,_mutex.getmutexlockptr());}
    
        void notify()
        {pthread_cond_signal(&_cond);}
    
        void notifyall()
        {pthread_cond_broadcast(&_cond);}
    private:
        pthread_cond_t _cond;
        mutexlock & _mutex;
    };
}
#endif

==cache:==

 ///=======================================
 /// file:    cache.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-05 19:52:40
 /// dream:   don't forget your dreams!
 /// ======================================
 
#ifndef __cache_h__
#define __cache_h__
#include <unordered_map>
#include <string>
using namespace std;
namespace wd
{
    class cache
    {
    public:
        void addelement(string,string);//增加缓存信息
        void readfromfile(string);//从文件中读取信息
        void writetofile(string);//将信息写入文件中
        void update(const cache&);//更新缓存消息
        bool find(string querry);//从数据库中找寻信息
        string &operator[](string key);
    private:
        unordered_map<string,string>_hashtable;//采用hashtable进行缓存
    };
};
#endif
 ///=======================================
 /// file:    cache.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-05 20:01:25
 /// dream:   don't forget your dreams!
 /// ======================================
#include "cache.h"
#include <fstream>
#include <utility>
#include <iostream>
using namespace std;
using namespace wd;

void cache::addelement(string querry,string result)
{
    _hashtable[querry]=result;
}

void cache::readfromfile(string filepath)
{
    ifstream ifs(filepath);
    if(!ifs){
        cout<<"cache::read readfromfile file open error!"<<endl;
        return;
    }
    string querry,result;
    while(ifs>>querry,!ifs.eof())
    {
        ifs>>result;
        _hashtable[querry]=result;
    }
}
#if 0
void cache::writetofile(string filepath)
{
    ofstream ofs(filepath);
    if(!ofs){
        cout<<""<<endl;
        return;
    }
    for(auto &mypair:_hashtable)
    {
        ofs<<mypair.first<<" ";
        ofs<<mypair.second<<endl;
    }
}

void cache::update(const cache & cache)
{   
    for(auto &mypair:cache._hashtable)
    {
        auto cit =_hashtable.find(mypair.first);
        if(cit==_hashtable.end())
        {
            _hashtable.insert(std::move(mypair));
        }
    }
}
#endif

void cache::writetofile(string filepath)
{
    ofstream ofs(filepath);
    if(!ofs){
        cout<<"file write error!"<<endl;
        return;
    }
    for(auto &mypair:_hashtable)
    {
        ofs<<mypair.first<<" ";
        ofs<<mypair.second<<endl;
    }
}

void cache::update(const cache & cache)
{
    for(auto &mypair:cache._hashtable)
    {
        auto cit =_hashtable.find(mypair.first);
        if(cit==_hashtable.end())
        {
            _hashtable.insert(std::move(mypair));
        }
    }
}

bool cache::find(string querry)
{
    auto cit =_hashtable.find(querry);
    if(cit==_hashtable.end())
        return false;
    return true;
}

string &cache::operator[](string key)
{
    return _hashtable[key];
}

#if 0
int main()
{
    cout<<"cache is correct!"<<endl;
}
#endif

==cachemanger:==

 ///=======================================
 /// file:    cachemanger.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-05 20:51:09
 /// dream:   don't forget your dreams!
 /// ======================================
 
#ifndef __cachemanger_h__
#define __cachemanger_h__
#include "cache.h"
#include <vector>
#define threadnum 4//线程数目设置为4个,可自定义

using std::vector;
namespace wd
{
    class cachemanger
    {
    public:
        cachemanger(string filepath);
        void init(string);//创建缓存
        cache & getcache(size_t);//获取某个缓存
        void periodicupdate();//定时更新所有缓存
    private:
        string _cachefilepath;
        vector<cache>_cachelist;
    };
};

#endif
 ///=======================================
 /// file:    cachemanger.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-05 20:56:50
 /// dream:   don't forget your dreams!
 /// ======================================
#include "cachemanger.h"
#include <iostream>
#include <fstream>
#include <utility>
#include <iostream>
using namespace std;
using namespace wd;

cachemanger::cachemanger(string cachefilepath)
{
    init(cachefilepath);
}
             
void cachemanger::init(string cachefilepath)
{
    _cachefilepath=cachefilepath;
    _cachelist.reserve(threadnum);
    cache tmp;
    tmp.readfromfile(_cachefilepath);
    for(size_t i=0;i!=threadnum;++i)
    {
        _cachelist.push_back(std::move(tmp));
    }
}

cache & cachemanger::getcache(size_t number)
{
    return _cachelist[number];
}

void cachemanger::periodicupdate()
{
    auto cit=_cachelist.begin();
    cache lastwrite=*(cit ++);
    for(;cit<_cachelist.end();++cit)
    {
        lastwrite.update(*cit);
    }
    for(cit=_cachelist.begin()+1;cit!=_cachelist.end();++cit)
    {
        (*cit).update(lastwrite);
    }
    lastwrite.writetofile(_cachefilepath);
}

==epollpoller:==

 ///=======================================
 /// file:    epollpoller.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-06 11:03:36
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __wd_epollpoller_h__
#define __wd_epollpoller_h__

#include "tcpconnection.h"
#include "noncopyable.h"
#include "mutexlock.h"
#include <sys/epoll.h>
#include <vector>
#include <map>
#include <functional>

namespace wd
{
    class acceptor;
    class epollpoller
    :noncopyable
    {
    public:
        typedef tcpconnection::tcpconnectioncallback epollcallback;
        typedef  std::function<void()> functor;
        epollpoller(acceptor &acceptor);
        ~epollpoller();
    
        void loop();
        void unloop();
        void runinloop(const functor && cb);
        void dopendingfunctors();
        void wakeup();
    
        void setconnectioncallback(epollcallback cb);
        void setmessagecallback(epollcallback cb);
        void setclosecallback(epollcallback cb);
    private:
        void waitepollfd();
        void handleconnection();
        void handlemessage(int peerfd);
        void handleread();
    
        acceptor & _acceptor;
        int _epollfd;
        int _eventfd;
        int _listenfd;
        bool _islooping;
    
        mutexlock _mutex;
        std::vector<functor> _pendingfunctors;
    
        typedef std::vector<struct epoll_event>eventlist;
        eventlist _eventlist;
    
        typedef std::map<int,tcpconnectionptr> connectionmap;
        connectionmap _connmap;
        epollcallback _onconnectioncb;
        epollcallback _onmessagecb;
        epollcallback _onclosecb;
    };
}
#endif
 ///=======================================
 /// file:    epollpoller.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 15:42:54
 /// dream:   don't forget your dreams!
 /// ======================================

#include "epollpoller.h"
#include "socketutil.h"
#include "acceptor.h"
#include <assert.h>
#include <iostream>
using namespace std;

namespace wd
{
    epollpoller::epollpoller(acceptor & acceptor)
    :_acceptor(acceptor)
    ,_epollfd(createepollfd())
    ,_eventfd(createeventfd())
    ,_listenfd(_acceptor.fd())
    ,_islooping(false)
    ,_eventlist(1024)
    {
        addepollfdread(_epollfd,_listenfd);
        addepollfdread(_epollfd,_eventfd);

    }
    
    epollpoller::~epollpoller()
    {
        ::close(_epollfd);
    }
    
    void epollpoller::loop()
    {
        _islooping=true;
        while(_islooping)
        {
            waitepollfd();
        }
    }

    void epollpoller::unloop()
    {
        if(_islooping)
            _islooping=false;
    }

    void epollpoller::setconnectioncallback(epollcallback cb)
    {
        _onconnectioncb=cb;
    }
    
    void epollpoller::setmessagecallback(epollcallback cb)
    {
        _onmessagecb=cb;
    }
    
    void epollpoller::setclosecallback(epollcallback cb)
    {
        _onclosecb=cb;
    }
    void epollpoller::waitepollfd()
    {
        int nready;
        do
        {
            nready =::epoll_wait(_epollfd,&(*_eventlist.begin()),_eventlist.size(),10000);
                
        }while(-1==nready && errno ==eintr);

        if(-1==nready){
            perror("epoll wait error!");
            exit(exit_failure);
        }else if(0==nready){
            cout<<"epoll_wait timeout!"<<endl;
        }else{//扩容
            if(nready==static_cast<int>(_eventlist.size())){
                _eventlist.resize(_eventlist.size()*2);
            }

            for(int idx=0;idx!=nready;++idx)//正宗罗老师循环体(twt)
            {
                if(_eventlist[idx].data.fd ==_listenfd)
                {
                    if(_eventlist[idx].events & epollin)
                    {
                        handleconnection();
                    }
                }else if(_eventlist[idx].data.fd ==_eventfd){
                    handleread();
                    cout<<">>dopendingfunctors()"<<endl;
                    dopendingfunctors();
                }else{
                    if(_eventlist[idx].events & epollin){
                        handlemessage(_eventlist[idx].data.fd);
                    }
                }
            }
        }
    }

    void epollpoller::handleconnection()
    {
        int peerfd=_acceptor.accept();
        addepollfdread(_epollfd,peerfd);
        tcpconnectionptr conn(new tcpconnection(peerfd,this));
        conn->setconnectioncallback(_onconnectioncb);
        conn->setmessagecallback(_onmessagecb);
        conn->setclosecallback(_onclosecb);
        std::pair<connectionmap::iterator,bool>ret;
        ret=_connmap.insert(std::make_pair(peerfd,conn));
        assert(ret.second ==true);
        (void)ret;
        conn->handleconnectioncallback();
    }

    void epollpoller::handlemessage(int peerfd)
    {
        bool isclosed=isconnectionclosed(peerfd);
        connectionmap::iterator it =_connmap.find(peerfd);
        assert(it!=_connmap.end());

        if(isclosed)
        {
            it->second->handleclosecallback();
            delepollreadfd(_epollfd,peerfd);
            _connmap.erase(it);
        }else{
            it->second->handlemessagecallback();
        }
    }
    
    void epollpoller::runinloop(const functor && cb)//在计算线程中执行
    {
        mutexlockguard mlg(_mutex);
        _pendingfunctors.push_back(std::move(cb));
        wakeup();
    }

    void epollpoller::dopendingfunctors()
    {
        std::vector<functor>tmp;
        {
            mutexlockguard mlg(_mutex);
            tmp.swap(_pendingfunctors);
        }
        for(auto & functor:tmp)
        {
            functor();
        }
    }

    void epollpoller::handleread()
    {
        uint64_t howmany;
        int ret=::read(_eventfd,&howmany,sizeof(howmany));
        if(ret !=sizeof(howmany))
        {
            perror("read error!");
        }
    }

    void epollpoller::wakeup()
    {
        uint64_t one =1;
        int ret =::write(_eventfd,&one,sizeof(one));
        if(ret!=sizeof(one))
        {
            perror("write error!");
        }
    }
}
 

==inetaddress:==

 ///=======================================
 /// file:    inetaddress.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-05 21:55:19
 /// dream:   don't forget your dreams!
 /// ======================================
#ifndef __wd_inetaddress_h__
#define __wd_inetaddress_h__
#include <netinet/in.h>
#include <string>
namespace wd
{
    class inetaddress
    {
    public:
        inetaddress(short port);
        inetaddress(const char *pip,short port);
        inetaddress(const struct sockaddr_in & addr);
        std::string ip()const;
        unsigned short port() const;
        const struct sockaddr_in *getsockaddrptr() const;
    private:
        struct sockaddr_in _addr;
    };
}
#endif
 ///=======================================
 /// file:    inetaddress.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 20:55:18
 /// dream:   don't forget your dreams!
 /// ======================================

#include "inetaddress.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>

namespace wd
{
inetaddress::inetaddress(short port)
{
    ::memset(&_addr,0,sizeof(_addr));
    _addr.sin_family=af_inet;
    _addr.sin_port=htons(port);
    _addr.sin_addr.s_addr=inaddr_any;
}

inetaddress::inetaddress(const char * pip,short port)
{
    ::memset(&_addr,0,sizeof(_addr));
    _addr.sin_family=af_inet;
    _addr.sin_port=htons(port);
    _addr.sin_addr.s_addr=inet_addr(pip);
}

inetaddress::inetaddress(const struct sockaddr_in & addr)
:_addr(addr)
{}

const struct sockaddr_in * inetaddress::getsockaddrptr()const
{
    return & _addr;
}

std::string inetaddress::ip()const
{
    return std::string(inet_ntoa(_addr.sin_addr));
}

unsigned short inetaddress::port() const
{
    return ntohs(_addr.sin_port);
}

}

==mutexlock:==

#ifndef  __wd_mutexlock_h__
#define  __wd_mutexlock_h__

#include "noncopyable.h"
#include <pthread.h>

namespace wd
{
    class mutexlock
    :noncopyable
    {
    public:
        mutexlock()
        {pthread_mutex_init(&_mutex,null);}
        ~mutexlock()
        {pthread_mutex_destroy(&_mutex);}
        void lock()
        {pthread_mutex_lock(&_mutex);}
        void unlock()
        {pthread_mutex_unlock(&_mutex);}
        pthread_mutex_t *getmutexlockptr()
        {return &_mutex;}
    private:
        pthread_mutex_t _mutex;
};

class mutexlockguard//c++之父bs提出的raii
{
public:
    mutexlockguard(mutexlock &mutex)
    :_mutex(mutex)
    {
        _mutex.lock();
    }
    ~mutexlockguard()
    {
        _mutex.unlock();
    }
private:
    mutexlock &_mutex;
};
}
#endif

==mydict:==

 ///=======================================
 /// file:    mydict.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-06 11:12:19
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __mydict_h__
#define __mydict_h__
#include <string>
#include <vector>
#include <map>
#include <utility>
#include <set>
#include <fstream>
#include <iostream>
#include <sstream>
using namespace std;
namespace wd
{
    struct myresult
    {
        string _word;
        int _ifreq;//词频
        int _idist;//最小编辑距离
    };
    
    class mydict
    {
    public:
        mydict(const string dictdir,const string indexdir)
        {
            ifstream ifs1(dictdir),ifs2(indexdir);
            if(!ifs1||!ifs2)
                cout<<"mydict open file error!"<<endl;
            string key;
            int value;
            ifs1>>value;
            _dict.push_back(std::make_pair(string(" "),value));
            ifs1>>value;
            _dict.push_back(std::make_pair(string(" "),value));
            while(ifs1>>key)
            {
                ifs1>>value;
                _dict.push_back(std::make_pair(key,value));
            }
            string line;
            while(std::getline(ifs2,line))
            {
                istringstream iss(line);
                string ikey;
                int ivalue;
                iss>>ikey;
                set<int> tmp;
                while(iss>>ivalue)
                {
                    tmp.insert(ivalue);
                }
                _index.insert(std::make_pair(ikey,tmp));
            }
        }

        vector<pair<string,int>> & getdict(){return _dict;}

        map<string ,set<int>> & getindextable(){return _index;}

    private:
        vector<pair<string,int>> _dict;
        map<string,set<int>> _index;
    };
}
#endif

==mytask:==

 ///=======================================
 /// file:    mytask.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-06 21:04:54
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __mytask_h__
#define __mytask_h__
#include "tcpconnection.h"
#include "configuration.h"
#include "mydict.h"
#include "cache.h"
#include <string>
#include <queue>

using namespace std;

class mycompare
{
public:
    bool operator()(const wd::myresult & lhs,const wd::myresult &rhs)
    {
        if(lhs._idist !=rhs._idist)
            return lhs._idist<rhs._idist;
        else
            return lhs._ifreq>rhs._ifreq;
    }
private:
};

using character =string;

class mytask
{
public:
    mytask(const string &querry,const wd::tcpconnectionptr conn)
    :_querry(std::move(querry))
    ,_conn(conn)
    {}
    void execute();
private:
    void queryindextable();//查询索引(四个索引)
    void statistic(set<int> &iset);//计算
    int distance(const string & rhs);//计算最小编辑距离
    bool response(wd::cache & cache);//响应客户端的请求
    vector<character>getonecharacter(const string &word);//获取字符数组
    string _querry;
    wd::tcpconnectionptr _conn;
    priority_queue<wd::myresult,vector<wd::myresult>,mycompare> _resultque;
};
#endif
 ///=======================================
 /// file:    mytask.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 22:47:19
 /// dream:   don't forget your dreams!
 /// ======================================

#include "mytask.h"
#include "configuration.h"
#include "mydict.h"
#include "cachemanger.h"
#include "json/json.h"
#include <string.h>
#include <algorithm>
extern __thread int t_number;

bool mytask::response(wd::cache &cache)
{
    if(cache.find(_querry))
    {
        _conn->sendinloop(cache[_querry]);
        return true;
    }
    return false;
}

int mytask::distance(const string &rhs)
{
    vector<character>querrycharacter =getonecharacter(_querry);
    vector<character>indexcharacter =getonecharacter(rhs);

    int len1,len2;
    len1=querrycharacter.size();
    len2=indexcharacter.size();
    int edit[len1+1][len2+1];
    int i,j;
    for(i=0;i<=len1;++i){
        for(j=0;j<=len2;++j){
            edit[i][j]=0;
        }
    }
    for(i=0;i<len1;++i){
        edit[i][0]=i;
    }
    for(j=0;j<=len2;++j){
        edit[0][j]=j;
    }
    for(i=1;i<len1;++i){
        for(j=1;j<=len2;++j){
            int cost =((querrycharacter[i-1]==indexcharacter[j-1])?0:1);
            int deletion =edit[i-1][j]+1;
            int insertion=edit[i][j-1]+1;
            int substitution=edit[i-1][j-1]+cost;
            edit[i][j]=std::min(deletion,std::min(insertion,substitution));
        }
    }
    return edit[len1][len2];
}

void mytask::statistic(set<int> &iset)
{
    vector<pair<string,int>>dict=(singleton<wd::mydict>::getinstance(singleton<wd::configuration>::getinstance(confpath)->getdictdir(),
                                                                     singleton<wd::configuration>::getinstance(confpath)->getindexdir()))->getdict();

    for(auto &idx:iset)
    {
        string key=dict[idx].first;
        int idist =distance(key);
        if(idist<=3)
        {
            wd::myresult res;
            res._word=key;
            res._idist=idist;
            res._ifreq=dict[idx].second;
            _resultque.push(res);
        }
    }
}

vector<character>mytask::getonecharacter(const string & word)
{
    auto cit =word.begin();
    vector<character> ret;
    while(cit<word.end())
    {
        if(224==(*cit &224)){
            character onecharacter;
            onecharacter.append(cit,cit+3);
            ret.push_back(onecharacter);
            cit =cit+3;
        }else if(240==(*cit &240)){
            character onecharacter;
            onecharacter.append(cit,cit+4);
            ret.push_back(onecharacter);
            cit =cit+4;
        }else{
            character onecharacter(1,*cit);
            ret.push_back(onecharacter);
            cit ++;
        }
    }
    return ret;
}

void mytask::queryindextable()
{
    map<string,set<int>>index=(singleton<wd::mydict>::getinstance(singleton<wd::configuration>::getinstance(confpath)->getdictdir(),
                                                                  singleton<wd::configuration>::getinstance(confpath)->getindexdir()))->getindextable();

    vector<character> onecharacter=getonecharacter(_querry);
    set<int>allrally;
    for(auto mycharacter:onecharacter)
    {
        auto cit =index.find(mycharacter);
        if(cit!=index.end())
        {
            for(auto &idx:cit->second)
                allrally.insert(idx);
        }
    }
    statistic(allrally);
}

void mytask::execute()
{
    wd::cache &mycache =(singleton<wd::cachemanger>::getinstance(singleton<wd::configuration>::getinstance(confpath)->getcache()))->getcache(t_number);
    if(response(mycache))
        return;
    else{
        queryindextable();
        json::fastwriter writerinfo;
        json::value arrayobj;
        while(!_resultque.empty())
        {
            json::value new_item;
            new_item[""]=_resultque.top()._word;
            _resultque.pop();
            arrayobj.append(new_item);
        }
        string stremail=writerinfo.write(arrayobj);
        mycache.addelement(_querry,stremail);
        _conn->sendinloop(stremail);
    }
}

==noncopyable:==

#ifndef __wd_noncopyable_h__
#define __wd_noncopyable_h__

namespace  wd
{
    class noncopyable
    {
    protected:
        noncopyable(){}
        ~noncopyable(){}
    private:
        noncopyable(const noncopyable &);
        noncopyable & operator=(const noncopyable &);
    
    };
}
#endif

==socket:==

 ///=======================================
 /// file:    socket.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-05 21:46:26
 /// dream:   don't forget your dreams!
 /// ======================================
 
#ifndef __wd_socket_h__
#define __wd_socket_h__
#include "noncopyable.h"
namespace wd
{
    class inetaddress;
    class socket
    :noncopyable
    {
    public:
        socket(int socket);
        socket();
        ~socket();
    
        void shutdownwrite();
        int fd()const {return _sockfd;}
        void nonblock();
        static inetaddress getlocaladdr(int socketfd);
        static inetaddress getpeeraddr(int sockfd);
    private:
        int _sockfd;
    };
}
#endif
 
 ///=======================================
 /// file:    socket.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 20:38:20
 /// dream:   don't forget your dreams!
 /// ======================================

#include "socket.h"
#include "socketutil.h"
#include "inetaddress.h"

namespace wd
{
socket::socket(int sockfd)
:_sockfd(sockfd)
{}

socket::socket()
:_sockfd(createsocketfd())
{}

socket::~socket()
{
    ::close(_sockfd);
}

void socket::nonblock()
{
    setnonblock(_sockfd);
}

void socket::shutdownwrite()
{
    if(-1==::shutdown(_sockfd,shut_wr)){
        perror("shutdown write error!");
    }
}

inetaddress socket::getlocaladdr(int sockfd)
{
    struct sockaddr_in addr;
    socklen_t len=sizeof(sockaddr_in);
    if(-1==::getsockname(sockfd,(struct sockaddr *)&addr,&len)){
        perror("getsockname error!");
    }
    return inetaddress(addr);
}

inetaddress socket::getpeeraddr(int sockfd)
{
    struct sockaddr_in addr;
    socklen_t len=sizeof(sockaddr_in);
    if(-1==::getpeername(sockfd,(struct sockaddr *)&addr,&len)){
        perror("getpeername error!");
    }
    return inetaddress(addr);
    
}

}

==socketio:==

 ///=======================================
 /// file:    socketio.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-06 17:10:23
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __socketio_h__
#define __socketio_h__
#include <stdio.h>

namespace wd
{
    class socketio
    {
    public:
        socketio(int sockfd);
        size_t readn(char *buf,size_t count);
        size_t writen(const char *buf,size_t count);
        size_t readline(char *buf,size_t max_len);
    private:
        size_t recv_peek(char *buf,size_t count);
        int _sockfd;
    };
}
#endif
 ///=======================================
 /// file:    socketio.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 21:56:34
 /// dream:   don't forget your dreams!
 /// ======================================

#include "socketio.h"
#include "socketutil.h"
namespace wd
{
socketio::socketio(int sockfd)
:_sockfd(sockfd)
{}

size_t socketio::readn(char *buf,size_t count)
{
    size_t nleft =count;
    char *pbuf=buf;
    while(nleft>0)
    {
        int nread =::read(_sockfd,pbuf,nleft);
        if(-1==nread)
        {
            if(errno ==eintr)
                continue;
            return exit_failure;
        }else if(0==nread){
            break;
        }
        pbuf =pbuf+nread;
        nleft=nleft-nread;
    }
    return (count -nleft);
}

size_t socketio::writen(const char * buf,size_t count)
{
    size_t nleft =count;
    const char *pbuf=buf;
    while(nleft >0)
    {
        int nwrite=::write(_sockfd,pbuf,nleft);
        if(-1==nwrite)
        {
            if(errno ==eintr)
                continue;
            return exit_failure;
        }
        nleft =nleft -nwrite;
        pbuf =pbuf +nwrite;
    }
    return (count -nleft);
}
size_t socketio::recv_peek(char *buf,size_t count)
{
    int nread;
    do{
        nread=::recv(_sockfd,buf,count,msg_peek);
    }while(-1==nread && errno ==eintr);
    return nread;
}

size_t socketio::readline(char *buf,size_t maxlen)
{
    size_t nleft =maxlen-1;
    char *pbuf=buf;
    size_t total=0;
    while(nleft>0)
    {
        size_t nread =recv_peek(pbuf,nleft);
        if(nread<=0)
            return nread;

        for(size_t idx =0;idx!=nread;++idx){//检查换行符/n
            if(pbuf[idx]=='\n'){
                size_t nsize =idx +1;
                if(readn(pbuf,nsize)!=nsize)
                    return exit_failure;
                pbuf +=nsize;
                total +=nsize;
                *pbuf=0;
                return total;
            }
        }
        if(readn(pbuf,nread)!=nread)
            return exit_failure;
        pbuf +=nread;
        nleft -=nread;
        total +=nread;
    }
    *pbuf=0;
    return maxlen-1;
}

}

==sockutil(根据陈硕编写的linux书上分开头文件)==

 ///=======================================
 /// file:    socktutil.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-05 22:01:30
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __wd_sockerutil_h__
#define __wd_sockerutil_h__
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/eventfd.h>
#include <sys/epoll.h>
namespace wd
{
    inline int createsocketfd()
    {
        int fd=::socket(af_inet,sock_stream,0);
        if(-1==fd)
        {
            perror("socket create error!");
        }
        return fd;
    }
    
    inline void setnonblock(int fd)
    {
        int flags=::fcntl(fd,f_getfl,0);
        flags |= o_nonblock;
        ::fcntl(fd,f_setfl,flags);
    }
    
    inline int createepollfd()
    {
        int efd=::epoll_create1(0);
        if(-1==efd)
        {
            perror("epoll create1 error!");
            exit(exit_failure);
        }
        return efd;
    }
    
    inline int createeventfd()
    {
        int evtfd=::eventfd(0,efd_nonblock|efd_cloexec);
        if(-1==evtfd)
        {
            perror("eventfd create error!");
        }
        return evtfd;
    }
    inline void addepollfdread(int efd,int fd)
    {
        struct epoll_event ev;
        ev.data.fd=fd;
        ev.events=epollin;
        int ret=epoll_ctl(efd,epoll_ctl_add,fd,&ev);
        if(-1==ret)
        {
            perror("epoll ctl add error!");
            exit(exit_failure);
        }
    }
    inline void delepollreadfd(int efd,int fd)
    {
        struct epoll_event ev;
        ev.data.fd=fd;
        int ret=epoll_ctl(efd,epoll_ctl_del,fd,&ev);
        if(-1==ret)
        {
            perror("epoll ctl delete error!");
            exit(exit_failure);
        }
    }
    
    inline size_t recvpeek(int sockfd,void *buf,size_t len)
    {
        int nread;
        do{
            nread=::recv(sockfd,buf,len,msg_peek);
        }while(nread==-1 && errno ==eintr);
        return nread;
    }
    
    inline bool isconnectionclosed(int sockfd)
    {
        char buf[1024];
        int nread=recvpeek(sockfd,buf,sizeof(buf));
        if(-1==nread)
        {
            perror("recvpeek error!");
            return true;
        }
        return (0==nread);
    }
}
#endif

==spellcorrrectsever:==

 ///=======================================
 /// file:    spellcorrectserver.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-06 20:41:13
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __spellcorrectserver_h__
#define __spellcorrectserver_h__
#include "tcpserver.h"
#include "threadpool.h"

using namespace wd;
namespace wd
{
    class spellcorrectserver
    {
    public:
        spellcorrectserver(const string & ip
                           ,unsigned short port
                           ,size_t threadnum
                           ,size_t quesize);
        void start();
    private:
        void onconnection(const tcpconnectionptr &);
        void onmessage(const tcpconnectionptr &);
        void onclose(const tcpconnectionptr &);
        tcpserver _tcpserver;
        threadpool _threadpoll;
    };
};
#endif
 ///=======================================
 /// file:    spellcorrectserver.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 21:20:41
 /// dream:   don't forget your dreams!
 /// ======================================

#include "spellcorrectserver.h"
#include "mytask.h"
#include <stdio.h>
#include <iostream>
#include <string>
#include <utility>
#include <functional>
using namespace std;

void spellcorrectserver::onconnection(const wd::tcpconnectionptr & conn)
{
    cout<<conn->tostring()<<endl;
    conn->send("hello ,welcome to wtp chat server.\r\n");
}

void spellcorrectserver::onmessage(const wd::tcpconnectionptr & conn)
{
    string s(conn->receive());
    mytask task(s,conn);
    _threadpoll.addtask(std::bind(&mytask::execute,&task));
    cout<<">add task to threadpool"<<endl;
}

void spellcorrectserver::onclose(const wd::tcpconnectionptr &conn)
{
    ::printf("%s close\n",conn->tostring().c_str());
}

spellcorrectserver::spellcorrectserver(const string & ip
                                       ,unsigned short port
                                       ,size_t threadnum
                                       ,size_t quesize)
:_tcpserver(ip,port)
,_threadpoll(threadnum,quesize)
{}

void spellcorrectserver::start()
{
    _threadpoll.start();
    _tcpserver.setconnectioncallback(std::bind(&spellcorrectserver::onconnection,this,std::placeholders::_1));
    _tcpserver.setmessagecallback(std::bind(&spellcorrectserver::onmessage,this,std::placeholders::_1));
    _tcpserver.setclosecallback(std::bind(&spellcorrectserver::onclose,this,std::placeholders::_1));
    _tcpserver.start();
}

==taskque:==

#ifndef __wd_taskqueue_h__
#define __wd_taskqueue_h__

#include "mutexlock.h"
#include "condition.h"
#include <queue>
#include <functional>

namespace wd
{
    typedef std::function<void()>task;
    
    class taskqueue
    {
    public:
        taskqueue(size_t quesize)
        :_quesize(quesize)
        ,_mutex()
        ,_notfull(_mutex)
        ,_notempty(_mutex)
        ,_flag(true)
        {}
    
        void push(task &&task);
        task pop();
        bool empty()const
        {
            return _que.size()==0;
        }
        bool full()const
        {return _que.size()==_quesize;}
        void wakeup()
        {   
            if(_flag)
                _flag=false;
            _notempty.notifyall();
        }
    private:
        size_t _quesize;
        std::queue<task> _que;
        mutexlock _mutex;
        condition _notfull;
        condition _notempty;
        bool _flag;
    };
}
#endif
#include "taskqueue.h"

using namespace wd;
//生产者所在的线程
void taskqueue::push(task && task)
{
    mutexlockguard autolock(_mutex);
    while(full())
    {
        _notfull.wait();
    }
    _que.push(std::move(task));
    _notempty.notify();
}

//消费者所在线程
task taskqueue::pop()
{
    mutexlockguard autolock(_mutex);
    while(_flag && empty())
    {
        _notempty.wait();
    }
    if(_flag){
        task task=_que.front();
        _que.pop();
        _notfull.notify();
        return task;
    }else{
        return null;
    }
}
#if 0
task taskqueue::pop()
{
    mutexlockguard autolock(_mutex);
    while(_flag && empty())
    {
        _notempty.wait();
    }
    if(_flag){
        task task =_que.front();
        _que.pop();
        _notfull.notify();
        return task;
    }else{
        return null;
    }
}
#endif

==tcpconnection:==

 ///=======================================
 /// file:    tcpconnection.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-06 17:15:33
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __wd_tcpconnection_h__
#define __wd_tcpconnection_h__

#include "noncopyable.h"
#include "inetaddress.h"
#include "socket.h"
#include "socketio.h"

#include <string>
#include <memory>
#include <functional>
namespace wd
{
    class epollpoller;
    class tcpconnection;
    typedef std::shared_ptr<tcpconnection> tcpconnectionptr;

    class tcpconnection
    :noncopyable
    ,public std::enable_shared_from_this<tcpconnection>
    {
    public:
        typedef std::function<void(const tcpconnectionptr &)>tcpconnectioncallback;
        tcpconnection(int sockfd,epollpoller *loop);
        ~tcpconnection();

        std::string receive();
        void send(const std::string &msg);
        void sendinloop(const std::string &msg);
        void shutdown();

        std::string tostring();
        void setconnectioncallback(tcpconnectioncallback cb);
        void setmessagecallback(tcpconnectioncallback cb);
        void setclosecallback(tcpconnectioncallback cb);

        void handleconnectioncallback();
        void handlemessagecallback();
        void handleclosecallback();
    private:
        socket _sockfd;
        socketio _sockio;
        const inetaddress _localaddr;
        const inetaddress _peeraddr;
        bool _isshutdownwrite;
        epollpoller * _loop;
        tcpconnectioncallback _onconnectioncb;
        tcpconnectioncallback _onmessagecb;
        tcpconnectioncallback _onclosecb;

    };
}
#endif
 ///=======================================
 /// file:    tcpconnection.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 22:22:22
 /// dream:   don't forget your dreams!
 /// ======================================

#include "tcpconnection.h"
#include "epollpoller.h"
#include <string.h>
#include <stdio.h>

namespace wd
{
tcpconnection::tcpconnection(int sockfd,epollpoller * loop)
:_sockfd(sockfd)
,_sockio(sockfd)
,_localaddr(wd::socket::getlocaladdr(sockfd))
,_peeraddr(wd::socket::getpeeraddr(sockfd))
,_isshutdownwrite(false)
,_loop(loop)
{_sockfd.nonblock();}

tcpconnection::~tcpconnection()
{
    if(!_isshutdownwrite)
    {
        _isshutdownwrite=true;
        shutdown();
    }
    printf("~tcpconnection()\n");
}

std::string tcpconnection::receive()
{
    char buf[65536];
    memset(buf,0,sizeof(buf));
    size_t ret =_sockio.readline(buf,sizeof(buf));
    if(0==ret){
        return std::string();
    }else{
        return std::string(buf);
    }
}

void tcpconnection::send(const std::string &msg)
{
    size_t len=msg.size();
    _sockio.writen((const char *)&len,sizeof(int));
    _sockio.writen(msg.c_str(),len);
}

void tcpconnection::shutdown()
{
    if(!_isshutdownwrite)
        _sockfd.shutdownwrite();
    _isshutdownwrite=true;
}

std::string tcpconnection::tostring()
{
    char str[100];
    snprintf(str,sizeof(str),"%s:%d->%s:%d"
             ,_localaddr.ip().c_str()
             ,_localaddr.port()
             ,_peeraddr.ip().c_str()
             ,_peeraddr.port());
    return std::string(str);
}

void tcpconnection::setconnectioncallback(tcpconnectioncallback cb)
{
    _onconnectioncb =cb;
}
void tcpconnection::setmessagecallback(tcpconnectioncallback cb)
{
    _onmessagecb =cb;
}
void tcpconnection::setclosecallback(tcpconnectioncallback cb)
{
    _onclosecb =cb;
}

void tcpconnection::handleconnectioncallback()
{
    if(_onconnectioncb){
        _onconnectioncb(shared_from_this());
    }
}
void tcpconnection::handlemessagecallback()
{
    if(_onmessagecb){
        _onmessagecb(shared_from_this());
    }
}
void tcpconnection::handleclosecallback()
{
    if(_onclosecb){
        _onclosecb(shared_from_this());
    }
}

void tcpconnection::sendinloop(const std::string & msg)
{
    _loop->runinloop(std::bind(&tcpconnection::send,this,msg));
}

}

==tcpserver:==

 ///=======================================
 /// file:    tcpserver.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-06 20:15:21
 /// dream:   don't forget your dreams!
 /// ======================================
 
#ifndef __wd_tcpserver_h__
#define __wd_tcpserver_h__

#include "acceptor.h"
#include "epollpoller.h"
#include <string>

using std::string;
namespace wd
{
    class tcpserver
    {
    public:
        typedef epollpoller::epollcallback tcpservercallback;
        tcpserver(const string & ip,unsigned short port);
        tcpserver(unsigned short port);

        void start();
        void stop();
        void setconnectioncallback(tcpservercallback cb);
        void setmessagecallback(tcpservercallback cb);
        void setclosecallback(tcpservercallback cb);

    private:
        acceptor _acceptor;
        epollpoller _poller;

        tcpservercallback _connectioncallback;
        tcpservercallback _messagecallback;
        tcpservercallback _closecallback;
    };
}
#endif
 ///=======================================
 /// file:    tcpserver.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 19:59:37
 /// dream:   don't forget your dreams!
 /// ======================================

#include "tcpserver.h"
#include "inetaddress.h"
#include "socketutil.h"
#include <iostream>
using namespace std;
namespace wd
{
    tcpserver::tcpserver(const string & ip,unsigned short port)
    :_acceptor(createsocketfd(),inetaddress(ip.c_str(),port))
    ,_poller(_acceptor)
    {}

    void tcpserver::start()
    {
        _acceptor.ready();
        _poller.setconnectioncallback(_connectioncallback);
        _poller.setmessagecallback(_messagecallback);
        _poller.setclosecallback(_closecallback);
        _poller.loop();
    }

    void tcpserver::stop()
    {
        _poller.unloop();
    }

    void tcpserver::setconnectioncallback(tcpservercallback cb)
    {_connectioncallback=cb;}

    void tcpserver::setmessagecallback(tcpservercallback cb)
    {_messagecallback=cb;}

    void tcpserver::setclosecallback(tcpservercallback cb)
    {_closecallback=cb;}
}

==thread:==

#ifndef  __wd_thread_h__
#define  __wd_thread_h__

#include "noncopyable.h"
#include <pthread.h>
#include <functional>
using std::function;
namespace wd
{
    class thread;
    struct threadptr
    {
        int _number;
        thread *_pthread;
    };
    class thread
    :noncopyable
    {
        using threadcallback =function<void()>;
    public:
        thread(threadcallback &&cb);
        ~thread();
    
        void start(int number);
        void join();
    
        bool isrunning()const {return _isrunning;}
    
    private:
        static void * threadfunc(void *);
        pthread_t _pthid;
        bool _isrunning;
        threadcallback _cb;
    };
}
#endif
#include "thread.h"
#include <iostream>
using namespace std;
using namespace wd;

__thread int t_number;//将线程编号作为线程存储的标记

thread::thread(threadcallback && cb)//这里的右值引用本身取决于是否有名字
:_pthid(0)
,_isrunning(false)
,_cb(std::move(cb))
{
    cout<<"thread(cb)"<<endl;
}

void thread::start(int number)
{
    threadptr *threadptr=new threadptr();
    threadptr->_number=number;
    threadptr->_pthread=this;
    pthread_create(&_pthid,null,threadfunc,threadptr);
    _isrunning=true;
}

void *thread::threadfunc(void *arg)
{//应用了线程存储
    threadptr *threadptr=static_cast<threadptr*>(arg);
    thread * pthread=threadptr->_pthread;
    t_number=threadptr->_number;
    if(pthread)
        pthread->_cb();//线程开始工作!
    delete threadptr;
    //thread * pthread =threadptr->_pthread;
    return null;
}
#if 0
void *thread::threadfunc(void *arg)
{
    threadptr *threadptr =static_cast<threadptr*>(arg);
    thread * pthread =threadptr->_pthread;
    t_number =threadptr->_number;
    if(pthread)
        pthread->_cb();
    delete threadptr;
    return null;
}
#endif
void thread::join()
{
    pthread_join(_pthid,null);
    _isrunning=false;
}

thread::~thread()
{
    if(_isrunning)
    {
        pthread_detach(_pthid);
        _isrunning=false;
    }
    cout<<"~thread()"<<endl;
}

==threadpool:==

#ifndef __wd_threadpoll_h__
#define __wd_threadpoll_h__
#include "taskqueue.h"
#include "thread.h"
#include <vector>
#include <memory>
#include <functional>
using std::shared_ptr;
using std::vector;
namespace  wd
{
    class threadpool
    {
    public:
        using task=std::function<void()>;
    
        threadpool(size_t threadnum,size_t quesize)
        :_threadnum(threadnum)
        ,_quesize(quesize)
        ,_taskque(_quesize)
        ,_isexit(false)
        {
            _threads.reserve(_threadnum);
        }
        
        ~threadpool();
    
        void start();
        void stop();
        void addtask(task && task);
    
    private:
        void threadfunc();
        task gettask();
        size_t _threadnum;
        size_t _quesize;
        vector<shared_ptr<thread>> _threads;
        taskqueue _taskque;
        bool _isexit;
    };
}
#endif
#include "threadpool.h"
#include "thread.h"
#include <unistd.h>
#include <iostream>

using namespace std;
using namespace wd;

void threadpool::start()
{
    for(size_t idx=0;idx<_threadnum;++idx)
    {
        shared_ptr<thread>pthread(new thread(std::bind(&threadpool::threadfunc,this)));
        _threads.push_back(std::move(pthread));
    }
    int number=0;
    for(auto &pthread:_threads)
    {
        pthread->start(number);
        ++number;
    }
}
void threadpool::stop()//为了线程安全,将stop方法置于主线程中
{
    if(!_isexit)
    {
        while(!_taskque.empty()){
            ::sleep(1);
            cout<<"threadpool sleep 1 second!"<<endl;
        }
        _isexit=true;
        cout<<"threadpool ->stop:_isexit="<<_isexit<<endl;
        _taskque.wakeup();
        for(auto &pthread:_threads){
            pthread->join();
        }
    }
}

threadpool::~threadpool()
{
    if(!_isexit){
        stop();
    }
}
void threadpool::addtask(task && task)
{
    _taskque.push(std::move(task));
}

task threadpool::gettask()
{
    return _taskque.pop();
}

void threadpool::threadfunc()
{
    while(!_isexit)
    {
        task task=gettask();
        if(task){
            task();
        }
    }
}

==timer:==

 ///=======================================
 /// file:    timer.h
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-06 20:00:45
 /// dream:   don't forget your dreams!
 /// ======================================

#ifndef __wd_timer_h__
#define __wd_timer_h__
#include <functional>

namespace wd
{
    class timer
    {
    public:
        using timercallback =std::function<void()>;
        timer(int initailtime,int intervaltime,timercallback && cb);
        ~timer();
        void start();
        void stop();
    private:
        int _fd;
        int _initialtime;
        int _intervaltime;
        timercallback _cb;
        bool _isstarted;
        int createtimerfd();
        void settimerfd(int initialtime, int intervaltime);
        void handleread();  
    };
}
#endif
 ///=======================================
 /// file:    timer.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 20:09:14
 /// dream:   don't forget your dreams!
 /// ======================================

#include "timer.h"
#include <unistd.h>
#include <errno.h>
#include <poll.h>
#include <sys/timerfd.h>
#include <iostream>
using namespace std;
using namespace wd;

timer::timer(int initialtime,int intervaltime,timercallback && cb)
:_fd(createtimerfd())
,_initialtime(initialtime)
,_intervaltime(intervaltime)
,_cb(std::move(cb))
,_isstarted(false)
{}

void timer::start()
{
    struct pollfd pfd;
    pfd.fd=_fd;
    pfd.events=pollin;
    settimerfd(_initialtime,_intervaltime);//开启定时器
    _isstarted=true;
    while(_isstarted){
        int nready=::poll(&pfd,1,5000);
        if(-1==nready &&errno ==eintr){
            continue;
        }else if(-1==nready){
            perror(">>>poll error!");
            exit(exit_failure);
        }else if(0==nready){
            cout<<">>>poll timeout!"<<endl;
        }else{
            if(pfd.revents & pollin){
                handleread();//先对定时器进行处理
                if(_cb){
                    _cb();//再去执行回调任务
                }
            }
        }
    }
}

void timer::stop()
{
    settimerfd(0,0);
    if(_isstarted){
        _isstarted=false;
    }
}

timer::~timer()
{
    if(_isstarted){
        stop();
    }
}

int timer::createtimerfd()
{
    int fd=::timerfd_create(clock_realtime,0);
    if(-1==fd){
        perror(">>timerfd_create error!");
    }
    return fd;
}

void timer::settimerfd(int initialtime,int intervaltime)
{
    struct itimerspec value;
    value.it_value.tv_sec=initialtime;
    value.it_value.tv_nsec=0;
    value.it_interval.tv_sec=intervaltime;
    value.it_interval.tv_nsec=0;
    int ret=::timerfd_settime(_fd,0,&value,null);
    if(-1==ret){
        perror(">>>timerfd_settime error!");
    }
}
#if 0
void timer::handleread()
{
    uint64_t howmany;
    int ret =::read(_fd,&howmany,sizeof(uint64_t));
    if(ret!=sizeof(uint64_t)){
        perror("read!");
    }
}
#endif


void timer::handleread()
{
    uint64_t howmany;//为一个64位
    int ret=::read(_fd,&howmany,sizeof(uint64_t));
    if(ret!=sizeof(uint64_t)){
        perror(">>>read error!");
    }
}

==timerthread:==

 ///=======================================
 /// file:    timerthread.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 17:12:51
 /// dream:   don't forget your dreams!
 /// ======================================
#ifndef __wd_timerthread_h__
#define __wd_timerthread_h__

#include "timer.h"
#include "thread.h"

#include <functional>

namespace wd
{
    
class timerthread
{
public:
    using timercallback = std::function<void()>;
    timerthread(int, int, timercallback && cb);
    ~timerthread();

    void start();
    void stop();


private:
    timer _timer;
    thread _subthread;
    bool _isstarted;
};
}//end of namespace wd

#endif
 ///=======================================
 /// file:    timerthread.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 20:09:14
 /// dream:   don't forget your dreams!
 /// ======================================
#include "timerthread.h"


using namespace wd;

timerthread::timerthread(int initialtime, int intervaltime, timercallback && cb)
: _timer(initialtime, intervaltime, std::move(cb))
, _subthread(std::bind(&timer::start, &_timer))
, _isstarted(false)
{}

void timerthread::start()
{
    _subthread.start(0);
    _isstarted = true;
}

void timerthread::stop()
{
    if(_isstarted) {
        _timer.stop();
        _subthread.join();
        _isstarted = false;
    }
}

timerthread::~timerthread()
{
    if(_isstarted)
        stop();
}

==main:==

 ///=======================================
 /// file:    main.cc
 /// author:  wtptorres(1584292712@qq.com)
 /// date:    2019-06-07 21:09:32
 /// dream:   don't forget your dreams!
 /// ======================================

#include "spellcorrectserver.h"
#include "configuration.h"
#include "cachemanger.h"
#include "timerthread.h"
#include <iostream>
#include <functional>
using namespace std;
using namespace wd;

int main()
{
    wd::cachemanger *mycachemanger=singleton<cachemanger>::getinstance(singleton<configuration>
                                                         ::getinstance(confpath)->getcache());
    timerthread timer(5,600,std::bind(&cachemanger::periodicupdate,mycachemanger));
    timer.start();
    spellcorrectserver myspell(singleton<configuration>::getinstance(confpath)->getip()
                               ,singleton<configuration>::getinstance(confpath)->getport()
                               ,4
                               ,10);
    myspell.start();
    return 0;
}

小结:(1)已经实现项目需求,中文和英文单词都能查询,经过测试,运行稳定,能输出不少候选词

(2)仍然存在少量bug,例如偶尔会发生段错误

(3)由于时间问题,json读出的数据key-value的key值没有打印,用户界面还未来得及优化

(4)陈硕的《linux多线程服务端编程》使用linux接口(timerfd),没用posix接口(eventfd)