본문 바로가기
프로그래밍/boost

boost::asio 비동기 TCP 서버 / 클라 예제

by neive 2012. 9. 3.
728x90

 

boost asio 안내서에 있는 기본 예제를 응용하여 작성했으며 컴파일러 옵션은 /Mtd 로 해야 합니다.

클라이언트 부분의 const string 은 내 IP 로 수정해줘야 합니다.

기존에 올렸던 내용은 소스 링크가 깨져서 다시 올립니다 (많은 분들이 보러 오셨는데 ㅠㅠ 깨져있었을 줄이야..)

소스는 퍼가실 때 소스 부분을 더블클릭하면 아랫쪽에 작은 창이 뜨면서 ctrl+c 로 전체 카피가 가능합니다

 

클라 소스

#include "stdafx.h"


#include <ctime>
#include <iostream>
#include <string>
#include <boost/asio.hpp>


const std::string _MY_IP("192.168.25.2 <-- 접속할 pc ip 로 바꿔줘야 합니다");

enum EEnum
{
	eBuffSize = 128,
};

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

int _tmain(int argc, char* argv[])
{
	try
	{
		// io_service를 하나 생성한다.
		boost::asio::io_service io_service;
		// 입력 받은 host을 resolving한다.
		tcp::resolver resolver(io_service);
		tcp::resolver::query query(_MY_IP, "daytime");
		tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
		tcp::resolver::iterator end;

		// 접속할 소켓을 생성한다.
		tcp::socket socket(io_service);
		boost::system::error_code error = boost::asio::error::host_not_found;
		// resolving된 endpoint로 접속을 시도한다.
		while (error && endpoint_iterator != end)
		{
			socket.close();
			socket.connect(*endpoint_iterator++, error);
		}
		// 접속 실패인지 확인
		if (error)
			throw boost::system::system_error(error);
		// 접속 성공
		while(true)
		{
			// 읽어올 데이터를 저장할 array를 만든다.
			boost::array<char, eBuffSize> buf;
			boost::system::error_code error;
			// read_some함수를 호출해 128만큼의 버퍼에 채워달라고 요청한다.
			// ( len <=128 일것이다. )
			size_t len = socket.read_some(boost::asio::buffer(buf), error);
			// daytime서버는 전송후 바로 끊어지기 때문에 error::eof를 리턴할것이다.
			if (error == boost::asio::error::eof)
				break;
			else if (error)
				throw boost::system::system_error(error);
			// 받은 데이터를 cout로 출력한다.
			std::cout.write(buf.data(), len);
		}
	}
	catch (std::exception& e)
	{
		std::cerr << e.what() << std::endl;
	}

	int in;
	std::cin >> in ;

	return 0;
}

 

서버 소스


#include"stdafx.h"

#include <ctime>
#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <ctime>
#include <iostream>
#include <string>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>

#include <boost/date_time/posix_time/posix_time.hpp>

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

// 메세지를 만든다.
std::string make_daytime_string()
{
	using namespace std; // For time_t, time and ctime;
	time_t now = time(0);
	return ctime(&now);	// ctime_s 권장. 예제니까 그냥 쓰고 넘어가지만
}

class CTCP_Connection : public boost::enable_shared_from_this<CTCP_Connection>
{
private:
	tcp::socket m_Socket;
	std::string m_sMessage;

	CTCP_Connection(boost::asio::io_service& io_service) : m_Socket(io_service) // m_Socket 초기화
	{
	}

	// 안쓰니까 안전하게 봉인
	void handle_write(const boost::system::error_code& /*error*/, size_t /*bytes_transferred*/)
	{
	}

public:
	typedef boost::shared_ptr<CTCP_Connection> pointer;

	static pointer create(boost::asio::io_service& io_service)
	{
		return pointer(new CTCP_Connection(io_service));
	}

	tcp::socket& socket()
	{
		return m_Socket;
	}

	void start()
	{
		m_sMessage = make_daytime_string();

		// 예제에서는 boost::asio::async_write (boost::asio::error::eof 포함) 를 썼지만
		// async_write_some, async_send 를 써야할 것이다
		// error, bytes_tran 부분은 사용하지 않아도 된다
		boost::asio::async_write(m_Socket, boost::asio::buffer(m_sMessage),
			boost::bind(&CTCP_Connection::handle_write, shared_from_this(),
			boost::asio::placeholders::error,
			boost::asio::placeholders::bytes_transferred));
	}
};

class CTCP_Server
{
private:
	tcp::acceptor m_Acceptor;

	void start_accept()
	{
		CTCP_Connection::pointer new_connection =
			CTCP_Connection::create(m_Acceptor.get_io_service());

		m_Acceptor.async_accept(new_connection->socket(),
			boost::bind(&CTCP_Server::handle_accept, this, new_connection,
			boost::asio::placeholders::error));
	}

	void handle_accept(CTCP_Connection::pointer new_connection, const boost::system::error_code& error)
	{
		if (!error)
		{
			new_connection->start();
			start_accept();
		}
	}

public:
	CTCP_Server(boost::asio::io_service& io_service) : m_Acceptor(io_service, tcp::endpoint(tcp::v4(), 13))
	{
		start_accept();
	}
};

int _tmain(int argc, _TCHAR* argv[])
{
	try
	{
		boost::asio::io_service io_service;	// asio 라면 무조건 있어야 한다

		CTCP_Server server(io_service);
		io_service.run();
	}
	catch (std::exception& e)
	{
		std::cerr << e.what() << std::endl;
	}

	return 0;
}

728x90

'프로그래밍 > boost' 카테고리의 다른 글

boost::random  (0) 2012.10.24
boost::asio 비동기 서버/클라 step 2  (4) 2012.09.25
boost::Program_options  (0) 2012.05.14
boost::multi_index  (0) 2012.03.30
boost::asio 로 만들어 보고 싶은 서버 구조  (0) 2012.03.28

댓글