c++ - 多线程服务器在一个线程中处理多个客户端

标签 c++ linux sockets c++11

我想使用 C++11 和标准 linux C 库创建一个多线程套接字服务器。

最简单的方法是为每个传入连接打开一个新线程,但必须有其他方法,因为 Apache 没有这样做。据我所知,Apache 在一个线程中处理多个连接。如何实现这样的系统?

我想创建一个线程,始终监听新客户端并将这个新客户端分配给一个线程。但是,如果所有线程当前都在执行“select()”,有无限超时并且没有任何已分配的客户端正在执行任何操作,则客户端可能需要一段时间才能可用。

所以“select()”需要超时。将超时设置为 0.5 毫秒会很好,但我想工作负载可能会增加太多,不是吗?

你们中有人能告诉我如何实现这样一个系统,为每个线程处理多个客户端吗? PS:希望我的英语足够好让你明白我的意思;)

最佳答案

将多个请求多路复用到单个线程上的标准方法是使用 Reactor 模式。一个中央对象(通常称为 SelectServer、SocketServer 或 IOService)监控所有套接字运行的请求,并在套接字准备好继续读取或写入时发出回调。

正如其他人所说,自己动手可能不是一个好主意。处理超时、错误和跨平台兼容性(例如,用于 linux 的 epoll、用于 bsd 的 kqueue、用于 windows 的 iocp)是棘手的。将 boost::asio 或 libevent 用于生产系统。

这里有一个框架 SelectServer(编译但未测试)给你一个想法:

#include <sys/select.h>

#include <functional>
#include <map>

class SelectServer {
 public:
  enum ReadyType {
    READABLE = 0,
    WRITABLE = 1
  };

  void CallWhenReady(ReadyType type, int fd, std::function<void()> closure) {
    SocketHolder holder;
    holder.fd = fd;
    holder.type = type;
    holder.closure = closure;
    socket_map_[fd] = holder;
  }

  void Run() {
    fd_set read_fds;
    fd_set write_fds;
    while (1) {
      if (socket_map_.empty()) break;

      int max_fd = -1;
      FD_ZERO(&read_fds);
      FD_ZERO(&write_fds);
      for (const auto& pr : socket_map_) {
        if (pr.second.type == READABLE) {
          FD_SET(pr.second.fd, &read_fds);
        } else {
          FD_SET(pr.second.fd, &write_fds);
        }
        if (pr.second.fd > max_fd) max_fd = pr.second.fd;
      }

      int ret_val = select(max_fd + 1, &read_fds, &write_fds, 0, 0);
      if (ret_val <= 0) {
        // TODO: Handle error.
        break;
      } else {
        for (auto it = socket_map_.begin(); it != socket_map_.end(); ) {
          if (FD_ISSET(it->first, &read_fds) ||
              FD_ISSET(it->first, &write_fds)) {
            it->second.closure();
            socket_map_.erase(it++);
          } else {
            ++it;
          }
        }
      }
    }
  }

 private:
  struct SocketHolder {
    int fd;
    ReadyType type;
    std::function<void()> closure;
  };

  std::map<int, SocketHolder> socket_map_;
};

关于c++ - 多线程服务器在一个线程中处理多个客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12236903/

相关文章:

linux - 如何使用 curl 将文本文件打印到 jira api

sockets - 为什么我们需要SocketOptions.SO_BROADCAST才能启用广播?

c++ - 不使用 STL 的原因是什么?

c++ - 为什么 g++ 无法找到已安装的系统包含?

c - 如何验证tcp校验和

c - linux c 中的信号?

java - ubuntu (C) 和 windows (Java) 之间的 TCP/IP 连接

c++ - Windows Metro 模式 (C++) : Waiting on semaphore (WaitForSingleObjectEx): failed with Access Denied [partially solved]

c++ - 通过引用 v. 通过指针传递——优点?

android - Qt/C++ 的跨平台移动通知?