实现一个同步的并发型TCP服务器

来源:互联网 发布:spring boot 配置端口 编辑:程序博客网 时间:2024/04/29 02:32

1. 相关定义

  1. 同步: 使用会阻塞线程执行的I/O和控制操作,该阻塞会持续到相关操作完成或有错误产生
  2. 并发型: 服务器可以同时处理多个客户端请求

2. 基本流程

  1. 分配一个acceptor套接字并将其绑定到一个特定的TCP端口上.
  2. 服务器执行以下的循环直至停止:
    1. 等待客户端的连接请求
    2. 接受客户端的连接请求(会发生tcp的三次握手)
    3. 产生(spawn)一个控制线程,在这个线程的上下文中:
      • 等待客户端发送的请求信息
      • 读取请求信息内容
      • 处理请求信息内容
      • 将(处理完毕的)请求信息回送给客户端
      • 关闭和客户端的连接并销毁相关套接字

3. 相关源代码

//Compile: g++ -std=c++11 -o server Server.cc -lboost_system -lpthread#include <boost/asio.hpp>#include <thread>#include <atomic>#include <memory>#include <iostream>using namespace boost;class Service { public:  Service() {}  void StartHandligClient(std::shared_ptr<asio::ip::tcp::socket> sock) {    std::thread th(([this, sock]() {          HandleClient(sock);    }));    th.detach();  } private:  void HandleClient(std::shared_ptr<asio::ip::tcp::socket> sock) {    try {      asio::streambuf request;      asio::read_until(*sock.get(), request, '\n');      // Emulate request processing.      int i = 0;      while (i != 1000000)        ++i;      std::this_thread::sleep_for(std::chrono::milliseconds(500));      // sending response.      std::string response = "Response\n";      asio::write(*sock.get(), asio::buffer(response));    } catch (const system::system_error &e) {      std::cout << "Error occured! Error code = " << e.code()                 << ". Message: " << e.what();    }    // Clean-up.cause Service instance is allocated in heap;    delete this;  }};class Acceptor { public:  Acceptor(asio::io_service &ios, unsigned short port_num)    : ios_(ios), acceptor_(ios_, asio::ip::tcp::endpoint(asio::ip::address_v4::any(), port_num))  {    acceptor_.listen();  }  void Accept() {    std::shared_ptr<asio::ip::tcp::socket> sock(new asio::ip::tcp::socket(ios_));    acceptor_.accept(*sock.get());    (new Service)->StartHandligClient(sock);  }private: asio::io_service &ios_; asio::ip::tcp::acceptor acceptor_;};class Server { public:  Server() : stop_(false)  {  }  void Start(unsigned short port_num) {    thread_.reset(new std::thread([this, port_num]() {          Run(port_num);          }));  }  void Stop() {    stop_.store(true);    thread_->join();  } private:  void Run(unsigned short port_num) {    Acceptor acc(ios_, port_num);    while (!stop_.load()) {      acc.Accept();    }  }  std::unique_ptr<std::thread> thread_;  std::atomic<bool> stop_;  asio::io_service ios_;};int main(){  unsigned short port_num = 3333;  try {    Server srv;    srv.Start(port_num);    std::this_thread::sleep_for(std::chrono::seconds(600));    srv.Stop();  } catch (const system::system_error &e) {    std::cout << "Error occured! Error code = " << e.code() << ". Message: "              << e.what();  }  return 0;}

4. 缺陷及解决方案

  1. 在Server类中调用Stop()方法后,服务器可能会一直阻塞,直至最后的连接请求到来。(E.g. 当Server的线程阻塞在acc.Accept()时, 调用Stop()方法后,服务器将会等待这些阻塞操作完成而不会停止)

    解决方案:

    • 可以在Stop()方法中创建一个虚拟的主动连接,发送虚拟的请求
    • 创建一个特殊的客户端,发送特殊的关闭服务消息(E.g. stop\n)
  2. 服务器容易被客户端恶意攻击(E.g. 客户端只连接,却不发送请求,那么服务器将一直处于阻塞状态)

    解决方案:

    • 使用非阻塞套接字(将会把我们的服务器转入reactive模式)
    • 使用异步I/O
0 0
原创粉丝点击