找回密码
 用户注册

QQ登录

只需一步,快速开始

查看: 12598|回复: 11

求助ACE中ACE_Acceptor下函数peer().recv_n接收不到数据

[复制链接]
发表于 2009-10-20 21:43:30 | 显示全部楼层 |阅读模式
为什么在客户端给服务器端发信息的时候,服务器端的handle_input(ACE_HANDLE)函数被调用后,函数中的this->peer().recv_n(data,DATA_SIZE))中是收不到数据?而且handle_input被调用了两次,这是为什么。请哪位大哥解答,谢谢了。小弟在线等!

服务器端代码:
#include "ace/Reactor.h"
#include "ace/Svc_Handler.h"
#include "ace/Acceptor.h"
#include "ace/Synch.h"
#include "ace/SOCK_Acceptor.h"
#include <iostream>

#define PORT_NUM 19999
#define DATA_SIZE 13

class My_Svc_Handler;

typedef ACE_Acceptor <My_Svc_Handler,ACE_SOCK_ACCEPTOR>MyAcceptor;

class My_Svc_Handler:public ACE_Svc_Handler <ACE_SOCK_STREAM,ACE_NULL_SYNCH>
{
public:
    My_Svc_Handler()
   {
        data= new char[DATA_SIZE];
   }
   int open(void*)
   {
        std::cout < <"Connection established" < <std::endl;

        ACE_Reactor::instance()->register_handler(this, ACE_Event_Handler::READ_MASK);
        return 0;
    }

    int handle_input(ACE_HANDLE)
    {
        int byteCount = 0;

        if ( (byteCount = this->peer().recv_n(data,DATA_SIZE)) == -1)
        {
            ACE_OS::printf(" < < Error!\n");
        }
        else
        {
            data[byteCount] = 0;
            ACE_OS::printf(" < < %s\n",data);
        }

        return 0;
    }
private:
    char* data;
};

int main(int argc, char* argv[])
{
    ACE_INET_Addr addr(PORT_NUM);

    MyAcceptor acceptor(addr,ACE_Reactor::instance());
    while(1)
    {
        ACE_Reactor::instance()->handle_events();
    }

    return 0;
}

客户端代码:
#include "ace/SOCK_Connector.h"
#include "ace/OS.h"
#include "ace/Log_Msg.h"

class Client
{
public:
    Client( char *addr, int port )
           :remoteAddr_( port, addr )
    {
    }

    int ConnectToServer()
    {
        if ( connector_.connect( clientStream_, remoteAddr_ ) == -1  )
        {
              ACE_ERROR_RETURN ((LM_ERROR,"(%P|%t) %p\n","connection failed"),-1);
        }
       else
       {
            ACE_DEBUG ((LM_DEBUG,"(%P|%t) connected to %s\n",remoteAddr_.get_host_name()));
       }

    return 0;
    }

    int SendToServer()
    {
        char *buf = "Hello world!";
        if( clientStream_.send_n( buf, ACE_OS::strlen(buf)+1, 0 ) != -1 )
        {
            ACE_DEBUG( (LM_DEBUG,"Send %s to server succeed!\n", buf) );
        }
        else
        {
            ACE_DEBUG( (LM_DEBUG,"Send %s to server failed!\n", buf) );
        }

     return 0;
     }

private:
    ACE_INET_Addr remoteAddr_;
    ACE_SOCK_Connector connector_;
    ACE_SOCK_Stream clientStream_;
};

int main( int argc, char *argv[] )
{
    char *remoteAddr = "127.0.0.1";
    int  port = 19999;
    Client client( remoteAddr, port );
    client.ConnectToServer();
    client.SendToServer();

    return 0;
};

编译环境为windows xp.编译工具为visual c++ 2003.ACE版本包为ACE+TAO+CIAO-5.6.9

[ 本帖最后由 pengxiqin 于 2009-10-20 21:58 编辑 ]
发表于 2009-10-21 11:15:17 | 显示全部楼层
1.收不到是一个什么概念?收不全还是recv返回-1了?最好提供一些详细的运行期信息。
2.handle_input被调用了两次,描述的太笼统了,把堆栈信息贴出来看看先。
发表于 2009-10-22 15:57:44 | 显示全部楼层
原因:client发送完后立刻退出了,发送成功返回只是表示数据已经发到socket buffer里了,但不一定发到对端。如果立即退出进程,系统会自动调用close,buffer里的数据被丢弃了,只向server发送一个fin包。(这种情况可能不同的系统有不同的实现行为,而且跟so_linger的设置有关)
所以在Client::SendToServer()的ruturn前加一句:ACE_OS::sleep(1);就可以了。

另外My_Svc_Handler::handle_input()中的处理也有问题,没有考虑client退出连接的情况。
发表于 2009-10-22 15:59:02 | 显示全部楼层
#include "ace/Reactor.h"
#include "ace/Svc_Handler.h"
#include "ace/Acceptor.h"
#include "ace/Synch.h"
#include "ace/SOCK_Acceptor.h"
#include "ace/SOCK_Connector.h"
#include "ace/OS.h"
#include "ace/Log_Msg.h"
#include <iostream>

#define PORT_NUM 19999
#define DATA_SIZE 13

class My_Svc_Handler;

typedef ACE_Acceptor <My_Svc_Handler,ACE_SOCK_Acceptor>MyAcceptor;

