반응형

code : https://github.com/EomTaeWook/Cpp-Util/tree/master/Util/Logger


C#처럼 Parallel 환경 테스트가 안되어서 싱글쓰레드 테스트


Default Message 입력된 시간으로 정렬됨.


2번째 인자로 시간을 넘겨주면 시간 순대로 정렬



사용예제


1000000개 11초 걸림


int count = 0;

auto now = std::chrono::system_clock::now();

try

{

while (count++ < 5)

{

for (int i = 0; i < 200000; i++)

{

auto now = std::chrono::system_clock::now();

auto second = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());

Util::Logger::FileLogger::Instance()->Write(L"한글 테스트" + std::to_wstring(second.count()), now);

}

}

}

catch (const std::exception ex)

{

printf("%s", ex.what());

}

catch (...)

{


}

Util::Logger::FileLogger::Instance()->~FileLogger();

std::chrono::duration<double> span = std::chrono::system_clock::now() - now;

printf("%lf", span);



FileLogger.h


#pragma once

#include "NS.h"

#include "EnumLogger.h"

#include "../Threading/CriticalSection.h"

#include "LogMessage.h"

#include "../Common/Singleton.h"

#include "../Common/Finally.h"

#include "../Collections/DoublePriorityQueue.h"

#include "../Threading/Thread.h"

#include <fstream>

#include <condition_variable>

#include <mutex>

#include <codecvt>

NS_LOGGER_BEGIN

class FileLogger : public Common::Singleton<FileLogger>

{

public :

FileLogger();

~FileLogger();

private:

LoggerPeriod _period;

std::string _path;

std::string _moduleName;

Threading::CriticalSection _appand;

Collections::DoublePriorityQueue<LogMessage, LogMessage::Compare> _queue;

std::wfstream _fs;

std::function<void()> _periodCompare;

Threading::Thread _thread;

bool _isStart, _doWork;

std::mutex _write;

std::condition_variable _trigger;

tm _time;

public:

void Init(LoggerPeriod period = LoggerPeriod::Infinitely, const std::string& moduleName="", const std::string& path = "");

void Write(const std::wstring& message, const std::chrono::system_clock::time_point& timeStamp = std::chrono::system_clock::now());

private:

void WriteMessage(const LogMessage& message);

void Invoke();

void DayCompare();

void HourCompare();

void CreateLogFile();

}; 

NS_LOGGER_END


FileLogger.cpp


#include "FileLogger.h"

#include <ctime>

#include "../Threading/IOCPThreadPool.h"

#include "../Common/Trace.h"

NS_LOGGER_BEGIN

FileLogger::FileLogger() : _periodCompare(nullptr), 

_thread(std::bind(&FileLogger::Invoke, this), nullptr),

_isStart(false)

{

}

FileLogger::~FileLogger()

{

_isStart = false;

_trigger.notify_all();

_thread.Join();

if(_fs.is_open())

_fs.close();

}

void FileLogger::Init(LoggerPeriod period, const std::string& moduleName, const std::string& path)

{

if (_isStart)

return;

_period = period;

_path = path;

_moduleName = moduleName;

char moduleFileName[MAX_PATH];

::GetModuleFileName(NULL, moduleFileName, MAX_PATH);

if (_path.size() == 0)

{

_path.append(moduleFileName);

_path = _path.substr(0, _path.find_last_of("\\")).append("\\Log");

}

if (_moduleName.size() == 0)

{

_moduleName.append(moduleFileName);

_moduleName = _moduleName.substr(_moduleName.find_last_of("\\") + 1, _moduleName.find_last_of(".") - _moduleName.find_last_of("\\") - 1);

}

DWORD attribs = ::GetFileAttributesA(_path.c_str());

if (attribs == INVALID_FILE_ATTRIBUTES) 

::CreateDirectory(_path.c_str(), NULL);

switch (_period)

{

case Util::Logger::LoggerPeriod::Hour:

_periodCompare = std::bind(&FileLogger::HourCompare, this);

break;

case Util::Logger::LoggerPeriod::Day:

_periodCompare = std::bind(&FileLogger::DayCompare, this);

break;

}

_fs.imbue(std::locale(std::locale::empty(), new std::codecvt_utf8<wchar_t, 0x10ffff, static_cast<std::codecvt_mode>(std::generate_header | std::consume_header)>));

_fs.sync_with_stdio(false);

CreateLogFile();

_isStart = true;

_thread.Start();

}

void FileLogger::Write(const std::wstring& message, const std::chrono::system_clock::time_point& timeStamp)

{

if (!_fs.is_open())

throw std::exception("Logger Not Initialization");


auto finally = Common::Finally(std::bind(&Threading::CriticalSection::LeaveCriticalSection, &_appand));

_appand.EnterCriticalSection();

_queue.Push(LogMessage(message, timeStamp));

if (!_doWork)

_trigger.notify_all();

}

void FileLogger::WriteMessage (const LogMessage& message)

{

auto now = std::chrono::system_clock::now();

auto since = now.time_since_epoch();

auto second = std::chrono::duration_cast<std::chrono::seconds>(since);

since -= second;

auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(since);

auto time = std::chrono::system_clock::to_time_t(now);

tm timeInfo;

::localtime_s(&timeInfo, &time);

wchar_t timeBuff[20];

std::wcsftime(timeBuff, 20, L"%Y-%m-%d %H:%M:%S", &timeInfo);

std::wstring ms = std::to_wstring(milliseconds.count());

auto format = std::wstring(L"[")

.append(timeBuff)

.append(L"." + std::wstring().insert(0, 3 - ms.size(), '0') + ms.c_str())

.append(L"]")

.append(L" " + ((LogMessage)message).GetLogMessage());

#if _DEBUG

Common::Trace::WriteLine(format.c_str());

#endif

_fs.write(format.c_str(), format.size());

_fs.put(L'\r').put(L'\n').flush();

}

void FileLogger::Invoke()

{

std::unique_lock<std::mutex> lock(_write);

while (_isStart)

{

_doWork = false;

_trigger.wait(lock);

_doWork = true;

while (_queue.AppendCount() > 0)

{

_appand.EnterCriticalSection();

_queue.Swap();

_appand.LeaveCriticalSection();


while (_queue.ReadCount() > 0)

{

if (_periodCompare != nullptr)

_periodCompare();

WriteMessage(_queue.Pop());

}

}

}

}

void FileLogger::DayCompare()

{

auto time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());

tm timeInfo;

::localtime_s(&timeInfo, &time);

if (timeInfo.tm_mday != _time.tm_mday)

{

_fs.close();

CreateLogFile();

}

}

void FileLogger::HourCompare()

{

auto time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());

tm timeInfo;

::localtime_s(&timeInfo, &time);

if (timeInfo.tm_hour != _time.tm_hour)

{

_fs.close();

CreateLogFile();

}

}

void FileLogger::CreateLogFile()

{

auto time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());

::localtime_s(&_time, &time);

std::string fileName;

fileName.resize(20);

switch (_period)

{

case LoggerPeriod::Infinitely:

fileName = "Log";

break;

case LoggerPeriod::Day:

std::strftime(&fileName.front(), fileName.size(), "%Y-%m-%d", &_time);

break;

case LoggerPeriod::Hour:

std::strftime(&fileName.front(), fileName.size(), "%Y-%m-%d-%H", &_time);

break;

default:

fileName = "";

break;

}

fileName = fileName.substr(0, fileName.find('\0'));

if (fileName.size() == 0)

throw std::exception("LoggerPeriod Not Initialization");

fileName.append(".log");

_fs.open(_path + "\\"+ _moduleName + " " + fileName, std::ios::app | std::ios::binary);

}

NS_LOGGER_END

반응형

'개발관련 > C&C++' 카테고리의 다른 글

반복자(iterator)가 포함된 Queue  (0) 2018.09.08
IOCP Socket Client 구현  (0) 2018.05.31
HttpClient  (0) 2018.05.25
MSMQ(MS MessageQueue)  (0) 2018.05.15
Functional 이용한 델리게이트  (0) 2018.04.26
반응형

code : https://github.com/EomTaeWook/Cpp-Util/blob/master/Util/Collections/Queue.h


std::find 로 Queue 안에 데이터를 찾기 위해 반복자가 포함된 Queue를 만듦


릴리즈 모드 => STL Queue랑 비교시 조금 빠르다.





std::chrono::duration<double> stlQueueSec;

Queue<TEMP> uq;

std::queue<TEMP> q;

std::chrono::duration<double> utilQueueSec;

{

std::chrono::system_clock::time_point start = std::chrono::system_clock::now();

for (int i = 0; i < 10000000; i++)

uq.Push(TEMP(i));

while (!uq.Empty())

uq.Pop();

for (int i = 0; i < 20000000; i++)

uq.Push(TEMP(i));

while (!uq.Empty())

uq.Pop();

std::chrono::system_clock::time_point end = std::chrono::system_clock::now();

utilQueueSec = end - start;

}


{

std::chrono::system_clock::time_point start = std::chrono::system_clock::now();

for (int i = 0; i < 10000000; i++)

q.push(TEMP(i));

while (!q.empty())

q.pop();

for (int i = 0; i < 20000000; i++)

q.push(TEMP(i));

while (!q.empty())

q.pop();

std::chrono::system_clock::time_point end = std::chrono::system_clock::now();

stlQueueSec = end - start;

}

printf("util : %lf STL : %lf", utilQueueSec, stlQueueSec);

getchar();




Queue.h


#pragma once

#include "Iterator.h"

#include <vector>

#include"NS.h"

NS_COLLECTIONS_BEGIN

template<typename T>

class  Queue

{

public:

Queue();

virtual ~Queue();

private:

Iterator<T> _pAlloc;

std::allocator<T> _alloc;

private:

Iterator<T> _begin;

Iterator<T> _end;

Iterator<T> _endPoint;

private:

void ReAllocateAndCopy(Iterator<T> position, const Iterator<T> first, const Iterator<T> last);

void ReAllocateAndCopy(Iterator<T> position, size_t size, const T& item);

void DestroyAndDeallocateAll();

private:

Iterator<T> Insert(const Iterator<T> position, const T& item);

void Insert(const Iterator<T> position, size_t size, const T& item);

void Insert(const Iterator<T> position, const Iterator<T> first, const Iterator<T> last);

public:

Iterator<T> Begin();

Iterator<T> End();

public:

size_t Count() const;

size_t Capacity() const;

public:

void Clear();

Queue<T>& Push(const T& item);

Queue<T>& Push(T* items, size_t size);

T& Front();

T Peek();

std::vector<T> Peek(size_t offset, size_t length);

void Pop();

public:

bool Empty();

};

template<typename T>

inline Queue<T>::Queue()

{

}

template<typename T>

inline Queue<T>::~Queue()

{

Clear();

}

template<typename T>

inline Iterator<T> Queue<T>::Begin()

{

return _begin;

}

template<typename T>

inline Iterator<T> Queue<T>::End()

{

return _end;

}

template<typename T>

size_t Queue<T>::Count() const

{

return _end - _begin;

}

template<typename T>

size_t Queue<T>::Capacity() const

{

return _endPoint - _pAlloc;

}


template<typename T>

inline void Queue<T>::Clear()

{

DestroyAndDeallocateAll();

}


template<typename T>

inline Queue<T>& Queue<T>::Push(const T& item)

{

Insert(End(), item);

return *this;

}


template<typename T>

inline Queue<T>& Queue<T>::Push(T * items, size_t size)

{

Insert(End(), Iterator<T>(items), Iterator<T>(items + size));

return *this;

}


template<typename T>

inline T& Queue<T>::Front()

{

return *_begin;

}


template<typename T>

inline T Queue<T>::Peek()

{

T item = *_begin;

return item;

}


template<typename T>

inline std::vector<T> Queue<T>::Peek(size_t offset, size_t length)

{

std::vector<T> items;

auto it = _begin + offset;

for (int i = 0; i < length; i++, ++it)

items.push_back(*it);

return items;

}


