1. 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