Apache thrift多客户端服务器

时间:2017-12-27 21:22:20

标签: apache qt c++11 thrift thrift-protocol

我在Qt + Apache Thrift中编写简单的聊天,但是现在我需要面对连接多个客户端的问题。乍一看,一切看起来都很好,我找不到问题所在。

这是我的服务器main.cpp:

int main(int argc, char **argv) 
{
    int port = 9090;

    ::apache::thrift::stdcxx::shared_ptr<UsersStorageHandler> handler(new UsersStorageHandler());
    ::apache::thrift::stdcxx::shared_ptr<TProcessor> processor(new UsersStorageProcessor(handler));
    ::apache::thrift::stdcxx::shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
    ::apache::thrift::stdcxx::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
    ::apache::thrift::stdcxx::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());

    TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);

    std::cout << "Users server started..." << std::endl;
    std::cout << std::endl;
    std::cout << std::endl;

    server.serve();

    return 0;
}

这是我的服务器handler.h:

class UsersStorageHandler : virtual public UsersStorageIf
{
public:
    UsersStorageHandler();
    int32_t subscribeUser(const std::string& username);
    void unsubscribeUser(const int32_t userID);

private:
    Users users;
};

这是我的服务器handler.cpp:

UsersStorageHandler::UsersStorageHandler()
{
    srand(time(NULL));
}

int32_t UsersStorageHandler::subscribeUser(const std::string &username)
{
    ++idGenerator;

    assert(username != "");

    User user;
    user.userId  = idGenerator;
    user.username = username;
    user.colorR = (rand() % 255) + 0;
    user.colorG = (rand() % 255) + 0;
    user.colorB = (rand() % 255) + 0;
    user.colorA = 0;

    users[idGenerator] = user;

    std::cout << "NEW USER CONNECTED" << std::endl;
    std::cout << "==================" << std::endl;
    std::cout << "Username:\t" << user.username << std::endl;
    std::cout << "User ID:\t" << user.userId << std::endl;
    std::cout << "User R:\t" << user.colorR << std::endl;
    std::cout << "User G:\t" << user.colorG << std::endl;
    std::cout << "User B:\t" << user.colorB << std::endl;
    std::cout << "User A:\t" << user.colorA << std::endl;
    std::cout << "==================" << std::endl;
    std::cout << "CURRENT USERS COUNT:\t" << users.size() << std::endl;
    std::cout << std::endl;
    std::cout << std::endl;

    /*
     * SEND TO CLIENT INFO ABOUT NEW USER HERE
     */

    return idGenerator;
}

void UsersStorageHandler::unsubscribeUser(const int32_t userID)
{
    auto index = users.find(userID);

    assert(index != users.end());

    users.erase(index);

    std::cout << "USER DISCONNECTED" << std::endl;
    std::cout << "=================" << std::endl;
    std::cout << "USER WITH ID " << userID << " ERASED" << std::endl;
    std::cout << "USERS COUNT:\t" << users.size() << std::endl;
    std::cout << std::endl;
    std::cout << std::endl;

    /*
     * SEND TO CLIENT INFO ABOUT NEW USER HERE
     */
}

这里是一个连接到客户端应用程序服务器的方法:

void MainWindow::connectToServers(const std::string &ip, const uint32_t &port, const std::string &nick)
{
    m_usersServerIP = ip;
    m_usersServerPort = port;

    try
    {
        ::apache::thrift::stdcxx::shared_ptr<TTransport> socket(new TSocket(m_usersServerIP, m_usersServerPort));
        ::apache::thrift::stdcxx::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
        ::apache::thrift::stdcxx::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));

        m_usersServerClient = std::make_shared<UsersStorageClient>(protocol);
        transport->open();

        m_clientID = m_usersServerClient.get()->subscribeUser(nick);

        QMessageBox::information(this, "Connected",
                             "You are connected "
                             "with users server");

        createAndRegisterUsersServerReactor();

        activateChatScreen();

    }
    catch (const std::exception &e)
    {
        qDebug() << e.what();
    }

    qDebug() << "ID FROM SERVER:\t" << m_clientID;
}

据我现在检查,它的工作原理如下: 创建了两个客户端应用程序实例。在一个实例中填写昵称,ip,端口并单击connect(connectToServers方法)。客户已连接。在另一个例子做了相同但点击连接后......没有任何反应。应用冻结在这一行:

m_clientID = m_usersServerClient.get()->subscribeUser(nick);

关闭第一个客户端后,第二个连接到服务器。

2 个答案:

答案 0 :(得分:0)

TSimplerServer支持单个连接。您应该尝试使用TThreadedServer来支持多个同时客户端。

答案 1 :(得分:0)

如上所述,Chris要么使一个线程服务器同时处理多个请求。对我来说,我创建了一个如下所示的非阻塞服务器,以便能够以异步方式为多个客户端提供服务,以实现松耦合。

public static void start(dataClass configData, String env, int port) throws TTransportException {

    TNonblockingServerTransport transport = new TNonblockingServerSocket(port);
    TNonblockingServer.Args nBlockServer = new TNonblockingServer.Args(transport);

    ccmProviderServiceImpl impl = new ccmProviderServiceImpl(configData, env);
    Processor<ccmProviderServiceImpl> processor = new ccmProviderService.Processor<>(impl);

    TServer server = new TNonblockingServer(nBlockServer.processor(processor));

    //custom event handling for tracking
    ccmServerEventHandler cse = new ccmServerEventHandler();
    server.setServerEventHandler(cse);

    server.serve();
}