这么简单 你为什么想不到 四个 服务器设计模型(42)

四个 服务器设计模型(42)

五个简单TCP协议(MuduoManual.pdf P50)
muduo库网络模型使用示例(sudoku求解服务器MuduoManual.pdf P35 )

reactor(一个IO线程)

reactor + threadpool (一个IO + 多个计算线程)

multiple reactor (多个IO线程)

one loop per thread + thread pool (多个IO线程 + 计算线程池)




网络编程关注4个半事件:
连接建立
连接断开
消息到达
信息发送完毕(对于低流量的服务来说,通常不需要关注该事件)

如何实现server
1 提供一个xxxServer类
2 在该类中包含一个TcpServer对象
注册一些事件
OnConnection
OnMessage
OnWriteComplete

TcpConnection::shutdown () 内部实现,只关闭写入这一半

--------------------------------------

----------------------------------------

下面的程序都是用来解 数独 的,数独的实现如下

sudoku.h

  1. #ifndef MUDUO_EXAMPLES_SUDOKU_SUDOKU_H  
  2. #define MUDUO_EXAMPLES_SUDOKU_SUDOKU_H  
  3.   
  4.   
  5. #include <muduo/base/Types.h>  
  6.   
  7. // FIXME, use (const char*, len) for saving memory copying.  
  8. muduo::string solveSudoku(const muduo::string& puzzle);  
  9. const int kCells = 81;  
  10.   
  11. #endif  


