update husky to version v0.2.0

This commit is contained in:
yanyiwu 2015-12-12 19:43:49 +08:00
parent 194550823f
commit 484ce39d36
7 changed files with 197 additions and 211 deletions

View File

@ -1,107 +0,0 @@
#ifndef HUSKY_WORKER_HPP
#define HUSKY_WORKER_HPP
#include "limonp/ThreadPool.hpp"
#include "IRequestHandler.hpp"
#include "NetUtils.hpp"
namespace husky {
const char* const CLIENT_IP_K = "CLIENT_IP";
const size_t RECV_BUFFER_SIZE = 16 * 1024;
const struct linger LNG = {1, 1};
const struct timeval SOCKET_TIMEOUT = {16, 0};
class WorkerThread: public ITask {
public:
WorkerThread(int sockfs, IRequestHandler& reqHandler):
_sockfd(sockfs), _reqHandler(reqHandler) {
}
virtual ~WorkerThread() {
}
public:
void run() {
do {
if(!_setsockopt(_sockfd)) {
LogError("_getsockopt failed.");
break;
}
string strSnd, strRetByHandler;
HttpReqInfo httpReq;
if(!_receive(_sockfd, httpReq)) {
LogError("_receive failed.");
break;
}
if(httpReq.isGET() && !_reqHandler.doGET(httpReq, strRetByHandler)) {
LogError("doGET failed.");
break;
}
if(httpReq.isPOST() && !_reqHandler.doPOST(httpReq, strRetByHandler)) {
LogError("doPOST failed.");
break;
}
strSnd = string_format(HTTP_FORMAT, CHARSET_UTF8, strRetByHandler.length(), strRetByHandler.c_str());
if(!_send(_sockfd, strSnd)) {
LogError("_send failed.");
break;
}
LogInfo("response:%s", strRetByHandler.c_str());
} while(false);
if(-1 == close(_sockfd)) {
LogError(strerror(errno));
}
}
private:
bool _receive(int sockfd, HttpReqInfo& httpInfo) const {
char recvBuf[RECV_BUFFER_SIZE];
int n = 0;
while(!httpInfo.isBodyFinished() && (n = recv(sockfd, recvBuf, RECV_BUFFER_SIZE, 0)) > 0) {
if(!httpInfo.isHeaderFinished()) {
if(!httpInfo.parseHeader(recvBuf, n)) {
LogError("parseHeader failed. ");
return false;
}
continue;
}
httpInfo.appendBody(recvBuf, n);
}
if(n < 0) {
LogError(strerror(errno));
return false;
}
return true;
}
bool _send(int sockfd, const string& strSnd) const {
if(-1 == send(sockfd, strSnd.c_str(), strSnd.length(), 0)) {
LogError(strerror(errno));
return false;
}
return true;
}
bool _setsockopt(int sockfd) const {
if(-1 == setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (const char*)&LNG, sizeof(LNG))) {
LogError(strerror(errno));
return false;
}
if(-1 == setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&SOCKET_TIMEOUT, sizeof(SOCKET_TIMEOUT))) {
LogError(strerror(errno));
return false;
}
if(-1 == setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&SOCKET_TIMEOUT, sizeof(SOCKET_TIMEOUT))) {
LogError(strerror(errno));
return false;
}
return true;
}
private:
int _sockfd;
IRequestHandler& _reqHandler;
};
}
#endif

View File

