289 lines
7.6 KiB
C++
289 lines
7.6 KiB
C++
#include <iostream>
|
|
#include <asio.hpp>
|
|
#include <thread>
|
|
#include <mutex>
|
|
#include <queue>
|
|
#include <string>
|
|
#include "Tool.hpp"
|
|
#include "nlohmann/json.hpp"
|
|
|
|
using namespace asio::ip;
|
|
using namespace std;
|
|
using namespace asio;
|
|
using json = nlohmann::json;
|
|
|
|
# define skey {8,1,2,5,4}
|
|
|
|
io_context ioContext;
|
|
ip::udp::endpoint endpoint(ip::udp::v4(), 12345);
|
|
ip::udp::socket socketObj(ioContext, endpoint);
|
|
|
|
std::mutex mtx;
|
|
int TotalId = 0;
|
|
|
|
//信息包结构体
|
|
struct MessagePack
|
|
{
|
|
unsigned char* Msg;
|
|
int Length;
|
|
};
|
|
std::queue<std::pair<udp::endpoint, MessagePack*>> messages;
|
|
|
|
struct ClientObject
|
|
{
|
|
udp::endpoint Client;
|
|
int HeartTime;
|
|
int ObjectId;
|
|
};
|
|
|
|
//主机
|
|
ClientObject MasterClient;
|
|
//从机MAP
|
|
std::map< udp::endpoint, ClientObject> SubClient;
|
|
|
|
//身份包
|
|
void IdentificationPack(udp::endpoint Client , json Jso) {
|
|
int Type = Jso["IC"].get<int>();
|
|
switch (Type)
|
|
{
|
|
//主机
|
|
case 0:
|
|
std::cout << "主机: " << Client.address() << " : " << Client.port() << "已连接" << endl;;
|
|
MasterClient.Client = Client;
|
|
MasterClient.HeartTime = clock();
|
|
MasterClient.ObjectId = TotalId;
|
|
TotalId++;
|
|
break;
|
|
//从机
|
|
case 1:
|
|
std::cout << "从机: " << Client.address() << " : " << Client.port() << "已连接" << endl;;
|
|
ClientObject SubBuffer;
|
|
SubBuffer.Client = Client;
|
|
SubBuffer.HeartTime = clock();
|
|
SubBuffer.ObjectId = TotalId;
|
|
TotalId++;
|
|
SubClient[Client] = SubBuffer;
|
|
break;
|
|
}
|
|
}
|
|
//心跳包
|
|
void UpdateHeartPack(udp::endpoint Client, json Jso) {
|
|
int Type = Jso["IC"].get<int>();
|
|
switch (Type)
|
|
{
|
|
//主机
|
|
case 0:
|
|
MasterClient.HeartTime = clock();
|
|
break;
|
|
//从机
|
|
case 1:
|
|
SubClient[Client].HeartTime = clock();
|
|
break;
|
|
}
|
|
|
|
std::string P = "{ \"op\" : 11 }";
|
|
unsigned char* StrPck = StringToByte(P);
|
|
socketObj.send_to(buffer(StrPck, strlen(P.c_str()) + 4), Client);
|
|
}
|
|
//下发信息包
|
|
void DistributePack(udp::endpoint Client, json Jso) {
|
|
|
|
std::string Str = Jso.dump();
|
|
unsigned char* StrPck = StringToByte(Str);
|
|
|
|
for (const auto& pair : SubClient) {
|
|
socketObj.send_to(buffer(StrPck, strlen(Str.c_str()) + 4),pair.first);
|
|
}
|
|
std::cout << "[ ";
|
|
for (size_t i = 0; i < strlen(Str.c_str()) + 4; i++)
|
|
{
|
|
std::cout << (int)(StrPck[i]);
|
|
std::cout << ",";
|
|
}
|
|
std::cout << "]" << endl;
|
|
}
|
|
//得到所有对象包
|
|
void GetAllClient(udp::endpoint Client, MessagePack* Pck) {
|
|
json Pack;
|
|
Pack["Arr"] = json::array();
|
|
for (const auto& pair : SubClient) {
|
|
std::cout << "遍历到" << std::endl;
|
|
json Jso;
|
|
Jso["ObjectId"] = pair.second.ObjectId;
|
|
Jso["Client"] = (pair.second.Client.address().to_string() + " : " + (std::to_string(pair.second.Client.port())));
|
|
Pack["Arr"].push_back(Jso);
|
|
}
|
|
std::string jsonString = Pack.dump();
|
|
|
|
unsigned char* StrPck = StringToByte(jsonString);
|
|
socketObj.send_to(buffer(StrPck, strlen(jsonString.c_str()) + 4), Client);
|
|
}
|
|
|
|
|
|
//销毁信息包
|
|
void DestoryPck(MessagePack* Pck) {
|
|
delete[] Pck->Msg;
|
|
delete[] Pck;
|
|
}
|
|
|
|
void TotalMessageLogic(udp::endpoint Client, MessagePack* Pck) {
|
|
//得到包长度
|
|
//int Type = ByteLittleToInt((unsigned char*)Pck->Msg);
|
|
|
|
string Scode((char*)Pck->Msg, Pck->Length);
|
|
|
|
char* Code = (char*)Scode.c_str();
|
|
int key[] = skey;
|
|
Cutecode(Code, key);
|
|
|
|
try
|
|
{
|
|
json Jso = json::parse(Code);
|
|
switch (Jso["op"].get<int>())
|
|
{
|
|
//身份包
|
|
case 0:
|
|
IdentificationPack(Client, Jso);
|
|
break;
|
|
//心跳包
|
|
case 1:
|
|
UpdateHeartPack(Client, Jso);
|
|
break;
|
|
//下发信息包
|
|
case 2:
|
|
DistributePack(Client, Jso);
|
|
break;
|
|
//得到所有对象
|
|
case 3:
|
|
GetAllClient(Client, Pck);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
catch (const std::exception&)
|
|
{
|
|
std::cout << "错误!!!!!!!!!!!!!请联系管理员" << std::endl;
|
|
}
|
|
|
|
DestoryPck(Pck);
|
|
}
|
|
|
|
void CheckClientHeart(int NowTime) {
|
|
if (!MasterClient.HeartTime)return;
|
|
if ((NowTime - MasterClient.HeartTime) > 10000) {
|
|
cout << "主机已断开连接 程序结束,请重新启动服务端" << std::endl;;
|
|
Sleep(3000);
|
|
exit(0);
|
|
}
|
|
|
|
std::vector<udp::endpoint> keysToRemove;
|
|
for (const auto& pair : SubClient) {
|
|
if ((NowTime - pair.second.HeartTime) > 10000) {
|
|
cout << "从机: " << pair.first.address() << " : " << pair.first.port() << " 已失去连接." << endl;
|
|
keysToRemove.push_back(pair.first);
|
|
}
|
|
}
|
|
// 移除标记的元素
|
|
for (udp::endpoint key : keysToRemove) {
|
|
SubClient.erase(key);
|
|
}
|
|
}
|
|
|
|
|
|
//子线程消息处理逻辑
|
|
void handle_messages() {
|
|
static int BaseTime = clock();
|
|
|
|
while (true) {
|
|
std::pair<udp::endpoint, MessagePack*> message;
|
|
{
|
|
std::lock_guard<std::mutex> lock(mtx);
|
|
if (!messages.empty()) {
|
|
message = messages.front();
|
|
//调用全局处理逻辑
|
|
TotalMessageLogic(message.first, message.second);
|
|
messages.pop();
|
|
}
|
|
}
|
|
|
|
int NowTime = clock();
|
|
if (NowTime - BaseTime > 3000) {
|
|
CheckClientHeart(NowTime);
|
|
BaseTime = NowTime;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int main() {
|
|
|
|
//char test[] = {33, 80, 55, 37, 36, 125, 101, 105, 126, 111, 33, 80, 122, 47, 109, 119, 125, 98, 104, 36, 57, 143, 39, 113, 36, 57, 78, 64, 63, 54, 33, 141, 39, 55, 62, 63, 52, 124, 118, 135};
|
|
//int key[] = skey;
|
|
//Cutecode(test, key);
|
|
//for (size_t i = 0; i < 40; i++)
|
|
//{
|
|
// std::cout << (int)test[i] << ",";
|
|
//}
|
|
|
|
|
|
|
|
//io_context ioContext;
|
|
//ip::udp::endpoint endpoint(ip::udp::v4(), 12345);
|
|
//ip::udp::socket socket(ioContext, endpoint);
|
|
std::thread message_thread(handle_messages);
|
|
|
|
while (true) {
|
|
char data[1024];
|
|
ip::udp::endpoint senderEndpoint;
|
|
size_t length = 0;
|
|
|
|
|
|
try
|
|
{
|
|
length = socketObj.receive_from(buffer(data), senderEndpoint);
|
|
if (length >= 4) {
|
|
uint32_t msgLength = *(reinterpret_cast<uint32_t*>(data));
|
|
|
|
if (length >= msgLength + 4) {
|
|
unsigned char* Str = new unsigned char[msgLength];
|
|
memcpy(Str, data + 4, msgLength);
|
|
MessagePack* Pck = new MessagePack();
|
|
Pck->Msg = Str;
|
|
Pck->Length = msgLength;
|
|
|
|
std::lock_guard<std::mutex> lock(mtx);
|
|
messages.push(std::make_pair(senderEndpoint, Pck));
|
|
}
|
|
else {
|
|
cout << "Incomplete message received, length: " << length << endl;
|
|
}
|
|
}
|
|
else {
|
|
cout << "Invalid message length received" << endl;
|
|
}
|
|
}
|
|
catch (const asio::system_error& e)
|
|
{
|
|
if (e.code() == asio::error::connection_reset) {
|
|
if (MasterClient.Client == senderEndpoint) {
|
|
cout << "主机已断开连接 程序结束,请重新启动服务端";
|
|
exit(0);
|
|
}
|
|
else if (SubClient.count(senderEndpoint)) {
|
|
cout << "从机: " << senderEndpoint.address() <<":" << senderEndpoint.port() << " 已失去连接." << endl;
|
|
SubClient.erase(senderEndpoint);
|
|
}
|
|
// 处理断开连接的逻辑
|
|
break;
|
|
}
|
|
else {
|
|
throw;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
}
|