template<typename T>

inline void Queue<T>::Pop()

{

_alloc.destroy(&*_begin);

_begin++;

if (Empty())

{

memset(&*_pAlloc, 0, Capacity());

_end = _begin = _pAlloc;

}

}


template<typename T>

inline bool Queue<T>::Empty()

{

return Begin() == End();

}


template<typename T>

inline Iterator<T> Queue<T>::Insert(const Iterator<T> position, const T& item)

{

auto index = position - Begin();

Insert(position, 1, item);

return Begin() + index;

}

template<typename T>

inline void Queue<T>::Insert(const Iterator<T> position, const Iterator<T> first, const Iterator<T> last)

{

int64_t size = last - first;

auto remainingSize = _endPoint - _end;

auto end = position;

if (remainingSize >= size)

{

for (auto it = first; it != last; ++it)

{

_alloc.construct(&*end, *it);

end++;

}

_end += size;

}

else

ReAllocateAndCopy(position, first, last);

}

template<typename T>

inline void Queue<T>::Insert(const Iterator<T> position, size_t size, const T& item)

{

size_t remainingSize = _endPoint - _end;

if (remainingSize >= size)

{

for (auto i = 0; i < size; i++)

_alloc.construct(&*(position + i), item);

_end += size;

}

else

ReAllocateAndCopy(position, size, item);

}


template<typename T>

inline void Queue<T>::ReAllocateAndCopy(Iterator<T> position, const Iterator<T> first, const Iterator<T> last)

{

auto size = last - first;

size_t capacity = Capacity() * 2 + size;

T* begin = _alloc.allocate(capacity);

if (begin == nullptr)

throw std::exception("OutOfMemory");

T* end = begin + (position - Begin());

T* endPoint = begin + capacity;

memcpy(begin, &*Begin(), (End() - Begin()) * sizeof(T));


for (auto it = first; it != last; ++it)

{

_alloc.construct(end, *it);

end++;

}


DestroyAndDeallocateAll();


_pAlloc = _begin = begin;

_end = end;

_endPoint = endPoint;

}


template<typename T>

inline void Queue<T>::ReAllocateAndCopy(Iterator<T> position, size_t size, const T & item)

{

size_t capacity = Capacity() * 2 + size;

T* begin = _alloc.allocate(capacity);

if (begin == nullptr)

throw std::exception("OutOfMemory");

T* end = begin + (position - Begin());

T* endPoint = begin + capacity;

memcpy(begin, &*Begin(), (End() - Begin()) * sizeof(T));

for (auto i = 0; i < size; i++)

{

_alloc.construct(end, item);

end++;

}


DestroyAndDeallocateAll();


_pAlloc = _begin = begin;

_end = end;

_endPoint = endPoint;

}

template<typename T>

inline void Queue<T>::DestroyAndDeallocateAll()

{

if (Capacity() != 0)

{

for (auto it = Begin(); it != End(); it++)

_alloc.destroy(&*it);

_alloc.deallocate(&*_pAlloc, Capacity());

_pAlloc = _begin = _end = _endPoint = nullptr;

}

}

NS_COLLECTIONS_END

반응형

'개발관련 > C&C++' 카테고리의 다른 글

FileLogger  (0) 2018.10.02
IOCP Socket Client 구현  (0) 2018.05.31
HttpClient  (0) 2018.05.25
MSMQ(MS MessageQueue)  (0) 2018.05.15
Functional 이용한 델리게이트  (0) 2018.04.26
반응형

code : https://github.com/EomTaeWook/Cpp-Util/tree/master/Util/Socket


사용예제


#include <Socket\IOCPSocketClient.h>

#pragma comment(lib, "Util_d.lib")

#include<string>

struct Header

{

UINT32 dataSize;

USHORT protocol;

};

struct Packet : Util::Socket::DefaultPacket

{

Header Header;

std::vector<char> Data;

};


class TEST : public Util::Socket::IOCPSocketClient<USHORT, Packet>

{

public:

TEST() {}

virtual ~TEST() {}


public:

void TESTFUNCTION(Packet packet);


// IOCPSocketClient을(를) 통해 상속됨

virtual void OnDisconnected() override

{

}

virtual void OnConnected(Util::Socket::StateObject & stateObject) override

{

}

virtual void OnRecieved(Util::Socket::StateObject & stateObject) override

{

if (stateObject.ReceiveBuffer().Count() >= 6)

{

Header header;

memcpy(&header, &stateObject.ReceiveBuffer().Read(sizeof(Header)).front(), sizeof(Header));

Packet packet;

packet.Header = header;

packet.Data.assign(header.dataSize - sizeof(Header), '\n');

memcpy(&packet.Data.front(), &stateObject.ReceiveBuffer().Read(header.dataSize - sizeof(Header)).front(), header.dataSize - sizeof(Header));

RunCallback(packet.Header.protocol, packet);

}

}

};

void TEST::TESTFUNCTION(Packet packet)

{

//Callback 떨어짐

}


int main()

{

TEST t;

t.BindCallback(1234, std::bind(&TEST::TESTFUNCTION, &t, std::placeholders::_1));

t.Connect("127.0.0.1", 10000);

while (true)

{

Sleep(1000);

}

return 0;

}




IOCPSocketClient.h


#pragma once

#include "NS.h"

#include "IOCPBaseClient.h"

#include <map>

#include "../Common/Trace.h"

NS_SOCKET_BEGIN

template<typename ProtocolType, typename ...Types>

class IOCPSocketClient : public IOCPBaseClient

{

protected:

IOCPSocketClient();

public:

virtual ~IOCPSocketClient();

protected:

std::map<ProtocolType, Util::Common::MulticastDelegate<void, Types...>> _funcMaps;

public:

void BindCallback(ProtocolType protocol, const std::function<void(Types...)>& callback);

void OnCallback(ProtocolType protocol, Types...);

};

template<typename ProtocolType, typename ...Types>

inline IOCPSocketClient<ProtocolType, Types...>::IOCPSocketClient()

{

}

template<typename ProtocolType, typename ...Types>

inline IOCPSocketClient<ProtocolType, Types...>::~IOCPSocketClient()

{

_funcMaps.clear();

}


template<typename ProtocolType, typename ...Types>

inline void IOCPSocketClient<ProtocolType, Types...>::BindCallback(ProtocolType protocol, const std::function<void(Types...)>& callback)

{

if (_funcMaps.find(protocol) == _funcMaps.end())

_funcMaps.insert(std::pair<ProtocolType, Util::Common::MulticastDelegate<void, Types...>>(protocol, std::move(callback)));

else

throw std::exception("An item with the same key has already been Added");

}


template<typename ProtocolType, typename ...Types>

inline void IOCPSocketClient<ProtocolType, Types...>::OnCallback(ProtocolType protocol, Types... params)

{

try

{

auto it = _funcMaps.find(protocol);

if (it != _funcMaps.end())

it->second(std::forward<Types>(params)...);

else

throw std::exception("KeyNotFoundException");

}

catch (const std::exception& ex)

{

Util::Common::Trace::WriteLine(ex.what());

}

catch (...)

{

Util::Common::Trace::WriteLine("OnCallbackException");

}

}


NS_SOCKET_END


IOCPBaseClient.h


#pragma once

#include "NS.h"

#include "StateObject.h"

#include "../Threading/Thread.h"


NS_SOCKET_BEGIN

class IOCPBaseClient

{

private:

static const LONG_PTR _CLOSE_THREAD = -1;

protected:

IOCPBaseClient();

public:

virtual ~IOCPBaseClient();

private:

HANDLE _completionPort;

std::vector<HANDLE> _hWorkerThread;

StateObject _stateObject;

sockaddr_in _iPEndPoint;

UINT _threadSize;

private:

std::unique_ptr<Util::Threading::Thread> _keepAliveThread;

public:

void Init(UINT threadSize = 0);

void Connect(std::string ip, int port, int timeOut = 5000);

bool IsConnect();

void DisConnect();

private:

void KeepAlive(void* state);

void BeginReceive();

int Invoke();

void Stop();

public:

void Send(Util::Socket::IPacket& packet);

protected:

//abstract Method

virtual void OnKeepAlive(Util::Socket::StateObject& stateObject);

virtual void OnDisconnected() = 0;

virtual void OnConnected(Util::Socket::StateObject& stateObject) = 0;

virtual void OnRecieved(Util::Socket::StateObject& stateObject) = 0;

public:

static unsigned int __stdcall Run(void*);

};

inline IOCPBaseClient::IOCPBaseClient() : _threadSize(0), _completionPort(NULL)

{

}

inline IOCPBaseClient::~IOCPBaseClient()

{

Stop();

}

NS_SOCKET_END


IOCPBaseClient.cpp


#include "IOCPBaseClient.h"

#include <WS2tcpip.h>

#include "../Common/Trace.h"

#pragma comment(lib, "Ws2_32.lib")

NS_SOCKET_BEGIN

void IOCPBaseClient::Init(UINT threadSize)

{

_completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);

if (_completionPort == INVALID_HANDLE_VALUE)

throw std::exception(std::string("CreateIoCompletionPort Fail : " + std::to_string(GetLastError())).c_str());

SYSTEM_INFO info;

GetSystemInfo(&info);

if (info.dwNumberOfProcessors * 2 < threadSize && threadSize > 0)

threadSize = info.dwNumberOfProcessors;

else

threadSize = info.dwNumberOfProcessors * 2;

for (size_t i = 0; i < threadSize; i++)

_hWorkerThread.push_back((HANDLE)_beginthreadex(0, 0, Run, this, 0, NULL));

_threadSize = threadSize;

}

bool IOCPBaseClient::IsConnect()

{

return _stateObject.Socket() != NULL;

}

void IOCPBaseClient::DisConnect()

{

_stateObject.Close();

}

void IOCPBaseClient::Connect(std::string ip, int port, int timeOut)

{

if (_completionPort == NULL)

Init(_threadSize);

WSADATA wsaData;

if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)

throw std::exception(std::string("WSAStartupError : " + std::to_string(GetLastError())).c_str());


auto socket = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);

if (socket == INVALID_SOCKET)

throw std::exception(std::string("SocketCreateError : " + std::to_string(GetLastError())).c_str());


memset(&_iPEndPoint, 0, sizeof(sockaddr_in));

if (inet_pton(AF_INET, ip.c_str(), &_iPEndPoint.sin_addr) != 1)

throw std::exception(std::string("inet_ptonError : " + std::to_string(GetLastError())).c_str());


_iPEndPoint.sin_family = AF_INET;

_iPEndPoint.sin_port = htons(port);


ULONG mode = 1;

::ioctlsocket(socket, FIONBIO, &mode);

if (WSAConnect(socket, (SOCKADDR*)&_iPEndPoint, sizeof(sockaddr_in), NULL, NULL, NULL, NULL) == SOCKET_ERROR)

{

auto error = WSAGetLastError();

if (error == WSAEWOULDBLOCK)

{

TIMEVAL tv;

tv.tv_sec = timeOut / 1000;

tv.tv_usec = 0;

fd_set fdSet, fdError;

FD_ZERO(&fdSet);

FD_ZERO(&fdError);

FD_SET(socket, &fdSet);

FD_SET(socket, &fdError);

::select(0, NULL, &fdSet, &fdError, &tv);

if (FD_ISSET(socket, &fdSet))

{

_stateObject.Socket() = socket;

CreateIoCompletionPort((HANDLE)_stateObject.Socket(), _completionPort, (ULONG_PTR)&_stateObject, 0);

_keepAliveThread = std::make_unique<Util::Threading::Thread>(std::bind(&IOCPBaseClient::KeepAlive, this, std::placeholders::_1), &_stateObject);

_keepAliveThread->Start();

OnConnected(_stateObject);

BeginReceive();

}

else

{

closesocket(socket);

WSACleanup();

throw std::exception(std::string("ConnectFail : " + std::to_string(error)).c_str());

}

}

else

{

closesocket(socket);

WSACleanup();

throw std::exception(std::string("ConnectFail : " + std::to_string(error)).c_str());

}

}

}

