mirror of
https://github.com/yanyiwu/cppjieba.git
synced 2025-07-18 00:00:12 +08:00
update husky for server
This commit is contained in:
parent
660cd9d93e
commit
00f738a617
@ -6,288 +6,238 @@
|
||||
#include "Limonp/Logger.hpp"
|
||||
#include "Limonp/StringUtil.hpp"
|
||||
|
||||
namespace Husky
|
||||
{
|
||||
using namespace Limonp;
|
||||
using namespace std;
|
||||
namespace Husky {
|
||||
using namespace Limonp;
|
||||
using namespace std;
|
||||
|
||||
static const char* const KEY_METHOD = "METHOD";
|
||||
static const char* const KEY_PATH = "PATH";
|
||||
static const char* const KEY_PROTOCOL = "PROTOCOL";
|
||||
static const char* const KEY_METHOD = "METHOD";
|
||||
static const char* const KEY_URI = "URI";
|
||||
static const char* const KEY_PROTOCOL = "PROTOCOL";
|
||||
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned char BYTE;
|
||||
|
||||
inline BYTE toHex(BYTE x)
|
||||
{
|
||||
return x > 9 ? x -10 + 'A': x + '0';
|
||||
inline BYTE toHex(BYTE x) {
|
||||
return x > 9 ? x -10 + 'A': x + '0';
|
||||
}
|
||||
|
||||
inline BYTE fromHex(BYTE x) {
|
||||
return isdigit(x) ? x-'0' : x-'A'+10;
|
||||
}
|
||||
|
||||
inline void URLEncode(const string &sIn, string& sOut) {
|
||||
for( size_t ix = 0; ix < sIn.size(); ix++ ) {
|
||||
BYTE buf[4];
|
||||
memset( buf, 0, 4 );
|
||||
if( isalnum( (BYTE)sIn[ix] ) ) {
|
||||
buf[0] = sIn[ix];
|
||||
} else {
|
||||
buf[0] = '%';
|
||||
buf[1] = toHex( (BYTE)sIn[ix] >> 4 );
|
||||
buf[2] = toHex( (BYTE)sIn[ix] % 16);
|
||||
}
|
||||
sOut += (char *)buf;
|
||||
}
|
||||
};
|
||||
|
||||
inline void URLDecode(const string &sIn, string& sOut) {
|
||||
for( size_t ix = 0; ix < sIn.size(); ix++ ) {
|
||||
BYTE ch = 0;
|
||||
if(sIn[ix]=='%') {
|
||||
ch = (fromHex(sIn[ix+1])<<4);
|
||||
ch |= fromHex(sIn[ix+2]);
|
||||
ix += 2;
|
||||
} else if(sIn[ix] == '+') {
|
||||
ch = ' ';
|
||||
} else {
|
||||
ch = sIn[ix];
|
||||
}
|
||||
sOut += (char)ch;
|
||||
}
|
||||
}
|
||||
|
||||
class HttpReqInfo {
|
||||
public:
|
||||
HttpReqInfo() {
|
||||
_isHeaderFinished = false;
|
||||
_isBodyFinished = false;
|
||||
_contentLength = 0;
|
||||
}
|
||||
public:
|
||||
bool parseHeader(const string& buffer) {
|
||||
return parseHeader(buffer.c_str(), buffer.size());
|
||||
}
|
||||
bool parseHeader(const char* buffer, size_t len) {
|
||||
string headerStr(buffer, len);
|
||||
size_t lpos = 0, rpos = 0;
|
||||
vector<string> buf;
|
||||
rpos = headerStr.find("\n", lpos);
|
||||
if(string::npos == rpos) {
|
||||
LogError("headerStr[%s] illegal.", headerStr.c_str());
|
||||
return false;
|
||||
}
|
||||
string firstline(headerStr, lpos, rpos - lpos);
|
||||
trim(firstline);
|
||||
if(!split(firstline, buf, " ") || 3 != buf.size()) {
|
||||
LogError("parse header firstline[%s] failed.", firstline.c_str());
|
||||
return false;
|
||||
}
|
||||
_headerMap[KEY_METHOD] = trim(buf[0]);
|
||||
_headerMap[KEY_URI] = trim(buf[1]);
|
||||
_headerMap[KEY_PROTOCOL] = trim(buf[2]);
|
||||
_parseUri(_headerMap[KEY_URI], _path, _methodGetMap);
|
||||
|
||||
lpos = rpos + 1;
|
||||
if(lpos >= headerStr.size()) {
|
||||
LogError("headerStr[%s] illegal.", headerStr.c_str());
|
||||
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()) {
|
||||
LogError("headerStr[%s] illegal.", headerStr.c_str());
|
||||
return false;
|
||||
}
|
||||
upper(k);
|
||||
_headerMap[k] = v;
|
||||
lpos = rpos + 1;
|
||||
}
|
||||
rpos ++;
|
||||
_isHeaderFinished = true;
|
||||
string content_length;
|
||||
if(!find("CONTENT-LENGTH", content_length)) {
|
||||
_isBodyFinished = true;
|
||||
return true;
|
||||
}
|
||||
_contentLength = atoi(content_length.c_str());
|
||||
if(rpos < headerStr.size()) {
|
||||
appendBody(headerStr.c_str() + rpos, headerStr.size() - rpos);
|
||||
}
|
||||
return true;
|
||||
//message header end
|
||||
}
|
||||
void appendBody(const char* buffer, size_t len) {
|
||||
if(_isBodyFinished) {
|
||||
return;
|
||||
}
|
||||
_body.append(buffer, len);
|
||||
if(_body.size() >= _contentLength) {
|
||||
_isBodyFinished = true;
|
||||
} else {
|
||||
_isBodyFinished = false;
|
||||
}
|
||||
}
|
||||
bool isHeaderFinished() const {
|
||||
return _isHeaderFinished;
|
||||
}
|
||||
bool isBodyFinished() const {
|
||||
return _isBodyFinished;
|
||||
}
|
||||
public:
|
||||
const string& set(const string& key, const string& value) {
|
||||
return _headerMap[key] = value;
|
||||
}
|
||||
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);
|
||||
}
|
||||
//const string& getMethod() const
|
||||
//{
|
||||
// return _headerMap.find(KEY_METHOD)->second;
|
||||
//}
|
||||
bool isGET() const {
|
||||
string str;
|
||||
if(!_find(_headerMap, KEY_METHOD, str)) {
|
||||
return false;
|
||||
}
|
||||
return str == "GET";
|
||||
}
|
||||
bool isPOST() const {
|
||||
string str;
|
||||
if(!_find(_headerMap, KEY_METHOD, str)) {
|
||||
return false;
|
||||
}
|
||||
return str == "POST";
|
||||
}
|
||||
const unordered_map<string, string> & getMethodGetMap() const {
|
||||
return _methodGetMap;
|
||||
}
|
||||
const unordered_map<string, string> & getHeaders() const {
|
||||
return _headerMap;
|
||||
}
|
||||
const string& getBody() const {
|
||||
return _body;
|
||||
}
|
||||
const string& getPath() const {
|
||||
return _path;
|
||||
}
|
||||
private:
|
||||
bool _isHeaderFinished;
|
||||
bool _isBodyFinished;
|
||||
size_t _contentLength;
|
||||
unordered_map<string, string> _headerMap;
|
||||
unordered_map<string, string> _methodGetMap;
|
||||
string _path;
|
||||
string _body;
|
||||
friend ostream& operator<<(ostream& os, const HttpReqInfo& obj);
|
||||
private:
|
||||
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);
|
||||
if(it == mp.end()) {
|
||||
return false;
|
||||
}
|
||||
res = it->second;
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
void _parseUri(const string& uri, string& path, std::unordered_map<string, string>& mp) {
|
||||
if(uri.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
inline BYTE fromHex(BYTE x)
|
||||
{
|
||||
return isdigit(x) ? x-'0' : x-'A'+10;
|
||||
size_t pos = uri.find('?');
|
||||
path = uri.substr(0, pos);
|
||||
if(string::npos == pos) {
|
||||
return ;
|
||||
}
|
||||
size_t kleft = 0, kright = 0;
|
||||
size_t vleft = 0, vright = 0;
|
||||
for(size_t i = pos + 1; i < uri.size();) {
|
||||
kleft = i;
|
||||
while(i < uri.size() && uri[i] != '=') {
|
||||
i++;
|
||||
}
|
||||
if(i >= uri.size()) {
|
||||
break;
|
||||
}
|
||||
kright = i;
|
||||
i++;
|
||||
vleft = i;
|
||||
while(i < uri.size() && uri[i] != '&' && uri[i] != ' ') {
|
||||
i++;
|
||||
}
|
||||
vright = i;
|
||||
mp[uri.substr(kleft, kright - kleft)] = uri.substr(vleft, vright - vleft);
|
||||
i++;
|
||||
}
|
||||
|
||||
inline void URLEncode(const string &sIn, string& sOut)
|
||||
{
|
||||
for( size_t ix = 0; ix < sIn.size(); ix++ )
|
||||
{
|
||||
BYTE buf[4];
|
||||
memset( buf, 0, 4 );
|
||||
if( isalnum( (BYTE)sIn[ix] ) )
|
||||
{
|
||||
buf[0] = sIn[ix];
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[0] = '%';
|
||||
buf[1] = toHex( (BYTE)sIn[ix] >> 4 );
|
||||
buf[2] = toHex( (BYTE)sIn[ix] % 16);
|
||||
}
|
||||
sOut += (char *)buf;
|
||||
}
|
||||
};
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
inline void URLDecode(const string &sIn, string& sOut)
|
||||
{
|
||||
for( size_t ix = 0; ix < sIn.size(); ix++ )
|
||||
{
|
||||
BYTE ch = 0;
|
||||
if(sIn[ix]=='%')
|
||||
{
|
||||
ch = (fromHex(sIn[ix+1])<<4);
|
||||
ch |= fromHex(sIn[ix+2]);
|
||||
ix += 2;
|
||||
}
|
||||
else if(sIn[ix] == '+')
|
||||
{
|
||||
ch = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
ch = sIn[ix];
|
||||
}
|
||||
sOut += (char)ch;
|
||||
}
|
||||
}
|
||||
|
||||
class HttpReqInfo
|
||||
{
|
||||
public:
|
||||
HttpReqInfo()
|
||||
{
|
||||
_isHeaderFinished = false;
|
||||
_isBodyFinished = false;
|
||||
_contentLength = 0;
|
||||
}
|
||||
public:
|
||||
bool parseHeader(const char* buffer, size_t len)
|
||||
{
|
||||
string headerStr(buffer, len);
|
||||
size_t lpos = 0, rpos = 0;
|
||||
vector<string> buf;
|
||||
rpos = headerStr.find("\n", lpos);
|
||||
if(string::npos == rpos)
|
||||
{
|
||||
LogError("headerStr[%s] illegal.", headerStr.c_str());
|
||||
return false;
|
||||
}
|
||||
string firstline(headerStr, lpos, rpos - lpos);
|
||||
trim(firstline);
|
||||
if(!split(firstline, buf, " ") || 3 != buf.size())
|
||||
{
|
||||
LogError("parse header firstline[%s] failed.", firstline.c_str());
|
||||
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())
|
||||
{
|
||||
LogError("headerStr[%s] illegal.", headerStr.c_str());
|
||||
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())
|
||||
{
|
||||
LogError("headerStr[%s] illegal.", headerStr.c_str());
|
||||
return false;
|
||||
}
|
||||
upper(k);
|
||||
_headerMap[k] = v;
|
||||
lpos = rpos + 1;
|
||||
}
|
||||
rpos ++;
|
||||
_isHeaderFinished = true;
|
||||
string content_length;
|
||||
if(!find("CONTENT-LENGTH", content_length))
|
||||
{
|
||||
_isBodyFinished = true;
|
||||
return true;
|
||||
}
|
||||
_contentLength = atoi(content_length.c_str());
|
||||
if(rpos < headerStr.size())
|
||||
{
|
||||
appendBody(headerStr.c_str() + rpos, headerStr.size() - rpos);
|
||||
}
|
||||
return true;
|
||||
//message header end
|
||||
}
|
||||
void appendBody(const char* buffer, size_t len)
|
||||
{
|
||||
if(_isBodyFinished)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_body.append(buffer, len);
|
||||
if(_body.size() >= _contentLength)
|
||||
{
|
||||
_isBodyFinished = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_isBodyFinished = false;
|
||||
}
|
||||
}
|
||||
bool isHeaderFinished() const
|
||||
{
|
||||
return _isHeaderFinished;
|
||||
}
|
||||
bool isBodyFinished() const
|
||||
{
|
||||
return _isBodyFinished;
|
||||
}
|
||||
public:
|
||||
const string& set(const string& key, const string& value)
|
||||
{
|
||||
return _headerMap[key] = value;
|
||||
}
|
||||
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);
|
||||
}
|
||||
//const string& getMethod() const
|
||||
//{
|
||||
// return _headerMap.find(KEY_METHOD)->second;
|
||||
//}
|
||||
bool isGET() const
|
||||
{
|
||||
string str;
|
||||
if(!_find(_headerMap, KEY_METHOD, str))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return str == "GET";
|
||||
}
|
||||
bool isPOST() const
|
||||
{
|
||||
string str;
|
||||
if(!_find(_headerMap, KEY_METHOD, str))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return str == "POST";
|
||||
}
|
||||
const unordered_map<string, string> & getMethodGetMap() const
|
||||
{
|
||||
return _methodGetMap;
|
||||
}
|
||||
const unordered_map<string, string> & getHeaders() const
|
||||
{
|
||||
return _headerMap;
|
||||
}
|
||||
const string& getBody() const
|
||||
{
|
||||
return _body;
|
||||
}
|
||||
private:
|
||||
bool _isHeaderFinished;
|
||||
bool _isBodyFinished;
|
||||
size_t _contentLength;
|
||||
unordered_map<string, string> _headerMap;
|
||||
unordered_map<string, string> _methodGetMap;
|
||||
string _body;
|
||||
friend ostream& operator<<(ostream& os, const HttpReqInfo& obj);
|
||||
private:
|
||||
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);
|
||||
if(it == mp.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
res = it->second;
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
bool _parseUrl(const string& url, std::unordered_map<string, string>& mp)
|
||||
{
|
||||
if(url.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t pos = url.find('?');
|
||||
if(string::npos == pos)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
size_t kleft = 0, kright = 0;
|
||||
size_t vleft = 0, vright = 0;
|
||||
for(size_t 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;
|
||||
}
|
||||
};
|
||||
|
||||
inline std::ostream& operator << (std::ostream& os, const Husky::HttpReqInfo& obj)
|
||||
{
|
||||
return os << obj._headerMap << obj._methodGetMap/* << obj._methodPostMap*/ << obj._body;
|
||||
}
|
||||
inline std::ostream& operator << (std::ostream& os, const Husky::HttpReqInfo& obj) {
|
||||
return os << obj._headerMap << obj._methodGetMap/* << obj._methodPostMap*/ << obj._path << obj._body ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -3,16 +3,14 @@
|
||||
|
||||
#include "HttpReqInfo.hpp"
|
||||
|
||||
namespace Husky
|
||||
{
|
||||
class IRequestHandler
|
||||
{
|
||||
public:
|
||||
virtual ~IRequestHandler(){};
|
||||
public:
|
||||
virtual bool do_GET(const HttpReqInfo& httpReq, string& res) const = 0;
|
||||
virtual bool do_POST(const HttpReqInfo& httpReq, string& res) const = 0;
|
||||
};
|
||||
namespace Husky {
|
||||
class IRequestHandler {
|
||||
public:
|
||||
virtual ~IRequestHandler() {};
|
||||
public:
|
||||
virtual bool do_GET(const HttpReqInfo& httpReq, string& res) const = 0;
|
||||
virtual bool do_POST(const HttpReqInfo& httpReq, string& res) const = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
53
server/Husky/NetUtils.hpp
Normal file
53
server/Husky/NetUtils.hpp
Normal file
@ -0,0 +1,53 @@
|
||||
#ifndef HUSKY_NET_UTILS_HPP
|
||||
#define HUSKY_NET_UTILS_HPP
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <cassert>
|
||||
#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 "Limonp/StdExtension.hpp"
|
||||
#include "Limonp/HandyMacro.hpp"
|
||||
|
||||
namespace Husky {
|
||||
static const size_t LISTEN_QUEUE_LEN = 1024;
|
||||
|
||||
typedef int SocketFd;
|
||||
SocketFd CreateAndListenSocket(int port) {
|
||||
SocketFd sock;
|
||||
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
LIMONP_CHECK(sock != -1);
|
||||
|
||||
int optval = 1; // nozero
|
||||
int ret;
|
||||
ret = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
|
||||
LIMONP_CHECK(-1 != ret);
|
||||
|
||||
struct sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
ret = ::bind(sock, (sockaddr*)&addr, sizeof(addr));
|
||||
LIMONP_CHECK(-1 != ret);
|
||||
|
||||
ret = listen(sock, LISTEN_QUEUE_LEN);
|
||||
LIMONP_CHECK(-1 != ret);
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
const char* const HTTP_FORMAT = "HTTP/1.1 200 OK\r\nConnection: close\r\nServer: HuskyServer/1.0.0\r\nContent-Type: text/json; charset=%s\r\nContent-Length: %d\r\n\r\n%s";
|
||||
const char* const CHARSET_UTF8 = "UTF-8";
|
||||
} // namespace Husky
|
||||
|
||||
|
||||
#endif
|
@ -1,108 +1,39 @@
|
||||
#ifndef HUSKY_EPOLLSERVER_H
|
||||
#define HUSKY_EPOLLSERVER_H
|
||||
#ifndef HUSKY_THREADPOOLSERVER_H
|
||||
#define HUSKY_THREADPOOLSERVER_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <cassert>
|
||||
#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 "NetUtils.hpp"
|
||||
#include "WorkerThread.hpp"
|
||||
|
||||
namespace Husky
|
||||
{
|
||||
using namespace Limonp;
|
||||
namespace Husky {
|
||||
using namespace Limonp;
|
||||
|
||||
class ThreadPoolServer
|
||||
{
|
||||
private:
|
||||
static const size_t LISTEN_QUEUE_LEN = 1024;
|
||||
class ThreadPoolServer {
|
||||
private:
|
||||
ThreadPool _pool;
|
||||
const IRequestHandler & _reqHandler;
|
||||
int _host_socket;
|
||||
public:
|
||||
ThreadPoolServer(size_t thread_number, size_t queue_max_size, size_t port, const IRequestHandler & handler):
|
||||
_pool(thread_number, queue_max_size), _reqHandler(handler), _host_socket(-1) {
|
||||
_host_socket = CreateAndListenSocket(port);
|
||||
}
|
||||
~ThreadPoolServer() {};
|
||||
public:
|
||||
bool start() {
|
||||
_pool.start();
|
||||
sockaddr_in clientaddr;
|
||||
socklen_t nSize = sizeof(clientaddr);
|
||||
int clientSock;
|
||||
|
||||
private:
|
||||
ThreadPool _pool;
|
||||
const IRequestHandler & _reqHandler;
|
||||
int _host_socket;
|
||||
public:
|
||||
ThreadPoolServer(size_t thread_number, size_t queue_max_size, size_t port, const IRequestHandler & handler):
|
||||
_pool(thread_number, queue_max_size), _reqHandler(handler), _host_socket(-1)
|
||||
{
|
||||
_init_host_socket(port);
|
||||
};
|
||||
~ThreadPoolServer(){};
|
||||
public:
|
||||
bool start()
|
||||
{
|
||||
_pool.start();
|
||||
sockaddr_in clientaddr;
|
||||
socklen_t nSize = sizeof(clientaddr);
|
||||
int clientSock;
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(-1 == (clientSock = accept(_host_socket, (struct sockaddr*) &clientaddr, &nSize)))
|
||||
{
|
||||
LogError(strerror(errno));
|
||||
break;
|
||||
//continue;
|
||||
}
|
||||
_pool.add(CreateTask<WorkerThread,int, const IRequestHandler&>(clientSock, _reqHandler));
|
||||
//_response(clientSock);
|
||||
//_closesocket(clientSock);
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
bool _init_host_socket(size_t port)
|
||||
{
|
||||
_host_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(-1 == _host_socket)
|
||||
{
|
||||
LogFatal(strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
int nRet = 1;
|
||||
if(-1 == setsockopt(_host_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&nRet, sizeof(nRet)))
|
||||
{
|
||||
LogFatal(strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sockaddr_in addrSock;
|
||||
addrSock.sin_family = AF_INET;
|
||||
addrSock.sin_port = htons(port);
|
||||
addrSock.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
if(-1 == ::bind(_host_socket, (sockaddr*)&addrSock, sizeof(sockaddr)))
|
||||
{
|
||||
LogFatal(strerror(errno));
|
||||
_closesocket(_host_socket);
|
||||
return false;
|
||||
}
|
||||
if(-1 == listen(_host_socket, LISTEN_QUEUE_LEN))
|
||||
{
|
||||
LogFatal(strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
LogInfo("create socket listening port[%u] init ok", port);
|
||||
return true;
|
||||
}
|
||||
void _closesocket(int sockfd)
|
||||
{
|
||||
if(-1 == close(sockfd))
|
||||
{
|
||||
LogError(strerror(errno));
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
while(true) {
|
||||
if(-1 == (clientSock = accept(_host_socket, (struct sockaddr*) &clientaddr, &nSize))) {
|
||||
LogError(strerror(errno));
|
||||
break;
|
||||
}
|
||||
_pool.add(CreateTask<WorkerThread,int, const IRequestHandler&>(clientSock, _reqHandler));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@ -3,131 +3,106 @@
|
||||
|
||||
#include "Limonp/ThreadPool.hpp"
|
||||
#include "IRequestHandler.hpp"
|
||||
#include "NetUtils.hpp"
|
||||
|
||||
namespace Husky
|
||||
{
|
||||
const char* const HTTP_FORMAT = "HTTP/1.1 200 OK\r\nConnection: close\r\nServer: HuskyServer/1.0.0\r\nContent-Type: text/json; charset=%s\r\nContent-Length: %d\r\n\r\n%s";
|
||||
const char* const CHARSET_UTF8 = "UTF-8";
|
||||
const char* const CLIENT_IP_K = "CLIENT_IP";
|
||||
const size_t RECV_BUFFER_SIZE = 16 * 1024;
|
||||
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};
|
||||
const struct linger LNG = {1, 1};
|
||||
const struct timeval SOCKET_TIMEOUT = {16, 0};
|
||||
|
||||
class WorkerThread: public ITask {
|
||||
public:
|
||||
WorkerThread(int sockfs, const IRequestHandler& reqHandler):
|
||||
_sockfd(sockfs), _reqHandler(reqHandler) {
|
||||
}
|
||||
virtual ~WorkerThread() {
|
||||
}
|
||||
private:
|
||||
int _sockfd;
|
||||
const IRequestHandler& _reqHandler;
|
||||
|
||||
public:
|
||||
void run() {
|
||||
do {
|
||||
if(!_setsockopt(_sockfd)) {
|
||||
LogFatal("_getsockopt failed.");
|
||||
break;
|
||||
}
|
||||
string strSnd, strRetByHandler;
|
||||
HttpReqInfo httpReq;
|
||||
if(!_receive(_sockfd, httpReq)) {
|
||||
LogFatal("_receive failed.");
|
||||
break;
|
||||
}
|
||||
|
||||
if(httpReq.isGET() && !_reqHandler.do_GET(httpReq, strRetByHandler)) {
|
||||
LogError("do_GET failed.");
|
||||
break;
|
||||
}
|
||||
if(httpReq.isPOST() && !_reqHandler.do_POST(httpReq, strRetByHandler)) {
|
||||
LogError("do_POST 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);
|
||||
|
||||
|
||||
class WorkerThread: public ITask
|
||||
{
|
||||
public:
|
||||
WorkerThread(int sockfs, const IRequestHandler& reqHandler):
|
||||
_sockfd(sockfs), _reqHandler(reqHandler)
|
||||
{
|
||||
}
|
||||
virtual ~WorkerThread()
|
||||
{
|
||||
}
|
||||
private:
|
||||
int _sockfd;
|
||||
const IRequestHandler& _reqHandler;
|
||||
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;
|
||||
}
|
||||
|
||||
public:
|
||||
void run()
|
||||
{
|
||||
do
|
||||
{
|
||||
if(!_setsockopt(_sockfd))
|
||||
{
|
||||
LogFatal("_setsockopt failed.");
|
||||
break;
|
||||
}
|
||||
string strSnd, strRetByHandler;
|
||||
HttpReqInfo httpReq;
|
||||
if(!_receive(_sockfd, httpReq))
|
||||
{
|
||||
LogFatal("_receive failed.");
|
||||
break;
|
||||
}
|
||||
|
||||
if(httpReq.isGET() && !_reqHandler.do_GET(httpReq, strRetByHandler))
|
||||
{
|
||||
LogError("do_GET failed.");
|
||||
break;
|
||||
}
|
||||
if(httpReq.isPOST() && !_reqHandler.do_POST(httpReq, strRetByHandler))
|
||||
{
|
||||
LogError("do_POST 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;
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user