sudoku.cc


  1. #include "sudoku.h"  
  2.   
  3. #include <vector>  
  4. #include <assert.h>  
  5. #include <string.h>  
  6.   
  7. using namespace muduo;  
  8.   
  9. struct Node;  
  10. typedef Node Column;  
  11. struct Node  
  12. {  
  13.     Node* left;  
  14.     Node* right;  
  15.     Node* up;  
  16.     Node* down;  
  17.     Column* col;  
  18.     int name;  
  19.     int size;  
  20. };  
  21.   
  22. const int kMaxNodes = 1 + 81*4 + 9*9*9*4;  
  23. const int kMaxColumns = 400;  
  24. const int kRow = 100, kCol = 200, kBox = 300;  
  25.   
  26. class SudokuSolver  
  27. {  
  28.  public:  
  29.     SudokuSolver(int board[kCells])  
  30.       : inout_(board),  
  31.         cur_node_(0)  
  32.     {  
  33.         stack_.reserve(100);  
  34.   
  35.         root_ = new_column();  
  36.         root_->left = root_->right = root_;  
  37.         memset(columns_, 0, sizeof(columns_));  
  38.   
  39.         bool rows[kCells][10] = { {false} };  
  40.         bool cols[kCells][10] = { {false} };  
  41.         bool boxes[kCells][10] = { {false} };  
  42.   
  43.         for (int i = 0; i < kCells; ++i) {  
  44.             int row = i / 9;  
  45.             int col = i % 9;  
  46.             int box = row/3*3 + col/3;  
  47.             int val = inout_[i];  
  48.             rows[row][val] = true;  
  49.             cols[col][val] = true;  
  50.             boxes[box][val] = true;  
  51.         }  
  52.   
  53.         for (int i = 0; i < kCells; ++i) {  
  54.             if (inout_[i] == 0) {  
  55.                 append_column(i);  
  56.             }  
  57.         }  
  58.   
  59.         for (int i = 0; i < 9; ++i) {  
  60.             for (int v = 1; v < 10; ++v) {  
  61.                 if (!rows[i][v])  
  62.                     append_column(get_row_col(i, v));  
  63.                 if (!cols[i][v])  
  64.                     append_column(get_col_col(i, v));  
  65.                 if (!boxes[i][v])  
  66.                     append_column(get_box_col(i, v));  
  67.             }  
  68.         }  
  69.   
  70.         for (int i = 0; i < kCells; ++i) {  
  71.             if (inout_[i] == 0) {  
  72.                 int row = i / 9;  
  73.                 int col = i % 9;  
  74.                 int box = row/3*3 + col/3;  
  75.                 //int val = inout[i];  
  76.                 for (int v = 1; v < 10; ++v) {  
  77.                     if (!(rows[row][v] || cols[col][v] || boxes[box][v])) {  
  78.                         Node* n0 = new_row(i);  
  79.                         Node* nr = new_row(get_row_col(row, v));  
  80.                         Node* nc = new_row(get_col_col(col, v));  
  81.                         Node* nb = new_row(get_box_col(box, v));  
  82.                         put_left(n0, nr);  
  83.                         put_left(n0, nc);  
  84.                         put_left(n0, nb);  
  85.                     }  
  86.                 }  
  87.             }  
  88.         }  
  89.     }  
  90.   
  91.     bool solve()  
  92.     {  
  93.         if (root_->left == root_) {  
  94.             for (size_t i = 0; i < stack_.size(); ++i) {  
  95.                 Node* n = stack_[i];  
  96.                 int cell = -1;  
  97.                 int val = -1;  
  98.                 while (cell == -1 || val == -1) {  
  99.                     if (n->name < 100)  
  100.                         cell = n->name;  
  101.                     else  
  102.                         val = n->name % 10;  
  103.                     n = n->right;  
  104.                 }  
  105.   
  106.                 //assert(cell != -1 && val != -1);  
  107.                 inout_[cell] = val;  
  108.             }  
  109.             return true;  
  110.         }  
  111.   
  112.         Column* const col = get_min_column();  
  113.         cover(col);  
  114.         for (Node* row = col->down; row != col; row = row->down) {  
  115.             stack_.push_back(row);  
  116.             for (Node* j = row->right; j != row; j = j->right) {  
  117.                 cover(j->col);  
  118.             }  
  119.             if (solve()) {  
  120.                 return true;  
  121.             }  
  122.             stack_.pop_back();  
  123.             for (Node* j = row->left; j != row; j = j->left) {  
  124.                 uncover(j->col);  
  125.             }  
  126.         }  
  127.         uncover(col);  
  128.         return false;  
  129.     }  
  130.   
  131.  private:  
  132.   
  133.     Column* root_;  
  134.     int*    inout_;  
  135.     Column* columns_[400];  
  136.     std::vector<Node*> stack_;  
  137.     Node    nodes_[kMaxNodes];  
  138.     int     cur_node_;  
  139.   
  140.     Column* new_column(int n = 0)  
  141.     {  
  142.         assert(cur_node_ < kMaxNodes);  
  143.         Column* c = &nodes_[cur_node_++];  
  144.         memset(c, 0, sizeof(Column));  
  145.         c->left = c;  
  146.         c->right = c;  
  147.         c->up = c;  
  148.         c->down = c;  
  149.         c->col = c;  
  150.         c->name = n;  
  151.         return c;  
  152.     }  
  153.   
  154.     void append_column(int n)  
  155.     {  
  156.         assert(columns_[n] == NULL);  
  157.   
  158.         Column* c = new_column(n);  
  159.         put_left(root_, c);  
  160.         columns_[n] = c;  
  161.     }  
  162.   
  163.     Node* new_row(int col)  
  164.     {  
  165.         assert(columns_[col] != NULL);  
  166.         assert(cur_node_ < kMaxNodes);  
  167.   
  168.         Node* r = &nodes_[cur_node_++];  
  169.   
  170.         //Node* r = new Node;  
  171.         memset(r, 0, sizeof(Node));  
  172.         r->left = r;  
  173.         r->right = r;  
  174.         r->up = r;  
  175.         r->down = r;  
  176.         r->name = col;  
  177.         r->col = columns_[col];  
  178.         put_up(r->col, r);  
  179.         return r;  
  180.     }  
  181.   
  182.     int get_row_col(int row, int val)  
  183.     {  
  184.         return kRow+row*10+val;  
  185.     }  
  186.   
  187.     int get_col_col(int col, int val)  
  188.     {  
  189.         return kCol+col*10+val;  
  190.     }  
  191.   
  192.     int get_box_col(int box, int val)  
  193.     {  
  194.         return kBox+box*10+val;  
  195.     }  
  196.   
  197.     Column* get_min_column()  
  198.     {  
  199.         Column* c = root_->right;  
  200.         int min_size = c->size;  
  201.         if (min_size > 1) {  
  202.             for (Column* cc = c->right; cc != root_; cc = cc->right) {  
  203.                 if (min_size > cc->size) {  
  204.                     c = cc;  
  205.                     min_size = cc->size;  
  206.                     if (min_size <= 1)  
  207.                         break;  
  208.                 }  
  209.             }  
  210.         }  
  211.         return c;  
  212.     }  
  213.   
  214.     void cover(Column* c)  
  215.     {  
  216.         c->right->left = c->left;  
  217.         c->left->right = c->right;  
  218.         for (Node* row = c->down; row != c; row = row->down) {  
  219.             for (Node* j = row->right; j != row; j = j->right) {  
  220.                 j->down->up = j->up;  
  221.                 j->up->down = j->down;  
  222.                 j->col->size--;  
  223.             }  
  224.         }  
  225.     }  
  226.   
  227.     void uncover(Column* c)  
  228.     {  
  229.         for (Node* row = c->up; row != c; row = row->up) {  
  230.             for (Node* j = row->left; j != row; j = j->left) {  
  231.                 j->col->size++;  
  232.                 j->down->up = j;  
  233.                 j->up->down = j;  
  234.             }  
  235.         }  
  236.         c->right->left = c;  
  237.         c->left->right = c;  
  238.     }  
  239.   
  240.     void put_left(Column* old, Column* nnew)  
  241.     {  
  242.         nnew->left = old->left;  
  243.         nnew->right = old;  
  244.         old->left->right = nnew;  
  245.         old->left = nnew;  
  246.     }  
  247.   
  248.     void put_up(Column* old, Node* nnew)  
  249.     {  
  250.         nnew->up = old->up;  
  251.         nnew->down = old;  
  252.         old->up->down = nnew;  
  253.         old->up = nnew;  
  254.         old->size++;  
  255.         nnew->col = old;  
  256.     }  
  257. };  
  258.   
  259. string solveSudoku(const string& puzzle)  
  260. {  
  261.   assert(puzzle.size() == implicit_cast<size_t>(kCells));  
  262.   
  263.   string result = "NoSolution";  
  264.   
  265.   int board[kCells] = { 0 };  
  266.   bool valid = true;  
  267.   for (int i = 0; i < kCells; ++i)  
  268.   {  
  269.     board[i] = puzzle[i] - '0';  
  270.     valid = valid && (0 <= board[i] && board[i] <= 9);  
  271.   }  
  272.   
  273.   if (valid)  
  274.   {  
  275.     SudokuSolver s(board);  
  276.     if (s.solve())  
  277.     {  
  278.       result.clear();  
  279.       result.resize(kCells);  
  280.       for (int i = 0; i < kCells; ++i)  
  281.       {  
  282.         result[i] = static_cast<char>(board[i] + '0');  
  283.       }  
  284.     }  
  285.   }  
  286.   return result;  
  287. }  