void IOCPBaseClient::KeepAlive(void* state)

{

auto stateObject = reinterpret_cast<StateObject*>(state);

if(stateObject == NULL)

_stateObject.Close();

fd_set fdSet;

FD_ZERO(&fdSet);

FD_SET(_stateObject.Socket(), &fdSet);

TIMEVAL tv;

tv.tv_sec = 5;

tv.tv_usec = 1;

while (IsConnect())

{

auto check = fdSet;

auto error = ::select(1, &check, NULL, NULL, &tv);

switch (error)

{

case -1:

Util::Common::Trace::WriteLine(std::string("Error : " + std::to_string(GetLastError())), "KeepAlive");

case 0:

OnKeepAlive(*stateObject);

break;

case 1:

_stateObject.Close();

break;

}

}

}

void IOCPBaseClient::BeginReceive()

{

DWORD flags = 0;

if (WSARecv(_stateObject.Socket(), &_stateObject.WSABuff(), 1, 0, &flags, (LPWSAOVERLAPPED)&_stateObject.ReceiveOverlapped(), NULL) == SOCKET_ERROR)

{

if (WSAGetLastError() != WSA_IO_PENDING)

_stateObject.Close();

}

}

void IOCPBaseClient::Stop()

{

_keepAliveThread.reset();


for (size_t i = 0; i < _hWorkerThread.size(); i++)

PostQueuedCompletionStatus(_completionPort, 0, _CLOSE_THREAD, NULL);

for (size_t i = 0; i < _hWorkerThread.size(); i++)

{

WaitForSingleObject(_hWorkerThread[i], INFINITE);

CloseHandle(_hWorkerThread[i]);

}

_stateObject.Close();

WSACleanup();

CloseHandle(_completionPort);

_completionPort = NULL;

_hWorkerThread.clear();

}

void IOCPBaseClient::Send(Util::Socket::IPacket& packet)

{

_stateObject.Send(packet);

}

int IOCPBaseClient::Invoke()

{

ULONG bytesTrans = 0;

ULONG_PTR stateObject = 0;

Socket::Overlapped* overlapped = nullptr;

while (true)

{

if (!GetQueuedCompletionStatus(_completionPort, &bytesTrans, &stateObject, (LPOVERLAPPED*)&overlapped, INFINITE))

{

auto pHandle = reinterpret_cast<StateObject*>(stateObject);

int error = ::WSAGetLastError();

Common::Trace::WriteLine(std::to_string(error), "Error");

switch (error)

{

case ERROR_NETNAME_DELETED:

case ERROR_SEM_TIMEOUT:

pHandle->Close();

_keepAliveThread.reset();

OnDisconnected();

break;

}

continue;

}

if ((LONG_PTR)stateObject == _CLOSE_THREAD && bytesTrans == 0)

break;

auto pHandle = reinterpret_cast<StateObject*>(stateObject);

if (bytesTrans == 0)

{

pHandle->Close();

_keepAliveThread.reset();

OnDisconnected();

continue;

}

if (overlapped->mode == Socket::Mode::Receive)

{

try

{

pHandle->ReceiveBuffer().Append(_stateObject.WSABuff().buf, bytesTrans);

OnRecieved(*pHandle);

}

catch (const std::exception& ex)

{

Common::Trace::WriteLine(ex.what(), "Invoke");

}

BeginReceive();

}

}

return 0;

}

unsigned int __stdcall IOCPBaseClient::Run(void* obj)

{

auto client = reinterpret_cast<IOCPBaseClient*>(obj);

if (client != NULL)

return client->Invoke();

return 0;

}

void IOCPBaseClient::OnKeepAlive(Util::Socket::StateObject& stateObject)

{

stateObject.Send("", 1);

}

NS_SOCKET_END

반응형

'개발관련 > C&C++' 카테고리의 다른 글

FileLogger  (0) 2018.10.02
반복자(iterator)가 포함된 Queue  (0) 2018.09.08
HttpClient  (0) 2018.05.25
MSMQ(MS MessageQueue)  (0) 2018.05.15
Functional 이용한 델리게이트  (0) 2018.04.26
반응형

code : https://github.com/EomTaeWook/Cpp-Util/tree/master/Util/Web


윈도우 함수 Wrapping


NS.h


#pragma once

#ifndef HTTP_H

#define HTTP_H

#define NS_WEB_HTTP_BEGIN namespace Util { namespace Web { namespace Http {

#define NS_WEB_HTTP_END } } } 

#define USING_WEB_HTTP using namespace Util::Web::Http;


#define NS_WEB_BEGIN namespace Util { namespace Web {

#define NS_WEB_END } }

#define USING_WEB_HTTP using namespace Util::Web::Http;

#define USING_WEB using namespace Util::Web;

#endif


WebEnum.h


#pragma once

#include "NS.h"


NS_WEB_BEGIN


enum class Method

{

Get,

Post,

Put,

Delete

};


NS_WEB_END


Url.h


#pragma once

#pragma once

#include "NS.h"

#include <string>

#include <algorithm>

NS_WEB_BEGIN

class Url

{

public:

Url();

Url(std::string url);

Url(std::wstring url);

virtual ~Url();

private:

std::wstring _path;

std::wstring _protocol;

std::wstring _host;

int _port;

public:

void Parse(std::string url);

void Parse(std::wstring url);

std::wstring GetPath();

std::wstring GetProtocol();

std::wstring GetHost();

int GetPort();

};

inline Url::Url()

{

}

inline Url::Url(std::string url)

{

Parse(std::wstring().assign(url.begin(), url.end()));

}

inline Url::Url(std::wstring url)

{

Parse(url);

}

inline Url::~Url()

{

}

inline void Url::Parse(std::string url)

{

Parse(std::wstring().assign(url.begin(), url.end()));

}

inline void Url::Parse(std::wstring url)

{

if (url.size() == 0) return;

auto beginIdx = url.find(L"://");

if (beginIdx != std::wstring::npos)

{

_protocol = url.substr(0, beginIdx).c_str();

std::transform(_protocol.begin(), _protocol.end(), _protocol.begin(), ::tolower);

beginIdx += 3;

}

else

{

_protocol = L"http";

beginIdx = 0;

}

auto endIdx = url.find(L"/", beginIdx);

if (endIdx != std::wstring::npos)

{

_host = url.substr(beginIdx, endIdx - beginIdx);

std::transform(_host.begin(), _host.end(), _host.begin(), ::tolower);

beginIdx = endIdx;

}

else

_host = url.substr(beginIdx, url.size() - beginIdx);


endIdx = _host.rfind(L":");

if (endIdx != std::wstring::npos)

{

_port = std::stoi(_host.substr(endIdx + 1, _host.size() - endIdx));

_host.erase(endIdx, _host.size() - endIdx);

}

else

_port = 80;

if (beginIdx != 0)

{

_path = url.substr(beginIdx, url.size() - beginIdx);

std::transform(_path.begin(), _path.end(), _path.begin(), ::tolower);

}

}

inline std::wstring Url::GetPath()

{

return _path;

}

inline std::wstring Url::GetProtocol()

{

return _protocol;

}

inline std::wstring Url::GetHost()

{

return _host;

}

inline int Url::GetPort()

{

return _port;

}

NS_WEB_END


HttpClient.h


#pragma once

#include <Windows.h>

#include <winhttp.h>

#include "WebEnum.h"

#include "Url.h"

#include <string>

#include <functional>

#pragma comment(lib ,"winhttp.lib")

NS_WEB_HTTP_BEGIN

class HttpClient

{

public:

HttpClient();

virtual ~HttpClient();

private:

HINTERNET _session;

HINTERNET _connect;

HINTERNET _request;

int _protocolType;

char _buffer[2048];

Url _url;

std::wstring _header;

std::function<void(int, std::string&)> _callback;

std::string _response;

int _responseCode;

public:

void Init(std::string url);

bool SendRequestAsync(std::string requestData = "", Method method = Method::Get, std::function<void(int, std::string&)> callback = nullptr);

std::string SendRequest(std::string requestData = "", Method method = Method::Get);

void HeaderAppend(std::string header);

private:

void Invoke(unsigned long code, void* info, unsigned long length);

void Close();

private:

static void __stdcall Invoke(HINTERNET handle, DWORD_PTR context, DWORD status, void* info, DWORD infoLength);

};

inline HttpClient::HttpClient()

{

_protocolType = 0;

}

inline HttpClient::~HttpClient()

{

Close();

}

NS_WEB_HTTP_END


HttpClient.cpp


#include "HttpClient.h"

NS_WEB_HTTP_BEGIN

void HttpClient::Init(std::string url)

{

try

{

_url.Parse(url);

if (_url.GetProtocol() == L"https")

_protocolType = WINHTTP_FLAG_SECURE;

}

catch (...)

{

throw std::exception("InitException");

}

}

std::string HttpClient::SendRequest(std::string requestData, Method method)

{

try

{

_session = WinHttpOpen(L"0",

WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,

WINHTTP_NO_PROXY_NAME,

WINHTTP_NO_PROXY_BYPASS,

0);

if (_session)

{

_connect = WinHttpConnect(_session,

_url.GetHost().c_str(),

_url.GetPort(),

0);

}

std::wstring type = L"GET";

std::wstring path = _url.GetPath().c_str();

switch (method)

{

case Method::Get:

path.append(requestData.begin(), requestData.end());

requestData.clear();

break;

case Method::Post:

type = L"POST";

break;

case Method::Put:

type = L"PUT";

break;

case Method::Delete:

type = L"Delete";

break;

}


_request = WinHttpOpenRequest(_connect,

type.c_str(),

path.c_str(),

NULL,

WINHTTP_NO_REFERER,

WINHTTP_DEFAULT_ACCEPT_TYPES,

_protocolType);


if (_header.size() == 0)

_header = L"content-type:application/x-www-form-urlencoded";


WinHttpAddRequestHeaders(_request, _header.c_str(), (DWORD)_header.size(), WINHTTP_ADDREQ_FLAG_ADD);


if (WinHttpSendRequest(_request,

WINHTTP_NO_ADDITIONAL_HEADERS,

0,

(LPVOID)requestData.c_str(),

(DWORD)requestData.size(),

(DWORD)requestData.size(),

(DWORD_PTR)this))

{

if (WinHttpReceiveResponse(_request, NULL))

{

unsigned long readSize = 0;

do

{

WinHttpQueryDataAvailable(_request, &readSize);

if (readSize <= 0) break;

WinHttpReadData(_request, _buffer, sizeof(_buffer), &readSize);

_response.append(_buffer, readSize);

readSize = 0;

} while (readSize > 0);

}

}

else

{

throw std::exception();

}

}

catch (...)

{

Close();

throw std::exception("RequestException");

}

Close();

return _response;

}

bool HttpClient::SendRequestAsync(std::string requestData, Method method, std::function<void(int, std::string&)> callback)

{

try

{

_session = WinHttpOpen(L"0",

WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,

WINHTTP_NO_PROXY_NAME,

WINHTTP_NO_PROXY_BYPASS,

WINHTTP_FLAG_ASYNC);


if (_session)

{

_connect = WinHttpConnect(_session,

_url.GetHost().c_str(),

_url.GetPort(),

0);

}


std::wstring type = L"GET";

std::wstring path = _url.GetPath().c_str();

_callback = callback;

switch (method)

{

case Method::Get:

path.append(requestData.begin(), requestData.end());

requestData.clear();

break;

case Method::Post:

type = L"POST";

break;

case Method::Put:

type = L"PUT";

break;

case Method::Delete:

type = L"Delete";

break;

}


_request = WinHttpOpenRequest(_connect,

type.c_str(),

path.c_str(),

NULL,

WINHTTP_NO_REFERER,

WINHTTP_DEFAULT_ACCEPT_TYPES,

_protocolType);


if (_header.size() == 0)

_header = L"content-type:application/x-www-form-urlencoded";


WinHttpAddRequestHeaders(_request, _header.c_str(), (DWORD)_header.size(), WINHTTP_ADDREQ_FLAG_ADD);


WinHttpSetStatusCallback(_request,

HttpClient::Invoke,

WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS,

0);


auto result = WinHttpSendRequest(_request,

WINHTTP_NO_ADDITIONAL_HEADERS,

0,

(LPVOID)requestData.c_str(),

(DWORD)requestData.size(),

(DWORD)requestData.size(),

(DWORD_PTR)this);

return result;

}

catch (...)

{

throw std::exception("RequestException");

}

}

