Thinking Different




 

이번에는 서버 세션 객체를 작성하였습니다. 패킷 읽기 부분에 대한것은 내부적으로 사용되므로 private 하였습니다.

 

핵심 부분은 handle_read_body() 함수에서 패킷 데이터를 읽어서 ProcessPacket으로 패킷을 넘겨주는 부분이 있겠습니다.

특별히 어려운 부분은 없으므로 코드를 보시면 쉽게 이해 가능하실거라 생각됩니다. 람다코드와 shared_ptr 부분은 기초적인 것이므로 해설을 생략하였습니다.

 

어려운 부분이 있거나 궁금한 내용이 있으시면 댓글 부탁합니다.

 

 

Session.h

#pragma once
#include "Message.h"

class CChatServer;

class CSession : public std::enable_shared_from_this<CSession>
{
public:
	CSession(boost::asio::ip::tcp::socket socket, CChatServer* pServer);
	~CSession();

public:
	boost::asio::ip::tcp::socket& Socket() { return m_Socket; }

	void Start();
	void Write(const CMessage& msg);

	void SetName(const char* pszName) { m_Name = pszName; }
	const char* GetName() { return m_Name.c_str(); }

private:
	void handle_write();
	void handle_read_header();
	void handle_read_body();

private:
	boost::asio::ip::tcp::socket m_Socket;

	std::string m_Name;
	CChatServer* m_pServer;

	CMessage m_ReadMessage;
	std::deque<CMessage> m_WriteMessage;
};

 

 

Session.cpp

#include "stdafx.h"
#include "Session.h"
#include "ChatServer.h"

CSession::CSession(boost::asio::ip::tcp::socket socket, CChatServer* pServer)
	: m_Socket(std::move(socket))
	, m_pServer(pServer)
{
}

CSession::~CSession()
{
}

void CSession::Start()
{
	handle_read_header();
}

void CSession::Write(const CMessage& msg)
{
    m_WriteMessage.push_back(msg);
    if (!m_WriteMessage.empty())
    {
        handle_write();
    }
}

void CSession::handle_write()
{
    auto self(shared_from_this());
    boost::asio::async_write(m_Socket,
        boost::asio::buffer(m_WriteMessage.front().data(), m_WriteMessage.front().length()),
        [this, self](boost::system::error_code error, std::size_t /*length*/)
        {
            if (!error)
            {
                m_WriteMessage.pop_front();
                if (!m_WriteMessage.empty())
                {
                    handle_write();
                }
            }
            else
            {
                m_pServer->EndSession(shared_from_this());
            }
        });
}

void CSession::handle_read_header()
{
    auto self(shared_from_this());
    boost::asio::async_read(m_Socket,
        boost::asio::buffer(m_ReadMessage.data(), CMessage::header_length),
        [this, self](boost::system::error_code error, std::size_t /*length*/)
        {
            if (!error && m_ReadMessage.decode_header())
            {
                handle_read_body();
            }
            else
            {
                m_pServer->EndSession(shared_from_this());
            }
        });
}

void CSession::handle_read_body()
{
    auto self(shared_from_this());
    boost::asio::async_read(m_Socket,
        boost::asio::buffer(m_ReadMessage.body(), m_ReadMessage.body_length()),
        [this, self](boost::system::error_code error, std::size_t /*length*/)
        {
            if (!error)
            {
                m_pServer->ProcessPacket(shared_from_this(), m_ReadMessage.body(), m_ReadMessage.body_length());

                handle_read_header();
            }
            else
            {
                if (error == boost::asio::error::eof)
                {
                    std::cout << "클라이언트와 연결이 끊어졌습니다" << std::endl;
                }
                else
                {
                    std::cout << "error No: " << error.value() << " error Message: " << error.message() << std::endl;
                }

                m_pServer->EndSession(shared_from_this());
            }
        });
}