当前位置: 首页 > news >正文

南宁 网站设计百度站长统计工具

南宁 网站设计,百度站长统计工具,网站打开的速度特别慢的原因,营销比较成功的品牌1. 简介 Apache Thrift软件框架用于可伸缩的跨语言服务开发,它将软件栈和代码生成引擎结合在一起,以构建在C、Java、Python、PHP、Ruby、Erlang、Perl、Haskell、C#、Cocoa、JavaScript、Node.js、Smalltalk、OCaml和Delphi等语言之间高效、无缝地工作的…

1. 简介

        Apache Thrift软件框架用于可伸缩的跨语言服务开发,它将软件栈和代码生成引擎结合在一起,以构建在C++、Java、Python、PHP、Ruby、Erlang、Perl、Haskell、C#、Cocoa、JavaScript、Node.js、Smalltalk、OCaml和Delphi等语言之间高效、无缝地工作的服务。

        Thrift 采用IDL(Interface Definition Language)来定义通用的服务接口,然后通过Thrift提供的编译器,可以将服务接口编译成不同语言编写的代码,通过这个方式来实现跨语言的功能。

通过命令调用Thrift提供的编译器将服务接口编译成不同语言编写的代码

这些代码又分为服务端和客户端,将所在不同进程(或服务器)的功能连接起来

thrift -r --gen <language> <Thrift filename>

创建一个Thrift服务

  1. 定义服务接口(存放接口的文件夹就是thrift文件)

  2. 作为服务端的服务,需要生成server

  3. 作为请求端的服务,需要生成client

2. 案例:游戏的匹配服务

2.1 初始化git仓库

mkdir thrift_lesson
cd thrift_lesson
git initmkdir thrift        # 存放 thrift 源文件
mkdir game          # 实现 游戏应用端 的 客户端 功能
mkdir match_system  # 实现 匹配系统服务器 的 服务端 和 客户端 功能touch readme.md
# 远程创建好git上的repo
git remote add origin git@git.acwing.com:lansfair/thrift_learning.git
git add .
git commit -m "init repo"
git push -u origin master

2.2 初步实现 游戏应用端 与 匹配系统服务器 的交互

2.2.1 创建 match.thrift 接口文件

match.thrift:用于实现 游戏应用端 与 匹配系统服务器 交互的 service

namespace cpp match_service //声明转换为C++语言struct User {   //定义结构体 User1: i32 id, 2: string name,3: i32 score
}service Match { //定义service服务/** * user: 添加的用户信息* info: 附加信息* 在匹配池中添加一个名用户*/  i32 add_user(1: User user, 2: string info),/** * user: 删除的用户信息* info: 附加信息* 从匹配池中删除一名用户*/  i32 remove_user(1: User user, 2: string info),
}

2.2.2 匹配系统的服务端

利用match.thrift接口文件生成C++的匹配系统服务端

  1. 进入 match_system 中新建文件夹 src (之后所有的 匹配服务器 源文件放在 src 下)

  2. 并在 src 文件夹中运行 thrift 脚本生成 C++ 版本的文件

# 原始的thrift生成文件语法:thrift -r --gen <language> <Thrift filename>
mkdir match_system/src
cd match_system/src
thrift -r --gen cpp ../../thrift/match.thrift# 将该文件夹重命名为 match_server(区别于之后要此处生成的client server)
# match_server 与 游戏应用端交互 ; client_server 与 数据存储服务器交互
mv gen-cpp match_server# 把 Match_server.skeleton.cpp 移动到当前 src 目录下并重命名为 main.cpp
# 方便之后调试 main.cpp 文件,其他的源文件仍被存放在 src 文件夹下
mv match_server/Match_server.skeleton.cpp main.cpp# 移动后,需要修改一下 main.cpp 中头文件里Math.cpp 的引用路径
# 并且先暂时让main.cpp中的函数return 0

生成完成后的工作区路径

编译并运行 cpp 文件