reactor模型

只有一个IO线程:
    这个IO线程既负责listenfd也负责connfd

  1. #include "sudoku.h"  
  2.   
  3. #include <muduo/base/Atomic.h>  
  4. #include <muduo/base/Logging.h>  
  5. #include <muduo/base/Thread.h>  
  6. #include <muduo/net/EventLoop.h>  
  7. #include <muduo/net/InetAddress.h>  
  8. #include <muduo/net/TcpServer.h>  
  9.   
  10. #include <boost/bind.hpp>  
  11.   
  12. #include <utility>  
  13.   
  14. #include <mcheck.h>  
  15. #include <stdio.h>  
  16. #include <unistd.h>  
  17.   
  18. using namespace muduo;  
  19. using namespace muduo::net;  
  20.   
  21. class SudokuServer  
  22. {  
  23.  public:  
  24.   SudokuServer(EventLoop* loop, const InetAddress& listenAddr)  
  25.     : loop_(loop),  
  26.       server_(loop, listenAddr, "SudokuServer"),  
  27.       startTime_(Timestamp::now())  
  28.   {  
  29.     server_.setConnectionCallback(  
  30.         boost::bind(&SudokuServer::onConnection, this, _1));  
  31.     server_.setMessageCallback(  
  32.         boost::bind(&SudokuServer::onMessage, this, _1, _2, _3));  
  33.   }  
  34.   
  35.   void start()  
  36.   {  
  37.     server_.start();  
  38.   }  
  39.   
  40.  private:  
  41.   void onConnection(const TcpConnectionPtr& conn)  
  42.   {  
  43.     LOG_TRACE << conn->peerAddress().toIpPort() << " -> "  
  44.         << conn->localAddress().toIpPort() << " is "  
  45.         << (conn->connected() ? "UP" : "DOWN");  
  46.   }  
  47.   
  48.   void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp)  
  49.   {  
  50.     LOG_DEBUG << conn->name();  
  51.     size_t len = buf->readableBytes();  
  52.     while (len >= kCells + 2)  
  53.     {  
  54.       const char* crlf = buf->findCRLF();  
  55.       if (crlf)  
  56.       {  
  57.         string request(buf->peek(), crlf);  
  58.         buf->retrieveUntil(crlf + 2);  
  59.         len = buf->readableBytes();  
  60.         if (!processRequest(conn, request))  
  61.         {  
  62.           conn->send("Bad Request!\r\n");  
  63.           conn->shutdown();  
  64.           break;  
  65.         }  
  66.       }  
  67.       else if (len > 100) // id + ":" + kCells + "\r\n"  
  68.       {  
  69.         conn->send("Id too long!\r\n");  
  70.         conn->shutdown();  
  71.         break;  
  72.       }  
  73.       else  
  74.       {  
  75.         break;  
  76.       }  
  77.     }  
  78.   }  
  79.   
  80.   bool processRequest(const TcpConnectionPtr& conn, const string& request)  
  81.   {  
  82.     string id;  
  83.     string puzzle;  
  84.     bool goodRequest = true;  
  85.   
  86.     string::const_iterator colon = find(request.begin(), request.end(), ':');  
  87.     if (colon != request.end())  
  88.     {  
  89.       id.assign(request.begin(), colon);  
  90.       puzzle.assign(colon+1, request.end());  
  91.     }  
  92.     else  
  93.     {  
  94.       puzzle = request;  
  95.     }  
  96.   
  97.     if (puzzle.size() == implicit_cast<size_t>(kCells))  
  98.     {  
  99.       LOG_DEBUG << conn->name();  
  100.       string result = solveSudoku(puzzle);  
  101.       if (id.empty())  
  102.       {  
  103.         conn->send(result+"\r\n");  
  104.       }  
  105.       else  
  106.       {  
  107.         conn->send(id+":"+result+"\r\n");  
  108.       }  
  109.     }  
  110.     else  
  111.     {  
  112.       goodRequest = false;  
  113.     }  
  114.     return goodRequest;  
  115.   }  
  116.   
  117.   EventLoop* loop_;  
  118.   TcpServer server_;  
  119.   Timestamp startTime_;  
  120. };  
  121.   
  122. int main(int argc, char* argv[])  
  123. {  
  124.   LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid();  
  125.   EventLoop loop;  
  126.   InetAddress listenAddr(9981);  
  127.   SudokuServer server(&loop, listenAddr);  
  128.   
  129.   server.start();  
  130.   
  131.   loop.loop();  
  132. }  





