Example #1
0
void DataSocket::postDisConnect()
{
    if (mEventLoop != nullptr)
    {
        DataSocket::PTR tmp = this;
        mEventLoop->pushAsyncProc([=](){
            tmp->procCloseInLoop();
        });
    }
}
void SSDBMultiClient::sendPing(DataSocket::PTR ds)
{
    DBServerUserData* dbUserData = (DBServerUserData*)ds->getUserData();
    if (dbUserData->pingTime > 0)
    {
        SSDBProtocolRequest sr;
        sr.init();
        sr.appendStr("ping");
        sr.endl();

        ds->send(sr.getResult(), sr.getResultLen());

        /*自动发送的ping操作,也要模拟一个完成回调,不然会导致业务上的请求乱序*/
        queue<std::function<void(const string& response)>>* callbacklist = dbUserData->callbacklist;
        callbacklist->push(nullptr);

        dbUserData->pingTimer = mNetService.getTimerMgr().AddTimer(dbUserData->pingTime, [this, ds](){
            sendPing(ds);
        });
    }
}
void SSDBMultiClient::startNetThread(std::function<void(void)> frameCallback)
{
    if (mNetThread == nullptr)
    {
        mRunIOLoop = true;
        mNetThread = new thread([&, frameCallback](){
            while (mRunIOLoop)
            {
                mNetService.loop(1);

                mRequestList.SyncRead(0);
                RequestMsg tmp;
                while (mRequestList.PopFront(&tmp))
                {
                    if (!mBackends.empty())
                    {
                        /*  随机选择一个服务器   */
                        DataSocket::PTR client = mBackends[rand() % mBackends.size()];
                        DBServerUserData* dbUserData = (DBServerUserData*)client->getUserData();
                        queue<std::function<void(const string& response)>>* callbacklist = dbUserData->callbacklist;
                        callbacklist->push(tmp.callback);

                        client->send(tmp.content.c_str(), tmp.content.size());
                    }
                    else
                    {
                        forgeError("no server", tmp.callback);
                    }
                }

                mLogicFunctorMQ.ForceSyncWrite();
                /*  TODO::目前只在通知队列里有数据时,才调用帧回调--可在其中唤醒主线程--就无需把外部mainloop设置到此类   */
                if (mLogicFunctorMQ.SharedListSize() > 0 && frameCallback != nullptr)
                {
                    frameCallback();
                }
            }
        });
    }
}
int main(int argc, char** argv)
{
    if (argc != 5)
    {
        fprintf(stderr, "Usage: <server ip> <server port> <session num> <packet size>\n");

        exit(-1);
    }

    std::string ip = argv[1];
    int client_num = atoi(argv[2]);
    int packet_len = atoi(argv[3]);
    int port_num = atoi(argv[4]);

    ox_socket_init();

    EventLoop       mainLoop;

    /*  客户端IO线程   */

    std::thread* ts = new std::thread([&mainLoop, client_num, packet_len, port_num, ip]{
        printf("start one client thread \n");
        /*  客户端eventloop*/
        EventLoop clientEventLoop;

        char* senddata = (char*)malloc(packet_len);

        /*  消息包大小定义 */
        atomic_llong  packet_num = ATOMIC_VAR_INIT(0);
        atomic_llong total_recv = ATOMIC_VAR_INIT(0);
        TimerMgr tm;
        for (int i = 0; i < client_num; i++)
        {
            int client = ox_socket_connect(ip.c_str(), port_num);
            ox_socket_nodelay(client);

            DataSocket::PTR pClient = new DataSocket(client, 1024 * 1024);
            pClient->setEnterCallback([&](DataSocket::PTR ds){

                LongPacket sp(1);
                sp.writeINT64((int64_t)ds);
                sp.writeBinary(senddata, packet_len);

                for (int i = 0; i < 1; ++i)
                {
                    ds->send(sp.getData(), sp.getLen());
                }

                /*  可以放入消息队列,然后唤醒它主线程的eventloop,然后主线程通过消息队列去获取*/
                ds->setDataCallback([&total_recv, &packet_num](DataSocket::PTR ds, const char* buffer, size_t len){
                    const char* parse_str = buffer;
                    int total_proc_len = 0;
                    int left_len = len;

                    while (true)
                    {
                        bool flag = false;
                        if (left_len >= sizeof(sizeof(uint16_t) + sizeof(uint16_t)))
                        {
                            ReadPacket rp(parse_str, left_len);
                            uint16_t packet_len = rp.readINT16();
                            if (left_len >= packet_len && packet_len >= (sizeof(uint16_t) + sizeof(uint16_t)))
                            {
                                total_recv += packet_len;
                                packet_num++;

                                ReadPacket rp(parse_str, packet_len);
                                rp.readINT16();
                                rp.readINT16();
                                int64_t addr = rp.readINT64();

                                if (addr == (int64_t)(ds))
                                {
                                    ds->send(parse_str, packet_len);
                                }

                                total_proc_len += packet_len;
                                parse_str += packet_len;
                                left_len -= packet_len;
                                flag = true;
                            }
                        }

                        if (!flag)
                        {
                            break;
                        }
                    }

                    return total_proc_len;
                });

                ds->setDisConnectCallback([](DataSocket::PTR arg){
                    delete arg;
                });
            });

            clientEventLoop.pushAsyncProc([&, pClient](){
                if (!pClient->onEnterEventLoop(&clientEventLoop))
                {
                    delete pClient;
                }
            });
        }

        int64_t now = ox_getnowtime();
        while (true)
        {
            clientEventLoop.loop(tm.NearEndMs());
            tm.Schedule();
            if ((ox_getnowtime() - now) >= 1000)
            {
                cout << "total recv:" << (total_recv / 1024) / 1024 << " M /s" << " , num " << packet_num << endl;
                now = ox_getnowtime();
                total_recv = 0;
                packet_num = 0;
            }
        }
    });

    ts->join();
}
void SSDBMultiClient::addConnection(sock fd, string ip, int port, int pingTime, bool isAutoConnection)
{
    ox_socket_nodelay(fd);

    DataSocket::PTR ds = new DataSocket(fd, 32 * 1024 * 1024);
    DBServerUserData* dbUserData = new DBServerUserData;
    dbUserData->ip = ip;
    dbUserData->port = port;
    dbUserData->pingTime = pingTime;
    dbUserData->isAutoConnection = isAutoConnection;
    dbUserData->callbacklist = new queue<std::function<void(const string& response)>>();
    dbUserData->p = parse_tree_new();
    ds->setUserData((int64_t)dbUserData);

    ds->setEnterCallback([this](DataSocket::PTR ds){
        DBServerUserData* dbUserData = (DBServerUserData*)ds->getUserData();
        mBackends.push_back(ds);
        ds->setCheckTime(dbUserData->pingTime);
        sendPing(ds);
    });

    ds->setDataCallback([&](DataSocket::PTR ds, const char* buffer, size_t len){
        const char* parse_str = buffer;
        DBServerUserData* dbUserData = (DBServerUserData*)ds->getUserData();
        while (parse_str < (buffer + len))
        {
            /*  TODO::检测是否redis协议, 并编写redis reply到ssdb reply的转换 */
            char c = parse_str[0];
            int packet_len = 0;

            if (c == '+' ||
                c == '-' ||
                c == ':' ||
                c == '$' ||
                c == '*')
            {
                if (dbUserData->p == nullptr)
                {
                    dbUserData->p = parse_tree_new();
                }

                char* parseEndPos = (char*)parse_str;
                int parseRet = parse(dbUserData->p, &parseEndPos, (char*)buffer + len);
                if (parseRet == REDIS_OK)
                {
                    packet_len = (parseEndPos - parse_str);
                }
                else if (parseRet == REDIS_RETRY)
                {

                }
                else
                {
                    assert(false);
                }

                parse_tree_del(dbUserData->p);
                dbUserData->p = nullptr;
            }
            else
            {
                packet_len = SSDBProtocolResponse::check_ssdb_packet(parse_str, (len - (parse_str - buffer)));
            }

            if (packet_len > 0)
            {
                /*  取出等待的异步回调,并将response附加给它,再投递给逻辑线程去执行    */
                queue<std::function<void(const string& response)>>* callbacklist = dbUserData->callbacklist;
                assert(!callbacklist->empty());
                if (!callbacklist->empty())
                {
                    auto& callback = callbacklist->front();
                    if (callback != nullptr)
                    {
                        std::shared_ptr<string > response = std::make_shared<string>(parse_str, packet_len);
                        mLogicFunctorMQ.Push([callback, response](){
                            callback(*response);
                        });
                    }
                    callbacklist->pop();
                }

                parse_str += packet_len;
            }
            else
            {
                break;
            }
        }

        return parse_str - buffer;
    });

    ds->setDisConnectCallback([&](DataSocket::PTR arg){

        DBServerUserData* dbUserData = (DBServerUserData*)arg->getUserData();

        queue<std::function<void(const string& response)>>* callbacklist = dbUserData->callbacklist;

        while (!callbacklist->empty())
        {
            forgeError("server close", callbacklist->front());
            callbacklist->pop();
        }

        cout << "disconnect of " << dbUserData->ip << " port " << dbUserData->port << endl;
        if (dbUserData->isAutoConnection)
        {
            asyncConnection(dbUserData->ip, dbUserData->port, dbUserData->pingTime, dbUserData->isAutoConnection);
        }

        Timer::Ptr timer = dbUserData->pingTimer.lock();
        if (timer != nullptr)
        {
            timer->Cancel();
        }
        delete dbUserData->callbacklist;
        if (dbUserData->p != nullptr)
        {
            parse_tree_del(dbUserData->p);
        }
        delete dbUserData;

        for (size_t i = 0; i < mBackends.size(); ++i)
        {
            if (mBackends[i] == arg)
            {
                mBackends.erase(mBackends.begin() + i);
            }
        }
        delete arg;
    });


    mNetService.pushAsyncProc([&, ds](){
        if (!ds->onEnterEventLoop(&mNetService))
        {
            delete ds;
        }
    });
}