用ACE写网络服务器

Java的NIO写网络服务是非常简单的,而且性能和伸缩性都较高。如何用C++也达到这样的效果呢?答案是肯定的。 ACE就可以完成这个任务。ACE是一个重型的网络服务实现方案,也具有跨平台,但毕竟是C++实现,而且它的怪异的命名和高级的模式使它的学习曲线都较高,对于追求高性能的C++实现,这些又算不了什么。

与Java的NIO相比,ACE更进一步,它使用了Reactor模式,将Socket的操作封装在一个个的对象实例中,我们可以不关心Socket操作,而只关心自己的逻辑实现了。ACE也采用了“事件分离”的方法,将对Socket的读和写操作分离到对应的实例中处理。可以达到很高的性能。

下面是服务器端的代码,读取一个文件,并将文件的内容发给到客户端上。和对应的Java例子一样,也是以4K为单位进行传送。在open()函数中注册了写事件。

#include <stdio.h>
#include <tchar.h>
#include <ace/Acceptor.h>
#include <ace/SOCK_Acceptor.h>
#include <ace/SOCK_Stream.h>
#include <ace/Svc_Handler.h>

static const char * filename = "bigfile.dat";
// 服务器处理代码,每一个链接都要隐式生成这样一个的实例
class ACEServer : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
{
  typedef ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> super;
public:
  ACEServer() {
    ACE_DEBUG ((LM_DEBUG,"(%P|%t) Create New ACEServer/n"));
  };
public:
  virtual ~ACEServer() {
    ACE_DEBUG ((LM_DEBUG,"(%P|%t) Destory ACEServer/n"));
  };
  virtual int open(void *p){
    if((file = fopen(filename, "rb")) == NULL) {
      ACE_DEBUG ((LM_DEBUG,"(%P|%t) Failed to open file/n"));
      return -1;
    }
    total = 0;
    ACE_DEBUG ((LM_DEBUG,"(%P|%t) New Client Connection/n"));
    // 要注册写事件
    ACE_Reactor::instance()->register_handler(this, 
      ACE_Event_Handler::WRITE_MASK);
    return super::open(p);
  }
protected:
  virtual int handle_output(ACE_HANDLE) {
    size_t count = fread(block, sizeof(char), sizeof(block), file);
    // 没有内容了,就注销
    if(count <= 0) {
      ACE_DEBUG ((LM_DEBUG,"/n(%P|%t) Send Finished!/n"));
      fclose(file);
      file = NULL;
      return -1;
    }
    this->peer().send(block, count);
    total += count;
    ACE_DEBUG((LM_DEBUG, ".", total));
    return 1;
  }
private:
  char block[4096];
  FILE *file;
  size_t total;
};

int _tmain(int argc, _TCHAR* argv[])
{
  typedef  ACE_Acceptor<ACEServer, ACE_SOCK_ACCEPTOR> MyServer;
  ACE_INET_Addr address(12345);
  MyServer server;
  if(server.open(address== -1) {
    ACE_DEBUG((LM_DEBUG, "(%P|%t) Failed to Create Server/n"));
    return -1;
  }
  ACE_Reactor::instance()->run_reactor_event_loop();
  return 0;
}

下面是客户端代码,注意:由于open()函数默认注册了读事件,所以在open()中没有做注册事件的动作。

#include <stdio.h>
#include <tchar.h>
#include <ace/Connector.h>
#include <ace/SOCK_Connector.h>
#include <ace/SOCK_Stream.h>
#include <ace/Svc_Handler.h>
// 客户端,获取服务器的文件内容
class ACEClient : public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
{
  typedef ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> super;
public:
  ACEClient() {
    ACE_DEBUG ((LM_DEBUG,"(%P|%t) Create New ACEClient/n"));
  };
public:
  virtual ~ACEClient() {
    ACE_DEBUG ((LM_DEBUG,"(%P|%t) Destory ACEClient/n"));
  };
  virtual int open(void *p){
    total = 0;
    ACE_DEBUG ((LM_DEBUG,"(%P|%t) Connected to Server/n"));
    return super::open(p);
  }
protected:
  // 处理服务器发过来的内容
  virtual int handle_input(ACE_HANDLE) {
    int count = this->peer().recv(block, sizeof(block));
    if(count > 0) {
      total += count;
      ACE_DEBUG ((LM_DEBUG,"(%P|%t) Received %d bytes/n", total));
      return 0;
    }
    // 结束了,停止反应器
    if(count == && ACE_OS::last_error() != EWOULDBLOCK) {
      ACE_Reactor::instance()->end_reactor_event_loop();
      return -1;
    }
    ACE_DEBUG ((LM_DEBUG,"(%P|%t) Received %d bytes/n", total));
    return 0;
  }
private:
  char block[4096];
  size_t total;
};


int _tmain(int argc, _TCHAR* argv[])
{
  typedef ACE_Connector<ACEClient, ACE_SOCK_CONNECTOR> MyClient;
  ACE_INET_Addr address(12345"localhost");
  MyClient client;
  ACEClient c;
  ACEClient *pc = &c;
  if(client.connect(pc, address== -1) {
    ACE_DEBUG((LM_DEBUG, "(%P|%t) Failed to connect server!/n"));
    return -1;
  }
  ACE_Reactor::instance()->run_reactor_event_loop();
  return 0;
}
 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值