void HttpClient::HeaderAppend(std::string header)

{

if (header.size() == 0) return;

auto data = std::wstring().assign(header.begin(), header.end());

_header.append(data + L"\n");

}

void HttpClient::Close()

{

if (_request) WinHttpCloseHandle(_request);

if (_connect) WinHttpCloseHandle(_connect);

if (_session) WinHttpCloseHandle(_session);

}


void HttpClient::Invoke(unsigned long code, void* info, unsigned long length)

{

switch (code)

{

case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:

WinHttpReceiveResponse(_request, NULL);

break;

case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:

{

unsigned long status = 0;

unsigned long statusSize = sizeof(unsigned long);

std::string response;

WinHttpQueryHeaders(_request,

WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,

WINHTTP_HEADER_NAME_BY_INDEX,

&status,

&statusSize,

WINHTTP_NO_HEADER_INDEX);

_responseCode = status;

WinHttpQueryDataAvailable(_request, NULL);

break;

}

case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE:

{

WinHttpReadData(_request, &_buffer, sizeof(_buffer), NULL);

break;

}

case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:

{

if (length != 0)

{

_response.append(_buffer, length);

WinHttpQueryDataAvailable(_request, NULL);

}

else

{

if (_callback != nullptr)

{

_callback(_responseCode, _response);

this->Close();

}

}

break;

}

case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:

if (_callback != nullptr)

{

_callback(code, _response.append("WINHTTP_CALLBACK_STATUS_REQUEST_ERROR"));

this->Close();

}

break;

}

}

void __stdcall HttpClient::Invoke(HINTERNET handle, DWORD_PTR context, DWORD status, void* info, DWORD infoLength)

{

auto client = reinterpret_cast<HttpClient*>(context);

if (client != NULL)

client->Invoke(status, info, infoLength);

}

NS_WEB_HTTP_END

반응형

'개발관련 > C&C++' 카테고리의 다른 글

반복자(iterator)가 포함된 Queue  (0) 2018.09.08
IOCP Socket Client 구현  (0) 2018.05.31
MSMQ(MS MessageQueue)  (0) 2018.05.15
Functional 이용한 델리게이트  (0) 2018.04.26
IOCP Socket Server 구현  (0) 2018.04.16
반응형

code : https://github.com/EomTaeWook/Cpp-Util/tree/master/Util/System/Message


C#은 워낙 API가 잘되어 있어서 사용법이 간단함.


Receive 동기적


Receive 쪽은 C#은 10만건 1700byte를 전체 Read 하는데 6초 정도 걸리고 C++은 3초 후반대 정도임.

Send 쪽은 C# 10만건 1700byte 4초, C++ 1.7초...


API와 사용법을 좀 더 찾아보고 다른 MQ 속도도 비교해보고 속도 개선 해봐야 할 듯


C#>> 


namespace MSMQ

{

    //Send {00:00:04.3840442}

    //Receive {00:00:05.5640045}

    //한글 690 자 1700 byte

    class Program

    {

        static void Main(string[] args)

        {

            string _path = @".\Private$\NotifyQueue";

            MessageQueue _mq = null;

            if (MessageQueue.Exists(_path))

            {

                _mq = new MessageQueue(_path);

            }

            else

                _mq = MessageQueue.Create(_path);


            var now = DateTime.Now;

            for (int i = 0; i < 100000; i++)

                _mq.Send(@"{ 계절이 지나가는 하늘에는 ...");

            for (int i = 0; i < 100000; i++)

            {

                var m = _mq.Receive(MessageQueueTransactionType.None);

                var data = m.Body;

            }

  _mq.Dispose();

        }

    }

}


C++>> API Class Wrapping


NS.h


#pragma once


#ifndef MESSAGE_MSMQ_H

#define MESSAGE_MSMQ_H

#define NS_MESSAGE_MSMQ_BEGIN namespace Util { namespace Message { namespace MS { 

#define NS_MESSAGE_MSMQ_END } } }

#define USING_MESSAGE_MSMQ using namespace Util::Message::MS;

#endif


MessageQueue.h


#pragma once


#include <Windows.h>

#include <Mq.h>

#include <string>


#include "NS.h"

#include "MSMQEnum.h"

#include "Message.h"

#pragma comment (lib, "Mqrt.lib")


NS_MESSAGE_MSMQ_BEGIN

class MessageQueue

{

private:

HANDLE _hQueue;

MessageQueueMode _mode;

public:

MessageQueue()

{

_hQueue = INVALID_HANDLE_VALUE;

}

virtual ~MessageQueue()

{

MQCloseQueue(_hQueue);

}

public:

void Init(std::wstring pathName, MessageQueueMode mode);

HRESULT Receive(Message& message, int timeOutMillis);

HRESULT Send(Message& message);

bool IsRead();

};

inline bool MessageQueue::IsRead() { return _mode == MessageQueueMode::READ; }

NS_MESSAGE_MSMQ_END



MessageQueue.cpp


#include "MessageQueue.h"


NS_MESSAGE_MSMQ_BEGIN


void MessageQueue::Init(std::wstring pathName, MessageQueueMode mode)

{

if (pathName.size() == 0)

throw "MQ_ERROR_INVALID_PARAMETER";


_mode = mode;

DWORD formatNameBufferLength = 256;

WCHAR formatNameBuffer[256];

auto hr = MQPathNameToFormatName(pathName.c_str(),

formatNameBuffer,

&formatNameBufferLength);


if (FAILED(hr))

{

// Set queue properties.

const int NUMBEROFPROPERTIES = 1;

MQQUEUEPROPS queueProps;

QUEUEPROPID queuePropId[NUMBEROFPROPERTIES];

MQPROPVARIANT queuePropVar[NUMBEROFPROPERTIES];

HRESULT queueStatus[NUMBEROFPROPERTIES];

DWORD propId = 0;

queuePropId[propId] = PROPID_Q_PATHNAME;

queuePropVar[propId].vt = VT_LPWSTR;

queuePropVar[propId].pwszVal = const_cast<wchar_t*>(pathName.c_str());

propId++;


queueProps.cProp = propId;

queueProps.aPropID = queuePropId;

queueProps.aPropVar = queuePropVar;

queueProps.aStatus = queueStatus;


MQCreateQueue(NULL, &queueProps, formatNameBuffer, &formatNameBufferLength);

}

if (_mode == MessageQueueMode::READ)

MQOpenQueue(formatNameBuffer, (int)MessageQueueAccess::RECEIVE_ACCESS, (int)MessageQueueShare::DENY_RECEIVE_SHARE, &_hQueue);

else

MQOpenQueue(formatNameBuffer, (int)MessageQueueAccess::SEND_ACCESS, (int)MessageQueueShare::DENY_NONE, &_hQueue);

}

HRESULT MessageQueue::Receive(Message& message, int timeOutMillis)

{

if (_hQueue == NULL)

throw "Invalid Handle";


// Define an MQMSGPROPS structure.

const int NUMBEROFPROPERTIES = 5;

DWORD propId = 0;


MQMSGPROPS msgProps;

MSGPROPID msgPropId[NUMBEROFPROPERTIES];

MQPROPVARIANT msgPropVar[NUMBEROFPROPERTIES];

HRESULT msgStatus[NUMBEROFPROPERTIES];


// Specify the message properties to be retrieved.  

msgPropId[propId] = PROPID_M_LABEL_LEN;           // Property ID  

msgPropVar[propId].vt = VT_UI4;                   // Type indicator  

msgPropVar[propId].ulVal = MQ_MAX_MSG_LABEL_LEN;  // Length of label  

propId++;


WCHAR labelBuffer[MQ_MAX_MSG_LABEL_LEN];        // Label buffer  

msgPropId[propId] = PROPID_M_LABEL; // Property ID  

msgPropVar[propId].vt = VT_LPWSTR; // Type indicator  

msgPropVar[propId].pwszVal = labelBuffer;       // Label buffer  

propId++;


msgPropId[propId] = PROPID_M_BODY_SIZE;           // Property ID  

msgPropVar[propId].vt = VT_NULL;                  // Type indicator  

propId++;


msgPropId[propId] = PROPID_M_BODY; // Property ID  

msgPropVar[propId].vt = VT_VECTOR | VT_UI1; // Type indicator

msgPropVar[propId].caub.pElems = message.GetBuffer().get(); // Body buffer

msgPropVar[propId].caub.cElems = message.GetBufferSize(); // Buffer size

propId++;


msgPropId[propId] = PROPID_M_BODY_TYPE; // Property ID

msgPropVar[propId].vt = VT_NULL; // Type indicator

propId++;


// Initialize the MQMSGPROPS structure.  

msgProps.cProp = propId; // Number of message properties  

msgProps.aPropID = msgPropId; // IDs of the message properties  

msgProps.aPropVar = msgPropVar; // Values of the message properties  

msgProps.aStatus = msgStatus; // Error reports  


msgPropVar[0].ulVal = MQ_MAX_MSG_LABEL_LEN;

auto hr = MQReceiveMessage(_hQueue,

timeOutMillis,

MQ_ACTION_RECEIVE,

&msgProps,

NULL,

NULL,

NULL,

MQ_NO_TRANSACTION);

if (hr == S_OK)

message.SetReadSize(msgPropVar[2].ulVal);

return hr;

}

HRESULT MessageQueue::Send(Message& message)

{

if (_hQueue == NULL)

throw "Invalid Handle";


const int NUMBEROFPROPERTIES = 2;

DWORD propId = 0;


// Define an MQMSGPROPS structure.  

MQMSGPROPS msgProps;

MSGPROPID msgPropId[NUMBEROFPROPERTIES];

MQPROPVARIANT msgPropVar[NUMBEROFPROPERTIES];

HRESULT msgStatus[NUMBEROFPROPERTIES];


// Specify the message properties to be retrieved.  

msgPropId[propId] = PROPID_M_BODY; // Property ID 

msgPropVar[propId].vt = VT_VECTOR | VT_UI1; // Type indicator  

msgPropVar[propId].caub.pElems = message.GetBuffer().get(); // Body buffer

msgPropVar[propId].caub.cElems = message.GetBufferSize(); // Buffer size

propId++;


msgPropId[propId] = PROPID_M_LABEL; // Property ID  

msgPropVar[propId].vt = VT_LPWSTR; // Type indicator  

msgPropVar[propId].pwszVal = L"";       // Label buffer  

propId++;


// Initialize the MQMSGPROPS structure.  

msgProps.cProp = propId;

msgProps.aPropID = msgPropId;

msgProps.aPropVar = msgPropVar;

msgProps.aStatus = msgStatus;


return MQSendMessage(_hQueue, &msgProps, MQ_NO_TRANSACTION);

}

NS_MESSAGE_MSMQ_END


Message.h


#pragma once

#include <memory>

#include <string>

#include "NS.h"


NS_MESSAGE_MSMQ_BEGIN

class Message

