- 메세지를 한번 주고 받고 세션을 종료하는 클라이언트 소켓
- boost::asio 라이브러리 사용 (boost 의 date_time, thread, system 컴파일 필요)
- boost::asio::deadline_timer 를 이용하여 timeout 기능 구현 
- 비동시 소켓으로 구현한 동기 소켓(?)



#pragma once

#include <algorithm>
using namespace std;

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>

using boost::asio::ip::tcp;


struct IsEOF_Basic
{
bool operator()(const std::string &)
{
return true;
}
};



template <class Ty = IsEOF_Basic>
class ClientSocket 
{
public:
ClientSocket() : socket_(io_service_), timeout_(io_service_), nResponse_(0) {}

~ClientSocket() 
{
Close();
}

bool Connect(const string &sIP, const string &sPort) 
{
bool bResult = false;

tcp::resolver resolver(io_service_);
tcp::resolver::query query(tcp::v4(), sIP, sPort);
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::resolver::iterator end;

boost::system::error_code error = boost::asio::error::host_not_found;
while (error && endpoint_iterator != end)
{
socket_.close();
socket_.connect(*endpoint_iterator++, error);
}

if (!error) {
bResult = true;
}
return bResult;
}

void Send(const string &s, const int nTimeout = 5)
{
copy(s.begin(), s.end(), szBuff);

socket_.async_write_some(boost::asio::buffer(szBuff, s.length()),
boost::bind(&ClientSocket::handle_write, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));

timeout_.expires_from_now(boost::posix_time::seconds(nTimeout));
timeout_.async_wait(boost::bind(&ClientSocket::Timeout, this));

handle_read_wait();
}

int WaitForResponse()
{
socket_.io_service().reset();

while (socket_.io_service().run_one()) 
{
if (nResponse_) break;
}

return nResponse_;
}

void Close()
{
socket_.close();
}

std::string GetReadBuffer()
{
return sReadBuff_;
}

enum { TIMEOUT = -1, READY = 0, SUCCESS = 1 };

private:
void Timeout()
{
nResponse_ = TIMEOUT;
}

void handle_read_wait() 
{
socket_.async_read_some(boost::asio::buffer(szBuff, BUFF_SIZE),
boost::bind(&ClientSocket::handle_read, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));

nResponse_ = READY;
}

void handle_read(const boost::system::error_code& error, size_t bytes_transferred)
{
if (error) {
Close();
return;
}

sReadBuff_.append(szBuff, szBuff + bytes_transferred);

if (IsEOF(sReadBuff_)) {
nResponse_ = SUCCESS;
}
else {
handle_read_wait();
}
}

void handle_write(const boost::system::error_code& error, size_t bytes_transferred)
{
if (error) {
Close();
return;
}
}

private:
boost::asio::io_service io_service_;

boost::asio::deadline_timer timeout_;
tcp::socket socket_;
std::string sReadBuff_;
volatile int nResponse_;

Ty IsEOF;
enum { BUFF_SIZE = 8192};
char szBuff[BUFF_SIZE];
};

int SendPacket (
LPCSTR strIP, LPCSTR strPort, int nTimeoutSecond, LPCSTR szMessage, LPSTR szRetMessage)
{
int nResult = -2;

try {
typedef ClientSocket<> ClientSocketType;
ClientSocketType socket;

if (!socket.Connect(strIP, strPort)) {
throw -1;
}

if (nTimeoutSecond == 0) nTimeoutSecond = 5;

socket.Send(szMessage, nTimeoutSecond);
int nResponse = socket.WaitForResponse();

if (nResponse == ClientSocketType::TIMEOUT) {
throw 0;
}

if (nResponse == ClientSocketType::SUCCESS) {
std::string s = socket.GetReadBuffer();
std::copy(s.begin(), s.end(), szRetMessage);

nResult = s.size();
}
}
catch (int nErr) {
nResult = nErr;
}
catch (...) {}

return nResult;
}



'Dev > C++' 카테고리의 다른 글

[C++11] Variadic template  (0) 2014.11.02
boost 설치  (0) 2013.11.20
이미지 변환 모듈 (모바일용, GDI+)  (0) 2010.06.22
C++0x, RValue Reference  (0) 2009.05.27
C++0x Lambda  (0) 2009.05.20

+ Recent posts