Basic
一个应用, 包含有 多个 服务
, 不同的服务 在不同的服务器上 (也可以在同个服务器)
比如说一个游戏, 一些玩家可以匹配到一起, 然后开始游戏.
(游戏 主服务
) (匹配系统 服务
)
主服务
里, 一个玩家 点击开始匹配
, 那么此时: 主服务 会调用 匹配服务的 一个函数add_user
函数, 将这个玩家 加入到 匹配系统里
然后比如, 这个玩家 又点击了取消匹配
, 就对应为: 主服务 会调用 匹配服务的 remove_user
函数, 将这个玩家 从 匹配系统中, 移除掉
比如, 匹配系统, 成功的匹配了一些人, 然后调用 数据库系统 服务
的 save_match
函数, 将匹配的结果 存到数据库里, 做一些log记录
thrift, 就是上面的这些函数接口 add_user, remove_user, save_match
, 即 服务间的 通信
也就是: A服务器的x进程, 想要调用, B服务器的y进程 AB可以是同个服务器
, 这就是thrift
而且, 不同的服务, 使用的语言 可以是不同的! 比如, 游戏服务是 python语言, 匹配系统是 c++语言
thrift是: rpc框架 remote procedure call 远程函数调用
在这里, 比如A 调用了 B的一个函数add_user
, 那么: A称为client端
, B称为:server端
匹配-服务1
创建 ~/thrift_lession文件夹
, 表示, 我们整个项目的工作区, 进入该工作区
vim readme.md
mkdir game ' 游戏 服务 '
mkdir match ' 匹配 服务 '
mkdir thrift ' 放一些 thrift的函数接口 '
vim match.thrift ' 文件名是match, 说明这是 (针对 match匹配服务的 接口) '
内容如下 这是thrift语法
:
namespace cpp match_service
' 表示, 如果这个thrift去生成一个cpp文件, 则你这里定义的(结构体/函数), 都是在(match_service)的命名空间下的 '
struct User{
' 一个结构体 '
1: i32 id,
2: string name,
3: i32 score
}
service Match{
' 函数; match服务, 向外提供的接口 '
i32 add_user(1: User user, 2: string info),
i32 remove_user(1: User user, 2: string info),
}
' 进入 ~/thrift_lession/match 文件夹, 即当前是在 匹配服务(也就是一个项目)'
mkdir src ' 任何一个项目, 最好都要有一个src 存源文件 '
cd src/
thrift -r --gen cpp ~/thrift_lesson/thrift/match.thrift ' 根据之前写的thrift接口, 生成对应的cpp代码 '
此时, 在match/src/下, 有一个gen-cpp/的文件夹 ' 这就是上面生成的cpp代码 '
里面有: 'Match.cpp Match.h Match_server.skeleton.cpp match_types.cpp match_types.h'
mv gen-cpp/ match_server ' 改个名字. match_server表示: 这个是服务端的接口. 即是当前match 提供给外界来使用的接口 '
mv match_server/Match_server.skeleton.cpp main.cpp
此时src/里是:
|-- main.cpp
|-- match_server
|-- Match.cpp
|-- Match.h
|-- match_types.cpp
|-- match_types.h
main.cpp
#include "Match.h"
int32_t add_user(const User& user, const std::string& info) {
// Your implementation goes here
printf("add_user\n");
}
int32_t remove_user(const User& user, const std::string& info) {
// Your implementation goes here
printf("remove_user\n");
}
int main(){
serve();
return 0;
}
可以发现, 我们的这些接口的实现, 并没有返回值; 手动把函数加上返回值.
由于, 我们将main.cpp, 放到了src下, 自然#include "Match.h"
也是错的, 需要加一个match_server/
目录
在main函数里, 写一个: ::std::cout<< "test" << ::std::endl;
, 注意, 要写上endl
因为, main里有个serve函数, 程序是一直运行的. cout的缓冲区, 刷新到屏幕, 要么是程序结束, 要么你手动的调用endl
. 否则, 你看不到cout
的输出
先编译下, 让项目正常运行
g++ -c main.cpp ./match_server/*.cpp
: 编译, 生成.o
此时, src/下, 有很多的.o
g++ *.o -o main -lthrift
(链接dll)
./main
执行
假如你修改了某个cpp, 比如修改了main.cpp. 无需g++ *.cpp -o main
因为, 其他的.o文件
已经有了.
最好是: g++ main.cpp -c
, 单独去生成main.o
. 然后再: g++ *.o -o main -lthrift
在/src目录下:
git add .
git restore --staged *.o
git restore --staged main
此时, 所有非.o文件 非执行文件
, 就都在 暂存区里了 最好只是把一些源文件 放到git里, 把编译结果文件放进去 不太好
游戏-服务1
' 进入 ~/thrift_lession/game 文件夹 '
mkdir src ' 同样生成src, 存储源文件 '
thrift -r --gen py ../../thrift/match.thrift ' 根据接口, 生成python代码; 因为, game也需要调用这些接口 '
' 此时, 当前目录下多了: gen-py文件夹 '
mv gen-py/ match_client ' 改个名字. 表示, 这是客户端要使用的接口 '
tree ' 这是: src/match_client/ 的目录 '
|-- __init__.py
|-- match
|-- Match-remote ' 删除这个文件; 他是提供远程服务的, 而此时是客户端, 不是服务端; 删不删都可以 '
|-- Match.py
|-- __init__.py
|-- constants.py
|-- ttypes.py
client.py
' 在game/src目录下 (此时, 这个目录下 有一个match_client): '
vim client.py
' client.py 如下: '
def main():
# Make socket
transport = TSocket.TSocket('127.0.0.1', 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(1, 'wchang', 15000)
client.add_user( user, "me")
if __name__ == "__main__":
main()
此时, 先将我们的match服务里的 之前生成的./main 可执行文件
给运行起来. 他会一直在运行, 在监听
然后, 在这里game 服务里