{

private:

std::unique_ptr<unsigned char[]> _buffer;

int _bufferSize = 4096;

int _readSize = 0;

public:

Message() : Message(4096)

{

}

Message(int bufferSize) : Message("", bufferSize)

{

}

Message(char* buffer, int bufferSize) : _bufferSize(bufferSize)

{

_buffer = std::make_unique<unsigned char[]>(bufferSize);

memcpy(_buffer.get(), buffer, bufferSize);

}

Message(std::string item)

{

_buffer = std::make_unique<unsigned char[]>(item.size());

memcpy(_buffer.get(), item.c_str(), item.size());

_bufferSize = item.size();

}


virtual ~Message() {

_buffer.reset();

}

public:

std::unique_ptr<unsigned char[]>& GetBuffer();

int GetBufferSize();

std::string GetBody();

void SetReadSize(int size);

};

inline std::unique_ptr<unsigned char[]>& Message::GetBuffer()

{

return _buffer;

}

inline void Message::SetReadSize(int size)

{

_readSize = size;

}

inline int Message::GetBufferSize()

{

return _bufferSize;

}

inline std::string Message::GetBody()

{

std::string body(reinterpret_cast<char*>(_buffer.get()));

auto begin = body.find("<string>") + 8;

auto end = body.rfind("</string>") - begin;

return body.substr(begin, end);

}

NS_MESSAGE_MSMQ_END


MSMQEnum.h


#pragma once


#include "NS.h"


NS_MESSAGE_MSMQ_BEGIN

enum class MessageQueueAccess

{

RECEIVE_ACCESS = 1,

SEND_ACCESS = 2,

MOVE_ACCESS = 4,

PEEK_ACCESS = 32,

ADMIN_ACCESS = 128

};

enum class MessageQueueMode

{

READ = 1,

WRITE = 2,

};

enum class MessageQueueShare

{

DENY_NONE = 0,

DENY_RECEIVE_SHARE = 1

};

NS_MESSAGE_MSMQ_END

반응형

'개발관련 > C&C++' 카테고리의 다른 글

IOCP Socket Client 구현  (0) 2018.05.31
HttpClient  (0) 2018.05.25
Functional 이용한 델리게이트  (0) 2018.04.26
IOCP Socket Server 구현  (0) 2018.04.16
StringFormat  (0) 2018.03.20
반응형

C++용 소켓 서버/클라이언트 콜백 메소드를 담기위해 만듦.


모든 델리게이터는 MulticastDelegate로만 생성 하거나 상속


NS.h


#pragma once

#ifndef COMMON_H

#define COMMON_H

#define NS_COMMON_BEGIN namespace Util { namespace Common {

#define NS_COMMON_END } }

#define USING_COMMON using namespace Util::Common;

#endif


Delegate.h


#pragma once

#include "NS.h"

#include <functional>

#include <vector>

NS_COMMON_BEGIN

template<typename R, typename T1, typename T2, typename T3, typename T4, typename T5>

class MulticastDelegate;


template<typename R, typename ...Types>

class Delegate

{

private:

template<typename R, typename T1, typename T2, typename T3, typename T4, typename T5>

friend class MulticastDelegate;

protected:

std::vector<std::function<R(Types...)>> _methods;

private:

Delegate();

public:

virtual ~Delegate();

public:

R operator() (Types...);

bool operator != (const Delegate& d) const;

bool operator != (nullptr_t) const;

bool operator == (const Delegate& d) const;

bool operator == (nullptr_t) const;

Delegate& operator = (const nullptr_t);

Delegate& operator = (const std::function<R(Types...)>&);

Delegate& operator += (const std::function<R(Types...)>&);

public:

virtual Delegate& Combine(const Delegate&);

virtual Delegate& operator + (const Delegate&);

};

template<typename R, typename ...Types>

inline Delegate<R, Types...>::Delegate()

{

_methods.clear();

}

template<typename R, typename ...Types>

inline Delegate<R, Types...>::~Delegate()

{

_methods.clear();

}


template<typename R, typename ...Types>

inline Delegate<R, Types...>& Delegate<R, Types...>::Combine(const Delegate<R, Types...>& other)

{

for (auto m : other._methods)

{

_methods.push_back(m);

}

return *this;

}

template<typename R, typename ...Types>

inline Delegate<R, Types...>& Delegate<R, Types...>::operator += (const std::function<R(Types...)>& method)

{

if (method == nullptr)

return;

_methods.push_back(method);

return *this;

}

template<typename R, typename ...Types>

inline Delegate<R, Types...>& Delegate<R, Types...>::operator + (const Delegate<R, Types...>& other)

{

return Combine(other);

}

template<typename R, typename ...Types>

inline Delegate<R, Types...>& Delegate<R, Types...>::operator = (const std::function<R(Types...)>& method)

{

if (method == nullptr)

return *this;

_methods.clear();

_methods.push_back(method);

return *this;

}


template<>

inline void Delegate<void>::operator() ()

{

for (auto m : _methods)

{

m();

}

}

template<typename R, typename ...Types>

inline R Delegate<R, Types...>::operator() (Types... params)

{

for (size_t i = 0; i < _methods.size() - 1; i++)

{

_methods[i](std::forward<Types>(params)...);

}

return _methods.back()(std::forward<Types>(params)...);

}

template<typename R, typename ...Types>

inline bool Delegate<R, Types...>::operator != (nullptr_t) const

{

return _methods.size() != 0;

}


template<typename R, typename ...Types>

inline bool Delegate<R, Types...>::operator != (const Delegate<R, Types...>& del) const

{

return this != &del;

}


template<typename R, typename ...Types>

inline bool Delegate<R, Types...>::operator == (nullptr_t) const

{

return _methods.size() == 0;

}


template<typename R, typename ...Types>

inline bool Delegate<R, Types...>::operator == (const Delegate<R, Types...>& del) const

{

return this == &del;

}


template<typename R, typename ...Types>

inline Delegate<R, Types...>& Delegate<R, Types...>::operator = (const nullptr_t)

{

_methods.clear();

return *this;

}


NS_COMMON_END



MulticastDelegate.h


#pragma once

#include "NS.h"

#include "Delegate.h"

NS_COMMON_BEGIN

template<typename R, typename T1 = void, typename T2 = void, typename T3 = void, typename T4 = void, typename T5 = void>

class MulticastDelegate : public Delegate<R, T1, T2, T3, T4, T5>

{

private :

typedef const std::function<R(T1, T2, T3, T4, T5)> DelegateType;

public:

MulticastDelegate()

{

}

MulticastDelegate(DelegateType& method)

{

this->operator= (method);

}

virtual ~MulticastDelegate() {}

public:

MulticastDelegate& operator = (DelegateType& method);

};

template<typename R, typename T1, typename T2, typename T3, typename T4, typename T5>

inline MulticastDelegate<R, T1, T2, T3, T4, T5>& MulticastDelegate<R, T1, T2, T3, T4, T5>::operator = (DelegateType& method)

{

Delegate<R, T1, T2, T3, T4, T5>::operator = (method);

return *this;

}


template<typename R, typename T1, typename T2, typename T3, typename T4>

class MulticastDelegate<R, T1, T2, T3, T4, void> : public Delegate<R, T1, T2, T3, T4>

{

private:

typedef const std::function<R(T1, T2, T3, T4)> DelegateType;

public:

MulticastDelegate()

{

}

MulticastDelegate(DelegateType method)

{

this->operator= (method);

}

virtual ~MulticastDelegate() {}

public:

MulticastDelegate& operator = (DelegateType& method);

};

template<typename R, typename T1, typename T2, typename T3, typename T4>

inline MulticastDelegate<R, T1, T2, T3, T4>& MulticastDelegate<R, T1, T2, T3, T4>::operator = (DelegateType& method)

{

Delegate<R, T1, T2, T3, T4>::operator = (method);

return *this;

}


template<typename R, typename T1, typename T2, typename T3>

class MulticastDelegate<R, T1, T2, T3, void, void> : public Delegate<R, T1, T2, T3>

{

private:

typedef const std::function<R(T1, T2, T3)> DelegateType;

public:

MulticastDelegate()

{

}

MulticastDelegate(DelegateType& method)

{

this->operator= (method);

}

virtual ~MulticastDelegate() {}

public:

MulticastDelegate& operator = (DelegateType& method);

};

template<typename R, typename T1, typename T2, typename T3>

inline MulticastDelegate<R, T1, T2, T3>& MulticastDelegate<R, T1, T2, T3>::operator = (DelegateType& method)

{

Delegate<R, T1, T2, T3>::operator = (method);

return *this;

}


template<typename R, typename T1, typename T2>

class MulticastDelegate<R, T1, T2, void, void, void> : public Delegate<R, T1, T2>

{

private:

typedef const std::function<R(T1, T2)> DelegateType;

public:

MulticastDelegate()

{

}

MulticastDelegate(DelegateType& method)

{

this->operator= (method);

}

virtual ~MulticastDelegate() {}

public:

MulticastDelegate& operator = (DelegateType& method);

};

template<typename R, typename T1, typename T2>

inline MulticastDelegate<R, T1, T2>& MulticastDelegate<R, T1, T2>::operator = (DelegateType& method)

{

Delegate<R, T1, T2>::operator = (method);

return *this;

}


template<typename R, typename T>

class MulticastDelegate<R, T, void, void, void, void> : public Delegate<R, T>

{

private:

typedef const std::function<R(T)> DelegateType;

public:

MulticastDelegate()

{

}

MulticastDelegate(DelegateType& method)

{

this->operator= (method);

}

virtual ~MulticastDelegate() {}

public:

MulticastDelegate& operator = (DelegateType&);

};

template<typename R, typename T>

inline MulticastDelegate<R, T>& MulticastDelegate<R, T>::operator = (DelegateType& method)

{

Delegate<R, T>::operator = (method);

return *this;

}


template<typename R>

class MulticastDelegate<R, void, void, void, void, void> : public Delegate<R>

{

private:

typedef const std::function<R()> DelegateType;

public:

MulticastDelegate()

{

}

MulticastDelegate(DelegateType& method)

{

this->operator= (method);

}

virtual ~MulticastDelegate() {}

public:

MulticastDelegate& operator = (DelegateType& method);

};


template<typename R>

inline MulticastDelegate<R>& MulticastDelegate<R>::operator = (DelegateType& method)

{

Delegate<R>::operator = (method);

return *this;

}

NS_COMMON_END

반응형

'개발관련 > C&C++' 카테고리의 다른 글

HttpClient  (0) 2018.05.25
MSMQ(MS MessageQueue)  (0) 2018.05.15
IOCP Socket Server 구현  (0) 2018.04.16
StringFormat  (0) 2018.03.20
라이브러리 빌드 전/후 이벤트 명령어  (0) 2018.03.16
반응형

code : https://github.com/EomTaeWook/Cpp-Util/tree/master/Util/Socket


IOCPServerSocket.h


#pragma once

#include "NS.h"

#include "IOCPBaseServer.h"


NS_SOCKET_BEGIN

template<typename ProtocolType, typename ...Types>

class IOCPServerSocket : public IOCPBaseServer

{

protected:

IOCPServerSocket();

public:

virtual ~IOCPServerSocket();

protected:

std::map<ProtocolType, Util::Common::MulticastDelegate<void, Util::Socket::StateObject&, Types...>> _funcMaps;

public:

void BindCallback(ProtocolType protocol, std::function<void(Util::Socket::StateObject&, Types...)> callback);

void OnCallback(ProtocolType protocol, Util::Socket::StateObject& stateObject, Types...);

};

template<typename ProtocolType, typename ...Types>

IOCPServerSocket<ProtocolType, Types...>::IOCPServerSocket()

{

}

template<typename ProtocolType, typename ...Types>

IOCPServerSocket<ProtocolType, Types...>::~IOCPServerSocket()

{

}

template<typename ProtocolType, typename ...Types>

inline void IOCPServerSocket<ProtocolType, Types...>::BindCallback(ProtocolType protocol, std::function<void(Util::Socket::StateObject&, Types...)> callback)

{

if (_funcMaps.find(protocol) == _funcMaps.end())

_funcMaps.insert(std::pair<ProtocolType, Util::Common::MulticastDelegate<void, Util::Socket::StateObject&, Types...>>(protocol, std::move(callback)));

else

throw std::exception("An item with the same key has already been Added");

}

