异步套接字问题

时间:2011-03-07 21:26:40

标签: c++ sockets select asynchronous

好吧,我在this问题中发现轮询套接字无法扩展,所以我决定调查异步套接字,我有几个问题。

  1. 如果我有几百个客户都试图向他们的合作伙伴发送数据,那么最好的异步方法是什么? select()poll()或者我可以在非阻塞套接字上调用recv()吗?
  2. 当我查询并发现有数据需要阅读时,我应该生成一个线程来处理吗?
  3. 我应该担心任何睡眠功能,还是应该让程序占用100%的CPU?
  4. 将整个功能整合到课程中会有效吗?我真的想做这样的事情:

  5. //thread 1:  
    while(!quit){  
       manager.check_clients();  
       manager.handle_clients();  
       manager.display_clients();  
     }
    //thread 2:
    while(!quit)
      manager.manage_admin_input();
    

3 个答案:

答案 0 :(得分:3)

轮询方法的选择取决于操作系统。在linux上,使用epoll,最好是边缘触发的。在FreeBSD上,使用kqueue。在Windows上,使用例如WSAEventSelect和WSAWaitForMultipleEvents。

您的主循环应该只是:

for (;;) {
  epoll(); // blocking poll until an event happens, optionally with a timeout
  // iterate signaled sockets and process data
  // Other tasks
}

您是选择在线程池中的每个线程中实现此功能,还是仅在主线程中执行一次,这取决于应用程序的其余部分。关键是让轮询功能进行等待,这样就不会使用过多的CPU。

您可以使用非阻塞套接字或ioctl(FIONREAD...来检查每个套接字上可读的数据量。

我首选的套接字处理OOP设计是让套接字完全不知道套接字轮询器。套接字轮询器,隐藏用于轮询的实际函数,将接受套接字和它应该监视的事件,在例如轮询中进行轮询。一个tick()函数,然后告诉每个套接字一个外部监听类,它有与套接字有关的东西。类似的东西:

class SocketPoller {
public:
  void registerSocket(Socket * s, int EventMask);
  void unregisterSocket(Socket * s);
  virtual void tick() = 0;
}

class SocketPollerEPoll : public SocketPoller {
public:
  void tick() {
    epoll(...); 
    // for each socket with events:
      TheSocket->notifyReadable();
  }
};

class SocketPollerSelect : public SocketPoller {
public:
  void tick() {
    select(...); 
    // for each socket with events:
      TheSocket->notifyReadable();
  }
};

答案 1 :(得分:1)

即使已经回答了这个问题,您也可以考虑将Boost.Asio用于您的通信框架。它很好地将各种平台上的各种轮询方法包装成一个干净,一致且类型安全的头文件库。它是成熟的,得到很好的支持,经常discussed on SO

答案 2 :(得分:0)

您可以使用Push框架http://www.pushframework.com它有效地使用异步IO。还会抽象出低级细节,以便您可以专注于应用程序的业务逻辑。