AcWing-Linux基础课-6.thrift

本次课主要通过实现一个游戏匹配系统来学习thrift。

1.thrift的概念

thrift本质上是一个调用远程服务器的函数的工具。

在一个匹配系统中,thrift就是上图中的每一条有向边。 

2.创建match_system 

2.1创建thrift_lesson项目

在本地和云端分别初始化git仓库

2.2创建match.thrift文件 

创建三个文件夹,分别为game,match_system,thrift

在thrift文件夹里创建一个match.thrift文件

namespace cpp match_service                                                                                                              


struct User {                        
    1: i32 id, 
    2: string name,
    3: i32 score   
}


service Match {    
    i32 add_User(1: User user, 2: string info),

    i32 remove_User(1: User user, 2: string info),
}

2.3实现match_server端

在../thrift_lesson/match_system/路径下创建一个src文件夹

输入以下命令:

thrift -r --gen cpp ../../thrift/match.thrift

就会在当前文件夹下生成gen-cpp文件夹

将gen-cpp重命名为match_server,并且将match_server目录下的Match_server.skeleton.cpp 移动到./src目录下并重命名为main.cpp。

进入main.cpp中,找到之前定义的两个函数并添加返回值。

之后再对其进行格式化

[Esc]
dd #回到第一行
=G #格式化从第一行到最后一行

在thrift中,我们需要先编译成功后再逐步添加模块中的内容。

首先将main.cpp中的头文件目录修改成正确的目录

然后是编译c++文件

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

 编译完成之后我们需要把所有的*.o文件链接起来

g++ *.o -o main -lthrift

 为了使我们的代码运行起来看上去有效果,我们可以在main.cpp中输出“Start Match Server”。

重新编译链接完成之后我们就可以运行代码了

./main #运行代码

 

 在持久化的时候,最好把可执行文件给删去,包括*.o,main文件。

git restore --stage *.o
git restore --stage main

2.4实现macth_client端

生成python代码的命令:

thrift -r --gen py ../../thrift/match.thrift

 重命名为match_client:

进入match文件夹之后找到一个可执行文件,由于我们只实现客户端,所以这个文件没有用,故删去。

https://thrift.apache.org/tutorial/py.html里找到python的代码

复制到~/thrift_lesson/game/src$目录下并命名为client.py。

代码的前四行是为了将当前路径加到python目录里,但是这里没有用到,删去。 

修改前两个头文件, 

怎么修改可以参考当前目录下的文件 

 

接下来我们需要修改一下里面的代码

完整代码如下:

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()

将文件中的.pyc,.swp文件删除出暂存区

2.5完善match_server端 

由于在这个过程中匹配和添加用户是同时进行的,所以我们需要引入生产者消费者模型。

生产者消费者模型:假如有两个线程A和B,A线程生产数据(类似本项目终端输入用户信息)并将信息加入缓冲区,B线程从缓冲区中取出数据进行操作(类似本项目中取出用户信息匹配),则A为生产者B为消费者。在多线程开发中,如果生产者生产数据的速度很快,而消费者消费数据的速度很慢,那么生产者就必须等待消费者消费完数据才能够继续生产数据,因为生产过多的数据可能会导致存储不足;同理如果消费者的速度大于生产者那么消费者就会经常处理等待状态,所以为了达到生产者和消费者生产数据和消费数据之间的平衡,那么就需要一个缓冲区用来存储生产者生产的数据,所以就引入了生产者-消费者模型。当缓冲区满的时候,生产者会进入休眠状态,当下次消费者开始消耗缓冲区的数据时,生产者才会被唤醒,开始往缓冲区中添加数据;当缓冲区空的时候,消费者也会进入休眠状态,直到生产者往缓冲区中添加数据时才会被唤醒。

生产者消费者模型可以用一个消息队列来实现,但是当生产者和消费者同时要操作同一个队列的时候往往会产生冲突,这个时候就需要有一个锁来控制。 

互斥锁mutex:保证共享数据操作的完整性,保证在任一时刻只能有一个线程访问对象。锁有两个操作。一个P操作(上锁),一个V操作(解锁)。P和V都是原子操作,就是在执行P和V操作时,不会被插队。锁一般使用信号量来实现的,mutex其实就是信号量=1。互斥量就是同一时间能够分给一个人,即S=1。S=10表示可以将信号量分给10个人来用。如果一共有20个人那么只能有10个人用,剩下10个人需要等待。
-- 在本项目中有两个操作添加用户和删除用户,信息都是存在消息队列当中,如果不上锁,这两个操作同时执行可能导致在消息队列当中信息错乱。 