multiple reactor
IO线程的数目多个
EventLoopThreadPoll IO线程池
直接设置server_.setThreadNum(numThreads)就OK了

main reactor 负责listenfd accept
sub reactor  负责connfd
使用roundbin轮叫策略
来一个连接,就选择下一个EventLoop,这样让多个连接分配给若干个EventLoop来处理,
而每个EventLoop属于一个IO线程,也就意味着,多个连接分配给若干个IO线程来处理。

  1. include "sudoku.h"  
  2.   
  3. #include <muduo/base/Atomic.h>  
  4. #include <muduo/base/Logging.h>  
  5. #include <muduo/base/Thread.h>  
  6. #include <muduo/net/EventLoop.h>  
  7. #include <muduo/net/InetAddress.h>  
  8. #include <muduo/net/TcpServer.h>  
  9.   
  10. #include <boost/bind.hpp>  
  11.   
  12. #include <utility>  
  13.   
  14. #include <mcheck.h>  
  15. #include <stdio.h>  
  16. #include <unistd.h>  
  17.   
  18. using namespace muduo;  
  19. using namespace muduo::net;  
  20.   
  21. class SudokuServer  
  22. {  
  23.  public:  
  24.   SudokuServer(EventLoop* loop, const InetAddress& listenAddr, int numThreads)  
  25.     : loop_(loop),  
  26.       server_(loop, listenAddr, "SudokuServer"),  
  27.       numThreads_(numThreads),  
  28.       startTime_(Timestamp::now())  
  29.   {  
  30.     server_.setConnectionCallback(  
  31.         boost::bind(&SudokuServer::onConnection, this, _1));  
  32.     server_.setMessageCallback(  
  33.         boost::bind(&SudokuServer::onMessage, this, _1, _2, _3));  
  34.     server_.setThreadNum(numThreads);  
  35.   }  
  36.   
  37.   void start()  
  38.   {  
  39.     LOG_INFO << "starting " << numThreads_ << " threads.";  
  40.     server_.start();  
  41.   }  
  42.   
  43.  private:  
  44.   void onConnection(const TcpConnectionPtr& conn)  
  45.   {  
  46.     LOG_TRACE << conn->peerAddress().toIpPort() << " -> "  
  47.         << conn->localAddress().toIpPort() << " is "  
  48.         << (conn->connected() ? "UP" : "DOWN");  
  49.   }  
  50.   
  51.   void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp)  
  52.   {  
  53.     LOG_DEBUG << conn->name();  
  54.     size_t len = buf->readableBytes();  
  55.     while (len >= kCells + 2)  
  56.     {  
  57.       const char* crlf = buf->findCRLF();  
  58.       if (crlf)  
  59.       {  
  60.         string request(buf->peek(), crlf);  
  61.         buf->retrieveUntil(crlf + 2);  
  62.         len = buf->readableBytes();  
  63.         if (!processRequest(conn, request))  
  64.         {  
  65.           conn->send("Bad Request!\r\n");  
  66.           conn->shutdown();  
  67.           break;  
  68.         }  
  69.       }  
  70.       else if (len > 100) // id + ":" + kCells + "\r\n"  
  71.       {  
  72.         conn->send("Id too long!\r\n");  
  73.         conn->shutdown();  
  74.         break;  
  75.       }  
  76.       else  
  77.       {  
  78.         break;  
  79.       }  
  80.     }  
  81.   }  
  82.   
  83.   bool processRequest(const TcpConnectionPtr& conn, const string& request)  
  84.   {  
  85.     string id;  
  86.     string puzzle;  
  87.     bool goodRequest = true;  
  88.   
  89.     string::const_iterator colon = find(request.begin(), request.end(), ':');  
  90.     if (colon != request.end())  
  91.     {  
  92.       id.assign(request.begin(), colon);  
  93.       puzzle.assign(colon+1, request.end());  
  94.     }  
  95.     else  
  96.     {  
  97.       puzzle = request;  
  98.     }  
  99.   
  100.     if (puzzle.size() == implicit_cast<size_t>(kCells))  
  101.     {  
  102.       LOG_DEBUG << conn->name();  
  103.       string result = solveSudoku(puzzle);  
  104.       if (id.empty())  
  105.       {  
  106.         conn->send(result+"\r\n");  
  107.       }  
  108.       else  
  109.       {  
  110.         conn->send(id+":"+result+"\r\n");  
  111.       }  
  112.     }  
  113.     else  
  114.     {  
  115.       goodRequest = false;  
  116.     }  
  117.     return goodRequest;  
  118.   }  
  119.   
  120.   EventLoop* loop_;  
  121.   TcpServer server_;  
  122.   int numThreads_;  
  123.   Timestamp startTime_;  
  124. };  
  125.   
  126. int main(int argc, char* argv[])  
  127. {  
  128.   LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid();  
  129.   int numThreads = 0;  
  130.   if (argc > 1)  
  131.   {  
  132.     numThreads = atoi(argv[1]);  
  133.   }  
  134.   EventLoop loop;  
  135.   InetAddress listenAddr(9981);  
  136.   SudokuServer server(&loop, listenAddr, numThreads);  
  137.   
  138.   server.start();  
  139.   
  140.   loop.loop();  
  141. }  





