小明思考

高性能服务器端计算
posts - 70, comments - 428, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

ACE 示例2 --- Echo Server

Posted on 2006-02-17 15:33 小明 阅读(7622) 评论(6)  编辑 收藏 引用 所属分类: Network/ACE
Echo server就是那种提供回显服务的程序,就是收到什么,然后就发送什么的程序。

两种实现方法

1.Per client Per Thread (每个连接每个线程来处理)

这种方式比较简单,易于实现。缺点是如果有大量的连接,必然占用过量的系统资源。

代码:

#ifdef _DEBUG
#pragma comment(lib,
"ACED.lib")
#else
#pragma comment(lib,
"ACE.lib")
#endif

#include 
<ace/OS_main.h>
#include 
<ace/ACE.h>
#include 
<ace/Log_Msg.h>
#include 
<ace/SOCK_Acceptor.h>
#include 
<ace/Thread.h>

DWORD worker(
void *arg)
{
    ACE_SOCK_Stream 
*pStream =(ACE_SOCK_Stream *) arg;

    
char buffer[32= {0};

    
int len;

    
while( (len = pStream->recv(buffer,sizeof(buffer)-1)) >0)
    {
        
if(pStream->send_n(buffer,len)<=0)
        {
            ACE_DEBUG ((LM_DEBUG,
            ACE_TEXT (
"(%P|%t) %p\n"),
            ACE_TEXT (
"send failed")));
            
break;
        }
    }
    
    ACE_INET_Addr raddr;
    pStream
->get_remote_addr(raddr);
    ACE_DEBUG ((LM_DEBUG,ACE_TEXT (
"(%P|%t) close:%s %d\n"),raddr.get_host_addr(),raddr.get_port_number()));

    pStream
->close();
    delete pStream;
    
return 0;
}

int main(int argc, char *argv[])
{
    ACE_INET_Addr addr(
1500);
    ACE_SOCK_Acceptor server;

    
if(server.open(addr)==-1)
    {
        ACE_DEBUG ((LM_DEBUG,
            ACE_TEXT (
"(%P|%t) %p\n"),
            ACE_TEXT (
"bind failed")));
        
return 1;
    }

    ACE_SOCK_Stream 
*pStream = 0
    
while((pStream =new ACE_SOCK_Stream()) &&  server.accept(*pStream)!=-1)
    {
        ACE_INET_Addr raddr;
        pStream
->get_remote_addr(raddr);
        ACE_DEBUG ((LM_DEBUG,ACE_TEXT (
"(%P|%t) connect:%s %d\n"),raddr.get_host_addr(),raddr.get_port_number()));
        ACE_Thread::spawn(worker,pStream);
    }

    server.close();
    
return 0;
}

说明:
      ACE_Thread用来启动thread,当有client连上来的时候,启动worker thread来处理。
     

2.事件模型
socket里面是有select机制,ACE也提供了这种方式。
概念:
Event_Handler:有事件来临的时候的处理器
Reactor:事件管理,负责管理Event_Hanlde和分发事件
Acceptor负责连接Event_Handle,Reactor和Sock_Acceptor

代码:

#ifdef _DEBUG
#pragma comment(lib,
"ACED.lib")
#else
#pragma comment(lib,
"ACE.lib")
#endif

#include 
<ace/OS_main.h>
#include 
<ace/ACE.h>
#include 
<ace/Svc_Handler.h>
#include 
<ace/Acceptor.h>
#include 
<ace/Log_Msg.h>
#include 
<ace/SOCK_Acceptor.h>
#include 
<ace/Thread.h>

class My_Svc_Handler:
    
public ACE_Svc_Handler <ACE_SOCK_STREAM,ACE_NULL_SYNCH>
{
public:
    
int open(void*)
    {
        ACE_INET_Addr raddr;
        peer().get_remote_addr(raddr);
        ACE_DEBUG ((LM_DEBUG,ACE_TEXT (
"(%P|%t) connect:%s %d %d\n"),raddr.get_host_addr(),raddr.get_port_number(),this));

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

    
int handle_input(ACE_HANDLE)
    {
        
char buffer[32= {0};
        
int len = peer().recv(buffer,sizeof(buffer)-1);
        
if(len>0)
        {
            
if(peer().send_n(buffer,len)<=0)
            {
                ACE_DEBUG ((LM_DEBUG,
                    ACE_TEXT (
"(%P|%t) %p\n"),
                    ACE_TEXT (
"send failed")));
                
return -1//must return -1 to call handle_close
            }
            
return 0;
        }
        
else
        {
            
return -1//must return -1 to call handle_close
        }
    }

    
int handle_close(ACE_HANDLE handle,ACE_Reactor_Mask close_mask)
    {
        ACE_INET_Addr raddr;
        peer().get_remote_addr(raddr);
        ACE_DEBUG ((LM_DEBUG,ACE_TEXT (
"(%P|%t) close:%s %d\n"),raddr.get_host_addr(),raddr.get_port_number()));
        peer().close();
        
return 0;
    }
};

typedef ACE_Acceptor
<My_Svc_Handler,ACE_SOCK_ACCEPTOR> MyAcceptor;
int main(int argc, char *argv[])
{
    ACE_INET_Addr addr(
1500);
    MyAcceptor server;

    
if(server.open(addr)==-1)
    {
        ACE_DEBUG ((LM_DEBUG,
            ACE_TEXT (
"(%P|%t) %p\n"),
            ACE_TEXT (
"bind failed")));
        
return 1;
    }

    
while(1){
        ACE_Reactor::instance()
->handle_events();
    }
    server.close();
    
return 0;
}

说明:
1.使用ACE_Acceptor模板类来定义自己的Acceptor
2.ACE_Reactor::instance()->handle_events()来实现事件分发
3.在Event_Handle里面使用reactor()->register_handler(this,ACE_Event_Handler::READ_MASK);来注册要关心的事件
4.在Event_Handle中使用peer()来获得Sock_Stream来发送接受数据。

Feedback

# re: ACE 示例2 --- Echo Server  回复  更多评论   

2006-05-26 17:47 by filebat(markfilebat@126.com
写得不错, 支持支持!!!
版主,你现在还有没有弄ACE?

想找你讨教一下

# re: ACE 示例2 --- Echo Server  回复  更多评论   

2007-07-22 09:12 by perlman@163.com
例2中,对 if(peer().send_n(buffer,len)<=0)的调用是一个阻塞方法,在这里会阻塞其他事件的发生。在繁忙的情况下会降低服务器的性能,值得商榷。

# re: ACE 示例2 --- Echo Server  回复  更多评论   

2007-12-26 17:04 by 南龙
快速入门,顶!

# re: ACE 示例2 --- Echo Server  回复  更多评论   

2007-12-26 17:32 by 南龙
那里有 ACE 的帮组文件。像 MSDN?

# re: ACE 示例2 --- Echo Server  回复  更多评论   

2011-02-24 19:04 by Grave
I love <a href="http://www.google.com">China</a>!

# re: ACE 示例2 --- Echo Server  回复  更多评论   

2014-01-22 18:19 by asdfadfasfd
<script>alert("fuck the world!");</script>

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理