mirror of
https://github.com/yanyiwu/cppjieba.git
synced 2025-07-18 00:00:12 +08:00
add husky
This commit is contained in:
parent
51e160bf1d
commit
b2d6fbbbe5
@ -2,7 +2,6 @@ CXX := g++
|
|||||||
LD := g++
|
LD := g++
|
||||||
AR := ar rc
|
AR := ar rc
|
||||||
|
|
||||||
INCS := -I../limonp
|
|
||||||
|
|
||||||
DEBUG_CXXFLAGS := -g -Wall -DDEBUG
|
DEBUG_CXXFLAGS := -g -Wall -DDEBUG
|
||||||
RELEASE_CXXFLAGS := -Wall -O3
|
RELEASE_CXXFLAGS := -Wall -O3
|
||||||
@ -15,7 +14,9 @@ else
|
|||||||
LDFLAGS := ${RELEASE_LDFLAGS}
|
LDFLAGS := ${RELEASE_LDFLAGS}
|
||||||
endif
|
endif
|
||||||
|
|
||||||
DOLINK := $(LD) $(LDFLAGS)
|
INCS := -I../limonp
|
||||||
|
LINK := -lpthread
|
||||||
|
|
||||||
SOURCES := $(wildcard *.cpp)
|
SOURCES := $(wildcard *.cpp)
|
||||||
OBJS := $(patsubst %.cpp,%.o,$(SOURCES))
|
OBJS := $(patsubst %.cpp,%.o,$(SOURCES))
|
||||||
DEMOS := $(patsubst %.cpp,%.demo,$(SOURCES))
|
DEMOS := $(patsubst %.cpp,%.demo,$(SOURCES))
|
||||||
@ -23,19 +24,26 @@ DEMOS := $(patsubst %.cpp,%.demo,$(SOURCES))
|
|||||||
CPPJIEBADIR := ../cppjieba
|
CPPJIEBADIR := ../cppjieba
|
||||||
LIBCPPJIEBA := $(CPPJIEBADIR)/libcppjieba.a
|
LIBCPPJIEBA := $(CPPJIEBADIR)/libcppjieba.a
|
||||||
|
|
||||||
|
HUSKYDIR := ../husky
|
||||||
|
LIBHUSKYA := $(HUSKYDIR)/libhusky.a
|
||||||
|
|
||||||
.PHONY: clean $(LIBCPPJIEBA)
|
.PHONY: clean $(LIBCPPJIEBA)
|
||||||
|
|
||||||
all: $(DEMOS)
|
all: $(DEMOS)
|
||||||
|
|
||||||
%.demo: %.cpp $(LIBCPPJIEBA)
|
%.demo: %.cpp $(LIBCPPJIEBA) $(LIBHUSKYA)
|
||||||
$(CXX) -o $@ $(CXXFLAGS) $^ $(INCS)
|
$(CXX) -o $@ $(CXXFLAGS) $^ $(INCS) $(LINK)
|
||||||
|
|
||||||
$(LIBCPPJIEBA):
|
$(LIBCPPJIEBA):
|
||||||
cd $(CPPJIEBADIR) && $(MAKE)
|
cd $(CPPJIEBADIR) && $(MAKE)
|
||||||
|
|
||||||
|
$(LIBHUSKYA):
|
||||||
|
cd $(HUSKYDIR) && $(MAKE)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o *.ut *.d *.d.* $(DEMOS)
|
rm -f *.o *.ut *.d *.d.* $(DEMOS)
|
||||||
cd $(CPPJIEBADIR) && make clean
|
cd $(CPPJIEBADIR) && make clean
|
||||||
|
cd $(HUSKYDIR) && make clean
|
||||||
|
|
||||||
sinclude $(SOURCES:.cpp=.d)
|
sinclude $(SOURCES:.cpp=.d)
|
||||||
%.d:%.cpp
|
%.d:%.cpp
|
||||||
|
4
demo/restart.sh
Executable file
4
demo/restart.sh
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
sh start.sh
|
||||||
|
sh stop.sh
|
59
demo/server.cpp
Normal file
59
demo/server.cpp
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#include <unistd.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ArgvContext.hpp>
|
||||||
|
#include "../husky/Daemon.h"
|
||||||
|
#include "../husky/ServerFrame.h"
|
||||||
|
#include "../cppjieba/MPSegment.h"
|
||||||
|
#include "../cppjieba/HMMSegment.h"
|
||||||
|
#include "../cppjieba/MixSegment.h"
|
||||||
|
|
||||||
|
using namespace Husky;
|
||||||
|
using namespace CppJieba;
|
||||||
|
|
||||||
|
const char * const DEFAULT_DICTPATH = "../dicts/jieba.dict.utf8";
|
||||||
|
const char * const DEFAULT_MODELPATH = "../dicts/hmm_model.utf8";
|
||||||
|
|
||||||
|
class ServerDemo: public IRequestHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ServerDemo(){};
|
||||||
|
virtual ~ServerDemo(){};
|
||||||
|
virtual bool init(){return _segment.init(DEFAULT_DICTPATH, DEFAULT_MODELPATH);};
|
||||||
|
virtual bool dispose(){return _segment.dispose();};
|
||||||
|
public:
|
||||||
|
virtual bool do_GET(const HttpReqInfo& httpReq, string& strSnd)
|
||||||
|
{
|
||||||
|
//HttpReqInfo info = httpReq;
|
||||||
|
strSnd = httpReq.toString();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
MixSegment _segment;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc,char* argv[])
|
||||||
|
{
|
||||||
|
if(argc != 7)
|
||||||
|
{
|
||||||
|
printf("usage: %s -n THREAD_NUMBER -p LISTEN_PORT -k start|stop\n",argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ArgvContext arg(argc, argv);
|
||||||
|
unsigned int port = atoi(arg["-p"].c_str());
|
||||||
|
unsigned int threadNum = atoi(arg["-n"].c_str());
|
||||||
|
|
||||||
|
ServerDemo s;
|
||||||
|
Daemon daemon(&s);
|
||||||
|
if(arg["-k"] == "start")
|
||||||
|
{
|
||||||
|
return !daemon.Start(port, threadNum);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return !daemon.Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
2
demo/start.sh
Executable file
2
demo/start.sh
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
./server.demo -n 4 -p 11258 -k start >> run.log 2>&1 &
|
2
demo/stop.sh
Executable file
2
demo/stop.sh
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
./server.demo -n 4 -p 11258 -k stop
|
196
husky/Daemon.cpp
Normal file
196
husky/Daemon.cpp
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
#include "Daemon.h"
|
||||||
|
|
||||||
|
namespace Husky
|
||||||
|
{
|
||||||
|
|
||||||
|
IRequestHandler * Daemon::m_pHandler;
|
||||||
|
ServerFrame Daemon::m_ServerFrame;
|
||||||
|
int Daemon::m_nChildPid = 0;
|
||||||
|
|
||||||
|
bool Daemon::isAbnormalExit(int pid, int status)
|
||||||
|
{
|
||||||
|
bool bRestart = true;
|
||||||
|
if (WIFEXITED(status)) //exit()or return
|
||||||
|
{
|
||||||
|
LogDebug("child normal termination, exit pid = %d, status = %d", pid, WEXITSTATUS(status));
|
||||||
|
bRestart = false;
|
||||||
|
}
|
||||||
|
else if (WIFSIGNALED(status)) //signal方式退出
|
||||||
|
{
|
||||||
|
LogError("abnormal termination, pid = %d, signal number = %d%s", pid, WTERMSIG(status),
|
||||||
|
#ifdef WCOREDUMP
|
||||||
|
WCOREDUMP(status) ? " (core file generated)" :
|
||||||
|
#endif
|
||||||
|
"");
|
||||||
|
|
||||||
|
if (WTERMSIG(status) == SIGKILL)
|
||||||
|
{
|
||||||
|
bRestart = false;
|
||||||
|
LogError("has been killed by user , exit pid = %d, status = %d", pid, WEXITSTATUS(status));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (WIFSTOPPED(status)) //暂停的子进程退出
|
||||||
|
{
|
||||||
|
LogError("child stopped, pid = %d, signal number = %d", pid, WSTOPSIG(status));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogError("child other reason quit, pid = %d, signal number = %d", pid, WSTOPSIG(status));
|
||||||
|
}
|
||||||
|
return bRestart;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Daemon::Start(unsigned int port, unsigned int threadNum)
|
||||||
|
{
|
||||||
|
string masterPidStr = loadFile2Str(MASTER_PID_FILE);
|
||||||
|
int masterPid = atoi(masterPidStr.c_str());
|
||||||
|
if(masterPid)
|
||||||
|
{
|
||||||
|
if (kill(masterPid, 0) == 0)
|
||||||
|
{
|
||||||
|
LogError("Another instance exist, ready to quit!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initAsDaemon();
|
||||||
|
|
||||||
|
char buf[64];
|
||||||
|
sprintf(buf, "%d", getpid());
|
||||||
|
if (!WriteStr2File(MASTER_PID_FILE,buf ,"w"))
|
||||||
|
{
|
||||||
|
LogFatal("Write master pid fail!");
|
||||||
|
}
|
||||||
|
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
pid_t pid = fork();
|
||||||
|
if (0 == pid)// child process do
|
||||||
|
{
|
||||||
|
signal(SIGUSR1, sigChildHandler);
|
||||||
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
signal(SIGTTOU, SIG_IGN);
|
||||||
|
signal(SIGTTIN, SIG_IGN);
|
||||||
|
signal(SIGTERM, SIG_IGN);
|
||||||
|
signal(SIGINT, SIG_IGN);
|
||||||
|
signal(SIGQUIT, SIG_IGN);
|
||||||
|
|
||||||
|
if(!m_pHandler->init())
|
||||||
|
{
|
||||||
|
LogFatal("m_pHandler init failed!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!m_ServerFrame.CreateServer(port, threadNum, m_pHandler))
|
||||||
|
{
|
||||||
|
LogFatal("m_ServerFrame CreateServer(%d, %d, m_pHandler) fail!", port, threadNum);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
LogDebug("Worker init ok pid = %d",(int)getpid());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!m_ServerFrame.RunServer())
|
||||||
|
{
|
||||||
|
LogError("m_ServerFrame.RunServer finish -fail!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
LogDebug("run finish -ok!");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(!m_pHandler->dispose())
|
||||||
|
{
|
||||||
|
LogError("m_pHandler.dispose -fail!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
LogDebug("Worker dispose -ok!");
|
||||||
|
#endif
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_nChildPid=pid;
|
||||||
|
int status;
|
||||||
|
pid = wait(&status);
|
||||||
|
if (!isAbnormalExit(pid, status))
|
||||||
|
{
|
||||||
|
LogDebug("child exit normally! and Daemon exit");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Daemon::Stop()
|
||||||
|
{
|
||||||
|
string masterPidStr = loadFile2Str(MASTER_PID_FILE);
|
||||||
|
int masterPid = atoi(masterPidStr.c_str());
|
||||||
|
if(masterPid)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
LogDebug("read last masterPid[%d]",masterPid);
|
||||||
|
#endif
|
||||||
|
if (kill(masterPid, 0) == 0)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
LogDebug("find previous daemon pid= %d, current pid= %d", masterPid, getpid());
|
||||||
|
#endif
|
||||||
|
kill(masterPid, SIGTERM);
|
||||||
|
|
||||||
|
int tryTime = 200;
|
||||||
|
while (kill(masterPid, 0) == 0 && --tryTime)
|
||||||
|
{
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tryTime && kill(masterPid, 0) == 0)
|
||||||
|
{
|
||||||
|
LogError("Time out shutdown fail!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogInfo("previous daemon pid[%d] shutdown ok.", masterPid);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
LogError("Another instance doesn't exist, ready to quit!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Daemon::initAsDaemon()
|
||||||
|
{
|
||||||
|
if (fork() > 0)
|
||||||
|
exit(0);
|
||||||
|
setsid();
|
||||||
|
|
||||||
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
signal(SIGTTOU, SIG_IGN);
|
||||||
|
signal(SIGTTIN, SIG_IGN);
|
||||||
|
signal(SIGTERM, sigMasterHandler);
|
||||||
|
signal(SIGINT, sigMasterHandler);
|
||||||
|
signal(SIGQUIT, sigMasterHandler);
|
||||||
|
signal(SIGKILL, sigMasterHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Daemon::sigMasterHandler(int sig)
|
||||||
|
{
|
||||||
|
kill(m_nChildPid,SIGUSR1);
|
||||||
|
LogDebug("master = %d sig child =%d!",getpid(),m_nChildPid);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Daemon::sigChildHandler(int sig)
|
||||||
|
{
|
||||||
|
if (sig == SIGUSR1)
|
||||||
|
{
|
||||||
|
m_ServerFrame.CloseServer();
|
||||||
|
LogDebug("master = %d signal accept current pid =%d!",getppid(),getpid());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
40
husky/Daemon.h
Normal file
40
husky/Daemon.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#ifndef HUSKY_DAEMON_H_
|
||||||
|
#define HUSKY_DAEMON_H_
|
||||||
|
#include "globals.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <logger.hpp>
|
||||||
|
#include "ServerFrame.h"
|
||||||
|
|
||||||
|
namespace Husky
|
||||||
|
{
|
||||||
|
using namespace Limonp;
|
||||||
|
|
||||||
|
class Daemon
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Daemon(IRequestHandler * pHandler)
|
||||||
|
{
|
||||||
|
m_pHandler = pHandler;
|
||||||
|
}
|
||||||
|
~Daemon(){};
|
||||||
|
public:
|
||||||
|
bool Start(unsigned int port, unsigned int threadNum);
|
||||||
|
bool Stop();
|
||||||
|
public:
|
||||||
|
static void initAsDaemon();
|
||||||
|
static void sigMasterHandler(int sig);
|
||||||
|
static void sigChildHandler(int sig);
|
||||||
|
static bool isAbnormalExit(int pid, int status);
|
||||||
|
private:
|
||||||
|
static IRequestHandler* m_pHandler;
|
||||||
|
static ServerFrame m_ServerFrame;
|
||||||
|
static int m_nChildPid;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
172
husky/HttpReqInfo.hpp
Normal file
172
husky/HttpReqInfo.hpp
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
#ifndef HUSKY_HTTP_REQINFO_H
|
||||||
|
#define HUSKY_HTTP_REQINFO_H
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include "globals.h"
|
||||||
|
#include <str_functs.hpp>
|
||||||
|
#include <logger.hpp>
|
||||||
|
#include <map_functs.hpp>
|
||||||
|
|
||||||
|
namespace Husky
|
||||||
|
{
|
||||||
|
using namespace Limonp;
|
||||||
|
|
||||||
|
static const char* const KEY_METHOD = "METHOD";
|
||||||
|
static const char* const KEY_PATH = "PATH";
|
||||||
|
static const char* const KEY_PROTOCOL = "PROTOCOL";
|
||||||
|
|
||||||
|
class HttpReqInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool load(const string& headerStr)
|
||||||
|
{
|
||||||
|
size_t lpos = 0, rpos = 0;
|
||||||
|
vector<string> buf;
|
||||||
|
rpos = headerStr.find("\n", lpos);
|
||||||
|
if(string::npos == rpos)
|
||||||
|
{
|
||||||
|
LogFatal("headerStr illegal.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
string firstline(headerStr, lpos, rpos - lpos);
|
||||||
|
trim(firstline);
|
||||||
|
if(!splitStr(firstline, buf, " ") || 3 != buf.size())
|
||||||
|
{
|
||||||
|
LogFatal("parse header first line failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_headerMap[KEY_METHOD] = trim(buf[0]);
|
||||||
|
_headerMap[KEY_PATH] = trim(buf[1]);
|
||||||
|
_headerMap[KEY_PROTOCOL] = trim(buf[2]);
|
||||||
|
//first request line end
|
||||||
|
//parse path to _methodGetMap
|
||||||
|
if("GET" == _headerMap[KEY_METHOD])
|
||||||
|
{
|
||||||
|
_parseUrl(firstline, _methodGetMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lpos = rpos + 1;
|
||||||
|
if(lpos >= headerStr.size())
|
||||||
|
{
|
||||||
|
LogFatal("headerStr illegal");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//message header begin
|
||||||
|
while(lpos < headerStr.size() && string::npos != (rpos = headerStr.find('\n', lpos)) && rpos > lpos)
|
||||||
|
{
|
||||||
|
string s(headerStr, lpos, rpos - lpos);
|
||||||
|
size_t p = s.find(':');
|
||||||
|
if(string::npos == p)
|
||||||
|
{
|
||||||
|
break;//encounter empty line
|
||||||
|
}
|
||||||
|
string k(s, 0, p);
|
||||||
|
string v(s, p+1);
|
||||||
|
trim(k);
|
||||||
|
trim(v);
|
||||||
|
if(k.empty()||v.empty())
|
||||||
|
{
|
||||||
|
LogFatal("headerStr illegal.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_headerMap[upperStr(k)] = v;
|
||||||
|
lpos = rpos + 1;
|
||||||
|
}
|
||||||
|
//message header end
|
||||||
|
|
||||||
|
//body begin
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
string& operator[] (const string& key)
|
||||||
|
{
|
||||||
|
return _headerMap[key];
|
||||||
|
}
|
||||||
|
bool find(const string& key, string& res)const
|
||||||
|
{
|
||||||
|
return _find(_headerMap, key, res);
|
||||||
|
}
|
||||||
|
bool GET(const string& argKey, string& res)const
|
||||||
|
{
|
||||||
|
return _find(_methodGetMap, argKey, res);
|
||||||
|
}
|
||||||
|
bool POST(const string& argKey, string& res)const
|
||||||
|
{
|
||||||
|
return _find(_methodPostMap, argKey, res);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
HashMap<string, string> _headerMap;
|
||||||
|
HashMap<string, string> _methodGetMap;
|
||||||
|
HashMap<string, string> _methodPostMap;
|
||||||
|
private:
|
||||||
|
bool _find(const HashMap<string, string>& mp, const string& key, string& res)const
|
||||||
|
{
|
||||||
|
HashMap<string, string>::const_iterator it = mp.find(key);
|
||||||
|
if(it == mp.end())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
res = it->second;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
//string toString() const;// function for debug because of heavy time consuming
|
||||||
|
string toString() const
|
||||||
|
{
|
||||||
|
string res("{");
|
||||||
|
res += HashMapToString(_headerMap);
|
||||||
|
res += ",";
|
||||||
|
res += HashMapToString(_methodGetMap);
|
||||||
|
res += ",";
|
||||||
|
res += HashMapToString(_methodPostMap);
|
||||||
|
res += "}";
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
bool _parseUrl(const string& url, HashMap<string, string>& mp)
|
||||||
|
{
|
||||||
|
if(url.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint pos = url.find('?');
|
||||||
|
if(string::npos == pos)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint kleft = 0, kright = 0;
|
||||||
|
uint vleft = 0, vright = 0;
|
||||||
|
for(uint i = pos + 1; i < url.size();)
|
||||||
|
{
|
||||||
|
kleft = i;
|
||||||
|
while(i < url.size() && url[i] != '=')
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if(i >= url.size())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
kright = i;
|
||||||
|
i++;
|
||||||
|
vleft = i;
|
||||||
|
while(i < url.size() && url[i] != '&' && url[i] != ' ')
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
vright = i;
|
||||||
|
mp[url.substr(kleft, kright - kleft)] = url.substr(vleft, vright - vleft);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
42
husky/Makefile
Normal file
42
husky/Makefile
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
CXX := g++
|
||||||
|
LD := g++
|
||||||
|
AR := ar rc
|
||||||
|
|
||||||
|
DEBUG_CXXFLAGS := -g -Wall -DDEBUG
|
||||||
|
RELEASE_CXXFLAGS := -Wall -O3
|
||||||
|
|
||||||
|
ifeq (YES, ${RELEASE})
|
||||||
|
CXXFLAGS := ${RELEASE_CXXFLAGS}
|
||||||
|
LDFLAGS := ${RELEASE_LDFLAGS}
|
||||||
|
else
|
||||||
|
CXXFLAGS := ${DEBUG_CXXFLAGS}
|
||||||
|
LDFLAGS := ${DEBUG_LDFLAGS}
|
||||||
|
endif
|
||||||
|
|
||||||
|
DOLINK := $(LD) $(LDFLAGS) -o $@ $^
|
||||||
|
DOPACK := $(AR)
|
||||||
|
SOURCES = $(wildcard *.cpp)
|
||||||
|
OBJS := $(patsubst %.cpp,%.o,$(SOURCES))
|
||||||
|
|
||||||
|
INC := -I../limonp
|
||||||
|
LIBA := libhusky.a
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
|
||||||
|
all: $(LIBA)
|
||||||
|
|
||||||
|
%.o: %.cpp
|
||||||
|
$(CXX) -c $(CXXFLAGS) $< $(INC)
|
||||||
|
|
||||||
|
${LIBA}: $(OBJS)
|
||||||
|
$(DOPACK) $@ $(OBJS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o *.d *.d.* $(LIBA)
|
||||||
|
|
||||||
|
sinclude $(SOURCES:.cpp=.d)
|
||||||
|
%.d:%.cpp
|
||||||
|
@set -e; rm -f $@; \
|
||||||
|
$(CXX) -MM $< > $@.$$$$; \
|
||||||
|
sed 's,\($*\).o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
|
||||||
|
rm -f $@.$$$$
|
227
husky/ServerFrame.cpp
Normal file
227
husky/ServerFrame.cpp
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
#include "ServerFrame.h"
|
||||||
|
namespace Husky
|
||||||
|
{
|
||||||
|
const struct timeval ServerFrame::m_timev = {SOCKET_TIMEOUT, 0};
|
||||||
|
|
||||||
|
pthread_mutex_t ServerFrame::m_pmAccept;
|
||||||
|
bool ServerFrame::m_bShutdown = false;
|
||||||
|
|
||||||
|
bool ServerFrame::CloseServer()
|
||||||
|
{
|
||||||
|
m_bShutdown=true;
|
||||||
|
if (SOCKET_ERROR==closesocket(m_lsnSock))
|
||||||
|
{
|
||||||
|
LogError("error [%s]", strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int sockfd;
|
||||||
|
struct sockaddr_in dest;
|
||||||
|
|
||||||
|
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
||||||
|
{
|
||||||
|
LogError("error [%s]", strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bzero(&dest, sizeof(dest));
|
||||||
|
dest.sin_family = AF_INET;
|
||||||
|
dest.sin_port = htons(m_nLsnPort);
|
||||||
|
if (inet_aton("127.0.0.1", (struct in_addr *) &dest.sin_addr.s_addr) == 0)
|
||||||
|
{
|
||||||
|
LogError("error [%s]", strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) < 0)
|
||||||
|
{
|
||||||
|
LogError("error [%s]", strerror(errno));
|
||||||
|
}
|
||||||
|
close(sockfd);
|
||||||
|
LogInfo("CloseServer ok.");
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ServerFrame::RunServer()
|
||||||
|
{
|
||||||
|
if(SOCKET_ERROR==listen(m_lsnSock,LISEN_QUEUR_LEN))
|
||||||
|
{
|
||||||
|
LogError("error [%s]", strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ThreadManager thrMngr;
|
||||||
|
int i;
|
||||||
|
SPara para;
|
||||||
|
para.hSock=m_lsnSock;
|
||||||
|
para.pHandler=m_pHandler;
|
||||||
|
for (i=0;i<m_nThreadCount;i++)
|
||||||
|
{
|
||||||
|
if (0!=thrMngr.CreateThread(ServerThread, ¶))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LogDebug("expect thread count %d, real count %d",m_nThreadCount,i);
|
||||||
|
if(i==0)
|
||||||
|
{
|
||||||
|
LogError("error [%s]", strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogInfo("server start to run.........");
|
||||||
|
|
||||||
|
if (thrMngr.WaitMultipleThread()!=0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void* ServerFrame::ServerThread(void *lpParameter )
|
||||||
|
{
|
||||||
|
SPara *pPara=(SPara*)lpParameter;
|
||||||
|
SOCKET hSockLsn=pPara->hSock;
|
||||||
|
IRequestHandler *pHandler=pPara->pHandler;
|
||||||
|
int nRetCode;
|
||||||
|
linger lng;
|
||||||
|
char chRecvBuf[RECV_BUFFER];
|
||||||
|
|
||||||
|
SOCKET hClientSock;
|
||||||
|
string strHttpResp;
|
||||||
|
|
||||||
|
sockaddr_in clientaddr;
|
||||||
|
socklen_t nSize = sizeof(clientaddr);
|
||||||
|
while(!m_bShutdown)
|
||||||
|
{
|
||||||
|
HttpReqInfo httpReq;
|
||||||
|
pthread_mutex_lock(&m_pmAccept);
|
||||||
|
hClientSock=accept(hSockLsn,(sockaddr *)&clientaddr, &nSize);
|
||||||
|
pthread_mutex_unlock(&m_pmAccept);
|
||||||
|
|
||||||
|
if(hClientSock==SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
if(!m_bShutdown)
|
||||||
|
LogError("error [%s]", strerror(errno));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
httpReq[CLIENT_IP_K] = inet_ntoa(clientaddr.sin_addr);// inet_ntoa is not thread safety at some version
|
||||||
|
|
||||||
|
lng.l_linger=1;
|
||||||
|
lng.l_onoff=1;
|
||||||
|
if(SOCKET_ERROR==setsockopt(hClientSock,SOL_SOCKET,SO_LINGER,(char*)&lng,sizeof(lng)))
|
||||||
|
{
|
||||||
|
LogError("error [%s]", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(SOCKET_ERROR==setsockopt(hClientSock,SOL_SOCKET,SO_RCVTIMEO,(char*)&m_timev,sizeof(m_timev)))
|
||||||
|
{
|
||||||
|
LogError("error [%s]", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(SOCKET_ERROR==setsockopt(hClientSock,SOL_SOCKET,SO_SNDTIMEO,(char*)&m_timev,sizeof(m_timev)))
|
||||||
|
{
|
||||||
|
LogError("error [%s]", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
string strRec;
|
||||||
|
string strSnd;
|
||||||
|
memset(chRecvBuf,0,sizeof(chRecvBuf));
|
||||||
|
nRetCode = recv(hClientSock, chRecvBuf, RECV_BUFFER, 0);
|
||||||
|
strRec = chRecvBuf;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
LogDebug("response[%s]", strRec.c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(SOCKET_ERROR==nRetCode)
|
||||||
|
{
|
||||||
|
LogError("error [%s]", strerror(errno));
|
||||||
|
closesocket(hClientSock);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(0==nRetCode)
|
||||||
|
{
|
||||||
|
LogDebug("connection has been gracefully closed");
|
||||||
|
closesocket(hClientSock);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
httpReq.load(strRec);
|
||||||
|
|
||||||
|
pHandler->do_GET(httpReq, strSnd);
|
||||||
|
|
||||||
|
char chHttpHeader[2048];
|
||||||
|
|
||||||
|
sprintf(chHttpHeader, RESPONSE_FORMAT, RESPONSE_CHARSET_UTF8, strSnd.length());
|
||||||
|
|
||||||
|
strHttpResp=chHttpHeader;
|
||||||
|
strHttpResp+=strSnd;
|
||||||
|
|
||||||
|
if (SOCKET_ERROR==send(hClientSock,strHttpResp.c_str(),strHttpResp.length(),0))
|
||||||
|
{
|
||||||
|
LogError("error [%s]", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
LogDebug("send response [%s] ", strHttpResp.c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
closesocket(hClientSock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ServerFrame::CreateServer(u_short nPort,u_short nThreadCount,IRequestHandler *pHandler)
|
||||||
|
{
|
||||||
|
m_nLsnPort=nPort;
|
||||||
|
m_nThreadCount=nThreadCount;
|
||||||
|
m_pHandler=pHandler;
|
||||||
|
|
||||||
|
if (!BindToLocalHost(m_lsnSock,m_nLsnPort))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pthread_mutex_init(&m_pmAccept,NULL);
|
||||||
|
LogInfo("CreatServer ok {port:%d, threadNum:%d}", nPort, nThreadCount);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ServerFrame::BindToLocalHost(SOCKET &sock,u_short nPort)
|
||||||
|
{
|
||||||
|
sock=socket(AF_INET,SOCK_STREAM,0);
|
||||||
|
if(INVALID_SOCKET==sock)
|
||||||
|
{
|
||||||
|
LogError("error [%s]", strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ʹµØÖ·ÂíÉÏ¿ÉÒÔÖØÓà */
|
||||||
|
int nRet = 1;
|
||||||
|
if(SOCKET_ERROR==setsockopt(m_lsnSock, SOL_SOCKET, SO_REUSEADDR, (char*)&nRet, sizeof(nRet)))
|
||||||
|
{
|
||||||
|
LogError("error [%s]", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in addrSock;
|
||||||
|
addrSock.sin_family=AF_INET;
|
||||||
|
addrSock.sin_port=htons(nPort);
|
||||||
|
addrSock.sin_addr.s_addr=htonl(INADDR_ANY);
|
||||||
|
int retval;
|
||||||
|
retval=bind(sock,(sockaddr*)&addrSock,sizeof(sockaddr));
|
||||||
|
if(SOCKET_ERROR==retval)
|
||||||
|
{
|
||||||
|
LogError("error [%s]", strerror(errno));
|
||||||
|
closesocket(sock);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
78
husky/ServerFrame.h
Normal file
78
husky/ServerFrame.h
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#ifndef HUSKY_SERVERFRAME_H
|
||||||
|
#define HUSKY_SERVERFRAME_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <vector>
|
||||||
|
#include "globals.h"
|
||||||
|
#include "ThreadManager.hpp"
|
||||||
|
#include "HttpReqInfo.hpp"
|
||||||
|
|
||||||
|
#define INVALID_SOCKET -1
|
||||||
|
#define SOCKET_ERROR -1
|
||||||
|
#define closesocket close
|
||||||
|
#define RECV_BUFFER 10240
|
||||||
|
#define LISEN_QUEUR_LEN 1024
|
||||||
|
|
||||||
|
|
||||||
|
namespace Husky
|
||||||
|
{
|
||||||
|
using namespace Limonp;
|
||||||
|
typedef int SOCKET;
|
||||||
|
|
||||||
|
class IRequestHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~IRequestHandler(){};
|
||||||
|
public:
|
||||||
|
virtual bool init() = 0;
|
||||||
|
virtual bool dispose() = 0;
|
||||||
|
|
||||||
|
virtual bool do_GET(const HttpReqInfo& httpReq, string& res) = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SPara
|
||||||
|
{
|
||||||
|
SOCKET hSock;
|
||||||
|
IRequestHandler * pHandler;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ServerFrame
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ServerFrame(){};
|
||||||
|
~ServerFrame(){pthread_mutex_destroy(&m_pmAccept);};
|
||||||
|
bool CreateServer(u_short nPort,u_short nThreadCount,IRequestHandler *pHandler);
|
||||||
|
bool CloseServer();
|
||||||
|
bool RunServer();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
bool BindToLocalHost(SOCKET &sock,u_short nPort);
|
||||||
|
|
||||||
|
static void * ServerThread(void * lpParameter );
|
||||||
|
|
||||||
|
private:
|
||||||
|
u_short m_nLsnPort;
|
||||||
|
u_short m_nThreadCount;
|
||||||
|
SOCKET m_lsnSock;
|
||||||
|
IRequestHandler *m_pHandler;
|
||||||
|
static bool m_bShutdown;
|
||||||
|
static pthread_mutex_t m_pmAccept;
|
||||||
|
static const struct timeval m_timev;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
98
husky/ThreadManager.hpp
Normal file
98
husky/ThreadManager.hpp
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
#ifndef HUSKY_THREAD_MANAGER_H
|
||||||
|
#define HUSKY_THREAD_MANAGER_H
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#define INFINITE 0
|
||||||
|
|
||||||
|
namespace Husky
|
||||||
|
{
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
class ThreadManager
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef int HANDLE;
|
||||||
|
typedef int DWORD;
|
||||||
|
typedef void *(* PThreadFunc)(void* param);
|
||||||
|
public:
|
||||||
|
ThreadManager(){;}
|
||||||
|
~ThreadManager(){}
|
||||||
|
|
||||||
|
unsigned int HandleCount(){return m_vecHandle.size();}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
m_vecHandle.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE CreateThread( PThreadFunc pFunc,void *pPara)
|
||||||
|
{
|
||||||
|
pthread_t pt;
|
||||||
|
int nErrorCode=pthread_create(&pt,NULL,pFunc,pPara);
|
||||||
|
if(nErrorCode!=0)
|
||||||
|
return nErrorCode;
|
||||||
|
m_vecHandle.push_back(pt); //加入线程列表 为WaitForMultipleObjects准备
|
||||||
|
return nErrorCode;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//hThread (thread handler) : 为0时为默认最后一个加入管理器的线程句柄
|
||||||
|
//dwMilliseconds等待时间 : 单位毫秒,默认值无穷时间
|
||||||
|
//return value : -1句柄无效,其他值 WaitForSingleObject函数的返回值
|
||||||
|
DWORD Wait(HANDLE hThread=0,DWORD dwMilliseconds=INFINITE )
|
||||||
|
{
|
||||||
|
if( hThread==0)//最后一个加入的线程
|
||||||
|
{
|
||||||
|
if(!m_vecHandle.empty())
|
||||||
|
{
|
||||||
|
return pthread_join(m_vecHandle.back(),NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (find(m_vecHandle.begin(),m_vecHandle.end(),hThread)==m_vecHandle.end())//不存在此句柄
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pthread_join(hThread, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//等待所有线程执行完毕
|
||||||
|
//bWaitAll是否所有线程 : 默认值1等待所有线程,0有任何线程结束,此函数返回
|
||||||
|
//dwMilliseconds : 单位毫秒,默认值无穷时间
|
||||||
|
//return value : -1没有任何句柄,其他值 WaitForMultipleObjects函数的返回值
|
||||||
|
DWORD WaitMultipleThread( bool bWaitAll=1,DWORD dwMilliseconds=INFINITE)
|
||||||
|
{
|
||||||
|
if (m_vecHandle.empty())
|
||||||
|
return -1;
|
||||||
|
int nErrorcode;
|
||||||
|
for (uint i=0;i<m_vecHandle.size();++i)
|
||||||
|
{
|
||||||
|
nErrorcode=pthread_join(m_vecHandle[i], NULL);
|
||||||
|
if (nErrorcode!=0)
|
||||||
|
return nErrorcode;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
vector<pthread_t> m_vecHandle;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ThreadManager(const ThreadManager&){;}// copy forbidden
|
||||||
|
void operator=(const ThreadManager &){}// copy forbidden
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
26
husky/globals.h
Normal file
26
husky/globals.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#ifndef HUSKY_GLOBALS_H
|
||||||
|
#define HUSKY_GLOBALS_H
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Husky
|
||||||
|
{
|
||||||
|
|
||||||
|
const char* const MASTER_PID_FILE= "masterDaemon.pid";
|
||||||
|
|
||||||
|
const char* const RESPONSE_CHARSET_UTF8 = "UTF-8";
|
||||||
|
const char* const RESPONSE_CHARSET_GB2312 = "GB2312";
|
||||||
|
const char* const CLIENT_IP_K = "CLIENT_IP";
|
||||||
|
|
||||||
|
const unsigned int SOCKET_TIMEOUT = 2;
|
||||||
|
|
||||||
|
const char* const RESPONSE_FORMAT = "HTTP/1.1 200 OK\r\nConnection: close\r\nServer: FrameServer/1.0.0\r\nContent-Type: text/json; charset=%s\r\nContent-Length: %d\r\n\r\n";
|
||||||
|
typedef unsigned short u_short;
|
||||||
|
typedef unsigned int u_int;
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user