Monday, December 15, 2008

boost::asio - Network Library modified by Terry - 2

boost::asio 내 맘대로 바꾼 버전 2번째.
session 부분임.

session 특징:
- TCP session. Server / Client 모두 다 사용.
- 접속하였을 때와 패킷을 받았을 때 콜백 호출. 나머지 필요하면 그때 새로운 콜백 추가.
- ReadBuffer 를 그냥 packet_parser 콜백에 넘기기 때문에, 더 좋은 성능을 이끌어 내고 싶으면
- packet_parser 콜백 받는 부분에서 버퍼를 복사한 후 다른 쓰레드로 넘겨서 처리해야 함.
- packet_parser 부분이 길어지게 되면 당연히 async_read 를 늦게 걸 수 밖에 없기 때문에 성능이 저하됨.
- 에러처리는 기본적인 것만 되어 있음.

session.h



#pragma once

#ifndef _SESSION_H_
#define _SESSION_H_

#include "structure.h"
#include
#include

using boost::asio::ip::tcp;
using namespace std;

class session;

typedef boost::shared_ptr session_ptr;
typedef boost::function cb_boost_func;

typedef bool (*cb_packet) (void* cb_class, packet_ptr p, session_ptr s);
typedef bool (*cb_connect) (void* cb_class, session_ptr s, const boost::system::error_code& error);

class session : public boost::enable_shared_from_this
{
private:
tcp::socket socket_;
data_buffer read_buffer_;
data_buffer write_buffer_;

bool authorized_;

void* cb_class_;
cb_packet parse_packet_;

public:
session(boost::asio::io_service& io_service) :
socket_(io_service), authorized_(0), cb_class_(0), parse_packet_(0)
{
}
virtual ~session() {;}

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

bool get_authorized() const { return authorized_; }
void set_authorized(bool value) { authorized_ = value; }

void start()
{
do_async_read();
}

void send_packet(packet_ptr packet)
{
// check a packet size
if(packet->body_length_ > max_body_size)
{
cerr << "\n -Error- packet size is too large : " << packet->body_length_ << "\n";
return;
}

do_async_write(packet);
}

void set_callback(void* cb_class, cb_packet cb_func)
{
cb_class_ = cb_class;
parse_packet_ = cb_func;
}

void do_async_read()
{
// read only header
boost::asio::async_read(socket_,
boost::asio::buffer(read_buffer_.data_.begin(), header_size),
boost::bind(&session::do_async_read_body,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred)
);

//socket_.async_read_some(
// boost::asio::buffer(read_buffer_.data_.begin(), max_packet_size),
// boost::bind(&session::handle_read,
// shared_from_this(),
// boost::asio::placeholders::error,
// boost::asio::placeholders::bytes_transferred)
// );
}

void do_async_read_body(const boost::system::error_code& error, size_t bytes_transferred)
{
if(error)
{
if(bytes_transferred == 0)
cerr << "\n -Close socket. \n";
else
cerr << "\n -Error- do_async_read_body (" << error.message() << ")\n";

// close this socket
this->socket_.close();
return;
}

packet_header header;
memcpy(&header, static_cast(read_buffer_.data_.begin()), header_size);

// read body
boost::asio::async_read(socket_,
boost::asio::buffer(&read_buffer_.data_[header_size], header.body_length_),
boost::bind(&session::handle_read,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred)
);
}

void do_async_write(packet_ptr packet)
{
memcpy((void*)&write_buffer_.data_[0], (void*)static_cast(packet.get()), header_size);
memcpy((void*)&write_buffer_.data_[header_size], (void*)packet->data_, packet->body_length_);

boost::asio::async_write(socket_,
boost::asio::buffer(write_buffer_.data_.begin(), header_size + packet->body_length_),
boost::bind(&session::handle_write,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred)
);
}

protected:
void handle_read(const boost::system::error_code& error, size_t bytes_transferred)
{
if(error)
{
cerr << "\n -Error- handler_read (" << error.message() << ")\n";
// close this socket ?
return;
}

cout << "\nhandle_read : bytes_transferred " << bytes_transferred << " bytes" << endl;

if(bytes_transferred == 0)
{
// normal close.
return;
}

if(bytes_transferred > max_packet_size)
{
cerr << "\n -Error- handler_read : too many transferred bytes (" << bytes_transferred << ")\n";
return;
}

packet_header* header = reinterpret_cast(read_buffer_.data_.begin());
if(!header || header->body_length_ <= 0 || header->body_length_ > max_body_size)
{
assert(header);
cerr << "\n -Error- handler_read : abnormal error read buffer" << std::endl;
return;
}

packet_ptr packet(new packet);
packet->index_ = header->index_;
packet->body_length_ = header->body_length_;

packet->data_ = new char[packet->body_length_];
memcpy(packet->data_, (void*)&read_buffer_.data_[header_size], packet->body_length_);

// invoke a callback function
if(parse_packet_(cb_class_, packet, shared_from_this()) == false)
{
cerr << "\n -Error- handler_read : packet_parse returned false. socket closed." << std::endl;
socket_.close();
return;
}

// do an asynchronous read again
do_async_read();
}

void handle_write(const boost::system::error_code& error, size_t bytes_transferred)
{
#ifdef _DEBUG
cout << "\nhander_write bytes transferred : " << bytes_transferred << " bytes" << endl;
#endif

// do nothing.
}
};

#endif//_SESSION_H_

No comments:

Post a Comment