@ -3,7 +3,7 @@
#include <iostream> #include <iostream>
#include <string> #include <string>
#include "limonp/Logger.hpp" #include "limonp/Logging.hpp"
#include "limonp/StringUtil.hpp" #include "limonp/StringUtil.hpp"
namespace husky { namespace husky {
@ -16,11 +16,11 @@ static const char* const KEY_PROTOCOL = "PROTOCOL";
typedef unsigned char BYTE; typedef unsigned char BYTE;
inline BYTE toHex(BYTE x) { inline BYTE ToHex(BYTE x) {
return x > 9 ? x -10 + 'A': x + '0'; return x > 9 ? x -10 + 'A': x + '0';
} }
inline BYTE fromHex(BYTE x) { inline BYTE FromHex(BYTE x) {
return isdigit(x) ? x-'0' : x-'A'+10; return isdigit(x) ? x-'0' : x-'A'+10;
} }
@ -32,8 +32,8 @@ inline void URLEncode(const string &sIn, string& sOut) {
buf[0] = sIn[ix]; buf[0] = sIn[ix];
} else { } else {
buf[0] = '%'; buf[0] = '%';
buf[1] = toHex( (BYTE)sIn[ix] >> 4 ); buf[1] = ToHex( (BYTE)sIn[ix] >> 4 );
buf[2] = toHex( (BYTE)sIn[ix] % 16); buf[2] = ToHex( (BYTE)sIn[ix] % 16);
} }
sOut += (char *)buf; sOut += (char *)buf;
} }
@ -43,8 +43,8 @@ inline void URLDecode(const string &sIn, string& sOut) {
for( size_t ix = 0; ix < sIn.size(); ix++ ) { for( size_t ix = 0; ix < sIn.size(); ix++ ) {
BYTE ch = 0; BYTE ch = 0;
if(sIn[ix]=='%') { if(sIn[ix]=='%') {
ch = (fromHex(sIn[ix+1])<<4); ch = (FromHex(sIn[ix+1])<<4);
ch |= fromHex(sIn[ix+2]); ch |= FromHex(sIn[ix+2]);
ix += 2; ix += 2;
} else if(sIn[ix] == '+') { } else if(sIn[ix] == '+') {
ch = ' '; ch = ' ';
@ -58,38 +58,38 @@ inline void URLDecode(const string &sIn, string& sOut) {
class HttpReqInfo { class HttpReqInfo {
public: public:
HttpReqInfo() { HttpReqInfo() {
_isHeaderFinished = false; is_header_finished_ = false;
_isBodyFinished = false; is_body_finished_ = false;
_contentLength = 0; content_length_ = 0;
} }
bool parseHeader(const string& buffer) { bool ParseHeader(const string& buffer) {
return parseHeader(buffer.c_str(), buffer.size()); return ParseHeader(buffer.c_str(), buffer.size());
} }
bool parseHeader(const char* buffer, size_t len) { bool ParseHeader(const char* buffer, size_t len) {
string headerStr(buffer, len); string headerStr(buffer, len);
size_t lpos = 0, rpos = 0; size_t lpos = 0, rpos = 0;
vector<string> buf; vector<string> buf;
rpos = headerStr.find("\n", lpos); rpos = headerStr.find("\n", lpos);
if(string::npos == rpos) { if(string::npos == rpos) {
LogError("headerStr[%s] illegal.", headerStr.c_str()); LOG(ERROR) << "headerStr[" << headerStr << "] illegal.";
return false; return false;
} }
string firstline(headerStr, lpos, rpos - lpos); string firstline(headerStr, lpos, rpos - lpos);
trim(firstline); Trim(firstline);
split(firstline, buf, " "); Split(firstline, buf, " ");
if (3 != buf.size()) { if (3 != buf.size()) {
LogError("parse header firstline[%s] failed.", firstline.c_str()); LOG(ERROR) << "parse header firstline [" << firstline << "] failed.";
return false; return false;
} }
_headerMap[KEY_METHOD] = trim(buf[0]); header_map_[KEY_METHOD] = Trim(buf[0]);
_headerMap[KEY_URI] = trim(buf[1]); header_map_[KEY_URI] = Trim(buf[1]);
_headerMap[KEY_PROTOCOL] = trim(buf[2]); header_map_[KEY_PROTOCOL] = Trim(buf[2]);
_parseUri(_headerMap[KEY_URI], _path, _methodGetMap); ParseUri(header_map_[KEY_URI], path_, method_get_map_);
lpos = rpos + 1; lpos = rpos + 1;
if(lpos >= headerStr.size()) { if(lpos >= headerStr.size()) {
LogError("headerStr[%s] illegal.", headerStr.c_str()); LOG(ERROR) << "headerStr[" << headerStr << "] illegal.";
return false; return false;
} }
//message header begin //message header begin
@ -101,57 +101,57 @@ class HttpReqInfo {
} }
string k(s, 0, p); string k(s, 0, p);
string v(s, p+1); string v(s, p+1);
trim(k); Trim(k);
trim(v); Trim(v);
if(k.empty()||v.empty()) { if(k.empty()||v.empty()) {
LogError("headerStr[%s] illegal.", headerStr.c_str()); LOG(ERROR) << "headerStr[" << headerStr << "] illegal.";
return false; return false;
} }
upper(k); Upper(k);
_headerMap[k] = v; header_map_[k] = v;
lpos = rpos + 1; lpos = rpos + 1;
} }
rpos ++; rpos ++;
_isHeaderFinished = true; is_header_finished_ = true;
string content_length; string content_length;
if(!find("CONTENT-LENGTH", content_length)) { if(!Find("CONTENT-LENGTH", content_length) || 0 == (content_length_ = atoi(content_length.c_str()))) {
_isBodyFinished = true; is_body_finished_ = true;
return true; return true;
} }
_contentLength = atoi(content_length.c_str()); content_length_ = atoi(content_length.c_str());
if(rpos < headerStr.size()) { if(rpos < headerStr.size()) {
appendBody(headerStr.c_str() + rpos, headerStr.size() - rpos); AppendBody(headerStr.c_str() + rpos, headerStr.size() - rpos);
} }
return true; return true;
//message header end //message header end
} }
void appendBody(const char* buffer, size_t len) { void AppendBody(const char* buffer, size_t len) {
if(_isBodyFinished) { if(is_body_finished_) {
return; return;
} }
_body.append(buffer, len); body_.append(buffer, len);
if(_body.size() >= _contentLength) { if(body_.size() >= content_length_) {
_isBodyFinished = true; is_body_finished_ = true;
} else { } else {
_isBodyFinished = false; is_body_finished_ = false;
} }
} }
bool isHeaderFinished() const { bool IsHeaderFinished() const {
return _isHeaderFinished; return is_header_finished_;
} }
bool isBodyFinished() const { bool IsBodyFinished() const {
return _isBodyFinished; return is_body_finished_;
} }
const string& set(const string& key, const string& value) { const string& Set(const string& key, const string& value) {
return _headerMap[key] = value; return header_map_[key] = value;
} }
bool find(const string& key, string& res)const { bool Find(const string& key, string& res)const {
return _find(_headerMap, key, res); return Find(header_map_, key, res);
} }
bool GET(const string& argKey, string& res)const { bool GET(const string& argKey, string& res)const {
string tmp; string tmp;
if (!_find(_methodGetMap, argKey, tmp)) { if (!Find(method_get_map_, argKey, tmp)) {
return false; return false;
} }
URLDecode(tmp, res); URLDecode(tmp, res);
@ -174,47 +174,44 @@ class HttpReqInfo {
return true; return true;
} }
//const string& getMethod() const bool IsGET() const {
//{
// return _headerMap.find(KEY_METHOD)->second;
//}
bool isGET() const {
string str; string str;
if(!_find(_headerMap, KEY_METHOD, str)) { if(!Find(header_map_, KEY_METHOD, str)) {
return false; return false;
} }
return str == "GET"; return str == "GET";
} }
bool isPOST() const { bool IsPOST() const {
string str; string str;
if(!_find(_headerMap, KEY_METHOD, str)) { if(!Find(header_map_, KEY_METHOD, str)) {
return false; return false;
} }
return str == "POST"; return str == "POST";
} }
const unordered_map<string, string> & getMethodGetMap() const { const unordered_map<string, string> & GetMethodGetMap() const {
return _methodGetMap; return method_get_map_;
} }
const unordered_map<string, string> & getHeaders() const { const unordered_map<string, string> & GetHeaders() const {
return _headerMap; return header_map_;
} }
const string& getBody() const { const string& GetBody() const {
return _body; return body_;
} }
const string& getPath() const { const string& GetPath() const {
return _path; return path_;
} }
private: private:
bool _isHeaderFinished; bool is_header_finished_;
bool _isBodyFinished; bool is_body_finished_;
size_t _contentLength; size_t content_length_;
unordered_map<string, string> _headerMap; unordered_map<string, string> header_map_;
unordered_map<string, string> _methodGetMap; unordered_map<string, string> method_get_map_;
string _path; string path_;
string _body; string body_;
friend ostream& operator<<(ostream& os, const HttpReqInfo& obj); friend ostream& operator<<(ostream& os, const HttpReqInfo& obj);
bool _find(const std::unordered_map<string, string>& mp, const string& key, string& res)const { bool Find(const std::unordered_map<string, string>& mp, const string& key, string& res)const {
std::unordered_map<string, string>::const_iterator it = mp.find(key); std::unordered_map<string, string>::const_iterator it = mp.find(key);
if(it == mp.end()) { if(it == mp.end()) {
return false; return false;
@ -223,7 +220,7 @@ class HttpReqInfo {
return true; return true;
} }
void _parseUri(const string& uri, string& path, std::unordered_map<string, string>& mp) { void ParseUri(const string& uri, string& path, std::unordered_map<string, string>& mp) {
if(uri.empty()) { if(uri.empty()) {
return; return;
} }
@ -259,7 +256,7 @@ class HttpReqInfo {
}; };
inline std::ostream& operator << (std::ostream& os, const husky::HttpReqInfo& obj) { inline std::ostream& operator << (std::ostream& os, const husky::HttpReqInfo& obj) {
return os << obj._headerMap << obj._methodGetMap/* << obj._methodPostMap*/ << obj._path << obj._body ; return os << obj.header_map_ << obj.method_get_map_/* << obj._methodPostMap*/ << obj.path_ << obj.body_ ;
} }
} }

View File

@ -1,7 +1,7 @@
#ifndef HUSKY_IREQUESTHANDLER_HPP #ifndef HUSKY_IREQUESTHANDLER_HPP
#define HUSKY_IREQUESTHANDLER_HPP #define HUSKY_IREQUESTHANDLER_HPP
#include "HttpReqInfo.hpp" #include "http_req_info.h"
namespace husky { namespace husky {
class IRequestHandler { class IRequestHandler {
@ -9,8 +9,8 @@ class IRequestHandler {
virtual ~IRequestHandler() { virtual ~IRequestHandler() {
} }
virtual bool doGET(const HttpReqInfo& httpReq, string& res) = 0; virtual bool DoGET(const HttpReqInfo& httpReq, string& res) = 0;
virtual bool doPOST(const HttpReqInfo& httpReq, string& res) = 0; virtual bool DoPOST(const HttpReqInfo& httpReq, string& res) = 0;
}; };
} }

View File

@ -16,34 +16,25 @@
#include <vector> #include <vector>
#include "limonp/StdExtension.hpp" #include "limonp/StdExtension.hpp"
#include "limonp/Logger.hpp" #include "limonp/Logging.hpp"
namespace husky { namespace husky {
static const size_t LISTEN_QUEUE_LEN = 1024; static const size_t LISTEN_QUEUE_LEN = 1024;
typedef int SocketFd; typedef int SocketFd;
inline SocketFd CreateAndListenSocket(int port) { inline SocketFd CreateAndListenSocket(int port) {
SocketFd sock; SocketFd sock = socket(AF_INET, SOCK_STREAM, 0);
sock = socket(AF_INET, SOCK_STREAM, 0); CHECK(sock != -1);
if (sock == -1) {
LogFatal("create socket failed");
}
int optval = 1; // nozero int optval = 1; // nozero
if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))) { CHECK(-1 != setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
LogFatal("setsockopt failed");
}
struct sockaddr_in addr; struct sockaddr_in addr;
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
addr.sin_port = htons(port); addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (-1 == ::bind(sock, (sockaddr*)&addr, sizeof(addr))) { CHECK(-1 != ::bind(sock, (sockaddr*)&addr, sizeof(addr)));
LogFatal(strerror(errno)); CHECK(-1 != ::listen(sock, LISTEN_QUEUE_LEN));
}
if (-1 == ::listen(sock, LISTEN_QUEUE_LEN)) {
LogFatal(strerror(errno));
}
return sock; return sock;
} }

View File

@ -1,8 +1,8 @@
#ifndef HUSKY_THREADPOOLSERVER_H #ifndef HUSKY_THREADPOOLSERVER_H
#define HUSKY_THREADPOOLSERVER_H #define HUSKY_THREADPOOLSERVER_H
#include "NetUtils.hpp" #include "net_util.h"
#include "WorkerThread.hpp" #include "worker_thread.h"
namespace husky { namespace husky {
using namespace limonp; using namespace limonp;
@ -10,31 +10,31 @@ using namespace limonp;
class ThreadPoolServer { class ThreadPoolServer {
public: public:
ThreadPoolServer(size_t thread_number, size_t queue_max_size, size_t port, IRequestHandler & handler): ThreadPoolServer(size_t thread_number, size_t queue_max_size, size_t port, IRequestHandler & handler):
_pool(thread_number, queue_max_size), _reqHandler(handler), _host_socket(-1) { pool_(thread_number, queue_max_size), req_handler_(handler), host_socket_(-1) {
_host_socket = CreateAndListenSocket(port); host_socket_ = CreateAndListenSocket(port);
} }
~ThreadPoolServer() {}; ~ThreadPoolServer() {};
bool start() { bool Start() {
_pool.start(); pool_.Start();
sockaddr_in clientaddr; sockaddr_in clientaddr;
socklen_t nSize = sizeof(clientaddr); socklen_t nSize = sizeof(clientaddr);
int clientSock; int clientSock;
while(true) { while(true) {
if(-1 == (clientSock = accept(_host_socket, (struct sockaddr*) &clientaddr, &nSize))) { if(-1 == (clientSock = accept(host_socket_, (struct sockaddr*) &clientaddr, &nSize))) {
LogError(strerror(errno)); LOG(ERROR) << strerror(errno);
break; break;
} }
_pool.add(CreateTask<WorkerThread,int, IRequestHandler&>(clientSock, _reqHandler)); pool_.Add(CreateTask<WorkerThread,int, IRequestHandler&>(clientSock, req_handler_));
} }
return true; return true;
} }
private: private:
ThreadPool _pool; ThreadPool pool_;
IRequestHandler & _reqHandler; IRequestHandler & req_handler_;
int _host_socket; int host_socket_;
}; // class ThreadPoolServer }; // class ThreadPoolServer
} // namespace husky } // namespace husky

View File

@ -0,0 +1,105 @@
#ifndef HUSKY_WORKER_HPP
#define HUSKY_WORKER_HPP
#include "limonp/ThreadPool.hpp"
#include "irequest_handler.h"
#include "net_util.h"
namespace husky {
const char* const CLIENT_IP_K = "CLIENT_IP";
const size_t RECV_BUFFER_SIZE = 16 * 1024;
const struct linger LNG = {1, 1};
const struct timeval SOCKET_TIMEOUT = {16, 0};
class WorkerThread: public ITask {
public:
WorkerThread(int sockfs, IRequestHandler& reqHandler):
sockfd_(sockfs), req_handler_(reqHandler) {
}
virtual ~WorkerThread() {
}
virtual void Run() {
do {
if(!SetSockopt(sockfd_)) {
LOG(ERROR) << "_getsockopt failed.";
break;
}
string strSnd, strRetByHandler;
HttpReqInfo httpReq;
if(!Receive(sockfd_, httpReq)) {
LOG(ERROR) << "Receive failed.";
break;
}
if(httpReq.IsGET() && !req_handler_.DoGET(httpReq, strRetByHandler)) {
LOG(ERROR) << "DoGET failed.";
break;
}
if(httpReq.IsPOST() && !req_handler_.DoPOST(httpReq, strRetByHandler)) {
LOG(ERROR) << "DoPOST failed.";
break;
}
strSnd = StringFormat(HTTP_FORMAT, CHARSET_UTF8, strRetByHandler.length(), strRetByHandler.c_str());
if(!Send(sockfd_, strSnd)) {
LOG(ERROR) << "Send failed.";
break;
}
} while(false);
if(-1 == close(sockfd_)) {
LOG(ERROR) << strerror(errno);
}
}
private:
bool Receive(int sockfd, HttpReqInfo& httpInfo) const {
char recvBuf[RECV_BUFFER_SIZE];
int n = 0;
while(!httpInfo.IsBodyFinished() && (n = recv(sockfd, recvBuf, RECV_BUFFER_SIZE, 0)) > 0) {
if(!httpInfo.IsHeaderFinished()) {
if(!httpInfo.ParseHeader(recvBuf, n)) {
LOG(ERROR) << "ParseHeader failed. ";
return false;
}
continue;
}
httpInfo.AppendBody(recvBuf, n);
}
if(n < 0) {
LOG(ERROR) << strerror(errno);
return false;
}
return true;
}
bool Send(int sockfd, const string& strSnd) const {
if(-1 == send(sockfd, strSnd.c_str(), strSnd.length(), 0)) {
LOG(ERROR) << strerror(errno);
return false;
}
return true;
}
bool SetSockopt(int sockfd) const {
if(-1 == setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (const char*)&LNG, sizeof(LNG))) {
LOG(ERROR) << strerror(errno);
return false;
}
if(-1 == setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&SOCKET_TIMEOUT, sizeof(SOCKET_TIMEOUT))) {
LOG(ERROR) << strerror(errno);
return false;
}
if(-1 == setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&SOCKET_TIMEOUT, sizeof(SOCKET_TIMEOUT))) {
LOG(ERROR) << strerror(errno);
return false;
}
return true;
}
int sockfd_;
IRequestHandler& req_handler_;
};
}
#endif

View File

@ -4,7 +4,7 @@
#include <ctype.h> #include <ctype.h>
#include <string.h> #include <string.h>
#include "limonp/Config.hpp" #include "limonp/Config.hpp"
#include "husky/ThreadPoolServer.hpp" #include "husky/thread_pool_server.h"
#include "Jieba.hpp" #include "Jieba.hpp"
using namespace husky; using namespace husky;