template<typename ProtocolType, typename ...Types>

inline void IOCPServerSocket<ProtocolType, Types...>::OnCallback(ProtocolType protocol, Util::Socket::StateObject& stateObject, Types... params)

{

try

{

auto it = _funcMaps.find(protocol);

if (it != _funcMaps.end())

{

it->second(std::forward<Util::Socket::StateObject&>(stateObject), std::forward<Types>(params)...);

}

}

catch (std::exception ex)

{

ex.what();

}

catch (...)

{

}

}

NS_SOCKET_END


IOCPBaseServer.h


#pragma once

#include "NS.h"

#include <WinSock2.h>

#include "StateObject.h"

#include <WS2tcpip.h>

#include <string>

#include <vector>

#include <memory>

#include "../Threading/Thread.h"

#include "SyncCount.h"

#include "IPacket.h"

#include <map>

#pragma comment(lib, "Ws2_32.lib")


NS_SOCKET_BEGIN

class IOCPBaseServer

{

private:

static const LONGLONG _CLOSE_THREAD = -1;

protected:

IOCPBaseServer();

public:

virtual ~IOCPBaseServer();

private:

std::unique_ptr<Util::Threading::Thread> _thread;

std::map<unsigned long, std::shared_ptr<StateObject>> _clients;

bool _isStart;

HANDLE _completionPort;

std::vector<HANDLE> _hWorkerThread;

sockaddr_in _iPEndPoint;

SyncCount _handleCount;

private:

SOCKET _listener;

Util::Threading::CriticalSection _remove;

Util::Threading::CriticalSection _read;

public:

void Start(std::string ip, int port);

void Stop();

private:

void BeginReceive(StateObject* pStateObject);

int Invoke();

void StartListening(void* pObj = nullptr);

void AddPeer(StateObject* pStateObject);

void ClosePeer(StateObject* pStateObject);

public:

void Init(UINT threadSize = 0);

protected:

//abstract Method

virtual void OnAccepted(Util::Socket::StateObject& stateObject) = 0;

virtual void OnDisconnected(unsigned long handle) = 0;

virtual void OnRecieved(Util::Socket::StateObject& stateObject) = 0;

//virtual

virtual void BroadCast(Util::Socket::IPacket& packet, StateObject state);

private:

static unsigned int __stdcall Run(void*);

};

inline IOCPBaseServer::IOCPBaseServer()

{

_completionPort = NULL;

_isStart = false;

}

inline IOCPBaseServer::~IOCPBaseServer()

{

Stop();

}

NS_SOCKET_END


IOCPBaseServer.cpp


#include "IOCPBaseServer.h"

#include "..\Common\Finally.h"

#include <iostream>


NS_SOCKET_BEGIN

void IOCPBaseServer::Stop()

{

_isStart = false;


for (auto it = _clients.begin(); it != _clients.end(); ++it)

{

it->second->Close();

it->second.reset();

}

_clients.clear();


for (size_t i = 0; i < _hWorkerThread.size(); i++)

PostQueuedCompletionStatus(_completionPort, 0, _CLOSE_THREAD, NULL);

for (size_t i = 0; i < _hWorkerThread.size(); i++)

{

WaitForSingleObject(_hWorkerThread[i], INFINITE);

CloseHandle(_hWorkerThread[i]);

}

closesocket(_listener);

WSACleanup();

_listener = NULL;

CloseHandle(_completionPort);

_completionPort = NULL;

_hWorkerThread.clear();

}

void IOCPBaseServer::Init(UINT threadSize)

{

_completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);

if (_completionPort == INVALID_HANDLE_VALUE)

throw std::exception("CreateIoCompletionPort Fail");


SYSTEM_INFO info;

GetSystemInfo(&info);

if (threadSize > 0)

{

if (info.dwNumberOfProcessors * 2 < threadSize)

threadSize = info.dwNumberOfProcessors * 2;

else

threadSize = info.dwNumberOfProcessors * 2;

}

else

threadSize = info.dwNumberOfProcessors * 2;

for (size_t i = 0; i < threadSize; i++)

_hWorkerThread.push_back((HANDLE)_beginthreadex(0, 0, Run, this, 0, NULL));

}

void IOCPBaseServer::Start(std::string ip, int port)

{

if (_isStart) return;

try

{

if (_completionPort == NULL)

Init();

WSADATA _wsaData;

if (WSAStartup(MAKEWORD(2, 2), &_wsaData) != 0)

throw std::exception();

if (_thread.get() == NULL)

{

_isStart = true;

memset(&_iPEndPoint, 0, sizeof(_iPEndPoint));

if (inet_pton(PF_INET, ip.c_str(), &_iPEndPoint) != 1)

{

throw std::exception();

}

_iPEndPoint.sin_family = PF_INET;

_iPEndPoint.sin_port = htons(port);

_listener = WSASocketW(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);

if (_listener == INVALID_SOCKET)

{

auto error = GetLastError();

Stop();

throw std::exception("Listener Create Error : " + error);

}


//accept시 NonBlock

//unsigned long mode = 1;

//ioctlsocket(_listener, FIONBIO, &mode);

int option = 1;

setsockopt(_listener, SOL_SOCKET, SO_REUSEADDR, (char*)&option, sizeof(option));

if (::bind(_listener, (SOCKADDR*)&_iPEndPoint, sizeof(_iPEndPoint)) == SOCKET_ERROR)

{

auto error = GetLastError();

Stop();

throw std::exception("BindException : " + error);

}

if (listen(_listener, 100) == SOCKET_ERROR)

{

auto error = GetLastError();

Stop();

throw std::exception("ListenExcption : " + error);

}

_thread = std::make_unique<Threading::Thread>(std::bind(&IOCPBaseServer::StartListening, this, nullptr));

_thread->Start();

}

}

catch (...)

{

_isStart = false;

throw std::exception("Server Start Fail");

}

}


void IOCPBaseServer::StartListening(void* pObj)

{

while (_isStart)

{

SOCKADDR_IN clientAddr;

int size = sizeof(clientAddr);

memset(&clientAddr, 0, size);

SOCKET handler = accept(_listener, (SOCKADDR*)&clientAddr, &size);

if (handler == INVALID_SOCKET)

continue;

auto stateObject = new StateObject();

stateObject->Socket() = handler;

std::memcpy(&stateObject->SocketAddr(), &clientAddr, size);

stateObject->Handle() = _handleCount.Add();

AddPeer(stateObject);

OnAccepted(*stateObject);

CreateIoCompletionPort((HANDLE)stateObject->Socket(), _completionPort, (ULONG_PTR)stateObject, 0);

BeginReceive(stateObject);

}

}

void IOCPBaseServer::BeginReceive(Socket::StateObject* pStateObject)

{

DWORD flags = 0;

if (WSARecv(pStateObject->Socket(), &pStateObject->WSABuff(), 1, 0, &flags, (LPWSAOVERLAPPED)(&pStateObject->ReceiveOverlapped()), NULL) == SOCKET_ERROR)

{

int error = WSAGetLastError();

if (error != WSA_IO_PENDING)

ClosePeer(pStateObject);

}

}

int IOCPBaseServer::Invoke()

{

unsigned long bytesTrans = 0;

ULONG_PTR stateObject = 0;

Socket::Overlapped* overlapped;

while (true)

{

if (!GetQueuedCompletionStatus(_completionPort, &bytesTrans, &stateObject, (LPOVERLAPPED *)&overlapped, INFINITE))

{

int error = WSAGetLastError();

if (error != ERROR_NETNAME_DELETED)

{

printf("Error : %d", error);

break;

}

}

if ((LONG_PTR)stateObject == _CLOSE_THREAD && bytesTrans == 0)

break;

auto pHandler = reinterpret_cast<StateObject*>(stateObject);

if (bytesTrans == 0)

{

ClosePeer(pHandler);

continue;

}

if (overlapped->mode == Util::Socket::Mode::Receive)

{

pHandler->ReceiveBuffer().Append(pHandler->WSABuff().buf, bytesTrans);

try

{

OnRecieved(*pHandler);

}

catch (std::exception ex)

{

printf("%s", ex.what());

}

BeginReceive(pHandler);

}

}

return 0;

}

void IOCPBaseServer::AddPeer(StateObject* pStateObject)

{

auto finally = Common::Finally(std::bind(&Threading::CriticalSection::LeaveCriticalSection, &_read));

try

{

_read.EnterCriticalSection();

auto it = _clients.find(pStateObject->Handle());

if (it != _clients.end())

{

it->second.get()->Close();

it->second.reset();

_clients.erase(pStateObject->Handle());

}

auto _pStateObject = std::make_shared<StateObject>(*pStateObject);

_clients.insert(std::make_pair(_pStateObject->Handle(), std::move(_pStateObject)));

}

catch (...)

{

}

}

void IOCPBaseServer::ClosePeer(StateObject* pStateObject)

{

auto finally = Common::Finally(std::bind(&Threading::CriticalSection::LeaveCriticalSection, &_remove));

try

{

_remove.EnterCriticalSection();

auto handle = pStateObject->Handle();

auto it = _clients.find(handle);

if (it != _clients.end())

{

it->second.get()->Close();

it->second.reset();

_clients.erase(it);

OnDisconnected(handle);

}

else

{

if (pStateObject->Socket() != NULL)

{

pStateObject->Close();

delete pStateObject;

pStateObject = nullptr;

}

}

}

catch (...)

{

}

}

void IOCPBaseServer::BroadCast(Util::Socket::IPacket& packet, StateObject state)

{

}

unsigned int __stdcall IOCPBaseServer::Run(void* obj)

{

auto server = reinterpret_cast<IOCPBaseServer*>(obj);

return server->Invoke();

}

NS_SOCKET_END


StateObject.h


#pragma once

#include "NS.h"

#include <WinSock2.h>

#include <memory>

#include "DefaultPacket.h"

#include "../Collections/SyncQueue.h"

#include "Overlapped.h"


NS_SOCKET_BEGIN

class StateObject

{

public:

StateObject();

virtual ~StateObject();

private:

static const int BUFF_SIZE = 4096;

private:

SOCKET _sock;

SOCKADDR_IN _addr;

Overlapped _receiveOverlapped;

Overlapped _sendOverlapped;

WSABUF _wsaBuf;

char _buffer[BUFF_SIZE];

unsigned long _handle;

Util::Collections::SyncQueue<char> _receiveBuffer;

Util::Collections::SyncQueue<Util::Socket::IPacket*> _receivePacketBuffer;

public:

SOCKET & Socket();

SOCKADDR_IN& SocketAddr();

Overlapped& ReceiveOverlapped();

WSABUF& WSABuff();

unsigned long& Handle();

Util::Collections::SyncQueue<char>& ReceiveBuffer();

Util::Collections::SyncQueue<Util::Socket::IPacket*>& ReceivePacketBuffer();

public:

void Close();

void Send(Util::Socket::IPacket& packet);

};


inline StateObject::StateObject()

{

memset(&_receiveOverlapped, 0, sizeof(Overlapped));


memset(&_sendOverlapped, 0, sizeof(Overlapped));

_sendOverlapped.mode = Socket::Mode::Send;


_wsaBuf.len = BUFF_SIZE;

_wsaBuf.buf = _buffer;

_sock = NULL;

}

inline StateObject::~StateObject()

{

Close();

}


inline Util::Collections::SyncQueue<Util::Socket::IPacket*>& StateObject::ReceivePacketBuffer()

{

return _receivePacketBuffer;

}

inline Util::Collections::SyncQueue<char>& StateObject::ReceiveBuffer()

{

return _receiveBuffer;

}

inline void StateObject::Send(Util::Socket::IPacket& packet)

{

WSABUF wsaBuf;

ULONG size = 0;

char* buffer = nullptr;

packet.GetBytes(&buffer, &size);

if (buffer != nullptr)

{

wsaBuf.buf = buffer;

wsaBuf.len = size;

if (WSASend(_sock, &wsaBuf, 1, NULL, 0, (LPWSAOVERLAPPED)&_sendOverlapped, NULL) == SOCKET_ERROR)

{

if (WSAGetLastError() != WSA_IO_PENDING)

Close();

}

}

}

