728x90
asio 라이브러리를 이용해 비동기 TCP 서버와 클라이언트를 만들어 봤습니다
예제에 있는거 그대로 이용을 했으니 뭐 특별할건 없고
컴파일 옵션에서 /Mtd 와 클라 소스에서 MY_IP 부분 수정이 필요합니다
# 소스 퍼가실 때 소스 부분을 더블클릭하면 선택 됩니다 드래그 하면 라인 정리가
안되니까 더블클릭으로 선택하고 카피하세요
# 소스에 대한 더 좋은 의견이나 개선사항은 비밀덧글로 주세요 ^^
# 소스 퍼가실 때 한마디 남겨주시면 힘이 됩니다 @_@
서버 소스
#include "stdafx.h" #include <ctime> #include <iostream> #include <string> #include <boost/asio.hpp> #include <ctime> #include <iostream> #include <string> #include <boost/array.hpp> #include <boost/bind.hpp> #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> #include <boost/asio.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 CConnection : public boost::enable_shared_from_this<CConnection> { private: enum EEnum { eBuffSize = 128, }; tcp::socket m_Socket; int m_nID; boost::array<BYTE, eBuffSize> m_RecvBuf; std::string m_sMessage; CConnection(boost::asio::io_service& io) : m_Socket(io), m_nID(-1) { } void handle_Accept(const boost::system::error_code& /*error*/, size_t /*bytes_transferred*/) { } void handle_Wait_Recv(const boost::system::error_code& error, size_t /*bytes_transferred*/) { if(!error) // 0 이 성공 나머지는 오류 플러그 { std::cout << "Waiting..." << std::endl; m_Socket.async_read_some(boost::asio::buffer(m_RecvBuf), boost::bind(&CConnection::handle_Send, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } else std::cout << m_nID << " Disconnect(Read) : " << error.message() << std::endl; } void handle_Send(const boost::system::error_code& error, size_t /*bytes_transferred*/) { if(!error) // 0 이 성공 나머지는 오류 플러그 { // 선처리 후 if(m_RecvBuf.size()) { std::cout << "Recv : " << (*(char*)(m_RecvBuf.data())) << std::endl; m_RecvBuf.assign(NULL); // 버퍼 초기화 } if(true) // 보낼게 있으면 보내고 { boost::asio::async_write(m_Socket, boost::asio::buffer("handle_read", 32), boost::bind(&CConnection::handle_Wait_Recv, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); std::cout << "Send " << std::endl; } else // 없으면 말고 { boost::array<BYTE, eBuffSize> buf; m_Socket.async_read_some(boost::asio::buffer(buf), boost::bind(&CConnection::handle_Send, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } } else std::cout << m_nID << " Disconnect(Write) : " << error.message() << std::endl; } public: typedef boost::shared_ptr<CConnection> pointer; static pointer create(boost::asio::io_service& io) { return pointer(new CConnection(io)); } tcp::socket& socket() { return m_Socket; } void start(int nID) { std::cout << "new connect id : "<< nID << " ::: Welcome !" << std::endl; m_nID = nID; m_sMessage = make_daytime_string(); boost::asio::async_write(m_Socket, boost::asio::buffer(m_sMessage), boost::bind(&CConnection::handle_Accept, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); boost::array<BYTE, eBuffSize> buf; m_Socket.async_receive(boost::asio::buffer(buf), boost::bind(&CConnection::handle_Send, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } }; class CTCP_Server { private: tcp::acceptor m_Acceptor; int m_nAcceptCnt; void WaitAccept() { ++m_nAcceptCnt; CConnection::pointer new_connection = CConnection::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(CConnection::pointer new_connection, const boost::system::error_code& error) { if (!error) { new_connection->start(m_nAcceptCnt); WaitAccept(); } } public: CTCP_Server(boost::asio::io_service& io) : m_Acceptor(io, tcp::endpoint(tcp::v4(), 13)), m_nAcceptCnt(0) { WaitAccept(); } }; int _tmain() { try { boost::asio::io_service io; CTCP_Server server(io); io.run(); } catch (std::exception& e) { std::cerr << e.what() << std::endl; } return 0; }
클라 소스
#include "stdafx.h" #include <ctime> #include <iostream> #include <string> #include <boost/asio.hpp> #include <boost/array.hpp> #include <boost/thread.hpp> #include <boost/bind.hpp> #include <boost/date_time/posix_time/posix_time.hpp> const std::string _MY_IP("192.168.0.1"); using boost::asio::ip::tcp; class CProtocol { private: enum EEnum { eBuffSize = 128, }; tcp::socket m_Socket; bool m_bConnect; int m_nTestCount; public: CProtocol(boost::asio::io_service& io) : m_Socket(io) { m_bConnect = false; m_nTestCount = 0; } ~CProtocol() {} void Connect() { // 입력 받은 host을 resolving한다. tcp::resolver resolver(m_Socket.get_io_service()); tcp::resolver::query query(_MY_IP, "daytime"); tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); tcp::resolver::iterator end; // resolving된 endpoint로 접속을 시도한다. boost::system::error_code error = boost::asio::error::host_not_found; while (error && endpoint_iterator != end) { m_Socket.close(); m_Socket.connect(*endpoint_iterator++, error); } // 접속 실패인지 확인 if (error) throw boost::system::system_error(error); m_bConnect = true; // 읽어올 데이터를 저장할 array를 만든다. boost::array<CHAR, eBuffSize> buf; size_t len = m_Socket.read_some(boost::asio::buffer(buf), error); if (error == boost::asio::error::eof) { m_bConnect = false; return; } else if (error) throw boost::system::system_error(error); // 받은 데이터를 cout로 출력한다. std::cout.write(buf.data(), len); } bool IsRun() { return m_bConnect; } bool IsSocketOpen() { if(!m_Socket.is_open() && m_bConnect) // 커넥트 된 이후 소켓이 닫혀버렸다면 { m_bConnect = false; // 커넥트도 끊김 판정 return false; } return true; } void handle_Recive() { while(m_bConnect) { if(!IsSocketOpen()) break; try { boost::array<BYTE, eBuffSize> buf; int len = m_Socket.receive(boost::asio::buffer(buf)); if(len > 0) { std::cout << "> Recv(len " << len << ") "; std::cout.write((CHAR*)buf.data(), len) << std::endl; } } catch (std::exception& e) { m_bConnect = false; std::cerr << e.what() << std::endl; } } } void handle_Send() { while(m_bConnect) { if(!IsSocketOpen()) break; try { boost::array<BYTE, eBuffSize> buf = { boost::lexical_cast<BYTE>(m_nTestCount) }; boost::system::error_code error; int len = boost::asio::write(m_Socket, boost::asio::buffer(buf, buf.size()), error); if(len > 0) std::cout << "> Send " << m_nTestCount << std::endl; m_nTestCount++; } catch (std::exception& e) { m_bConnect = false; std::cerr << e.what() << std::endl; } Sleep(3000); } } }; int _tmain(int argc, char* argv[]) { try { boost::asio::io_service io_service; // io_service를 하나 생성한다. CProtocol Ptc(io_service); boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service)); Ptc.Connect(); // 접속 시도 boost::thread Recv(boost::bind(&CProtocol::handle_Recive, &Ptc)); boost::thread Send(boost::bind(&CProtocol::handle_Send, &Ptc)); io_service.run(); while(Ptc.IsRun()) { } Recv.join(); Send.join(); t.join(); // 쓰레드가 종료될 때까지 메인 함수의 종료를 막는다 } catch (std::exception& e) { std::cerr << e.what() << std::endl; } int in; std::cout << "END"; std::cin >> in ; return 0; }
728x90
'프로그래밍 > boost' 카테고리의 다른 글
boost::function 으로 callback map 만들기 (0) | 2011.11.03 |
---|---|
boost::asio::buffer (0) | 2011.10.28 |
boost::asio 쓰레드, 타이머, Strand 의 사용법 예제 (0) | 2011.10.27 |
boost::asio (0) | 2011.10.27 |
boost 라이브러리 (0) | 2011.10.27 |
댓글