#pragma once #include #include #include #include #include #include #include #include #include #include #include #include class TcpServiceDetail : public NonCopyable { protected: using FrameCallback = std::function; const static unsigned int sDefaultLoopTimeOutMS = 100; void startWorkerThread(size_t threadNum, FrameCallback callback = nullptr) { std::lock_guard lck(mServiceGuard); std::lock_guard lock(mIOLoopGuard); if (!mIOLoopDatas.empty()) { return; } mRunIOLoop = std::make_shared(true); mIOLoopDatas.resize(threadNum); for (auto &v : mIOLoopDatas) { auto eventLoop = std::make_shared(); auto runIoLoop = mRunIOLoop; v = IOLoopData::Create(eventLoop, std::make_shared( [callback, runIoLoop, eventLoop]() { while (*runIoLoop) { eventLoop->loopCompareNearTimer(sDefaultLoopTimeOutMS); if (callback != nullptr) { callback(eventLoop); } } })); } } void stopWorkerThread() { std::lock_guard lck(mServiceGuard); std::lock_guard lock(mIOLoopGuard); *mRunIOLoop = false; for (const auto &v : mIOLoopDatas) { v->getEventLoop()->wakeup(); try { if (v->getIOThread()->joinable()) { v->getIOThread()->join(); } } catch (std::system_error &e) { (void)e; } } mIOLoopDatas.clear(); } bool addTcpConnection(TcpSocket::Ptr socket, ConnectionOption option) { if (option.maxRecvBufferSize <= 0) { throw BrynetCommonException("buffer size is zero"); } EventLoop::Ptr eventLoop; if (option.forceSameThreadLoop) { eventLoop = getSameThreadEventLoop(); } else { eventLoop = getRandomEventLoop(); } if (eventLoop == nullptr) { return false; } auto wrapperEnterCallback = [option](const TcpConnection::Ptr &tcpConnection) { for (const auto &callback : option.enterCallback) { callback(tcpConnection); } }; if (option.useSSL && option.sslHelper == nullptr) { option.sslHelper = SSLHelper::Create(); } TcpConnection::Create(std::move(socket), option.maxRecvBufferSize, wrapperEnterCallback, eventLoop, option.sslHelper); return true; } EventLoop::Ptr getRandomEventLoop() { std::lock_guard lock(mIOLoopGuard); const auto ioLoopSize = mIOLoopDatas.size(); if (ioLoopSize == 0) { return nullptr; } else if (ioLoopSize == 1) { return mIOLoopDatas.front()->getEventLoop(); } else { return mIOLoopDatas[mRandom() % ioLoopSize]->getEventLoop(); } } TcpServiceDetail() BRYNET_NOEXCEPT : mRandom(static_cast( std::chrono::system_clock::now().time_since_epoch().count())) { mRunIOLoop = std::make_shared(false); } virtual ~TcpServiceDetail() BRYNET_NOEXCEPT { stopWorkerThread(); } EventLoop::Ptr getSameThreadEventLoop() { std::lock_guard lock(mIOLoopGuard); for (const auto &v : mIOLoopDatas) { if (v->getEventLoop()->isInLoopThread()) { return v->getEventLoop(); } } return nullptr; } private: std::vector mIOLoopDatas; mutable std::mutex mIOLoopGuard; std::shared_ptr mRunIOLoop; std::mutex mServiceGuard; std::mt19937 mRandom; };