SkylineSoft

莽莽苍节兮 群山巍峨 日月光照兮 纷纭错落 丝竹共振兮 执节者歌 行云流水兮 用心无多 求大道以弹兵兮凌万物而超脱 觅知音因难得兮唯天地与作合
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

ACE学习系列(BufferedSocket)

Posted on 2010-09-18 11:38  Jiangwzh  阅读(456)  评论(0)    收藏  举报

/*
 * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/** \file
  \ingroup realmd
  */

#include "BufferedSocket.h"

#include <ace/OS_NS_string.h>
#include <ace/INET_Addr.h>
#include <ace/SString.h>

#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
#endif

BufferedSocket::BufferedSocket(void):
    input_buffer_(4096),
    remote_address_("<unknown>")
{
}

/*virtual*/ BufferedSocket::~BufferedSocket(void)
{
}

//重载基类函数Open,arg参数是一个函数指针
/*virtual*/ int BufferedSocket::open(void * arg)
{
 //调用基类的Open,基类的Open函数负责将Read事件注册到反应器
    if(Base::open(arg) == -1)
        return -1;

 //获取客户端的网络地址
    ACE_INET_Addr addr;

    if(peer().get_remote_addr(addr) == -1)
        return -1;

    char address[1024];
    addr.get_host_addr(address, 1024);

    this->remote_address_ = address;

 //触发OnAccept,通过已经有客户连接
    this->OnAccept();

    return 0;
}

const std::string& BufferedSocket::get_remote_address(void) const
{
    return this->remote_address_;
}

//接收到的数据长度
size_t BufferedSocket::recv_len(void) const
{
    return this->input_buffer_.length();
}


//读取指定长度的数据到缓冲区
bool BufferedSocket::recv_soft(char *buf, size_t len)
{
    if(this->input_buffer_.length() < len)
        return false;

    ACE_OS::memcpy(buf, this->input_buffer_.rd_ptr(), len);

    return true;
}

//读以指定长度的数据到缓冲区,如果读取成功,ACE_Message_Block的读指针跳过指定的长度
bool BufferedSocket::recv(char *buf, size_t len)
{
    bool ret = this->recv_soft(buf, len);

    if(ret)
        this->recv_skip(len);

    return ret;
}

//ACE_Message_Block的读指针跳过指定的长度
void BufferedSocket::recv_skip(size_t len)
{
    this->input_buffer_.rd_ptr(len);
}

//发送数据
ssize_t BufferedSocket::noblk_send(ACE_Message_Block &message_block)
{
 //消息长度
    const size_t len = message_block.length();

    if(len == 0)
        return -1;

    // 尝试直接发送消息
    ssize_t n = this->peer().send(message_block.rd_ptr(), len, MSG_NOSIGNAL);

    if(n < 0)
    {
        if(errno == EWOULDBLOCK)
            // 阻塞信息
            return 0;
        else
            // 错误
            return -1;
    }
    else if(n == 0)
    {
        // 没有发送成功(这种情况可能发生吗?)
        return -1;
    }

    // 返回已经传输的字节数
    return n;
}


//发送数据
bool BufferedSocket::send(const char *buf, size_t len)
{
    if(buf == NULL || len == 0)
        return true;

 //构建数据块
    ACE_Data_Block db(
            len,
            ACE_Message_Block::MB_DATA,
            (const char*)buf,
            0,
            0,
            ACE_Message_Block::DONT_DELETE,
            0);

 //构建消息块
    ACE_Message_Block message_block(
            &db,
            ACE_Message_Block::DONT_DELETE,
            0);

    message_block.wr_ptr(len);

 //判断消息队列是否曾为空,直接发送这个数据,不必再放入队列中等待
    if(this->msg_queue()->is_empty())
    {
        // 尝试直接发送它
        ssize_t n = this->noblk_send(message_block);

        if(n < 0)
            return false;//发送失败
        else if(n == len)
            return true;//发送成功

        // adjust how much bytes we sent
        message_block.rd_ptr((size_t)n);

        // fall down
    }

    // enqueue the message, note: clone is needed cause we cant enqueue stuff on the stack
    ACE_Message_Block *mb = message_block.clone();

 //将消息放到队尾
    if(this->msg_queue()->enqueue_tail(mb, (ACE_Time_Value *) &ACE_Time_Value::zero) == -1)
    {
  //如果不成功则释放它
        mb->release();
        return false;
    }

    //告诉反应器调用handle_output发送其他数据
    if(this->reactor()->schedule_wakeup(this, ACE_Event_Handler::WRITE_MASK) == -1)
        return false;

    return true;
}