完整代码 

// 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 <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <vector>



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 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", a, b);
        }
        void match()
        {
            while (users.size() > 1)
            {
                auto a = users[0], b = users[1];
                users.erase(users.begin());
                users.erase(users.begin());
                save_result(a.id, b.id);
            }
        }

        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;
        }

};

void consumer_task()
{
    while(true)
    {
        unique_lock<mutex> lck(message_queue.m);
        if(message_queue.q.empty())
        {
            message_queue.cv.wait(lck);
        }
        else
        {
            auto task = message_queue.q.front();
            message_queue.q.pop();
            lck.unlock();

            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) {
    int port = 9090;
    ::std::shared_ptr<MatchHandler> handler(new MatchHandler());                                                                                  
    ::std::shared_ptr<TProcessor> processor(new MatchProcessor(handler));
    ::std::shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
    ::std::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
    ::std::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());

    TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
    cout << "Start Match Server" << endl;

    thread matching_thread(consumer_task);

    server.serve();
    return 0;
}

2.6实现save_client端 

https://git.acwing.com/yxc/thrift_lesson/-/blob/master/thrift/save.thrift找到save.thrift并复制到本地。

我们需要根据.thrift文件生成c++代码:

thrift -r --gen cpp ../../thrift/save.thrift
mv gen-cpp/ save_client

由于c++中只能有一个main函数,所以要把Save_server.skeleton.cpp删去。

  

将这里的IP地址修改为第四节课服务器的地址 

求md5sum加密后的密码

md5sum
xxxxxxx #你的密码
[ctrl + d]

 

代码地址:https://git.acwing.com/dsxzfh/thrift/-/commit/5b193c80c563d55bd53326002e1aa5ed223c6602

2.7match_server端3.0

改进匹配机制:将排位分相差50以内的用户匹配到一起。同时每秒钟循环一次,观察是否有人匹配上。

 

2.8match_server端4.0

将单线程处理升级为多线程处理

代码:

 https://git.acwing.com/dsxzfh/thrift/-/commit/55523ad67a1e3ad8b11e3b72b80c9b5986acf549

2.9match_server端5.0

将匹配机制改为每隔1秒允许的分差值多50。

代码:

https://git.acwing.com/dsxzfh/thrift/-/commit/cc71dc42d7259d322b820fb3f8704173ed8defaa

 引用:

https://git.acwing.com/ycr2022/thrift/-/blob/master/readme.md

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
hive --service hiveserver2 --hiveconf hive.server2.thrift.port=21066 是一个用于启动HiveServer2服务并将Thrift端口设置为21066的命令。 Hive是一个基于Hadoop的数据仓库工具,用于处理和分析大规模的数据集。HiveServer2是Hive的服务器模式,允许用户通过Thrift接口与Hive交互。通过运行上述命令,我们可以启动HiveServer2服务并将Thrift端口设置为21066,这样客户端就可以连接到HiveServer2并执行查询和操作。 启动HiveServer2服务可以让用户通过网络连接到Hive,并通过执行SQL语句查询和操作存储在Hive中的数据。在启动服务时,我们可以通过--hiveconf参数设置一些Hive的配置属性。在上述命令中,通过指定hive.server2.thrift.port属性为21066,我们将Thrift端口设置为21066,这样客户端就可以通过该端口与HiveServer2通信。 通过启动HiveServer2服务,我们可以在分布式环境中运行Hive,并允许多个客户端同时连接和使用Hive。这样可以提高数据处理的效率和灵活性。同时,通过Thrift接口,HiveServer2还可以与其他编程语言进行交互,例如Java、Python等,使得开发人员可以方便地使用自己熟悉的编程语言进行数据处理和分析。 总之,hive --service hiveserver2 --hiveconf hive.server2.thrift.port=21066 是一个启动HiveServer2服务并将Thrift端口设置为21066的命令,通过这个命令我们可以连接到HiveServer2并使用Hive进行数据处理和分析。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值