class My_Svc_Handler:public ACE_Svc_Handler <ACE_SOCK_STREAM,ACE_NULL_SYNCH>
{
public:
    My_Svc_Handler()
   {
        data= new char[DATA_SIZE];
   }
   int open(void*)
   {
        std::cout <<"Connection established" <<std::endl;
        return ACE_Svc_Handler <ACE_SOCK_STREAM,ACE_NULL_SYNCH>::open();
    }

    int handle_input(ACE_HANDLE)
    {
        int byteCount = 0;
        if ( (byteCount = this->peer().recv_n(data,DATA_SIZE)) == -1)
        {
            ACE_OS::printf(" << Error!\n");
        }
        else if (byteCount == 0) {
                ACE_OS::printf(" client disconnected!\n");
                return -1;
        }
        else {
            data[byteCount] = 0;
            ACE_OS::printf(" << %s\n",data);
        }

        return 0;
    }
    int handle_close(ACE_HANDLE, ACE_Reactor_Mask) {
            ACE_OS::printf("handle_close() called!\n");
            delete[] data;
            return 0;
    }
private:
    char* data;
};

int main(int argc, char* argv[])
{
    ACE_INET_Addr addr(PORT_NUM);

    MyAcceptor acceptor(addr,ACE_Reactor::instance());
    ACE_Reactor::instance()->run_event_loop();

    return 0;
}

class Client
{
public:
    Client( char *addr, int port )
           :remoteAddr_( port, addr )
    {
    }

    int ConnectToServer()
    {
        if ( connector_.connect( clientStream_, remoteAddr_ ) == -1  )
        {
              ACE_ERROR_RETURN ((LM_ERROR,"(%P|%t) %p\n","connection failed"),-1);
        }
       else
       {
            ACE_DEBUG ((LM_DEBUG,"(%P|%t) connected to %s\n",remoteAddr_.get_host_name()));
       }

    return 0;
    }

    int SendToServer()
    {
        char *buf = "Hello world!";
        if( clientStream_.send_n( buf, ACE_OS::strlen(buf)+1, 0 ) != -1 )
        {
            ACE_DEBUG( (LM_DEBUG,"Send %s to server succeed!\n", buf) );
        }
        else
        {
            ACE_DEBUG( (LM_DEBUG,"Send %s to server failed!\n", buf) );
        }
     //ACE_OS::sleep(1);
     clientStream_.close();
     return 0;
     }

private:
    ACE_INET_Addr remoteAddr_;
    ACE_SOCK_Connector connector_;
    ACE_SOCK_Stream clientStream_;
};

int main_client( int argc, char *argv[] )
{
    char *remoteAddr = "127.0.0.1";
    int  port = 19999;
    Client client( remoteAddr, port );
    client.ConnectToServer();
    client.SendToServer();

    return 0;
};

[ 本帖最后由 wishel 于 2009-10-23 16:28 编辑 ]
发表于 2009-10-23 16:27:12 | 显示全部楼层
更好的办法是用clientStream_.close();代替ACE_OS::sleep(1)
这样用比较温和的方式关闭socket,而不是进程结束交给os强行关闭。残留在socket buffer中的数据仍然会发送出去。
 楼主| 发表于 2009-10-27 00:03:01 | 显示全部楼层

回复 #5 wishel 的帖子

谢谢版主,辛苦了,我调试到后来也想到这个问题了。小弟刚开始学习ACE,请多指教,谢谢
 楼主| 发表于 2009-10-27 00:31:26 | 显示全部楼层

回复 #5 wishel 的帖子

请问版主,为什么在class My_Svc_Handler中的函数  
  int handle_close(ACE_HANDLE, ACE_Reactor_Mask) {
            ACE_OS::printf("handle_close() called!\n");
            delete[] data;
            return 0;
}
释放内存失败呢?谢谢楼主,望得到你的指导,谢谢!
发表于 2009-10-27 16:27:25 | 显示全部楼层
原帖由 pengxiqin 于 2009-10-27 00:31 发表
请问版主,为什么在class My_Svc_Handler中的函数  
  int handle_close(ACE_HANDLE, ACE_Reactor_Mask) {
            ACE_OS::printf("handle_close() called!\n");
            delete[] data;
            return  ...

我运行的时候没问题的啊。释放失败后是什么表现呢?异常退出还是打印了出错信息?
 楼主| 发表于 2009-10-28 00:38:30 | 显示全部楼层

回复 #8 wishel 的帖子

弹出一个异常窗口报告如下错误:

我在很多释放内存的地方都碰到这种错误,不知道为什么?

我的操作系统是:Microsoft Windows XP Professional 版本2002 Service Pack2
编译器是vc 2003

[ 本帖最后由 pengxiqin 于 2009-10-28 00:51 编辑 ]

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?用户注册

×
发表于 2009-10-28 14:49:25 | 显示全部楼层
不知道你改了我发的程序没。这么简单的new[] + delete[],应该不会出问题。

你可以测下:
data= new char[12];
delete[] data;

如果出问题就是系统问题了。
您需要登录后才可以回帖 登录 | 用户注册

本版积分规则

Archiver|手机版|小黑屋|ACE Developer ( 京ICP备06055248号 )

GMT+8, 2024-11-22 18:17 , Processed in 0.021378 second(s), 5 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表