reactor + threadPool

一个IO线程,多个计算thread的模式
EventLoop + threadpool + numThreads_

  1. include "sudoku.h"  
  2.   
  3. #include <muduo/base/Atomic.h>  
  4. #include <muduo/base/Logging.h>  
  5. #include <muduo/base/Thread.h>  
  6. #include <muduo/base/ThreadPool.h>  
  7. #include <muduo/net/EventLoop.h>  
  8. #include <muduo/net/InetAddress.h>  
  9. #include <muduo/net/TcpServer.h>  
  10.   
  11. #include <boost/bind.hpp>  
  12.   
  13. #include <utility>  
  14.   
  15. #include <mcheck.h>  
  16. #include <stdio.h>  
  17. #include <unistd.h>  
  18.   
  19. using namespace muduo;  
  20. using namespace muduo::net;  
  21.   
  22. class SudokuServer  
  23. {  
  24.  public:  
  25.   SudokuServer(EventLoop* loop, const InetAddress& listenAddr, int numThreads)  
  26.     : loop_(loop),  
  27.       server_(loop, listenAddr, "SudokuServer"),  
  28.       numThreads_(numThreads),  
  29.       startTime_(Timestamp::now())  
  30.   {  
  31.     server_.setConnectionCallback(  
  32.         boost::bind(&SudokuServer::onConnection, this, _1));  
  33.     server_.setMessageCallback(  
  34.         boost::bind(&SudokuServer::onMessage, this, _1, _2, _3));  
  35.   }  
  36.   
  37.   void start()  
  38.   {  
  39.     LOG_INFO << "starting " << numThreads_ << " threads.";  
  40.     threadPool_.start(numThreads_);//线程池的线程个数  
  41.     server_.start();  
  42.   }  
  43.   
  44.  private:  
  45.   void onConnection(const TcpConnectionPtr& conn)  
  46.   {  
  47.     LOG_TRACE << conn->peerAddress().toIpPort() << " -> "  
  48.         << conn->localAddress().toIpPort() << " is "  
  49.         << (conn->connected() ? "UP" : "DOWN");  
  50.   }  
  51.   
  52.   void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp)  
  53.   {  
  54.     LOG_DEBUG << conn->name();  
  55.     size_t len = buf->readableBytes();  
  56.     while (len >= kCells + 2)  
  57.     {  
  58.       const char* crlf = buf->findCRLF();  
  59.       if (crlf)  
  60.       {  
  61.         string request(buf->peek(), crlf);  
  62.         buf->retrieveUntil(crlf + 2);  
  63.         len = buf->readableBytes();  
  64.         if (!processRequest(conn, request))  
  65.         {  
  66.           conn->send("Bad Request!\r\n");  
  67.           conn->shutdown();  
  68.           break;  
  69.         }  
  70.       }  
  71.       else if (len > 100) // id + ":" + kCells + "\r\n"  
  72.       {  
  73.         conn->send("Id too long!\r\n");  
  74.         conn->shutdown();  
  75.         break;  
  76.       }  
  77.       else  
  78.       {  
  79.         break;  
  80.       }  
  81.     }  
  82.   }  
  83.   
  84.   bool processRequest(const TcpConnectionPtr& conn, const string& request)  
  85.   {  
  86.     string id;  
  87.     string puzzle;  
  88.     bool goodRequest = true;  
  89.   
  90.     string::const_iterator colon = find(request.begin(), request.end(), ':');  
  91.     if (colon != request.end())  
  92.     {  
  93.       id.assign(request.begin(), colon);  
  94.       puzzle.assign(colon+1, request.end());  
  95.     }  
  96.     else  
  97.     {  
  98.       puzzle = request;  
  99.     }  
  100.     /*计算线程中的线程进行处理*/  
  101.     if (puzzle.size() == implicit_cast<size_t>(kCells))  
  102.     {  
  103.       threadPool_.run(boost::bind(&solve, conn, puzzle, id));  
  104.     }  
  105.     else  
  106.     {  
  107.       goodRequest = false;  
  108.     }  
  109.     return goodRequest;  
  110.   }  
  111.   
  112.   static void solve(const TcpConnectionPtr& conn,  
  113.                     const string& puzzle,  
  114.                     const string& id)  
  115.   {  
  116.     LOG_DEBUG << conn->name();  
  117.     string result = solveSudoku(puzzle);  
  118.     /*这里处理完数据后,conn->send() 还是在IO线程中发送,而不是 
  119. 在计算线程中处理 
  120.     */  
  121.     if (id.empty())  
  122.     {  
  123.       conn->send(result+"\r\n");  
  124.     }  
  125.     else  
  126.     {  
  127.       conn->send(id+":"+result+"\r\n");  
  128.     }  
  129.   }  
  130.   
  131.   EventLoop* loop_;  
  132.   TcpServer server_;  
  133.   ThreadPool threadPool_; //计算线程池  
  134.   int numThreads_;  
  135.   Timestamp startTime_;  
  136. };  
  137.   
  138. int main(int argc, char* argv[])  
  139. {  
  140.   LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid();  
  141.   int numThreads = 0;  
  142.   if (argc > 1)  
  143.   {  
  144.     numThreads = atoi(argv[1]);  
  145.   }  
  146.   EventLoop loop;  
  147.   InetAddress listenAddr(9981);  
  148.   SudokuServer server(&loop, listenAddr, numThreads);  
  149.   
  150.   server.start();  
  151.   
  152.   loop.loop();  
  153. }  






