mirror of
https://github.com/yanyiwu/cppjieba.git
synced 2025-07-18 00:00:12 +08:00
update limonp and husky for threadpool using
This commit is contained in:
parent
e25828e0a9
commit
fbbcfbdec7
@ -3,6 +3,8 @@
|
||||
#socket listen port
|
||||
port=11200
|
||||
|
||||
thread_number=4
|
||||
queue_max_size=4096
|
||||
|
||||
#dict path
|
||||
dict_path=/usr/share/CppJieba/dict/jieba.dict.utf8
|
||||
|
@ -1,286 +0,0 @@
|
||||
#ifndef HUSKY_EPOLLSERVER_H
|
||||
#define HUSKY_EPOLLSERVER_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 <sys/epoll.h>
|
||||
#include <fcntl.h>
|
||||
#include "HttpReqInfo.hpp"
|
||||
|
||||
|
||||
|
||||
namespace Husky
|
||||
{
|
||||
using namespace Limonp;
|
||||
|
||||
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 struct linger LNG = {1, 1};
|
||||
const struct timeval SOCKET_TIMEOUT = {5, 0};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
class EpollServer: public InitOnOff
|
||||
{
|
||||
private:
|
||||
static const size_t LISTEN_QUEUE_LEN = 1024;
|
||||
static const size_t RECV_BUFFER_SIZE = 1024*4;
|
||||
static const int MAXEPOLLSIZE = 512;
|
||||
|
||||
private:
|
||||
const IRequestHandler & _reqHandler;
|
||||
int _host_socket;
|
||||
int _epoll_fd;
|
||||
int _epollSize;
|
||||
unordered_map<int, string> _sockIpMap;
|
||||
public:
|
||||
explicit EpollServer(size_t port, const IRequestHandler & handler): _reqHandler(handler), _host_socket(-1), _epollSize(0)
|
||||
{
|
||||
_setInitFlag(_init_epoll(port));
|
||||
};
|
||||
~EpollServer(){};
|
||||
public:
|
||||
bool start()
|
||||
{
|
||||
sockaddr_in clientaddr;
|
||||
socklen_t nSize = sizeof(clientaddr);
|
||||
struct epoll_event events[MAXEPOLLSIZE];
|
||||
int nfds, clientSock;
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(-1 == (nfds = epoll_wait(_epoll_fd, events, _epollSize, -1)))
|
||||
{
|
||||
LogFatal(strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
//LogDebug("epoll_wait return event sum[%d]", nfds);
|
||||
|
||||
for(int i = 0; i < nfds; i++)
|
||||
{
|
||||
if(events[i].data.fd == _host_socket) /*new connect coming.*/
|
||||
{
|
||||
if(-1 == (clientSock = accept(_host_socket, (struct sockaddr*) &clientaddr, &nSize)))
|
||||
{
|
||||
LogError(strerror(errno));
|
||||
continue;
|
||||
}
|
||||
if(!_epoll_add(clientSock, EPOLLIN | EPOLLET))
|
||||
{
|
||||
LogError("_epoll_add(%d, EPOLLIN | EPOLLET)", clientSock);
|
||||
_closesocket(clientSock);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* inet_ntoa is not thread safety at some version */
|
||||
//_sockIpMap[clientSock] = inet_ntoa(clientaddr.sin_addr);
|
||||
|
||||
}
|
||||
else /*client socket data to be received*/
|
||||
{
|
||||
_response(events[i].data.fd);
|
||||
|
||||
/*close socket will case it to be removed from epoll automatically*/
|
||||
_closesocket(events[i].data.fd);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
bool _epoll_add(int sockfd, uint32_t events)
|
||||
{
|
||||
if (!_setNonBLock(sockfd))
|
||||
{
|
||||
LogError(strerror(errno));
|
||||
return false;
|
||||
}
|
||||
struct epoll_event ev;
|
||||
ev.data.fd = sockfd;
|
||||
ev.events = events;
|
||||
if(epoll_ctl(_epoll_fd, EPOLL_CTL_ADD, sockfd, &ev) < 0)
|
||||
{
|
||||
LogError("insert socket '%d' into epoll failed: %s", sockfd, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
_epollSize ++;
|
||||
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;
|
||||
}
|
||||
|
||||
bool _receive(int sockfd, string& strRec) const
|
||||
{
|
||||
char recvBuf[RECV_BUFFER_SIZE];
|
||||
int nRetCode = -1;
|
||||
while(true)
|
||||
{
|
||||
memset(recvBuf, 0, sizeof(recvBuf));
|
||||
nRetCode = recv(sockfd, recvBuf, sizeof(recvBuf) - 1, 0);
|
||||
if(-1 == nRetCode)
|
||||
{
|
||||
LogError(strerror(errno));
|
||||
return false;
|
||||
}
|
||||
if(0 == nRetCode)
|
||||
{
|
||||
LogDebug("client socket orderly shut down");
|
||||
return true;
|
||||
}
|
||||
strRec += recvBuf;
|
||||
if(nRetCode != sizeof(recvBuf) - 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
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 _response(int sockfd) const
|
||||
{
|
||||
if(!_setsockopt(sockfd))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
string strRec, strSnd, strRetByHandler;
|
||||
if(!_receive(sockfd, strRec))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
HttpReqInfo httpReq(strRec);
|
||||
if(!httpReq)
|
||||
{
|
||||
LogError("HttpReqInfo invalid.");
|
||||
return false;
|
||||
}
|
||||
if("GET" == httpReq.getMethod() && !_reqHandler.do_GET(httpReq, strRetByHandler))
|
||||
{
|
||||
LogError("do_GET failed.");
|
||||
return false;
|
||||
}
|
||||
if("POST" == httpReq.getMethod() && !_reqHandler.do_POST(httpReq, strRetByHandler))
|
||||
{
|
||||
LogError("do_POST failed.");
|
||||
return false;
|
||||
}
|
||||
string_format(strSnd, HTTP_FORMAT, CHARSET_UTF8, strRetByHandler.length(), strRetByHandler.c_str());
|
||||
|
||||
if(!_send(sockfd, strSnd))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
LogInfo("response:%s", strRetByHandler.c_str());
|
||||
return true;
|
||||
}
|
||||
bool _init_epoll(size_t port)
|
||||
{
|
||||
_host_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if(-1 == _host_socket)
|
||||
{
|
||||
LogError(strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
int nRet = 1;
|
||||
if(-1 == setsockopt(_host_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&nRet, sizeof(nRet)))
|
||||
{
|
||||
LogError(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)))
|
||||
{
|
||||
LogError(strerror(errno));
|
||||
_closesocket(_host_socket);
|
||||
return false;
|
||||
}
|
||||
if(-1 == listen(_host_socket, LISTEN_QUEUE_LEN))
|
||||
{
|
||||
LogError(strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(-1 == (_epoll_fd = epoll_create(MAXEPOLLSIZE)))
|
||||
{
|
||||
LogError(strerror(errno));
|
||||
return false;
|
||||
}
|
||||
if(!_epoll_add(_host_socket, EPOLLIN))
|
||||
{
|
||||
LogError("_epoll_add(%d, EPOLLIN) failed.", _host_socket);
|
||||
return false;
|
||||
}
|
||||
LogInfo("create socket listening port[%u], epoll{size:%d} init ok", port, MAXEPOLLSIZE);
|
||||
return true;
|
||||
}
|
||||
void _closesocket(int sockfd)
|
||||
{
|
||||
if(-1 == close(sockfd))
|
||||
{
|
||||
LogError(strerror(errno));
|
||||
return;
|
||||
}
|
||||
_epollSize--;
|
||||
}
|
||||
static bool _setNonBLock(int sockfd)
|
||||
{
|
||||
return -1 != fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFD, 0)|O_NONBLOCK);
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
@ -5,7 +5,6 @@
|
||||
#include <string>
|
||||
#include "Limonp/Logger.hpp"
|
||||
#include "Limonp/StringUtil.hpp"
|
||||
#include "Limonp/InitOnOff.hpp"
|
||||
|
||||
namespace Husky
|
||||
{
|
||||
@ -71,16 +70,19 @@ namespace Husky
|
||||
}
|
||||
}
|
||||
|
||||
class HttpReqInfo: public InitOnOff
|
||||
class HttpReqInfo
|
||||
{
|
||||
public:
|
||||
HttpReqInfo(const string& headerStr)
|
||||
HttpReqInfo()
|
||||
{
|
||||
_setInitFlag(_init(headerStr));
|
||||
_isHeaderFinished = false;
|
||||
_isBodyFinished = false;
|
||||
_contentLength = 0;
|
||||
}
|
||||
private:
|
||||
bool _init(const string& headerStr)
|
||||
public:
|
||||
bool parseHeaders(const char* buffer, size_t len)
|
||||
{
|
||||
string headerStr(buffer, len);
|
||||
size_t lpos = 0, rpos = 0;
|
||||
vector<string> buf;
|
||||
rpos = headerStr.find("\n", lpos);
|
||||
@ -134,19 +136,47 @@ namespace Husky
|
||||
_headerMap[k] = v;
|
||||
lpos = rpos + 1;
|
||||
}
|
||||
//message header end
|
||||
|
||||
//body begin
|
||||
_body.assign(headerStr.substr(rpos));
|
||||
trim(_body);
|
||||
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:
|
||||
//string& operator[] (const string& key)
|
||||
//{
|
||||
// return _headerMap[key];
|
||||
//}
|
||||
const string& set(const string& key, const string& value)
|
||||
{
|
||||
return _headerMap[key] = value;
|
||||
@ -176,6 +206,9 @@ namespace Husky
|
||||
return _body;
|
||||
}
|
||||
private:
|
||||
bool _isHeaderFinished;
|
||||
bool _isBodyFinished;
|
||||
size_t _contentLength;
|
||||
unordered_map<string, string> _headerMap;
|
||||
unordered_map<string, string> _methodGetMap;
|
||||
string _body;
|
||||
|
18
server/Husky/IRequestHandler.hpp
Normal file
18
server/Husky/IRequestHandler.hpp
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef HUSKY_IREQUESTHANDLER_HPP
|
||||
#define HUSKY_IREQUESTHANDLER_HPP
|
||||
|
||||
#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;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
108
server/Husky/ThreadPoolServer.hpp
Normal file
108
server/Husky/ThreadPoolServer.hpp
Normal file
@ -0,0 +1,108 @@
|
||||
#ifndef HUSKY_EPOLLSERVER_H
|
||||
#define HUSKY_EPOLLSERVER_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 "WorkerThread.hpp"
|
||||
|
||||
namespace Husky
|
||||
{
|
||||
using namespace Limonp;
|
||||
|
||||
class ThreadPoolServer
|
||||
{
|
||||
private:
|
||||
static const size_t LISTEN_QUEUE_LEN = 1024;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
134
server/Husky/WorkerThread.hpp
Normal file
134
server/Husky/WorkerThread.hpp
Normal file
@ -0,0 +1,134 @@
|
||||
#ifndef HUSKY_WORKER_HPP
|
||||
#define HUSKY_WORKER_HPP
|
||||
|
||||
#include "Limonp/ThreadPool.hpp"
|
||||
#include "IRequestHandler.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;
|
||||
|
||||
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("_setsockopt failed.");
|
||||
break;
|
||||
}
|
||||
string strSnd, strRetByHandler;
|
||||
HttpReqInfo httpReq;
|
||||
if(!_receive(_sockfd, httpReq))
|
||||
{
|
||||
LogFatal("_receive failed.");
|
||||
break;
|
||||
}
|
||||
|
||||
if("GET" == httpReq.getMethod() && !_reqHandler.do_GET(httpReq, strRetByHandler))
|
||||
{
|
||||
LogError("do_GET failed.");
|
||||
break;
|
||||
}
|
||||
if("POST" == httpReq.getMethod() && !_reqHandler.do_POST(httpReq, strRetByHandler))
|
||||
{
|
||||
LogError("do_POST failed.");
|
||||
break;
|
||||
}
|
||||
string_format(strSnd, 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;
|
||||
while((n = recv(sockfd, recvBuf, RECV_BUFFER_SIZE, 0)) > 0)
|
||||
{
|
||||
if(!httpInfo.isHeaderFinished())
|
||||
{
|
||||
httpInfo.parseHeaders(recvBuf, n);
|
||||
continue;
|
||||
}
|
||||
httpInfo.appendBody(recvBuf, n);
|
||||
if(!httpInfo.isBodyFinished())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
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
|
@ -4,7 +4,7 @@
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include "Limonp/Config.hpp"
|
||||
#include "Husky/EpollServer.hpp"
|
||||
#include "Husky/ThreadPoolServer.hpp"
|
||||
#include "MPSegment.hpp"
|
||||
#include "HMMSegment.hpp"
|
||||
#include "MixSegment.hpp"
|
||||
@ -55,37 +55,28 @@ bool run(int argc, char** argv)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
size_t port = 0;
|
||||
int port = 0;
|
||||
int threadNumber = 0;
|
||||
int queueMaxSize = 0;
|
||||
string dictPath;
|
||||
string modelPath;
|
||||
string userDictPath;
|
||||
string val;
|
||||
if(!conf.get("port", val))
|
||||
{
|
||||
LogFatal("conf get port failed.");
|
||||
return false;
|
||||
}
|
||||
port = atoi(val.c_str());
|
||||
|
||||
if(!conf.get("dict_path", dictPath))
|
||||
{
|
||||
LogFatal("conf get dict_path failed.");
|
||||
return false;
|
||||
}
|
||||
if(!conf.get("model_path", modelPath))
|
||||
{
|
||||
LogFatal("conf get model_path failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
LIMONP_CHECK(conf.get("port", port));
|
||||
LIMONP_CHECK(conf.get("thread_number", threadNumber));
|
||||
LIMONP_CHECK(conf.get("queue_max_size", queueMaxSize));
|
||||
LIMONP_CHECK(conf.get("dict_path", dictPath));
|
||||
LIMONP_CHECK(conf.get("model_path", modelPath));
|
||||
if(!conf.get("user_dict_path", userDictPath)) //optional
|
||||
{
|
||||
userDictPath = "";
|
||||
}
|
||||
|
||||
LogInfo("config info: %s", conf.getConfigInfo().c_str());
|
||||
|
||||
ReqHandler reqHandler(dictPath, modelPath, userDictPath);
|
||||
EpollServer sf(port, reqHandler);
|
||||
ThreadPoolServer sf(threadNumber, queueMaxSize, port, reqHandler);
|
||||
return sf.start();
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
|
84
src/Limonp/ArgvContext.hpp
Normal file
84
src/Limonp/ArgvContext.hpp
Normal file
@ -0,0 +1,84 @@
|
||||
/************************************
|
||||
* file enc : ascii
|
||||
* author : wuyanyi09@gmail.com
|
||||
************************************/
|
||||
|
||||
#ifndef LIMONP_ARGV_FUNCTS_H
|
||||
#define LIMONP_ARGV_FUNCTS_H
|
||||
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include "StringUtil.hpp"
|
||||
|
||||
namespace Limonp
|
||||
{
|
||||
using namespace std;
|
||||
class ArgvContext
|
||||
{
|
||||
public :
|
||||
ArgvContext(int argc, const char* const * argv)
|
||||
{
|
||||
|
||||
for(int i = 0; i < argc; i++)
|
||||
{
|
||||
if(startsWith(argv[i], "-"))
|
||||
{
|
||||
if(i + 1 < argc && !startsWith(argv[i + 1], "-"))
|
||||
{
|
||||
mpss_[argv[i]] = argv[i+1];
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
sset_.insert(argv[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
args_.push_back(argv[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
~ArgvContext(){};
|
||||
public:
|
||||
friend ostream& operator << (ostream& os, const ArgvContext& args);
|
||||
string operator [](size_t i) const
|
||||
{
|
||||
if(i < args_.size())
|
||||
{
|
||||
return args_[i];
|
||||
}
|
||||
return "";
|
||||
}
|
||||
string operator [](const string& key) const
|
||||
{
|
||||
map<string, string>::const_iterator it = mpss_.find(key);
|
||||
if(it != mpss_.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
public:
|
||||
bool hasKey(const string& key) const
|
||||
{
|
||||
if(mpss_.find(key) != mpss_.end() || sset_.find(key) != sset_.end())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
vector<string> args_;
|
||||
map<string, string> mpss_;
|
||||
set<string> sset_;
|
||||
|
||||
};
|
||||
|
||||
inline ostream& operator << (ostream& os, const ArgvContext& args)
|
||||
{
|
||||
return os<<args.args_<<args.mpss_<<args.sset_;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
128
src/Limonp/BlockingQueue.hpp
Normal file
128
src/Limonp/BlockingQueue.hpp
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
https://github.com/chenshuo/muduo/blob/master/muduo/base/BlockingQueue.h
|
||||
*/
|
||||
|
||||
#ifndef LIMONP_BLOCKINGQUEUE_HPP
|
||||
#define LIMONP_BLOCKINGQUEUE_HPP
|
||||
|
||||
#include <queue>
|
||||
#include "BoundedQueue.hpp"
|
||||
#include "Condition.hpp"
|
||||
|
||||
namespace Limonp
|
||||
{
|
||||
template<class T>
|
||||
class BlockingQueue: NonCopyable
|
||||
{
|
||||
public:
|
||||
BlockingQueue()
|
||||
: mutex_(), notEmpty_(mutex_), queue_()
|
||||
{
|
||||
}
|
||||
|
||||
void push(const T& x)
|
||||
{
|
||||
MutexLockGuard lock(mutex_);
|
||||
queue_.push(x);
|
||||
notEmpty_.notify(); // wait morphing saves us
|
||||
}
|
||||
|
||||
T pop()
|
||||
{
|
||||
MutexLockGuard lock(mutex_);
|
||||
// always use a while-loop, due to spurious wakeup
|
||||
while (queue_.empty())
|
||||
{
|
||||
notEmpty_.wait();
|
||||
}
|
||||
assert(!queue_.empty());
|
||||
T front(queue_.front());
|
||||
queue_.pop();
|
||||
return front;
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
MutexLockGuard lock(mutex_);
|
||||
return queue_.size();
|
||||
}
|
||||
bool empty() const
|
||||
{
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable MutexLock mutex_;
|
||||
Condition notEmpty_;
|
||||
std::queue<T> queue_;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class BoundedBlockingQueue : NonCopyable
|
||||
{
|
||||
public:
|
||||
explicit BoundedBlockingQueue(size_t maxSize)
|
||||
: mutex_(),
|
||||
notEmpty_(mutex_),
|
||||
notFull_(mutex_),
|
||||
queue_(maxSize)
|
||||
{}
|
||||
|
||||
void push(const T& x)
|
||||
{
|
||||
MutexLockGuard lock(mutex_);
|
||||
while (queue_.full())
|
||||
{
|
||||
notFull_.wait();
|
||||
}
|
||||
assert(!queue_.full());
|
||||
queue_.push(x);
|
||||
notEmpty_.notify();
|
||||
}
|
||||
|
||||
T pop()
|
||||
{
|
||||
MutexLockGuard lock(mutex_);
|
||||
while (queue_.empty())
|
||||
{
|
||||
notEmpty_.wait();
|
||||
}
|
||||
assert(!queue_.empty());
|
||||
T res = queue_.pop();
|
||||
notFull_.notify();
|
||||
return res;
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
MutexLockGuard lock(mutex_);
|
||||
return queue_.empty();
|
||||
}
|
||||
|
||||
bool full() const
|
||||
{
|
||||
MutexLockGuard lock(mutex_);
|
||||
return queue_.full();
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
MutexLockGuard lock(mutex_);
|
||||
return queue_.size();
|
||||
}
|
||||
|
||||
size_t capacity() const
|
||||
{
|
||||
return queue_.capacity();
|
||||
}
|
||||
|
||||
private:
|
||||
mutable MutexLock mutex_;
|
||||
Condition notEmpty_;
|
||||
Condition notFull_;
|
||||
BoundedQueue<T> queue_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
73
src/Limonp/BoundedQueue.hpp
Normal file
73
src/Limonp/BoundedQueue.hpp
Normal file
@ -0,0 +1,73 @@
|
||||
#ifndef LIMONP_BOUNDED_QUEUE_HPP
|
||||
#define LIMONP_BOUNDED_QUEUE_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <cassert>
|
||||
|
||||
namespace Limonp
|
||||
{
|
||||
using namespace std;
|
||||
template<class T>
|
||||
class BoundedQueue
|
||||
{
|
||||
private:
|
||||
size_t head_;
|
||||
size_t tail_;
|
||||
size_t size_;
|
||||
const size_t capacity_;
|
||||
vector<T> circular__buffer;
|
||||
public:
|
||||
explicit BoundedQueue(size_t capacity): capacity_(capacity), circular__buffer(capacity)
|
||||
{
|
||||
head_ = 0;
|
||||
tail_ = 0;
|
||||
size_ = 0;
|
||||
assert(capacity_);
|
||||
}
|
||||
~BoundedQueue(){}
|
||||
public:
|
||||
void clear()
|
||||
{
|
||||
head_ = 0;
|
||||
tail_ = 0;
|
||||
size_ = 0;
|
||||
}
|
||||
bool empty() const
|
||||
{
|
||||
return !size_;
|
||||
}
|
||||
bool full() const
|
||||
{
|
||||
return capacity_ == size_;
|
||||
}
|
||||
size_t size() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
size_t capacity() const
|
||||
{
|
||||
return capacity_;
|
||||
}
|
||||
|
||||
void push(const T& t)
|
||||
{
|
||||
assert(!full());
|
||||
circular__buffer[tail_] = t;
|
||||
tail_ = (tail_ + 1) % capacity_;
|
||||
size_ ++;
|
||||
}
|
||||
|
||||
T pop()
|
||||
{
|
||||
assert(!empty());
|
||||
size_t oldPos = head_;
|
||||
head_ = (head_ + 1) % capacity_;
|
||||
size_ --;
|
||||
return circular__buffer[oldPos];
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
90
src/Limonp/CastFloat.hpp
Normal file
90
src/Limonp/CastFloat.hpp
Normal file
@ -0,0 +1,90 @@
|
||||
#ifndef LIMONP_CAST_FUNCTS_H
|
||||
#define LIMONP_CAST_FUNCTS_H
|
||||
|
||||
namespace Limonp
|
||||
{
|
||||
namespace CastFloat
|
||||
{
|
||||
//logical and or
|
||||
static const int sign_32 = 0xC0000000;
|
||||
static const int exponent_32 = 0x07800000;
|
||||
static const int mantissa_32 = 0x007FE000;
|
||||
static const int sign_exponent_32 = 0x40000000;
|
||||
static const int loss_32 = 0x38000000;
|
||||
|
||||
static const short sign_16 = (short)0xC000;
|
||||
static const short exponent_16 = (short)0x3C00;
|
||||
static const short mantissa_16 = (short)0x03FF;
|
||||
static const short sign_exponent_16 = (short)0x4000;
|
||||
static const int exponent_fill_32 = 0x38000000;
|
||||
|
||||
//infinite
|
||||
static const short infinite_16 = (short) 0x7FFF;
|
||||
static const short infinitesmall_16 = (short) 0x0000;
|
||||
|
||||
inline float intBitsToFloat(unsigned int x)
|
||||
{
|
||||
union
|
||||
{
|
||||
float f;
|
||||
int i;
|
||||
}u;
|
||||
u.i = x;
|
||||
return u.f;
|
||||
}
|
||||
|
||||
inline int floatToIntBits(float f)
|
||||
{
|
||||
union
|
||||
{
|
||||
float f;
|
||||
int i ;
|
||||
}u;
|
||||
u.f = f;
|
||||
return u.i;
|
||||
}
|
||||
|
||||
inline short floatToShortBits(float f)
|
||||
{
|
||||
int fi = floatToIntBits(f);
|
||||
|
||||
// 提取关键信息
|
||||
short sign = (short) ((unsigned int)(fi & sign_32) >> 16);
|
||||
short exponent = (short) ((unsigned int)(fi & exponent_32) >> 13);
|
||||
short mantissa = (short) ((unsigned int)(fi & mantissa_32) >> 13);
|
||||
// 生成编码结果
|
||||
short code = (short) (sign | exponent | mantissa);
|
||||
// 无穷大量、无穷小量的处理
|
||||
if ((fi & loss_32) > 0 && (fi & sign_exponent_32) > 0) {
|
||||
// 当指数符号为1时(正次方),且左234位为1,返回无穷大量
|
||||
return (short) (code | infinite_16);
|
||||
}
|
||||
if (((fi & loss_32) ^ loss_32) > 0 && (fi & sign_exponent_32) == 0) {
|
||||
// 当指数符号位0时(负次方),且左234位为0(与111异或>0),返回无穷小量
|
||||
return infinitesmall_16;
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
inline float shortBitsToFloat(short s)
|
||||
{
|
||||
/*
|
||||
* 指数空余3位:若符号位为1,补0;若符号位为0,补1。 尾数位在后补0(13个)
|
||||
*/
|
||||
int sign = ((int) (s & sign_16)) << 16;
|
||||
int exponent = ((int) (s & exponent_16)) << 13;
|
||||
// 指数符号位为0,234位补1
|
||||
if ((s & sign_exponent_16) == 0 && s != 0) {
|
||||
exponent |= exponent_fill_32;
|
||||
}
|
||||
int mantissa = ((int) (s & mantissa_16)) << 13;
|
||||
// 生成解码结果
|
||||
int code = sign | exponent | mantissa;
|
||||
return intBitsToFloat(code);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -13,12 +13,12 @@ namespace Limonp
|
||||
public:
|
||||
CodeConverter(const char *from_charset,const char *to_charset)
|
||||
{
|
||||
_iconv_handle = iconv_open(to_charset,from_charset);
|
||||
iconv__handle = iconv_open(to_charset,from_charset);
|
||||
}
|
||||
|
||||
~CodeConverter()
|
||||
{
|
||||
iconv_close(_iconv_handle);
|
||||
iconv_close(iconv__handle);
|
||||
}
|
||||
|
||||
bool convert(const string& from, string& to) const
|
||||
@ -28,7 +28,7 @@ namespace Limonp
|
||||
to.resize(from_size * 2); // iconv failed, may be you can raise this 2 to bigger number.
|
||||
char * pto = (char*)to.c_str();
|
||||
size_t to_size = to.size();
|
||||
if(size_t(-1) == iconv(_iconv_handle, &pfrom, &from_size, &pto, &to_size))
|
||||
if(size_t(-1) == iconv(iconv__handle, &pfrom, &from_size, &pto, &to_size))
|
||||
{
|
||||
to.clear();
|
||||
return false;
|
||||
@ -37,7 +37,7 @@ namespace Limonp
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
iconv_t _iconv_handle;
|
||||
iconv_t iconv__handle;
|
||||
};
|
||||
|
||||
inline bool code_convert(const char* from_charset, const char* to_charset, const string& from, string& to)
|
||||
|
48
src/Limonp/Condition.hpp
Normal file
48
src/Limonp/Condition.hpp
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* https://github.com/chenshuo/muduo/blob/master/muduo/base/Condition.h
|
||||
*/
|
||||
|
||||
#ifndef LIMONP_CONDITION_HPP
|
||||
#define LIMONP_CONDITION_HPP
|
||||
|
||||
#include "MutexLock.hpp"
|
||||
|
||||
namespace Limonp
|
||||
{
|
||||
class Condition : NonCopyable
|
||||
{
|
||||
public:
|
||||
explicit Condition(MutexLock& mutex)
|
||||
: mutex_(mutex)
|
||||
{
|
||||
LIMONP_CHECK(!pthread_cond_init(&pcond_, NULL));
|
||||
}
|
||||
|
||||
~Condition()
|
||||
{
|
||||
LIMONP_CHECK(!pthread_cond_destroy(&pcond_));
|
||||
}
|
||||
|
||||
void wait()
|
||||
{
|
||||
LIMONP_CHECK(!pthread_cond_wait(&pcond_, mutex_.getPthreadMutex()));
|
||||
}
|
||||
|
||||
void notify()
|
||||
{
|
||||
LIMONP_CHECK(!pthread_cond_signal(&pcond_));
|
||||
}
|
||||
|
||||
void notifyAll()
|
||||
{
|
||||
LIMONP_CHECK(!pthread_cond_broadcast(&pcond_));
|
||||
}
|
||||
|
||||
private:
|
||||
MutexLock& mutex_;
|
||||
pthread_cond_t pcond_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -20,15 +20,15 @@ namespace Limonp
|
||||
public:
|
||||
explicit Config(const string& filePath)
|
||||
{
|
||||
_loadFile(filePath);
|
||||
loadFile_(filePath);
|
||||
}
|
||||
public:
|
||||
operator bool ()
|
||||
{
|
||||
return !_map.empty();
|
||||
return !map_.empty();
|
||||
}
|
||||
private:
|
||||
void _loadFile(const string& filePath)
|
||||
void loadFile_(const string& filePath)
|
||||
{
|
||||
ifstream ifs(filePath.c_str());
|
||||
assert(ifs);
|
||||
@ -54,7 +54,7 @@ namespace Limonp
|
||||
string& value = vecBuf[1];
|
||||
trim(key);
|
||||
trim(value);
|
||||
if(!_map.insert(make_pair(key, value)).second)
|
||||
if(!map_.insert(make_pair(key, value)).second)
|
||||
{
|
||||
fprintf(stderr, "key[%s] already exits.\n", key.c_str());
|
||||
assert(false);
|
||||
@ -66,36 +66,52 @@ namespace Limonp
|
||||
public:
|
||||
bool get(const string& key, string& value) const
|
||||
{
|
||||
map<string, string>::const_iterator it = _map.find(key);
|
||||
if(_map.end() != it)
|
||||
map<string, string>::const_iterator it = map_.find(key);
|
||||
if(map_.end() != it)
|
||||
{
|
||||
value = it->second;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool get(const string& key, int & value) const
|
||||
{
|
||||
string str;
|
||||
if(!get(key, str)) {
|
||||
return false;
|
||||
}
|
||||
value = atoi(str.c_str());
|
||||
return true;
|
||||
}
|
||||
const char* operator [] (const char* key) const
|
||||
{
|
||||
if(NULL == key)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
map<string, string>::const_iterator it = _map.find(key);
|
||||
if(_map.end() != it)
|
||||
map<string, string>::const_iterator it = map_.find(key);
|
||||
if(map_.end() != it)
|
||||
{
|
||||
return it->second.c_str();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
public:
|
||||
string getConfigInfo() const
|
||||
{
|
||||
string res;
|
||||
res << *this;
|
||||
return res;
|
||||
}
|
||||
private:
|
||||
map<string, string> _map;
|
||||
map<string, string> map_;
|
||||
private:
|
||||
friend ostream& operator << (ostream& os, const Config& config);
|
||||
};
|
||||
|
||||
inline ostream& operator << (ostream& os, const Config& config)
|
||||
{
|
||||
return os << config._map;
|
||||
return os << config.map_;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
#ifndef LIMONP_MACRO_DEF_H
|
||||
#define LIMONP_MACRO_DEF_H
|
||||
#ifndef LIMONP_HANDY_MACRO_HPP
|
||||
#define LIMONP_HANDY_MACRO_HPP
|
||||
|
||||
#include <stdio.h>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
#define LIMONP_CHECK(exp) \
|
||||
if(!(exp)){fprintf(stderr, "File:%s, Line:%d Exp:[" #exp "] is true, abort.\n", __FILE__, __LINE__); abort();}
|
||||
|
@ -6,14 +6,14 @@ namespace Limonp
|
||||
class InitOnOff
|
||||
{
|
||||
public:
|
||||
InitOnOff(){_setInitFlag(false);};
|
||||
InitOnOff():isInited_(false){};
|
||||
~InitOnOff(){};
|
||||
protected:
|
||||
bool _isInited;
|
||||
bool _getInitFlag()const{return _isInited;};
|
||||
bool _setInitFlag(bool flag){return _isInited = flag;};
|
||||
bool isInited_;
|
||||
bool getInitFlag_()const{return isInited_;};
|
||||
bool setInitFlag_(bool flag){return isInited_ = flag;};
|
||||
public:
|
||||
operator bool() const {return _getInitFlag();};
|
||||
operator bool() const {return getInitFlag_();};
|
||||
|
||||
};
|
||||
}
|
||||
|
@ -22,23 +22,23 @@ namespace Limonp
|
||||
typedef T value_type;
|
||||
typedef size_t size_type;
|
||||
private:
|
||||
T _buffer[LOCAL_VECTOR_BUFFER_SIZE];
|
||||
T * _ptr;
|
||||
size_t _size;
|
||||
size_t _capacity;
|
||||
T buffer_[LOCAL_VECTOR_BUFFER_SIZE];
|
||||
T * ptr_;
|
||||
size_t size_;
|
||||
size_t capacity_;
|
||||
public:
|
||||
LocalVector()
|
||||
{
|
||||
_init();
|
||||
init_();
|
||||
};
|
||||
LocalVector(const LocalVector<T>& vec)
|
||||
{
|
||||
_init();
|
||||
init_();
|
||||
*this = vec;
|
||||
}
|
||||
LocalVector(const_iterator begin, const_iterator end) // TODO: make it faster
|
||||
{
|
||||
_init();
|
||||
init_();
|
||||
while(begin != end)
|
||||
{
|
||||
push_back(*begin++);
|
||||
@ -46,7 +46,7 @@ namespace Limonp
|
||||
}
|
||||
LocalVector(size_t size, const T& t) // TODO: make it faster
|
||||
{
|
||||
_init();
|
||||
init_();
|
||||
while(size--)
|
||||
{
|
||||
push_back(t);
|
||||
@ -54,68 +54,68 @@ namespace Limonp
|
||||
}
|
||||
~LocalVector()
|
||||
{
|
||||
if(_ptr != _buffer)
|
||||
if(ptr_ != buffer_)
|
||||
{
|
||||
free(_ptr);
|
||||
free(ptr_);
|
||||
}
|
||||
};
|
||||
public:
|
||||
LocalVector<T>& operator = (const LocalVector<T>& vec)
|
||||
{
|
||||
clear();
|
||||
_size = vec.size();
|
||||
_capacity = vec.capacity();
|
||||
if(vec._buffer == vec._ptr)
|
||||
size_ = vec.size();
|
||||
capacity_ = vec.capacity();
|
||||
if(vec.buffer_ == vec.ptr_)
|
||||
{
|
||||
memcpy(_buffer, vec._buffer, sizeof(T) * _size);
|
||||
_ptr = _buffer;
|
||||
memcpy(buffer_, vec.buffer_, sizeof(T) * size_);
|
||||
ptr_ = buffer_;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ptr = (T*) malloc(vec.capacity() * sizeof(T));
|
||||
assert(_ptr);
|
||||
memcpy(_ptr, vec._ptr, vec.size() * sizeof(T));
|
||||
ptr_ = (T*) malloc(vec.capacity() * sizeof(T));
|
||||
assert(ptr_);
|
||||
memcpy(ptr_, vec.ptr_, vec.size() * sizeof(T));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
private:
|
||||
void _init()
|
||||
void init_()
|
||||
{
|
||||
_ptr = _buffer;
|
||||
_size = 0;
|
||||
_capacity = LOCAL_VECTOR_BUFFER_SIZE;
|
||||
ptr_ = buffer_;
|
||||
size_ = 0;
|
||||
capacity_ = LOCAL_VECTOR_BUFFER_SIZE;
|
||||
}
|
||||
public:
|
||||
T& operator [] (size_t i)
|
||||
{
|
||||
return _ptr[i];
|
||||
return ptr_[i];
|
||||
}
|
||||
const T& operator [] (size_t i) const
|
||||
{
|
||||
return _ptr[i];
|
||||
return ptr_[i];
|
||||
}
|
||||
void push_back(const T& t)
|
||||
{
|
||||
if(_size == _capacity)
|
||||
if(size_ == capacity_)
|
||||
{
|
||||
assert(_capacity);
|
||||
reserve(_capacity * 2);
|
||||
assert(capacity_);
|
||||
reserve(capacity_ * 2);
|
||||
}
|
||||
_ptr[_size ++ ] = t;
|
||||
ptr_[size_ ++ ] = t;
|
||||
}
|
||||
void reserve(size_t size)
|
||||
{
|
||||
if(size <= _capacity)
|
||||
if(size <= capacity_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
T * next = (T*)malloc(sizeof(T) * size);
|
||||
assert(next);
|
||||
T * old = _ptr;
|
||||
_ptr = next;
|
||||
memcpy(_ptr, old, sizeof(T) * _capacity);
|
||||
_capacity = size;
|
||||
if(old != _buffer)
|
||||
T * old = ptr_;
|
||||
ptr_ = next;
|
||||
memcpy(ptr_, old, sizeof(T) * capacity_);
|
||||
capacity_ = size;
|
||||
if(old != buffer_)
|
||||
{
|
||||
free(old);
|
||||
}
|
||||
@ -126,27 +126,27 @@ namespace Limonp
|
||||
}
|
||||
size_t size() const
|
||||
{
|
||||
return _size;
|
||||
return size_;
|
||||
}
|
||||
size_t capacity() const
|
||||
{
|
||||
return _capacity;
|
||||
return capacity_;
|
||||
}
|
||||
const_iterator begin() const
|
||||
{
|
||||
return _ptr;
|
||||
return ptr_;
|
||||
}
|
||||
const_iterator end() const
|
||||
{
|
||||
return _ptr + _size;
|
||||
return ptr_ + size_;
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
if(_ptr != _buffer)
|
||||
if(ptr_ != buffer_)
|
||||
{
|
||||
free(_ptr);
|
||||
free(ptr_);
|
||||
}
|
||||
_init();
|
||||
init_();
|
||||
}
|
||||
};
|
||||
|
||||
|
432
src/Limonp/Md5.hpp
Normal file
432
src/Limonp/Md5.hpp
Normal file
@ -0,0 +1,432 @@
|
||||
#ifndef __MD5_H__
|
||||
#define __MD5_H__
|
||||
|
||||
// Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
|
||||
// rights reserved.
|
||||
|
||||
// License to copy and use this software is granted provided that it
|
||||
// is identified as the "RSA Data Security, Inc. MD5 Message-Digest
|
||||
// Algorithm" in all material mentioning or referencing this software
|
||||
// or this function.
|
||||
//
|
||||
// License is also granted to make and use derivative works provided
|
||||
// that such works are identified as "derived from the RSA Data
|
||||
// Security, Inc. MD5 Message-Digest Algorithm" in all material
|
||||
// mentioning or referencing the derived work.
|
||||
//
|
||||
// RSA Data Security, Inc. makes no representations concerning either
|
||||
// the merchantability of this software or the suitability of this
|
||||
// software for any particular purpose. It is provided "as is"
|
||||
// without express or implied warranty of any kind.
|
||||
//
|
||||
// These notices must be retained in any copies of any part of this
|
||||
// documentation and/or software.
|
||||
|
||||
|
||||
|
||||
// The original md5 implementation avoids external libraries.
|
||||
// This version has dependency on stdio.h for file input and
|
||||
// string.h for memcpy.
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
namespace Limonp
|
||||
{
|
||||
|
||||
//#pragma region MD5 defines
|
||||
// Constants for MD5Transform routine.
|
||||
#define S11 7
|
||||
#define S12 12
|
||||
#define S13 17
|
||||
#define S14 22
|
||||
#define S21 5
|
||||
#define S22 9
|
||||
#define S23 14
|
||||
#define S24 20
|
||||
#define S31 4
|
||||
#define S32 11
|
||||
#define S33 16
|
||||
#define S34 23
|
||||
#define S41 6
|
||||
#define S42 10
|
||||
#define S43 15
|
||||
#define S44 21
|
||||
|
||||
|
||||
// F, G, H and I are basic MD5 functions.
|
||||
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
|
||||
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define I(x, y, z) ((y) ^ ((x) | (~z)))
|
||||
|
||||
// ROTATE_LEFT rotates x left n bits.
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
|
||||
|
||||
// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
|
||||
// Rotation is separate from addition to prevent recomputation.
|
||||
#define FF(a, b, c, d, x, s, ac) { \
|
||||
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define GG(a, b, c, d, x, s, ac) { \
|
||||
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define HH(a, b, c, d, x, s, ac) { \
|
||||
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define II(a, b, c, d, x, s, ac) { \
|
||||
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
//#pragma endregion
|
||||
|
||||
|
||||
typedef unsigned char BYTE ;
|
||||
|
||||
// POINTER defines a generic pointer type
|
||||
typedef unsigned char *POINTER;
|
||||
|
||||
// UINT2 defines a two byte word
|
||||
typedef unsigned short int UINT2;
|
||||
|
||||
// UINT4 defines a four byte word
|
||||
typedef unsigned int UINT4;
|
||||
|
||||
static unsigned char PADDING[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
// convenient object that wraps
|
||||
// the C-functions for use in C++ only
|
||||
class MD5
|
||||
{
|
||||
private:
|
||||
struct __context_t {
|
||||
UINT4 state[4]; /* state (ABCD) */
|
||||
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
|
||||
unsigned char buffer[64]; /* input buffer */
|
||||
} context ;
|
||||
|
||||
//#pragma region static helper functions
|
||||
// The core of the MD5 algorithm is here.
|
||||
// MD5 basic transformation. Transforms state based on block.
|
||||
static void MD5Transform( UINT4 state[4], unsigned char block[64] )
|
||||
{
|
||||
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
|
||||
|
||||
Decode (x, block, 64);
|
||||
|
||||
/* Round 1 */
|
||||
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
|
||||
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
|
||||
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
|
||||
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
|
||||
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
|
||||
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
|
||||
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
|
||||
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
|
||||
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
|
||||
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
|
||||
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
|
||||
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
|
||||
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
|
||||
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
|
||||
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
|
||||
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
|
||||
|
||||
/* Round 2 */
|
||||
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
|
||||
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
|
||||
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
|
||||
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
|
||||
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
|
||||
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
|
||||
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
|
||||
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
|
||||
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
|
||||
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
|
||||
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
|
||||
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
|
||||
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
|
||||
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
|
||||
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
|
||||
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
|
||||
|
||||
/* Round 3 */
|
||||
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
|
||||
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
|
||||
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
|
||||
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
|
||||
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
|
||||
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
|
||||
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
|
||||
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
|
||||
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
|
||||
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
|
||||
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
|
||||
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
|
||||
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
|
||||
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
|
||||
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
|
||||
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
|
||||
|
||||
/* Round 4 */
|
||||
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
|
||||
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
|
||||
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
|
||||
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
|
||||
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
|
||||
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
|
||||
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
|
||||
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
|
||||
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
|
||||
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
|
||||
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
|
||||
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
|
||||
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
|
||||
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
|
||||
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
|
||||
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
|
||||
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
|
||||
// Zeroize sensitive information.
|
||||
memset((POINTER)x, 0, sizeof (x));
|
||||
}
|
||||
|
||||
// Encodes input (UINT4) into output (unsigned char). Assumes len is
|
||||
// a multiple of 4.
|
||||
static void Encode( unsigned char *output, UINT4 *input, unsigned int len )
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4) {
|
||||
output[j] = (unsigned char)(input[i] & 0xff);
|
||||
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
|
||||
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
|
||||
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
// Decodes input (unsigned char) into output (UINT4). Assumes len is
|
||||
// a multiple of 4.
|
||||
static void Decode( UINT4 *output, unsigned char *input, unsigned int len )
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4)
|
||||
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
|
||||
(((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
|
||||
}
|
||||
//#pragma endregion
|
||||
|
||||
|
||||
public:
|
||||
// MAIN FUNCTIONS
|
||||
MD5()
|
||||
{
|
||||
Init() ;
|
||||
}
|
||||
|
||||
// MD5 initialization. Begins an MD5 operation, writing a new context.
|
||||
void Init()
|
||||
{
|
||||
context.count[0] = context.count[1] = 0;
|
||||
|
||||
// Load magic initialization constants.
|
||||
context.state[0] = 0x67452301;
|
||||
context.state[1] = 0xefcdab89;
|
||||
context.state[2] = 0x98badcfe;
|
||||
context.state[3] = 0x10325476;
|
||||
}
|
||||
|
||||
// MD5 block update operation. Continues an MD5 message-digest
|
||||
// operation, processing another message block, and updating the
|
||||
// context.
|
||||
void Update(
|
||||
unsigned char *input, // input block
|
||||
unsigned int inputLen ) // length of input block
|
||||
{
|
||||
unsigned int i, index, partLen;
|
||||
|
||||
// Compute number of bytes mod 64
|
||||
index = (unsigned int)((context.count[0] >> 3) & 0x3F);
|
||||
|
||||
// Update number of bits
|
||||
if ((context.count[0] += ((UINT4)inputLen << 3))
|
||||
< ((UINT4)inputLen << 3))
|
||||
context.count[1]++;
|
||||
context.count[1] += ((UINT4)inputLen >> 29);
|
||||
|
||||
partLen = 64 - index;
|
||||
|
||||
// Transform as many times as possible.
|
||||
if (inputLen >= partLen) {
|
||||
memcpy((POINTER)&context.buffer[index], (POINTER)input, partLen);
|
||||
MD5Transform (context.state, context.buffer);
|
||||
|
||||
for (i = partLen; i + 63 < inputLen; i += 64)
|
||||
MD5Transform (context.state, &input[i]);
|
||||
|
||||
index = 0;
|
||||
}
|
||||
else
|
||||
i = 0;
|
||||
|
||||
/* Buffer remaining input */
|
||||
memcpy((POINTER)&context.buffer[index], (POINTER)&input[i], inputLen-i);
|
||||
}
|
||||
|
||||
// MD5 finalization. Ends an MD5 message-digest operation, writing the
|
||||
// the message digest and zeroizing the context.
|
||||
// Writes to digestRaw
|
||||
void Final()
|
||||
{
|
||||
unsigned char bits[8];
|
||||
unsigned int index, padLen;
|
||||
|
||||
// Save number of bits
|
||||
Encode( bits, context.count, 8 );
|
||||
|
||||
// Pad out to 56 mod 64.
|
||||
index = (unsigned int)((context.count[0] >> 3) & 0x3f);
|
||||
padLen = (index < 56) ? (56 - index) : (120 - index);
|
||||
Update( PADDING, padLen );
|
||||
|
||||
// Append length (before padding)
|
||||
Update( bits, 8 );
|
||||
|
||||
// Store state in digest
|
||||
Encode( digestRaw, context.state, 16);
|
||||
|
||||
// Zeroize sensitive information.
|
||||
memset((POINTER)&context, 0, sizeof (context));
|
||||
|
||||
writeToString() ;
|
||||
}
|
||||
|
||||
/// Buffer must be 32+1 (nul) = 33 chars long at least
|
||||
void writeToString()
|
||||
{
|
||||
int pos ;
|
||||
|
||||
for( pos = 0 ; pos < 16 ; pos++ )
|
||||
sprintf( digestChars+(pos*2), "%02x", digestRaw[pos] ) ;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
// an MD5 digest is a 16-byte number (32 hex digits)
|
||||
BYTE digestRaw[ 16 ] ;
|
||||
|
||||
// This version of the digest is actually
|
||||
// a "printf'd" version of the digest.
|
||||
char digestChars[ 33 ] ;
|
||||
|
||||
/// Load a file from disk and digest it
|
||||
// Digests a file and returns the result.
|
||||
const char* digestFile( const char *filename )
|
||||
{
|
||||
if (NULL == filename || strcmp(filename, "") == 0)
|
||||
return NULL;
|
||||
|
||||
Init() ;
|
||||
|
||||
FILE *file;
|
||||
|
||||
unsigned char buffer[1024] ;
|
||||
|
||||
if((file = fopen (filename, "rb")) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
int len;
|
||||
while( (len = fread( buffer, 1, 1024, file )) )
|
||||
Update( buffer, len ) ;
|
||||
Final();
|
||||
|
||||
fclose( file );
|
||||
|
||||
return digestChars ;
|
||||
}
|
||||
|
||||
/// Digests a byte-array already in memory
|
||||
const char* digestMemory( BYTE *memchunk, int len )
|
||||
{
|
||||
if (NULL == memchunk)
|
||||
return NULL;
|
||||
|
||||
Init() ;
|
||||
Update( memchunk, len ) ;
|
||||
Final() ;
|
||||
|
||||
return digestChars ;
|
||||
}
|
||||
|
||||
// Digests a string and prints the result.
|
||||
const char* digestString(const char *string )
|
||||
{
|
||||
if (string == NULL)
|
||||
return NULL;
|
||||
|
||||
Init() ;
|
||||
Update( (unsigned char*)string, strlen(string) ) ;
|
||||
Final() ;
|
||||
|
||||
return digestChars ;
|
||||
}
|
||||
};
|
||||
|
||||
inline bool md5String(const char* str, std::string& res)
|
||||
{
|
||||
if (NULL == str)
|
||||
{
|
||||
res = "";
|
||||
return false;
|
||||
}
|
||||
|
||||
MD5 md5;
|
||||
const char *pRes = md5.digestString(str);
|
||||
if (NULL == pRes)
|
||||
{
|
||||
res = "";
|
||||
return false;
|
||||
}
|
||||
|
||||
res = pRes;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool md5File(const char* filepath, std::string& res)
|
||||
{
|
||||
if (NULL == filepath || strcmp(filepath, "") == 0)
|
||||
{
|
||||
res = "";
|
||||
return false;
|
||||
}
|
||||
|
||||
MD5 md5;
|
||||
const char *pRes = md5.digestFile(filepath);
|
||||
|
||||
if (NULL == pRes)
|
||||
{
|
||||
res = "";
|
||||
return false;
|
||||
}
|
||||
|
||||
res = pRes;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
57
src/Limonp/MutexLock.hpp
Normal file
57
src/Limonp/MutexLock.hpp
Normal file
@ -0,0 +1,57 @@
|
||||
#ifndef LIMONP_MUTEX_LOCK_HPP
|
||||
#define LIMONP_MUTEX_LOCK_HPP
|
||||
|
||||
#include <pthread.h>
|
||||
#include "NonCopyable.hpp"
|
||||
#include "HandyMacro.hpp"
|
||||
|
||||
namespace Limonp
|
||||
{
|
||||
class MutexLock: NonCopyable
|
||||
{
|
||||
private:
|
||||
pthread_mutex_t mutex_;
|
||||
public:
|
||||
pthread_mutex_t* getPthreadMutex()
|
||||
{
|
||||
return &mutex_;
|
||||
}
|
||||
public:
|
||||
MutexLock()
|
||||
{
|
||||
LIMONP_CHECK(!pthread_mutex_init(&mutex_, NULL));
|
||||
}
|
||||
~MutexLock()
|
||||
{
|
||||
LIMONP_CHECK(!pthread_mutex_destroy(&mutex_));
|
||||
}
|
||||
private:
|
||||
void lock()
|
||||
{
|
||||
LIMONP_CHECK(!pthread_mutex_lock(&mutex_));
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
LIMONP_CHECK(!pthread_mutex_unlock(&mutex_));
|
||||
}
|
||||
friend class MutexLockGuard;
|
||||
};
|
||||
class MutexLockGuard: NonCopyable
|
||||
{
|
||||
public:
|
||||
explicit MutexLockGuard(MutexLock & mutex)
|
||||
: mutex_(mutex)
|
||||
{
|
||||
mutex_.lock();
|
||||
}
|
||||
~MutexLockGuard()
|
||||
{
|
||||
mutex_.unlock();
|
||||
}
|
||||
private:
|
||||
MutexLock & mutex_;
|
||||
};
|
||||
#define MutexLockGuard(x) assert(false);
|
||||
}
|
||||
|
||||
#endif
|
@ -5,7 +5,7 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "logger.hpp"
|
||||
#include "Logger.hpp"
|
||||
#include "InitOnOff.hpp"
|
||||
|
||||
namespace Limonp
|
||||
@ -16,62 +16,62 @@ namespace Limonp
|
||||
public:
|
||||
typedef vector< vector<string> > RowsType;
|
||||
private:
|
||||
const string _host;
|
||||
const size_t _port;
|
||||
const string _user;
|
||||
const string _passwd;
|
||||
const string _db;
|
||||
const string _charset;
|
||||
const string host_;
|
||||
const size_t port_;
|
||||
const string user_;
|
||||
const string passwd_;
|
||||
const string db_;
|
||||
const string charset_;
|
||||
public:
|
||||
MysqlClient(const string& host, size_t port, const string& user, const string& passwd, const string& db, const string& charset = "utf8"): _host(host), _port(port), _user(user), _passwd(passwd), _db(db), _charset(charset), _conn(NULL)
|
||||
MysqlClient(const string& host, size_t port, const string& user, const string& passwd, const string& db, const string& charset = "utf8"): host_(host), port_(port), user_(user), passwd_(passwd), db_(db), charset_(charset), conn_(NULL)
|
||||
{
|
||||
_setInitFlag(_init());
|
||||
setInitFlag_(init_());
|
||||
}
|
||||
~MysqlClient()
|
||||
{
|
||||
if(_conn)
|
||||
if(conn_)
|
||||
{
|
||||
mysql_close(_conn);
|
||||
mysql_close(conn_);
|
||||
}
|
||||
};
|
||||
private:
|
||||
bool _init()
|
||||
bool init_()
|
||||
{
|
||||
//cout<<mysql_get_client_info()<<endl;
|
||||
if(NULL == (_conn = mysql_init(NULL)))
|
||||
if(NULL == (conn_ = mysql_init(NULL)))
|
||||
{
|
||||
LogError("mysql_init faield. %s", mysql_error(_conn));
|
||||
LogError("mysql_init faield. %s", mysql_error(conn_));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mysql_real_connect(_conn, _host.c_str(), _user.c_str(), _passwd.c_str(), _db.c_str(), _port, NULL, 0) == NULL)
|
||||
if (mysql_real_connect(conn_, host_.c_str(), user_.c_str(), passwd_.c_str(), db_.c_str(), port_, NULL, 0) == NULL)
|
||||
{
|
||||
LogError("mysql_real_connect failed. %s", mysql_error(_conn));
|
||||
mysql_close(_conn);
|
||||
_conn = NULL;
|
||||
LogError("mysql_real_connect failed. %s", mysql_error(conn_));
|
||||
mysql_close(conn_);
|
||||
conn_ = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(mysql_set_character_set(_conn, _charset.c_str()))
|
||||
if(mysql_set_character_set(conn_, charset_.c_str()))
|
||||
{
|
||||
LogError("mysql_set_character_set [%s] failed.", _charset.c_str());
|
||||
LogError("mysql_set_character_set [%s] failed.", charset_.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
//set reconenct
|
||||
char value = 1;
|
||||
mysql_options(_conn, MYSQL_OPT_RECONNECT, &value);
|
||||
mysql_options(conn_, MYSQL_OPT_RECONNECT, &value);
|
||||
|
||||
LogInfo("MysqlClient {host: %s, database:%s, charset:%s}", _host.c_str(), _db.c_str(), _charset.c_str());
|
||||
LogInfo("MysqlClient {host: %s, database:%s, charset:%s}", host_.c_str(), db_.c_str(), charset_.c_str());
|
||||
return true;
|
||||
}
|
||||
public:
|
||||
bool executeSql(const string& sql)
|
||||
{
|
||||
assert(_getInitFlag());
|
||||
if(mysql_query(_conn, sql.c_str()))
|
||||
assert(getInitFlag_());
|
||||
if(mysql_query(conn_, sql.c_str()))
|
||||
{
|
||||
LogError("mysql_query failed. %s", mysql_error(_conn));
|
||||
LogError("mysql_query failed. %s", mysql_error(conn_));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -95,10 +95,10 @@ namespace Limonp
|
||||
LogError("executeSql failed. [%s]", sql.c_str());
|
||||
return false;
|
||||
}
|
||||
MYSQL_RES * result = mysql_store_result(_conn);
|
||||
MYSQL_RES * result = mysql_store_result(conn_);
|
||||
if(!result)
|
||||
{
|
||||
LogError("mysql_store_result failed.[%d]", mysql_error(_conn));
|
||||
LogError("mysql_store_result failed.[%d]", mysql_error(conn_));
|
||||
return false;
|
||||
}
|
||||
size_t num_fields = mysql_num_fields(result);
|
||||
@ -117,7 +117,7 @@ namespace Limonp
|
||||
}
|
||||
|
||||
private:
|
||||
MYSQL * _conn;
|
||||
MYSQL * conn_;
|
||||
|
||||
};
|
||||
}
|
||||
|
50
src/Limonp/Thread.hpp
Normal file
50
src/Limonp/Thread.hpp
Normal file
@ -0,0 +1,50 @@
|
||||
#ifndef LIMONP_THREAD_HPP
|
||||
#define LIMONP_THREAD_HPP
|
||||
|
||||
#include "HandyMacro.hpp"
|
||||
#include "NonCopyable.hpp"
|
||||
|
||||
namespace Limonp
|
||||
{
|
||||
class IThread: NonCopyable
|
||||
{
|
||||
private:
|
||||
pthread_t thread_;
|
||||
bool isStarted;
|
||||
bool isJoined;
|
||||
public:
|
||||
IThread(): isStarted(false), isJoined(false)
|
||||
{
|
||||
}
|
||||
virtual ~IThread()
|
||||
{
|
||||
if(isStarted && !isJoined)
|
||||
{
|
||||
LIMONP_CHECK(!pthread_detach(thread_));
|
||||
}
|
||||
};
|
||||
public:
|
||||
virtual void run() = 0;
|
||||
void start()
|
||||
{
|
||||
assert(!isStarted);
|
||||
LIMONP_CHECK(!pthread_create(&thread_, NULL, worker_, this));
|
||||
isStarted = true;
|
||||
}
|
||||
void join()
|
||||
{
|
||||
assert(!isJoined);
|
||||
LIMONP_CHECK(!pthread_join(thread_, NULL));
|
||||
isJoined = true;
|
||||
}
|
||||
private:
|
||||
static void * worker_(void * data)
|
||||
{
|
||||
IThread * ptr = (IThread* ) data;
|
||||
ptr->run();
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
105
src/Limonp/ThreadPool.hpp
Normal file
105
src/Limonp/ThreadPool.hpp
Normal file
@ -0,0 +1,105 @@
|
||||
#ifndef LIMONP_THREAD_POOL_HPP
|
||||
#define LIMONP_THREAD_POOL_HPP
|
||||
|
||||
#include "Thread.hpp"
|
||||
#include "BlockingQueue.hpp"
|
||||
|
||||
namespace Limonp
|
||||
{
|
||||
class ITask
|
||||
{
|
||||
public:
|
||||
virtual void run() = 0;
|
||||
virtual ~ITask() {}
|
||||
};
|
||||
|
||||
template <class TaskType, class ArgType>
|
||||
ITask* CreateTask(ArgType arg)
|
||||
{
|
||||
return new TaskType(arg);
|
||||
}
|
||||
template <class TaskType, class ArgType0, class ArgType1>
|
||||
ITask* CreateTask(ArgType0 arg0, ArgType1 arg1)
|
||||
{
|
||||
return new TaskType(arg0, arg1);
|
||||
}
|
||||
|
||||
//class ThreadPool;
|
||||
class ThreadPool: NonCopyable
|
||||
{
|
||||
private:
|
||||
class Worker: public IThread
|
||||
{
|
||||
private:
|
||||
ThreadPool * ptThreadPool_;
|
||||
public:
|
||||
Worker(ThreadPool* pool): ptThreadPool_(pool)
|
||||
{
|
||||
assert(ptThreadPool_);
|
||||
}
|
||||
virtual ~Worker()
|
||||
{
|
||||
}
|
||||
public:
|
||||
virtual void run()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
ITask * task = ptThreadPool_->queue_.pop();
|
||||
if(task == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
task->run();
|
||||
delete task;
|
||||
}
|
||||
}
|
||||
};
|
||||
private:
|
||||
friend class Worker;
|
||||
private:
|
||||
vector<IThread*> threads_;
|
||||
BoundedBlockingQueue<ITask*> queue_;
|
||||
//mutable MutexLock mutex_;
|
||||
//Condition isEmpty__;
|
||||
public:
|
||||
ThreadPool(size_t threadNum, size_t queueMaxSize): threads_(threadNum), queue_(queueMaxSize)//, mutex_(), isEmpty__(mutex_)
|
||||
{
|
||||
assert(threadNum);
|
||||
assert(queueMaxSize);
|
||||
for(size_t i = 0; i < threads_.size(); i ++)
|
||||
{
|
||||
threads_[i] = new Worker(this);
|
||||
}
|
||||
}
|
||||
~ThreadPool()
|
||||
{
|
||||
for(size_t i = 0; i < threads_.size(); i ++)
|
||||
{
|
||||
queue_.push(NULL);
|
||||
}
|
||||
for(size_t i = 0; i < threads_.size(); i ++)
|
||||
{
|
||||
threads_[i]->join();
|
||||
delete threads_[i];
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void start()
|
||||
{
|
||||
for(size_t i = 0; i < threads_.size(); i++)
|
||||
{
|
||||
threads_[i]->start();
|
||||
}
|
||||
}
|
||||
|
||||
void add(ITask* task)
|
||||
{
|
||||
assert(task);
|
||||
queue_.push(task);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
2
test/testdata/server.conf
vendored
2
test/testdata/server.conf
vendored
@ -3,6 +3,8 @@
|
||||
#socket listen port
|
||||
port=11200
|
||||
|
||||
thread_number=4
|
||||
queue_max_size=4096
|
||||
|
||||
#dict path
|
||||
dict_path=../dict/jieba.dict.utf8
|
||||
|
Loading…
x
Reference in New Issue
Block a user