6. thrift

本文档详细介绍了如何使用Thrift框架创建一个匹配服务(match-server)和保存客户端(save-client)。首先,讲解了如何通过Thrift生成C++服务端和客户端代码,并提供了实现逻辑。接着,展示了如何在Python中实现match-client。最后,给出了编译、链接及运行服务和客户端的步骤。
摘要由CSDN通过智能技术生成

1. thrift教程

thrift官网
上课代码地址

2. 创建作业 & 测试作业的正确性

homework 6 create  # 可以重新创建所有lesson_6的作业
homework 6 test  # 可以评测lesson_6的所有作业

3. 作业

本次作业为复现课上最后一个版本的内容,课程视频地址:https://www.acwing.com/video/3479/
注意:本次作业的2个题目采用整体评测,即如果两个作业同时正确,则得100分;否则如果至少有一个作业错误,则得0分。

创建好作业后,先进入文件夹/home/acs/homework/lesson_6/,当前目录的文件结构如下:

`-- thrift_lesson
    |-- game
    |   `-- src
    |-- match_system
    |   `-- src 
    |-- readme.md
    `-- thrift
        |-- match.thrift
        `-- save.thrift
(0) 进入thrift_lesson/match_system/src/目录,用cpp实现课上的match-server和save-client逻辑。
接口文件在thrift_lesson/thrift/中。
实现后启动server,监听端口9090。

创建match-server:

cd thrift_lesson/match_system/src
thrift -r --gen cpp ../../thrift/match.thrift
mv gen-cpp match_server
rm match_server/Match_server.skeleton.cpp

创建save-client:

cd thrift_lesson/match_system/src
thrift -r --gen cpp ../../thrift/save.thrift
mv gen-cpp save_client
rm save_client/Save_server.skeleton.cpp

创建main.cpp,源代码:

// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.

#include "match_server/Match.h"
#include "save_client/Save.h"
#include <thrift/concurrency/ThreadManager.h>
#include <thrift/concurrency/ThreadFactory.h>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/server/TThreadedServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/transport/TTransportUtils.h>
#include <thrift/transport/TSocket.h>
#include <thrift/TToString.h>

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <vector>
#include <unistd.h>

using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;

using namespace ::match_service;
using namespace ::save_service;
using namespace std;



struct Task
{
    User user;
    string type;
};

struct MessageQueue
{
    queue<Task> q;
    mutex m;
    condition_variable cv;
}message_queue;

class Pool
{
    public:

        void save_result(int a, int b)
        {
            printf("Match Result: %d %d\n", a, b);


            std::shared_ptr<TTransport> socket(new TSocket("123.57.47.211", 9090));
            std::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
            std::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
            SaveClient client(protocol);

            try {
                transport->open();

                client.save_data("acs_4048","1a37e8ef", a, b);


                transport->close();
            } catch (TException& tx) {
                cout << "ERROR: " << tx.what() << endl;
            }
        }


        void match()
        {
            while(users.size() > 1)
            {
                sort(users.begin(), users.end(), [&](User& a, User&b)
                        {   return a.score < b.score;
                        });

                bool flag = true;
                for (uint32_t i = 1; i < users.size(); i++)
                {
                    auto a = users[i-1], b = users[i];
                    if (b.score - a.score <= 50)
                    {
                        users.erase(users.begin() + i - 1, users.begin()+ i + 1);
                        save_result(a.id, b.id);

                        flag = false;

                        break;
                    }
                }

                if(flag) break; 

            }
        }


        void add(User user)
        {
            users.push_back(user);
        }

        void remove(User user)
        {
            for (uint32_t i = 0 ;i < users.size(); i++)
                if(users[i].id == user.id)
                {
                    users.erase(users.begin() + i);
                    break;
                }
        }

    private:
        vector<User> users;


}pool;






class MatchHandler : virtual public MatchIf {
    public:
        MatchHandler() {
            // Your initialization goes here
        }

        int32_t add_user(const User& user, const std::string& info) {
            // Your implementation goes here
            printf("add_user\n");

            unique_lock<mutex> lck(message_queue.m);
            message_queue.q.push({user,"add"});
            message_queue.cv.notify_all();

            return 0;
        }

        int32_t remove_user(const User& user, const std::string& info) {
            // Your implementation goes here
            printf("remove_user\n");

            unique_lock<mutex> lck(message_queue.m);
            message_queue.q.push({user, "remove"});
            message_queue.cv.notify_all();


            return 0;
        }

};

class MatchCloneFactory : virtual public MatchIfFactory {
    public:
        ~MatchCloneFactory() override = default;
        MatchIf* getHandler(const ::apache::thrift::TConnectionInfo& connInfo) override
        {
            std::shared_ptr<TSocket> sock = std::dynamic_pointer_cast<TSocket>(connInfo.transport);
           /* cout << "Incoming connection\n";
            cout << "\tSocketInfo: "  << sock->getSocketInfo() << "\n";
            cout << "\tPeerHost: "    << sock->getPeerHost() << "\n";
            cout << "\tPeerAddress: " << sock->getPeerAddress() << "\n";
            cout << "\tPeerPort: "    << sock->getPeerPort() << "\n";
            */
            return new MatchHandler;
        }
        void releaseHandler( MatchIf* handler) override {
            delete handler;
        }
};

void consume_task()
{
    while(true)
    {   unique_lock<mutex> lck(message_queue.m);
        if (message_queue.q.empty())
        {
            lck.unlock();
            pool.match();
            sleep(1);
        }
        else
        {
            auto task = message_queue.q.front();
            message_queue.q.pop();
            lck.unlock();


            // do task
            if(task.type == "add") pool.add(task.user);
            else if(task.type == "remove") pool.remove(task.user);

            pool.match();
        }
    }

}



int main(int argc, char **argv) {
    TThreadedServer server(
            std::make_shared<MatchProcessorFactory>(std::make_shared<MatchCloneFactory>()),
            std::make_shared<TServerSocket>(9090), //port
            std::make_shared<TBufferedTransportFactory>(),
            std::make_shared<TBinaryProtocolFactory>());

    cout << "Start Match Server" << endl;

    thread matching_thread(consume_task);



    server.serve();
    return 0;
}


编译:

g++ -c main.cpp match_server/*.cpp save_client/*.cpp

链接:

g++ *.o -o main -lthrift -pthread

启动服务:

./main
(1) 进入thrift_lesson/game/src/目录,用python3实现课上的match-client逻辑。
文件名和输入格式与课上内容相同。

创建match-client:

cd thrift_lesson/game/src
thrift -r --gen py ../../thrift/match.thrift
mv gen-py match_client

创建client.py,内容:

from match_client.match import Match 
from match_client.match.ttypes import User

from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol

from sys import stdin

def operate(op, user_id, username, score):
    # Make socket
    transport = TSocket.TSocket('localhost', 9090)

    # Buffering is critical. Raw sockets are very slow
    transport = TTransport.TBufferedTransport(transport)

    # Wrap in a protocol
    protocol = TBinaryProtocol.TBinaryProtocol(transport)

    # Create a client to use the protocol encoder
    client = Match.Client(protocol)

    # Connect!
    transport.open()

    user = User(user_id, username, score)

    if op == "add":
        client.add_user(user,"")
    elif op == "remove":
        client.remove_user(user, "")
             

  

    # Close!
    transport.close()

def main():
    for line in stdin:
        op, user_id, username, score = line.split(' ')
        operate(op, int(user_id), username, int(score))

if __name__ == "__main__":
    main()


执行client.py:

python3 client.py
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

追寻远方的人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值