# 1. 编译 所有的 .cpp 文件生成 .o 文件
# g++ -c [文件1.cpp] [文件2.cpp] ...
g++ -c main.cpp match_server/*.cpp# 2. 链接 所有的 .o 文件生成可执行文件 .exe
# g++ [文件1.o] [文件2.o] ... -o [需要额外添加的动态库]
# 此处需要额外添加 -lthrift 的 thrift 动态库
g++ *.o -o main -lthrift# 3. 运行 可执行文件
./main

将代码提交到git

git add .
git restore --stage *.o     # .o文件是编译文件,不加入暂存区里
git restore --stage main    # main是可执行文件,不加入暂存区里
git commit -m "add match server"
git push

2.2.3 匹配系统的客户端

在 game 文件夹下,利用match.thrift接口文件生成python的匹配系统的客户端

# 原始的thrift生成文件语法:thrift -r --gen <language> <Thrift filename>
mkdir game/src
cd game/src
thrift -r --gen py ../../thrift/match.thrift# 将该文件夹重命名为 match_client
# 不过这里不改也无所谓,游戏应用端只有匹配的客户端
mv gen-py match_client# 删掉 Match_remote 
# 该文件是用 py 实现 服务端 时用的文件
# 此处我们只需要实现 客户端 功能,因此他没有作用,可以删去
rm match_client/match/Match-remote

利用官网提供的模板,编写 客户端 文件 client.py

# 先删去开头三行声明
# 此处修改路径,以及Calculator 为 Match
# 此处修改 ttypes 路径 以及 User 类
from match_client.match import Match
from match_client.match.ttypes import Userfrom thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocoldef main():# Make sockettransport = TSocket.TSocket('localhost', 9090)# Buffering is critical. Raw sockets are very slowtransport = TTransport.TBufferedTransport(transport)# Wrap in a protocolprotocol = TBinaryProtocol.TBinaryProtocol(transport)# Create a client to use the protocol encoderclient = Match.Client(protocol)# Connect!transport.open()# 调试语句user = User(1, 'yxc', 1500)client.add_user(user, "") # Close!transport.close()# 调用 main 函数
if __name__ == "__main__":main() 

此时服务之间已经可以交互

同样将代码文件提交到git

git add .
git restore --stage *.pyc   # .pyc文件是编译文件,不加入暂存区里
git restore --stage *.swp   # .swp文件是缓存文件,不加入暂存区里(vim没关时会生成)
git commit -m "add client"
git push

2.3 匹配系统2.0

2.3.1 重写 client.py

重写 client.py使之能不断从终端里读入信息

# 利用 python 在终端读入信息需要引入 stdin
from sys import stdin# 将原来的通信 main 函数改写成operate函数,每次需要的时候调用一次建立通信传递信息
# 目的是可以一直不断处理信息
# 然后重写 main 函数,使之能不断从终端读入信息
def operate(op, user_id, user_name, score):# ...........................# 针对 op 参数,分别进行 "增加" 与 "删出" 操作user = User(user_id, user_name, score)if op == "add":client.add_user(user, "")else:client.remove_user(user, "")# ...........................def main():for line in stdin:op, user_id, user_name, score = line.split(' ')operate(op, int(user_id), user_name, int(score))

2.3.2 在匹配服务器里给 匹配系统 开一个 线程

操作系统 里的 PV 原语 + 生产者-消费者 模型

// 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\n", 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; // 匹配池中的用户,用 vector 记录
}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 hereprintf("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 hereprintf("remove_user\n");unique_lock<mutex> lck(message_queue.m);    // 访问临界区(消息队列),先上锁message_queue.q.push({user, "remove"});     // 把新消息加入消息队列message_queue.cv.notify_all();              // 唤醒阻塞的线程return 0;}};// 基于 "生产者-消费者模型" 的线程
void consume_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(consume_task);   // 调用一个线程运行 consume_taskserver.serve();return 0;
}

同样编译,上传到git,运行,现在已经能初步实现匹配功能

g++ -c main.cpp
g++ *.o -o main -lthrift -pthreadgit add main.cpp
git commit -m "match-server ver:2.0"
git push

2.3.3 数据存储服务客户端

创建一个数据存储服务,将匹配结果存储到指定的服务器的文件中

创建数据存储的thrift接口:save.thrift

namespace cpp save_serviceservice Save {/*** username: myserver的名称* password: myserver的密码的md5sum的前8位* 用户名密码验证成功会返回0,验证失败会返回1* 验证成功后,结果会被保存到myserver:homework/lesson_6/result.txt中*/i32 save_data(1: string username, 2: string password, 3: i32 player1_id, 4: i32 player2_id)
}