4 、multiple reactors+threadpool

EventLoopThreadPoll + threadpool + IOnumThreads_ + ThreadPoolnumThreads_



  1. include "sudoku.h"  
  2.   
  3. #include <muduo/base/Atomic.h>  
  4. #include <muduo/base/Logging.h>  
  5. #include <muduo/base/Thread.h>  
  6. #include <muduo/base/ThreadPool.h>  
  7. #include <muduo/net/EventLoop.h>  
  8. #include <muduo/net/InetAddress.h>  
  9. #include <muduo/net/TcpServer.h>  
  10.   
  11. #include <boost/bind.hpp>  
  12.   
  13. #include <utility>  
  14.   
  15. #include <mcheck.h>  
  16. #include <stdio.h>  
  17. #include <unistd.h>  
  18.   
  19. using namespace muduo;  
  20. using namespace muduo::net;  
  21.   
  22. class SudokuServer  
  23. {  
  24.  public:  
  25.   SudokuServer(EventLoop* loop, const InetAddress& listenAddr, int numThreads)  
  26.     : loop_(loop),  
  27.       server_(loop, listenAddr, "SudokuServer"),  
  28.       numThreads_(numThreads),  
  29.       startTime_(Timestamp::now())  
  30.   {  
  31.     server_.setConnectionCallback(  
  32.         boost::bind(&SudokuServer::onConnection, this, _1));  
  33.     server_.setMessageCallback(  
  34.         boost::bind(&SudokuServer::onMessage, this, _1, _2, _3));  
  35.      server_.setThreadNum(numThreads);//IO线程池的初始化  
  36.   }  
  37.   
  38.   void start()  
  39.   {  
  40.     LOG_INFO << "starting " << numThreads_ << " threads.";  
  41.     threadPool_.start(numThreads_);  
  42.     server_.start();  
  43.   }  
  44.   
  45.  private:  
  46.   void onConnection(const TcpConnectionPtr& conn)  
  47.   {  
  48.     LOG_TRACE << conn->peerAddress().toIpPort() << " -> "  
  49.         << conn->localAddress().toIpPort() << " is "  
  50.         << (conn->connected() ? "UP" : "DOWN");  
  51.   }  
  52.   
  53.   void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp)  
  54.   {  
  55.     LOG_DEBUG << conn->name();  
  56.     size_t len = buf->readableBytes();  
  57.     while (len >= kCells + 2)  
  58.     {  
  59.       const char* crlf = buf->findCRLF();  
  60.       if (crlf)  
  61.       {  
  62.         string request(buf->peek(), crlf);  
  63.         buf->retrieveUntil(crlf + 2);  
  64.         len = buf->readableBytes();  
  65.         if (!processRequest(conn, request))  
  66.         {  
  67.           conn->send("Bad Request!\r\n");  
  68.           conn->shutdown();  
  69.           break;  
  70.         }  
  71.       }  
  72.       else if (len > 100) // id + ":" + kCells + "\r\n"  
  73.       {  
  74.         conn->send("Id too long!\r\n");  
  75.         conn->shutdown();  
  76.         break;  
  77.       }  
  78.       else  
  79.       {  
  80.         break;  
  81.       }  
  82.     }  
  83.   }  
  84.   
  85.   bool processRequest(const TcpConnectionPtr& conn, const string& request)  
  86.   {  
  87.     string id;  
  88.     string puzzle;  
  89.     bool goodRequest = true;  
  90.   
  91.     string::const_iterator colon = find(request.begin(), request.end(), ':');  
  92.     if (colon != request.end())  
  93.     {  
  94.       id.assign(request.begin(), colon);  
  95.       puzzle.assign(colon+1, request.end());  
  96.     }  
  97.     else  
  98.     {  
  99.       puzzle = request;  
  100.     }  
  101.     /*计算线程中的线程进行处理*/  
  102.     if (puzzle.size() == implicit_cast<size_t>(kCells))  
  103.     {  
  104.       threadPool_.run(boost::bind(&solve, conn, puzzle, id));  
  105.     }  
  106.     else  
  107.     {  
  108.       goodRequest = false;  
  109.     }  
  110.     return goodRequest;  
  111.   }  
  112.   
  113.   static void solve(const TcpConnectionPtr& conn,  
  114.                     const string& puzzle,  
  115.                     const string& id)  
  116.   {  
  117.     LOG_DEBUG << conn->name();  
  118.     string result = solveSudoku(puzzle);  
  119.     /*这里处理完数据后,conn->send() 还是在IO线程中发送,而不是 
  120. 在计算线程中处理 
  121.     */  
  122.     if (id.empty())  
  123.     {  
  124.       conn->send(result+"\r\n");  
  125.     }  
  126.     else  
  127.     {  
  128.       conn->send(id+":"+result+"\r\n");  
  129.     }  
  130.   }  
  131.   
  132.   EventLoop* loop_;  
  133.   TcpServer server_;  
  134.   ThreadPool threadPool_;  
  135.   int numThreads_;  
  136.   Timestamp startTime_;  
  137. };  
  138.   
  139. int main(int argc, char* argv[])  
  140. {  
  141.   LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid();  
  142.   int numThreads = 0;  
  143.   if (argc > 1)  
  144.   {  
  145.     numThreads = atoi(argv[1]);  
  146.   }  
  147.   EventLoop loop;  
  148.   InetAddress listenAddr(9981);  
  149.   SudokuServer server(&loop, listenAddr, numThreads);  
  150.   
  151.   server.start();  
  152.   
  153.   loop.loop();  
  154. }  


--------------------------------------------------


sudoKu 求解服务器,既是一个IO密集型,又是一个计算密集型的服务

IO线程池 + 计算线程池
计算时间如果比较久,就会使得IO线程阻塞,IO线程很快就用尽,就不处理大量的并发连接
一个IO线程+计算线程池


使用muduo 库来编程还是比较容易的,有兴趣的朋友可以试一下!

猜你喜欢

转载自blog.csdn.net/lusic01/article/details/80683182
今日推荐