muduo/examples/sudoku/server_hybrid.cc
2024-03-08 14:03:37 +08:00

196 lines
4.8 KiB
C++

#include "examples/sudoku/sudoku.h"
#include "muduo/base/Atomic.h"
#include "muduo/base/Logging.h"
#include "muduo/base/Thread.h"
#include "muduo/base/ThreadPool.h"
#include "muduo/net/EventLoop.h"
#include "muduo/net/EventLoopThread.h"
#include "muduo/net/InetAddress.h"
#include "muduo/net/TcpServer.h"
#include "muduo/net/inspect/Inspector.h"
#include <boost/circular_buffer.hpp>
//#include <stdio.h>
//#include <unistd.h>
using namespace muduo;
using namespace muduo::net;
#include "examples/sudoku/stat.h"
class SudokuServer : noncopyable
{
public:
SudokuServer(EventLoop* loop,
const InetAddress& listenAddr,
int numEventLoops,
int numThreads,
bool nodelay)
: server_(loop, listenAddr, "SudokuServer"),
threadPool_(),
numThreads_(numThreads),
tcpNoDelay_(nodelay),
startTime_(Timestamp::now()),
stat_(threadPool_),
inspectThread_(),
inspector_(inspectThread_.startLoop(), InetAddress(9982), "sudoku-solver")
{
LOG_INFO << "Use " << numEventLoops << " IO threads.";
LOG_INFO << "TCP no delay " << nodelay;
server_.setConnectionCallback(
std::bind(&SudokuServer::onConnection, this, _1));
server_.setMessageCallback(
std::bind(&SudokuServer::onMessage, this, _1, _2, _3));
server_.setThreadNum(numEventLoops);
inspector_.add("sudoku", "stats", std::bind(&SudokuStat::report, &stat_),
"statistics of sudoku solver");
inspector_.add("sudoku", "reset", std::bind(&SudokuStat::reset, &stat_),
"reset statistics of sudoku solver");
}
void start()
{
LOG_INFO << "Starting " << numThreads_ << " computing threads.";
threadPool_.start(numThreads_);
server_.start();
}
private:
void onConnection(const TcpConnectionPtr& conn)
{
LOG_TRACE << conn->peerAddress().toIpPort() << " -> "
<< conn->localAddress().toIpPort() << " is "
<< (conn->connected() ? "UP" : "DOWN");
if (conn->connected() && tcpNoDelay_)
conn->setTcpNoDelay(true);
}
void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp receiveTime)
{
LOG_DEBUG << conn->name();
size_t len = buf->readableBytes();
while (len >= kCells + 2)
{
const char* crlf = buf->findCRLF();
if (crlf)
{
string request(buf->peek(), crlf);
buf->retrieveUntil(crlf + 2);
len = buf->readableBytes();
stat_.recordRequest();
if (!processRequest(conn, request, receiveTime))
{
conn->send("Bad Request!\r\n");
conn->shutdown();
stat_.recordBadRequest();
break;
}
}
else if (len > 100) // id + ":" + kCells + "\r\n"
{
conn->send("Id too long!\r\n");
conn->shutdown();
stat_.recordBadRequest();
break;
}
else
{
break;
}
}
}
struct Request
{
string id;
string puzzle;
Timestamp receiveTime;
};
bool processRequest(const TcpConnectionPtr& conn, const string& request, Timestamp receiveTime)
{
Request req;
req.receiveTime = receiveTime;
string::const_iterator colon = find(request.begin(), request.end(), ':');
if (colon != request.end())
{
req.id.assign(request.begin(), colon);
req.puzzle.assign(colon+1, request.end());
}
else
{
// when using thread pool, an id must be provided in the request.
if (numThreads_ > 1)
return false;
req.puzzle = request;
}
if (req.puzzle.size() == implicit_cast<size_t>(kCells))
{
threadPool_.run(std::bind(&SudokuServer::solve, this, conn, req));
return true;
}
return false;
}
void solve(const TcpConnectionPtr& conn, const Request& req)
{
LOG_DEBUG << conn->name();
string result = solveSudoku(req.puzzle);
if (req.id.empty())
{
conn->send(result + "\r\n");
}
else
{
conn->send(req.id + ":" + result + "\r\n");
}
stat_.recordResponse(Timestamp::now(), req.receiveTime, result != kNoSolution);
}
TcpServer server_;
ThreadPool threadPool_;
const int numThreads_;
const bool tcpNoDelay_;
const Timestamp startTime_;
SudokuStat stat_;
EventLoopThread inspectThread_;
Inspector inspector_;
};
int main(int argc, char* argv[])
{
LOG_INFO << argv[0] << " [number of IO threads] [number of worker threads] [-n]";
LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid();
int numEventLoops = 0;
int numThreads = 0;
bool nodelay = false;
if (argc > 1)
{
numEventLoops = atoi(argv[1]);
}
if (argc > 2)
{
numThreads = atoi(argv[2]);
}
if (argc > 3 && string(argv[3]) == "-n")
{
nodelay = true;
}
EventLoop loop;
InetAddress listenAddr(9981);
SudokuServer server(&loop, listenAddr, numEventLoops, numThreads, nodelay);
server.start();
loop.loop();
}