//处理输出(从输出消息队列中逐一取出消息发送)
/*virtual*/ int BufferedSocket::handle_output(ACE_HANDLE /*= ACE_INVALID_HANDLE*/)
{
    ACE_Message_Block *mb = 0;

    if(this->msg_queue()->is_empty())
    {
        // 如果没有消息需要发送,则取消发送通知
        this->reactor()->cancel_wakeup(this, ACE_Event_Handler::WRITE_MASK);
        return 0;
    }

 //取队头消息
    if(this->msg_queue()->dequeue_head(mb, (ACE_Time_Value *) &ACE_Time_Value::zero) == -1)
        return -1;

 //发送消息
    ssize_t n = this->noblk_send(*mb);

    if(n < 0)
    {
  //发送失败
        mb->release();
        return -1;
    }
    else if(n == mb->length())
    {
  //发送成功
        mb->release();
        return 1;
    }
    else
    {
  //如果消息没有发送完,则移动读指针,跳过已经发送的数据,再将消息推入消息队列,下次继续发送
        mb->rd_ptr(n);

        if(this->msg_queue()->enqueue_head(mb, (ACE_Time_Value *) &ACE_Time_Value::zero) == -1)
        {
            mb->release();
            return -1;
        }

        return 0;
    }

    ACE_NOTREACHED(return -1);
}

//重载基类的handle_input函数,处理输入数据(也就是读取网络数据)
/*virtual*/ int BufferedSocket::handle_input(ACE_HANDLE /*= ACE_INVALID_HANDLE*/)
{
 //缓冲区剩下空间
    const ssize_t space = this->input_buffer_.space();

 //读取网络数据
    ssize_t n = this->peer().recv(this->input_buffer_.wr_ptr(), space);

    if(n < 0)
    {
        // 阻塞信号(EWOULDBLOCK是指一个非阻塞操作未能完成)或错误
  //如果返回0表示读取数据没有完成,如果返回-1表示读取数据失败
        return errno == EWOULDBLOCK ? 0 : -1;
    }
    else if(n == 0)
    {
        // EOF
        return -1;
    }

 //移动写指针
    this->input_buffer_.wr_ptr((size_t)n);

 //具体处理读到的数据
    this->OnRead();

    // 把read指针到write指针之间的内存移动到从0开始的内存里
 //实际上是一个数据操作。就是把后面的数据移到头部,用处是:
 //比如,做协议的时候,TCP的数据是以流的方式进来的,那么你从ACE_Message_Block中按照协议的方式取数据,
 //前面的数据取完了自然没有用了,要留出空间收后面的数据,那么你可以crunch一下,
 //把读指针之前的数据释放,然后把后面的数据整体往前移动一下。
    this->input_buffer_.crunch();

    //返回1表示可能有更多的数据需要读取(似乎有问题)
    return n == space ? 1 : 0;
}

//重载基类,处理网络连接关闭
/*virtual*/ int BufferedSocket::handle_close(ACE_HANDLE h, ACE_Reactor_Mask m)
{
    this->OnClose();

    Base::handle_close();

    return 0;
}

void BufferedSocket::close_connection(void)
{
    this->peer().close_reader();
    this->peer().close_writer();
}