inline void StateObject::Close()

{

_receiveBuffer.Clear();

_receivePacketBuffer.Clear();

closesocket(_sock);

_sock = NULL;

}

inline SOCKET& StateObject::Socket()

{

return _sock;

}

inline SOCKADDR_IN& StateObject::SocketAddr()

{

return _addr;

}


inline Overlapped& StateObject::ReceiveOverlapped()

{

return _receiveOverlapped;

}


inline WSABUF& StateObject::WSABuff()

{

return _wsaBuf;

}

inline unsigned long& StateObject::Handle()

{

return _handle;

}

NS_SOCKET_END

반응형

'개발관련 > C&C++' 카테고리의 다른 글

MSMQ(MS MessageQueue)  (0) 2018.05.15
Functional 이용한 델리게이트  (0) 2018.04.26
StringFormat  (0) 2018.03.20
라이브러리 빌드 전/후 이벤트 명령어  (0) 2018.03.16
C#처럼 이벤트 처리  (0) 2018.02.27
반응형

C# StringFormat 처럼 짜려다가 가변인자 타입 자체를 확인을 못함.

어쩔수 없이 출력 형식로 확인


code : https://github.com/EomTaeWook/Cpp-Util/tree/master/Util/Common


사용법

자리수까지 구현은 했으나 별로...

printf("%s",Common::String::Format("%lf %s", 10.0, "test").c_str());


※ 장점은 출력 형식을 내맘대로 정할수 있다는 점이지만 vsnprintf로 구현하는게 속 편할듯


NS.h


#pragma once

#ifndef COMMON_H

#define COMMON_H

#define NS_COMMON_BEGIN namespace Common {

#define NS_COMMON_END }

#define USING_COMMON using namespace Common;

#endif


StringFormat.h


#pragma once

#include <string>

#include <stdarg.h>

#include <map>

#include "NS.h"


NS_COMMON_BEGIN

class String

{

private:

class FormatEmun

{

private:

friend class String;

private:

enum class Signature

{

None,

d, //int

u, //unsigned int

f, //float

c, //char

s, //char*

wc, //wchar

ws, //wchar_t*

lf, //double

ld, //long

lld //long long

};

std::map<std::string, Signature> _enumMap;

public:

FormatEmun()

{

_enumMap = {

{ "d", Signature::d },

{ "u", Signature::u },

{ "f", Signature::f },

{ "c", Signature::c },

{ "s", Signature::s },

{ "wc", Signature::wc },

{ "ws", Signature::ws },

{ "lf", Signature::lf },

{ "ld", Signature::ld },

{ "lld", Signature::lld }

};

}

virtual ~FormatEmun()

{

_enumMap.clear();

}

private:

Signature Find(std::string signature);

Signature Find(std::wstring signature);

};

public:

static std::wstring String::Format(std::wstring format, ...);

static std::string String::Format(std::string format, ...);

private:

template<typename T, typename Traits, typename Alloc>

static std::basic_string<T, Traits, Alloc> Format(std::basic_string<T, Traits, Alloc> format, va_list& args);

template<typename T, typename Traits, typename Alloc>

static std::basic_string<T, Traits, Alloc> FillDigit(std::basic_string<T, Traits, Alloc>& arg, std::basic_string<T, Traits, Alloc>& digit);

};


inline String::FormatEmun::Signature String::FormatEmun::Find(std::string signature)

{

auto it = _enumMap.find(signature);

if (it != _enumMap.end())

return it->second;

else

return Signature::None;

}


inline String::FormatEmun::Signature String::FormatEmun::Find(std::wstring signature)

{

std::string _signature(signature.begin(), signature.end());

return Find(_signature);

}

NS_COMMON_END


StringFormat.cpp


#include "StringFormat.h"

#include <typeinfo>


NS_COMMON_BEGIN

template<typename T, typename Traits, typename Alloc>

std::basic_string<T, Traits, Alloc> String::Format(std::basic_string<T, Traits, Alloc> format, va_list& args)

{

FormatEmun formatEnum;

std::basic_string<T, Traits, Alloc> output;

for (size_t i = 0; i < format.size(); i++)

{

if (format[i] != '%')

{

output.push_back(format[i]);

}

else if (format[i] == '%')

{

std::basic_string<T, Traits, Alloc> key;

std::basic_string<T, Traits, Alloc> digit;

i++;

bool find = false;

while (i<format.size())

{

if (format[i] >= '0' && format[i] <= '9' || format[i] == '.')

digit.push_back(format[i]);

else

key.push_back(format[i]);

auto type = formatEnum.Find(key);

if (type != FormatEmun::Signature::None)

{

find = true;

switch (type)

{

case FormatEmun::Signature::d:

{

auto arg = va_arg(args, int);

if (typeid(T) == typeid(char))

{

auto fill = FillDigit<char, std::char_traits<char>, std::allocator<char>>(std::to_string(arg), std::string(digit.begin(), digit.end()));

output.append(fill.begin(), fill.end());

}

else if (typeid(T) == typeid(wchar_t))

{

auto fill = FillDigit<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>(std::to_wstring(arg), std::wstring(digit.begin(), digit.end()));

output.append(fill.begin(), fill.end());

}

break;

}

case FormatEmun::Signature::u:

{

auto arg = va_arg(args, unsigned int);

if (typeid(T) == typeid(char))

{

auto fill = FillDigit<char, std::char_traits<char>, std::allocator<char>>(std::to_string(arg), std::string(digit.begin(), digit.end()));

output.append(fill.begin(), fill.end());

}

else if (typeid(T) == typeid(wchar_t))

{

auto fill = FillDigit<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>(std::to_wstring(arg), std::wstring(digit.begin(), digit.end()));

output.append(fill.begin(), fill.end());

}

break;

}

case FormatEmun::Signature::f:

{

auto arg = va_arg(args, double);

if (typeid(T) == typeid(char))

{

auto fill = FillDigit<char, std::char_traits<char>, std::allocator<char>>(std::to_string(arg), std::string(digit.begin(), digit.end()));

output.append(fill.begin(), fill.end());

}

else if (typeid(T) == typeid(wchar_t))

{

auto fill = FillDigit<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>(std::to_wstring(arg), std::wstring(digit.begin(), digit.end()));

output.append(fill.begin(), fill.end());

}

break;

}

case FormatEmun::Signature::c:

{

auto arg = va_arg(args, char);

output.push_back(arg);

break;

}

case FormatEmun::Signature::s:

{

auto arg = va_arg(args, char*);

std::string str(arg);

output.append(str.begin(), str.end());

break;

}

case FormatEmun::Signature::wc:

{

auto arg = va_arg(args, wchar_t);

std::wstring wstr;

wstr.push_back(arg);

output.append(wstr.begin(), wstr.end());

break;

}

case FormatEmun::Signature::ws:

{

auto arg = va_arg(args, wchar_t*);

std::wstring wstr(arg);

output.append(wstr.begin(), wstr.end());

break;

}

case FormatEmun::Signature::lf:

{

auto arg = va_arg(args, double);

if (typeid(T) == typeid(char))

{

auto fill = FillDigit<char, std::char_traits<char>, std::allocator<char>>(std::to_string(arg), std::string(digit.begin(), digit.end()));

output.append(fill.begin(), fill.end());

}

else if (typeid(T) == typeid(wchar_t))

{

auto fill = FillDigit<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>(std::to_wstring(arg), std::wstring(digit.begin(), digit.end()));

output.append(fill.begin(), fill.end());

}

break;

}

case FormatEmun::Signature::ld:

{

auto arg = va_arg(args, long);

if (typeid(T) == typeid(char))

{

auto fill = FillDigit<char, std::char_traits<char>, std::allocator<char>>(std::to_string(arg), std::string(digit.begin(), digit.end()));

output.append(fill.begin(), fill.end());

}

else if (typeid(T) == typeid(wchar_t))

{

auto fill = FillDigit<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>(std::to_wstring(arg), std::wstring(digit.begin(), digit.end()));

output.append(fill.begin(), fill.end());

}

break;

}

case FormatEmun::Signature::lld:

{

auto arg = va_arg(args, long long);

if (typeid(T) == typeid(char))

{

auto fill = FillDigit<char, std::char_traits<char>, std::allocator<char>>(std::to_string(arg), std::string(digit.begin(), digit.end()));

output.append(fill.begin(), fill.end());

}

else if (typeid(T) == typeid(wchar_t))

{

auto fill = FillDigit<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>(std::to_wstring(arg), std::wstring(digit.begin(), digit.end()));

output.append(fill.begin(), fill.end());

}

break;

}

}

break;

}

i++;

}

if (!find)

output.append(key);

}

}

return output;

}


std::string String::Format(std::string format, ...)

{

FormatEmun formatEnum;

va_list args;

try

{

va_start(args, format);

std::string output;

output = Format<char, std::char_traits<char>, std::allocator<char>>(format, args);

va_end(args);

return output;

}

catch (std::exception ex)

{

va_end(args);

throw ex;

}

}


std::wstring String::Format(std::wstring format, ...)

{

FormatEmun formatEnum;

va_list args;

try

{

std::wstring output;

va_start(args, format);

output = Format<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>(format, args);

va_end(args);

return output;

}

catch (std::exception ex)

{

va_end(args);

throw ex;

}

}

template<typename T, typename Traits, typename Alloc>

static std::basic_string<T, Traits, Alloc> String::FillDigit(std::basic_string<T, Traits, Alloc>& arg, std::basic_string<T, Traits, Alloc>& digit)

{

if (digit.empty()) return arg;


std::basic_string<T, Traits, Alloc> output;

std::basic_string<T, Traits, Alloc> find_key;

find_key.push_back('.');

int idx = digit.find(find_key);

if (idx == -1)

{

auto size = std::stoi(digit) - arg.size();

for (unsigned int i = 0; i < size; i++)

{

output.push_back(' ');

}

output.append(arg);

}

else

{

auto decimalDigit = digit.substr(idx + 1, digit.size() - idx + 1);

auto argDigit = arg.find(find_key);

if (argDigit != -1)

output.append(arg.substr(0, argDigit));

else

output.append(arg);

if (!decimalDigit.empty())

{

std::basic_string<T, Traits, Alloc> argDecimal;

output.push_back('.');

if (argDigit != -1)

{

argDecimal = arg.substr(argDigit + 1, arg.size() - argDigit);

output.append(argDecimal.begin(), argDecimal.end());

}

size_t size = std::stoi(decimalDigit);


if (size > argDecimal.size())

{

for (size_t i = 0; i < size - argDecimal.size(); i++)

{

output.push_back('0');

}

}

else if (size != 0)

{

for (size_t i = 0; i < size; i++)

{

output.push_back(argDecimal[i]);

}

}

else

{

output.pop_back();

}

}

auto integerDigit = digit.substr(0, idx);

if (!integerDigit.empty())

{

auto size = std::stoi(integerDigit) - output.size();

for (unsigned int i = 0; i < size; i++)

{

output.insert(output.begin(), ' ');

}

}

}

return output;

}

NS_COMMON_END

반응형

'개발관련 > C&C++' 카테고리의 다른 글

Functional 이용한 델리게이트  (0) 2018.04.26
IOCP Socket Server 구현  (0) 2018.04.16
라이브러리 빌드 전/후 이벤트 명령어  (0) 2018.03.16
C#처럼 이벤트 처리  (0) 2018.02.27
Convert Json To Xml  (0) 2018.01.17
반응형

Header 파일과 Lib파일 출력 폴더에 복사


빌드 전 이벤트 :


IF NOT EXIST "$(SolutionDir)$(Configuration)\$(PlatformTarget)\include" (mkdir "$(SolutionDir)$(Configuration)\$(PlatformTarget)\include")


