pengxiqin 发表于 2009-10-20 21:43:30

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

为什么在客户端给服务器端发信息的时候,服务器端的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;
   }
   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 = 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";
    intport = 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 编辑 ]

modern 发表于 2009-10-21 11:15:17

1.收不到是一个什么概念?收不全还是recv返回-1了?最好提供一些详细的运行期信息。
2.handle_input被调用了两次,描述的太笼统了,把堆栈信息贴出来看看先。

wishel 发表于 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退出连接的情况。

wishel 发表于 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;
   }
   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 = 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";
    intport = 19999;
    Client client( remoteAddr, port );
    client.ConnectToServer();
    client.SendToServer();

    return 0;
};

[ 本帖最后由 wishel 于 2009-10-23 16:28 编辑 ]

wishel 发表于 2009-10-23 16:27:12

更好的办法是用clientStream_.close();代替ACE_OS::sleep(1)
这样用比较温和的方式关闭socket,而不是进程结束交给os强行关闭。残留在socket buffer中的数据仍然会发送出去。

pengxiqin 发表于 2009-10-27 00:03:01

回复 #5 wishel 的帖子

谢谢版主,辛苦了,我调试到后来也想到这个问题了。小弟刚开始学习ACE,请多指教,谢谢

pengxiqin 发表于 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;
}
释放内存失败呢?谢谢楼主,望得到你的指导,谢谢!

wishel 发表于 2009-10-27 16:27:25

原帖由 pengxiqin 于 2009-10-27 00:31 发表 http://www.acejoy.com/bbs/images/common/back.gif
请问版主,为什么在class My_Svc_Handler中的函数
int handle_close(ACE_HANDLE, ACE_Reactor_Mask) {
            ACE_OS::printf("handle_close() called!\n");
            delete[] data;
            return...

我运行的时候没问题的啊。释放失败后是什么表现呢?异常退出还是打印了出错信息?

pengxiqin 发表于 2009-10-28 00:38:30

回复 #8 wishel 的帖子

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

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

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

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

wishel 发表于 2009-10-28 14:49:25

不知道你改了我发的程序没。这么简单的new[] + delete[],应该不会出问题。

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

如果出问题就是系统问题了。
页: [1] 2
查看完整版本: 求助ACE中ACE_Acceptor下函数peer().recv_n接收不到数据