DP_S/include/l_socket.h

223 lines
7.7 KiB
C
Raw Normal View History

2024-04-24 10:25:44 +08:00
#pragma once
#include "Singleton.h"
#include "l_squirrel.h"
#include <iostream>
#include <asio.hpp>
extern HSQUIRRELVM v;
extern std::recursive_mutex SqMtx;
using namespace asio;
using asio::ip::tcp;
class Client
{
private:
asio::io_context io_context;
tcp::resolver resolver;
tcp::socket socket;
tcp::resolver::results_type endpoint;
std::array<char, 8192> buffer;
std::array<char, 8192000> PackData;
std::size_t writeDataSize = 0;
std::size_t receivedDataSize = 0;
std::size_t TestCode = 0;
std::string Ip = "192.168.200.27";
// std::string Ip = "127.0.0.1";
std::string Port = "65109";
std::mutex PackMtx;
public:
bool ConnectState = false;
public:
2024-04-30 03:01:48 +08:00
Client(asio::io_context &io_context, std::string Ip, std::string Port)
2024-04-24 10:25:44 +08:00
: resolver(io_context),
socket(io_context)
{
endpoint = resolver.resolve(Ip, Port);
2024-05-12 09:07:41 +08:00
this->Ip = Ip;
this->Port = Port;
2024-04-24 10:25:44 +08:00
PackData.fill(0);
}
void start()
{
async_connect(socket, endpoint, [this](const asio::error_code &error, const tcp::endpoint &endpoint)
{
if (!error) {
ConnectState = true;
read();
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v); // saves the stack size before the call
sq_pushroottable(v); // pushes the global table
sq_pushstring(v, _SC("OnGatewaySocketConnect"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{ // gets the field 'foo' from the global table
sq_pushroottable(v); // push the 'this' (in this case is the global table)
sq_call(v, 1, SQFalse, SQTrue); // calls the function
}
sq_settop(v, top); // restores the original stack size
io_context.poll(); // 处理一次事件循环,避免主线程阻塞
} else {
std::cerr << "Error connecting to server: " << error.message() << std::endl;
} });
}
void read()
{
socket.async_read_some(asio::buffer(buffer), [this](const asio::error_code &error, std::size_t bytes_transferred)
{
if (!error) {
PackMtx.lock();
for (std::size_t i = 0; i < bytes_transferred; ++i)
{
PackData[writeDataSize + i] = buffer[i];
}
writeDataSize += bytes_transferred;
PackMtx.unlock();
read();
} else {
std::cerr << "Error reading data: " << error.message() << std::endl;
reconnect();
} });
}
void reconnect()
{
ConnectState = false;
std::cout << "服务器断开连接,尝试重连." << std::endl;
// 执行重连操作
// 关闭当前连接
socket.close();
// 重新解析端点
endpoint = resolver.resolve(Ip, Port);
// 重新连接
async_connect(socket, endpoint, [this](const asio::error_code &error, const tcp::endpoint &endpoint)
{
if (!error) {
ConnectState = true;
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v); // saves the stack size before the call
sq_pushroottable(v); // pushes the global table
sq_pushstring(v, _SC("OnGatewaySocketConnect"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{ // gets the field 'foo' from the global table
sq_pushroottable(v); // push the 'this' (in this case is the global table)
sq_call(v, 1, SQFalse, SQTrue); // calls the function
}
sq_settop(v, top); // restores the original stack size
read();
} else {
std::cerr << "Error reconnecting to server: " << error.message() << std::endl;
// 可以在此处添加重连失败的处理逻辑
reconnect();
} });
}
void send(unsigned char *message, int Length)
{
async_write(socket, asio::buffer(message, Length), [this](const asio::error_code &error, std::size_t bytes_transferred)
{
if (!error) {
// std::cout << "Message sent" << std::endl;
} else {
std::cerr << "Error sending message: " << error.message() << std::endl;
} });
}
void PackLogic()
{
// 如果包长度不够直接返回
if (PackData.size() < 4)
return;
// 如果里面已经读了超过一半的大小了
if (writeDataSize >= 40960)
{
2024-08-09 20:04:31 +08:00
std::cout << "清空一次二级缓存" << std::endl;
std::cout << "清空一次二级缓存" << std::endl;
2024-04-24 10:25:44 +08:00
PackMtx.lock();
// 删除前XX个元素
std::copy(PackData.begin() + receivedDataSize, PackData.end(), PackData.begin());
// 将最后16个元素设置为0
std::fill(PackData.end() - receivedDataSize, PackData.end(), 0);
// 写的大小重置
writeDataSize -= receivedDataSize;
// 读的大小重置
receivedDataSize = 0;
PackMtx.unlock();
}
unsigned char *Count = new unsigned char[4];
std::copy(PackData.begin() + receivedDataSize, PackData.begin() + 4 + receivedDataSize, Count);
int PackSize = ByteLittleToInt(Count);
delete[] Count;
// 如果长度不够直接返回
if (PackSize <= 0)
return;
char *StrBuffer = new char[PackSize + 1];
std::copy(PackData.begin() + 4 + receivedDataSize, PackData.begin() + 4 + PackSize + receivedDataSize, StrBuffer);
StrBuffer[PackSize] = '\0';
// 这次读了多少
receivedDataSize += (4 + PackSize);
std::string Str = StrBuffer;
delete[] StrBuffer;
2024-07-19 13:36:35 +08:00
// std::cout << "包大小: " << PackSize << std::endl;
// std::cout << "包内容: " << Str << std::endl;
// std::cout << "收到了第: " << TestCode << "个包" << std::endl;
2024-04-24 10:25:44 +08:00
std::lock_guard<std::recursive_mutex> lock(SqMtx);
SQInteger top = sq_gettop(v); // saves the stack size before the call
sq_pushroottable(v); // pushes the global table
sq_pushstring(v, _SC("OnGatewaySocketMsg"), -1);
if (SQ_SUCCEEDED(sq_get(v, -2)))
{ // gets the field 'foo' from the global table
sq_pushroottable(v); // push the 'this' (in this case is the global table)
sq_pushstring(v, Str.c_str(), -1);
sq_call(v, 2, SQFalse, SQTrue); // calls the function
}
sq_settop(v, top); // restores the original stack size
TestCode++;
}
static int ByteLittleToInt(unsigned char *Count)
{
int int1 = Count[0] & 0xff;
int int2 = (Count[1] & 0xff) << 8;
int int3 = (Count[2] & 0xff) << 16;
int int4 = (Count[3] & 0xff) << 24;
return int1 | int2 | int3 | int4;
}
};
class l_socket
{
public:
private:
l_socket() {} // private constructor to prevent instantiation
l_socket(const l_socket &) = delete; // disable copy constructor
l_socket &operator=(const l_socket &) = delete; // disable assignment operator
Client *ClientObj;
public:
bool InitState = false;
static l_socket &getInstance()
{
static l_socket instance;
return instance;
}
void InitSqr();
void InitPackLogic();
2024-04-30 03:01:48 +08:00
void Init(std::string Ip, std::string Port);
2024-04-24 10:25:44 +08:00
void Send(const SQChar *Pck);
void Logic();
void IntToByteLittle(unsigned char *b, int Count);
public:
};