在 匹配系统服务器 利用 thrift 生成 C++ 文件

并删掉不必要 服务端 文件,因为在该交互功能里,匹配系统服务器 是作为客户端的(C++ 只能有一个main函数)

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

利用 md5 哈希函数获得服务器密码的 哈希值

md5sumxxxxxxx [<Enter>]
[Ctrl + D]
# 哈希值前 8 位就是我们要调用服务器接口时用的密码

从 thrift官网 复制 Client 端的模板到 main.cpp 下与 数据存储服务器 交互的函数中

(数据存储服务器已经写好了相关服务并开启)

// 需要额外引入的头文件
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TTransportUtils.h>// 需要额外声明的命名空间
using namespace  ::save_service;//重写 save_result 内的内容,使其能够与 "数据存储服务器" 交互
void save_result(int a, int b)  // 记录成功匹配的信息
{printf("Match Result: %d %d\n", a, b);// Client端的板子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();//调用接口,把信息存储 "数据存储服务器" 中int res = client.save_data("acs_2511", "ac046a27", a, b);//输出匹配结果if (!res) puts("success");else puts("fail");transport->close();} catch (TException& tx) {cout << "ERROR: " << tx.what() << endl;}
}

编译,运行,上传

g++ -c main.cpp save_client/*.cpp
g++ *.o -o main -lthrift -pthread
./main

此时运行匹配系统,匹配成果后,匹配数据将保存到数据存储服务器

# 上传到 git 服务器
git add main.cpp
git add ../../thrift/save.thrift
git commit -m "2.0: implement save-client"
git push

2.4 匹配系统3.0

增加功能:每次只匹配分差小于 50 的用户

由于我们的匹配策略发生了变化,可能匹配池中仍然有用户在等待匹配(当前匹配池各个用户分差都大于50),而消息队列此时仍为空,需要修改线程中消息队列为空时,不再是阻塞 直到唤醒为止,而是每经过 1 秒就进行一次 match() 调用,如果仍然采用先前的策略,可能会导致进程卡死(新用户不进去,老用户永远匹配不了)

//引入调用 sleep 函数的头文件
#include <unistd.h>// 用于调用 sleep 函数//修改 "生产者 - 消费者模型" 的线程中,关于消息队列为空时的处理
if (message_queue.q.empty())
{// 此处修改为每 1 秒进行一次匹配,而不是等到被唤醒时才匹配lck.unlock();   // 直接解锁临界区资源pool.match();     //调用math()sleep(1);
}//重写匹配池Pool类中的match函数,使之可以匹配分数差在 50 以内的两个用户
void match()    // 匹配池中的第一、第二个用户进行匹配
{while (users.size() > 1){// 按照 rank分 排序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 ++ ){User a = users[i - 1], b = users[i];// 两名玩家分数差小于50时进行匹配if (b.score - a.score <= 50){users.erase(users.begin() + i - 1, users.begin() + i); //删掉用户a,bsave_result(a.id, b.id);flag = false;break;}}if (flag) break;    // 一轮扫描后,发现没有能够匹配的用户,就停止扫描,等待下次调用}
}

g++ -c main.cpp
g++ *.o -o main -lthrift -pthread
./main# 上传到 git 服务器
git add main.cpp
git add ../../thrift/save.thrift
git commit -m "match server:3.0"
git push

2.4 匹配系统4.0

加入多线程

重写 main.cpp 文件

// 引入新的多线程头文件
#include <thrift/concurrency/ThreadManager.h>
#include <thrift/concurrency/ThreadFactory.h>
#include <thrift/server/TThreadPoolServer.h>
#include <thrift/server/TThreadedServer.h>
#include <thrift/TToString.h>// 复制模板的类 CalculatorCloneFactory 然后改一改,把所有的 Calculator 改为 Match
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 {    //改为MatchIf*  delete handler;}
};
// 重写main函数,启用多线程服务器
int main(int argc, char **argv) {TThreadedServer server(std::make_shared<MatchProcessorFactory>(std::make_shared<MatchCloneFactory>()),std::make_shared<TServerSocket>(9090), //portstd::make_shared<TBufferedTransportFactory>(),std::make_shared<TBinaryProtocolFactory>());cout << "Start Match Server" << endl;thread matching_thread(consume_task);   // 调用一个线程运行 consume_taskserver.serve();return 0;
}

编译,运行,上传

g++ -c main.cpp
g++ *.o -o main -lthrift -pthread
./main# 上传到 git 服务器
git add main.cpp
git commit -m "match server:4.0"
git push

2.5 匹配系统 5.0

随时间扩大匹配域:用额外一个数组 wt 来记录每个用户的等待时间,在消息队列为空时,线程会每 1 秒调用一次 match 函数,然后每次调用 match 函数,会首先对 匹配池中所有用户的 wt 值自增 1,从而实现用 wt 记录每个用户的等待时间,然后,每一单位的 wt 会扩大 50分 的匹配域。

修改main.cpp

// 主要修改的是 pool 类中关于 match 函数的部分
class Pool
{
public:....bool check(int i, int j){User a = users[i], b = users[j];int diff = abs(a.score - b.score);int a_diff_max = wt[i] * 50; int b_diff_max = wt[j] * 50; return diff <= a_diff_max && diff <= b_diff_max;}void match()    // 匹配池中的第一、第二个用户进行匹配{// 每 1 秒调用 1 次 match,实现 wt 自增 1,从而实现使所有用户等待时间增加for (auto &t: wt) t ++ ;while (users.size() > 1){bool flag = true;for (uint32_t i = 0; i < users.size(); i ++ ){for (uint32_t j = i + 1; j < users.size(); j ++ ){if (check(i, j)) {users.erase(users.begin() + j); users.erase(users.begin() + i); wt.erase(wt.begin() + j); wt.erase(wt.begin() + i); save_result(users[i].id, users[j].id);flag = false;break;}if (!flag) break;}}if (flag) break;    // 一轮扫描后,发现没有能够匹配的用户,就停止扫描,等待下次调用}}....
private:....vector<int> wt; //wait_time 记录每个用户的等待时间
}pool;

编译,运行,上传

g++ -c main.cpp
g++ *.o -o main -lthrift -pthread
./main
# 上传到 git 服务器
git add main.cpp
git commit -m "match server:5.0"
git push

http://www.15wanjia.com/news/33619.html

相关文章:

  • 延吉做网站seo 优化思路
  • 深圳建设局网站打不开seo教程百度网盘
  • 做网站大概要多久app开发公司排名
  • 网站SEO做点提升流量象客广州网络推广培训
  • 枣庄做网站的公司如何创建一个平台
  • 网站服务器维护内容seo承诺排名的公司
  • 如何做好网站内更新乱码链接怎么用
  • 最火的做网站源码语言百度收录提交
  • 卖菜网站应该怎么做武汉it培训机构排名前十
  • 菜谱网站模版自己建站的网站
  • 红色餐饮网站源码市场推广的方法和规划
  • 做时时彩网站平台嫌钱吗抚州网络推广
  • 丰宁县有做网站的吗搜索网站哪个好
  • 成都网站建设服务功能站长之家域名信息查询
  • 跟做网站的人谈什么百度网络推广怎么做
  • wordpress 功能菜单seo的最终是为了达到
  • 公司简介范本文字seo技术代理
  • 网站优化 前端怎么做搜索软件排行榜前十名
  • 网站开发公司官网知名网站排名
  • 茶叶网站建设公司惠州关键词排名优化
  • 网站怎么做支付宝支付接口优化营商环境的金句
  • 西安 网站建设私人做网站的流程
  • Wordpress删除主题的做博客的seo技巧
  • wordpress底部文件修改手机优化大师哪个好
  • aspaccess做网站seo发外链工具
  • wordpress 英文企业站刘雯每日资讯
  • 南昌网站建设利润西安网站开发
  • 泉州做网站建设站长之家网站
  • 国家建设部网站官网证件查询优化seo排名
  • 静态网站 动态网站南昌seo实用技巧