빌드 후 이벤트 :


IF NOT EXIST "$(SolutionDir)$(Configuration)\$(PlatformTarget)\include" (mkdir "$(SolutionDir)$(Configuration)\$(PlatformTarget)\include")

xcopy /S/Y "$(ProjectDir)*.h" "$(SolutionDir)$(Configuration)\$(PlatformTarget)\include\"

IF EXIST "$(SolutionDir)Lib" (xcopy /S/Y "$(SolutionDir)Lib\*.lib" "$(SolutionDir)$(Configuration)\$(PlatformTarget)")

IF EXIST "$(SolutionDir)Include" (xcopy /S/Y "$(SolutionDir)Include\*.*" "$(SolutionDir)$(Configuration)\$(PlatformTarget)\include")

반응형

'개발관련 > C&C++' 카테고리의 다른 글

IOCP Socket Server 구현  (0) 2018.04.16
StringFormat  (0) 2018.03.20
C#처럼 이벤트 처리  (0) 2018.02.27
Convert Json To Xml  (0) 2018.01.17
Xmllite SAX(Simple Api for Xml) TreeNode 구현 및 LIB (XMLParser)  (0) 2018.01.11
반응형

CEF 재작업중.. CEF 콜백에 대한 처리를 Event Bind 형식이 더 편할 것 같은 느낌이라


C# Event처럼 구현함.


template이라 Cpp 파일은 없음. 내부적으로 Delegate리스트는 unique_ptr 을 사용함.



사용법

이벤트 객체

class test

{

public:

Util::Event<bool*> LoadingState;

}


이벤트 구독

//void* sender 타입 고정

//bool* e 인 경우 Generic

void CLauncherDlg::OnLoadingStateChange(void* sender, bool* e)

{

//.....

}

BOOL CLauncherDlg::OnInitDialog()

{

//안에서만 namespace 사용

{

using namespace std::placeholders;

handler->LoadingState += std::bind(&CLauncherDlg::OnLoadingStateChange, this, _1, _2);

}

}


code>>


Ns.h


#pragma once

#ifndef EVENT_H

#define EVENT_H

#define NS_EVENT_BEGIN namespace Util { namespace Event {

#define NS_EVENT_END } }

#define USING_EVENT using namespace Util::Event;

#endif


NS.h


#pragma once

#ifndef COMMON_H

#define COMMON_H

#define NS_COMMON_BEGIN namespace Util { namespace Common {

#define NS_COMMON_END } }

#define USING_COMMON using namespace Util::Common;

#endif


Event.h


#pragma once

#include "../Common/MulticastDelegate.h"

#include <vector>

#include <memory>

#include "NS.h"


NS_EVENT_BEGIN

USING_COMMON

template<typename T>

class Event

{

public:

Event() {}

virtual ~Event()

{

_delegates.clear();

}

private:

std::vector<std::unique_ptr<MulticastDelegate<void, void*, T>>> _delegates;

private:

void operator += (std::unique_ptr<MulticastDelegate<void, void*, T>> func);

void operator -= (std::unique_ptr<MulticastDelegate<void, void*, T>> func);

public:

void operator()(void* sender, T e);

void operator += (std::function<void(void*, T)> func);

void operator -= (std::function<void(void*, T)> func);

void operator += (MulticastDelegate<void, void*, T>* func);

void operator -= (MulticastDelegate<void, void*, T>* func);

};

template<typename T>

inline void Event<T>::operator += (std::unique_ptr<MulticastDelegate<void, void*, T>> func)

{

auto it = _delegates.begin();

while (it != _delegates.end())

{

if (*it == func)

break;

}

if (it == _delegates.end())

{

_delegates.push_back(std::move(func));

}

}

template<typename T>

inline void Event<T>::operator -= (std::unique_ptr<MulticastDelegate<void, void*, T>> func)

{

for (auto it = _delegates.begin(); it != _delegates.end(); ++it)

{

if (*it == func)

{

it = _delegates.erase(it);

}

}

}

template<typename T>

inline void Event<T>::operator += (std::function<void(void*, T)> func)

{

std::unique_ptr<MulticastDelegate<void, void*, T>> ptr(new MulticastDelegate<void, void*, T>(func));

this->operator+=(std::move(ptr));

}

template<typename T>

inline void Event<T>::operator -= (std::function<void(void*, T)> func)

{

std::unique_ptr<MulticastDelegate<void, void*, T>> ptr(new MulticastDelegate<void, void*, T>(func));

this->operator-=(std::move(ptr));

}

template<typename T>

inline void Event<T>::operator += (MulticastDelegate<void, void*, T>* func)

{

std::unique_ptr<MulticastDelegate<void, void*, T>> ptr(func);

this->operator+=(std::move(ptr));

}

template<typename T>

inline void Event<T>::operator -= (MulticastDelegate<void, void*, T>* func)

{

std::unique_ptr<MulticastDelegate<void, void*, T>> ptr(func);

this->operator-=(std::move(ptr));

}

template<typename T>

inline void Event<T>::operator () (void* sender, T e)

{

for (auto it = _delegates.begin(); it != _delegates.end(); ++it)

{

(*it)->operator()(sender, e);

}

}

NS_EVENT_END


Delegate.h


//MulticastDelegate만 생성가능


#pragma once

#include "NS.h"

#include <functional>

#include <vector>

NS_COMMON_BEGIN

template<typename R, typename T1, typename T2, typename T3, typename T4, typename T5>

class MulticastDelegate;


template<typename R, typename ...Types>

class Delegate

{

private:

template<typename R, typename T1, typename T2, typename T3, typename T4, typename T5>

friend class MulticastDelegate;

protected:

std::vector<std::function<R(Types...)>> _methods;

private:

Delegate()

{

_methods.clear();

}

public:

virtual ~Delegate() { _methods.clear(); }

public:

R operator() (Types...);

bool operator != (const Delegate& d) const;

bool operator != (nullptr_t) const;

bool operator == (const Delegate& d) const;

bool operator == (nullptr_t) const;

void operator = (nullptr_t);

void operator = (std::function<R(Types...)>);

Delegate& operator += (std::function<R(Types...)>);

public:

virtual Delegate& Combine(Delegate);

virtual Delegate& operator + (Delegate);

};


template<typename R, typename ...Types>

inline Delegate<R, Types...>& Delegate<R, Types...>::Combine(Delegate<R, Types...> del)

{

for (auto m : del._methods)

{

_methods.push_back(m);

}

return *this;

}

template<typename R, typename ...Types>

inline Delegate<R, Types...>& Delegate<R, Types...>::operator += (std::function<R(Types...)> method)

{

_methods.push_back(method);

return *this;

}

template<typename R, typename ...Types>

inline Delegate<R, Types...>& Delegate<R, Types...>::operator + (Delegate<R, Types...> del)

{

return Combine(del);

}

template<typename R, typename ...Types>

void Delegate<R, Types...>::operator = (std::function<R(Types...)> method)

{

_methods.clear();

_methods.push_back(method);

}


template<>

inline void Delegate<void>::operator() ()

{

for (auto m : _methods)

{

m();

}

}

template<typename R, typename ...Types>

inline R Delegate<R, Types...>::operator() (Types... params)

{

for (int i = 0; i < _methods.size() - 1; i++)

{

_methods[i](params...);

}

return _methods.back()(params...);

}

template<typename R, typename ...Types>

bool Delegate<R, Types...>::operator != (nullptr_t) const

{

return _methods.size() != 0;

}


template<typename R, typename ...Types>

bool Delegate<R, Types...>::operator != (const Delegate<R, Types...>& del) const

{

return this != &del;

}


template<typename R, typename ...Types>

bool Delegate<R, Types...>::operator == (nullptr_t) const

{

return _methods.size() == 0;

}


template<typename R, typename ...Types>

bool Delegate<R, Types...>::operator == (const Delegate<R, Types...>& del) const

{

return this == &del;

}


template<typename R, typename ...Types>

void Delegate<R, Types...>::operator = (nullptr_t)

{

_methods.clear();

}


NS_COMMON_END


MulticastDelegate.h


#pragma once

#include "NS.h"

#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)

#include "Delegate.h"

#else

#include "Delegate98.h"

#endif

NS_COMMON_BEGIN

template<typename R, typename T1 = void, typename T2 = void, typename T3 = void, typename T4 = void, typename T5 = void>

class MulticastDelegate : public Delegate<R, T1, T2, T3, T4, T5>

{

public:

MulticastDelegate()

{

}

MulticastDelegate(std::function<R(T1, T2, T3, T4, T5)> method)

{

this->operator= (method);

}

virtual ~MulticastDelegate() {}

public:

void operator = (std::function<R(T1, T2, T3, T4, T5)>);

};

template<typename R, typename T1, typename T2, typename T3, typename T4, typename T5>

inline void MulticastDelegate<R, T1, T2, T3, T4, T5>::operator = (std::function<R(T1, T2, T3, T4, T5)> method)

{

Delegate<R, T1, T2, T3, T4, T5>::operator = (method);

}


template<typename R, typename T1, typename T2, typename T3, typename T4>

class MulticastDelegate<R, T1, T2, T3, T4, void> : public Delegate<R, T1, T2, T3, T4>

{

public:

MulticastDelegate()

{

}

MulticastDelegate(std::function<R(T1, T2, T3, T4)> method)

{

this->operator= (method);

}

virtual ~MulticastDelegate() {}

public:

void operator = (std::function<R(T1, T2, T3, T4)>);

};

template<typename R, typename T1, typename T2, typename T3, typename T4>

inline void MulticastDelegate<R, T1, T2, T3, T4>::operator = (std::function<R(T1, T2, T3, T4)> method)

{

Delegate<R, T1, T2, T3, T4>::operator = (method);

}


template<typename R, typename T1, typename T2, typename T3>

class MulticastDelegate<R, T1, T2, T3, void, void> : public Delegate<R, T1, T2, T3>

{

public:

MulticastDelegate()

{

}

MulticastDelegate(std::function<R(T1, T2, T3)> method)

{

this->operator= (method);

}

virtual ~MulticastDelegate() {}

public:

void operator = (std::function<R(T1, T2, T3)>);

};

template<typename R, typename T1, typename T2, typename T3>

inline void MulticastDelegate<R, T1, T2, T3>::operator = (std::function<R(T1, T2, T3)> method)

{

Delegate<R, T1, T2, T3>::operator = (method);

}


template<typename R, typename T1, typename T2>

class MulticastDelegate<R, T1, T2, void, void, void> : public Delegate<R, T1, T2>

{

public:

MulticastDelegate()

{

}

MulticastDelegate(std::function<R(T1, T2)> method)

{

this->operator= (method);

}

virtual ~MulticastDelegate() {}

public:

void operator = (std::function<R(T1, T2)>);

};

template<typename R, typename T1, typename T2>

inline void MulticastDelegate<R, T1, T2>::operator = (std::function<R(T1, T2)> method)

{

Delegate<R, T1, T2>::operator = (method);

}


template<typename R, typename T>

class MulticastDelegate<R, T, void, void, void, void> : public Delegate<R, T>

{

public:

MulticastDelegate()

{

}

MulticastDelegate(std::function<R(T)> method)

{

this->operator= (method);

}

virtual ~MulticastDelegate() {}

public:

void operator = (std::function<R(T)>);

};

template<typename R, typename T>

inline void MulticastDelegate<R, T>::operator = (std::function<R(T)> method)

{

Delegate<R, T>::operator = (method);

}


template<typename R>

class MulticastDelegate<R, void, void, void, void, void> : public Delegate<R>

{

public:

MulticastDelegate()

{

}

MulticastDelegate(std::function<R()> method)

{

this->operator= (method);

}

virtual ~MulticastDelegate() {}

public:

void operator = (std::function<R()> func);

};

template<typename R>

inline void MulticastDelegate<R>::operator = (std::function<R()> method)

{

Delegate<R>::operator = (method);

}

NS_COMMON_END


반응형

+ Recent posts