KRTS网络模块:UDP通信
KRTS网络模块:UDP通信
目录
- KRTS网络模块:UDP通信
- UDP简介
- KRST UDP简介
- 核心特性
- 界面设计
- 核心代码
- 运行实例
- 稳定性测试
UDP简介
UDP(User Datagram Protocol,用户数据报协议)是一种无连接的传输层协议,它位于OSI七层模型中的传输层,并且使用IP作为底层协议来发送数据。UDP的主要特点是它提供了轻量级的数据传输服务,不保证数据的可靠性、顺序性和流量控制。这意味着使用UDP发送的数据报可能丢失、重复或乱序到达,而且发送端并不追踪这些数据报是否成功到达接收端。由于UDP不进行连接管理,因此它的开销非常小,非常适合用于实时应用,如语音通话、视频会议和在线游戏等场景,这些应用能够容忍一定程度的数据丢失,但要求低延迟和高效率的数据传输。此外,UDP还被广泛应用于多播和广播通信中。
KRST UDP简介
KRTS UDP作为一个UDP协议的一个变种,其主要功能包括支持IP地址和端口配置、实时数据处理以及能够接受来自通用UDP和特定UDP的通信服务。KRTS UDP通过减少延迟和提高数据传输效率,确保了更流畅的实时通信体验。下面是KRTS服务端的一些核心特性和实现细节:
核心特性
- IP 和端口配置:
- 支持指定服务端监听的IP地址和端口号。
- 支持绑定到特定的网络接口。
- 实时数据处理:
- 实现高效的数据处理逻辑,确保低延迟和高吞吐量。
界面设计
Qt开发应用层界面
核心代码
内核层代码
/*
* KRTS 网络服务器 - 内核程序
* 时间: 2024-8-10
* 版本: 0.1
* 代码规范: Google 开源项目风格
* 版权所有: 山东易码智能科技股份有限公司
*/
#include "Base/SharedData.h"
SharedData *kernel_data_ {nullptr};
KSSocketAddr remote_addr_; // 远程地址
/* 套接字回调函数 */
KSError __stdcall SocketCallBack(void * /*pArgs*/, void *context);
extern "C" KSError __declspec(dllexport) __stdcall InitKernel(void *args, void * /*pContext*/)
{
KS_printK("-------------- InitKernel \n");
kernel_data_ = static_cast<SharedData *>(args);
/* 为传入数据创建管道。这将是一个消息管道 */
KSError error = KS_createPipe(&kernel_data_->pipe_handle, "NetworkUdpServerPipe", 1, BUFFER_SIZE * 4, KS_INVALID_HANDLE, KSF_MESSAGE_PIPE);
if (error != KS_OK) { return error; }
/* 创建接收事件。 */
error = KS_createEvent(&kernel_data_->receive_event_handle, "UdpServerReceiveEvent", KSF_NO_FLAGS);
if (error != KS_OK) { return error; }
// 为了对套接字上的事件做出反应,我们使用带有 KSF_DIRECT_EXEC 的回调。
error = KS_createCallBack(&kernel_data_->socket_call_back, SocketCallBack, nullptr, KSF_DIRECT_EXEC, 0);
if (error != KS_OK) { return error; }
/* 打开网络适配器 */
error = KS_openNetworkAdapter(&kernel_data_->adapter_handle, kernel_data_->device_name, nullptr, KSF_NO_FLAGS);
if (error != KS_OK) { return error; }
/* 网络将配置为使用在用户空间的应用程序中指定的 IP 地址、子网和网关。 */
error = KS_execNetworkCommand(kernel_data_->adapter_handle, KS_NETWORK_SET_IP_CONFIG, &kernel_data_->ip_config, KSF_NO_FLAGS);
if (error != KS_OK) { return error; }
/* 在端口上创建一个 Udp 服务器套接字。 */
KSSocketAddr socket_addr = {0};
socket_addr.family = KS_FAMILY_IPV4;
socket_addr.port = KS_htons(kernel_data_->port_config);
*socket_addr.address = kernel_data_->ip_config.localAddress;
error = KS_openSocket(&kernel_data_->socket_handle, kernel_data_->adapter_handle, &socket_addr, KS_PROTOCOL_UDP, KSF_NO_FLAGS);
if (error != KS_OK){ return error;}
// 设置套接字的最大传输单位 (MTU)。
int mtu = 1024;
error = KS_execSocketCommand( kernel_data_->socket_handle, KS_SOCKET_SET_MTU, &mtu,KSF_NO_FLAGS);
if (error != KS_OK){ return error;}
/* 安装数据接收回调 */
error = KS_installSocketHandler(kernel_data_->socket_handle, KS_SOCKET_RECV, kernel_data_->socket_call_back, KSF_NO_FLAGS);
if (error != KS_OK) { return error; }
// 初始化远程地址
remote_addr_.family = KS_FAMILY_IPV4;
remote_addr_.port = KS_htons(kernel_data_->port_config);
*remote_addr_.address = kernel_data_->remote_addr;
return KS_OK;
}
extern "C" KSError __declspec(dllexport) __stdcall ExitKernel(void * /*pArgs*/, void * /*pContext*/)
{
KS_printK("-------------- ExitKernel \n");
if (kernel_data_ == nullptr) { return KSERROR_FUNCTION_NOT_AVAILABLE; }
KS_installSocketHandler(kernel_data_->socket_handle, KS_SOCKET_RECV, KS_INVALID_HANDLE, KSF_NO_FLAGS);
/* 关闭套接字。 */
KS_closeSocket(kernel_data_->socket_handle);
/* 关闭网络适配器。 */
KS_closeNetwork(kernel_data_->adapter_handle,KSF_NO_FLAGS);
/* 移除回调。 */
KS_removeCallBack(kernel_data_->socket_call_back);
/*关闭事件 */
KS_closeEvent(kernel_data_->receive_event_handle);
/* 删除消息管道 */
KS_removePipe(kernel_data_->pipe_handle);
return KS_OK;
}
// 发送消息
extern "C" __declspec(dllexport) KSError __stdcall SendBufferContent(void* /*pArgs*/, void* /*pContext*/)
{
if (kernel_data_->send_length != 0)
{
KSError error = KS_sendToSocket(
kernel_data_->socket_handle,
&remote_addr_,
kernel_data_->send_buffer,
kernel_data_->send_length, nullptr,
KSF_NO_FLAGS);
if (error != KS_OK) {return error;}
error = KS_sendToSocket(
kernel_data_->socket_handle,
&remote_addr_,
"\r\n",
2, nullptr,
KSF_NO_FLAGS);
if (error != KS_OK) { return error;}
}
return KS_OK;
}
// 接收消息
KSError __stdcall SocketCallBack(void * /*pArgs*/, void */* context */)
{
KS_printK("-------------- SocketCallBack \n");
KSError error;
int length;
do
{
byte read_buffer[BUFFER_SIZE];
// 接收数据
error = KS_recvFromSocket(kernel_data_->socket_handle, &remote_addr_, read_buffer, BUFFER_SIZE, &length, KSF_NO_FLAGS);
if (error && KSERROR_CODE(error) != KSERROR_NO_DATA_AVAILABLE) { return error; }
if (error == KS_OK)
{
error = KS_putPipe(kernel_data_->pipe_handle, read_buffer, length, nullptr,KSF_NO_FLAGS);
KS_setEvent(kernel_data_->receive_event_handle);
}
} while (error == KS_OK);
return KS_OK;
}
#pragma pack(push, 8)
#include <windows.h>
#pragma pack(pop)
BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD reason, LPVOID pReserved)
{
return TRUE;
}
应用层代码
#include "KitharaUser.h"
#include "Universal/Universal.h"
#include <QtConcurrent>
#include <windows.h>
KitharaUser::KitharaUser(QObject *parent) : QObject(parent)
{
/* 打开驱动 */
if (const KSError error = KS_openDriver(customer_number_); error != KS_OK)
{
Universal::OutputErr(error, "KS_openDriver", "Unable to open the driver!");
return;
}
}
KitharaUser::~KitharaUser()
{
/* 关闭驱动 */
if (const KSError error = KS_closeDriver(); error != KS_OK)
{
Universal::OutputErr(error, "KS_closeDriver", "Unable to close the driver!");
}
Sleep(3000);
};
bool KitharaUser::Init()
{
/* 创建共享内存 */
KSError error = KS_createSharedMemEx(&shared_mem_handle_, "", sizeof(SharedData),KSF_NO_FLAGS);
if (error != KS_OK)
{
Universal::OutputErr(error, "KS_createSharedMemEx", "Unable to create the shared memory!");
return false;
}
/* 获取共享内存句柄,并于用户层数据绑定 */
error = KS_getSharedMemEx(shared_mem_handle_, reinterpret_cast<void **>(&user_data_), KSF_NO_FLAGS);
if (error != KS_OK)
{
Universal::OutputErr(error, "KS_getSharedMemEx", "Unable to get the shared memory!");
return false;
}
/* 加载内核层DLl */
error = KS_loadKernel(&user_data_->kernel_handle, "KernelUDP.dll", nullptr, nullptr,KSF_KERNEL_EXEC | KSF_SAVE_FPU);
if (error != KS_OK)
{
Universal::OutputErr(error, "KS_loadKernel", "Unable to load the kernel!");
return false;
}
return true;
}
bool KitharaUser::Start()
{
/* 遍历网卡 */
/* 获取网卡名称
*
* KSF_ACTIVE: 该设备不仅在Windows 系统中可用,而且还与 Kithara 驱动程序永久连接。
*
*/
KSError error = KS_enumDevices("NET", network_index_, user_data_->device_name, KSF_NO_FLAGS);
if (error != KS_OK)
{
Universal::OutputErr(error, "KS_enumDevices", "Unable to query network device name!");
return false;
}
// 为了发送 IP 数据包,我们必须设置自己的 IP 地址和子网掩码。
// 注意:以太网帧中的数据必须是“大端”!
KS_makeIPv4(&user_data_->ip_config.localAddress, 192, 168, 0, 182);
KS_makeIPv4(&user_data_->ip_config.subnetMask, 255, 255, 255, 0);
KS_makeIPv4(&user_data_->ip_config.gatewayAddress, 192, 168, 0, 1);
KS_makeIPv4(&user_data_->remote_addr, 192, 168, 0, 161);
user_data_->port_config = 2345;
error = KS_execKernelFunctionEx(user_data_->kernel_handle, "InitKernel", shared_mem_handle_, KS_INVALID_HANDLE, KSF_NO_FLAGS);
if (error != KS_OK)
{
Universal::OutputErr(error, "KS_execKernelFunctionEx", "Unable to initialize the kernel DLL!");
return false;
}
/* 创建线程 */
future_ = QtConcurrent::run(&KitharaUser::RecevicePipeData,this);
return true;
}
QStringList KitharaUser::GetNetworkList() const
{
QStringList network_list;
for (int i = 0;; ++i)
{
char device_name[256];
if (const KSError error = KS_enumDevices("NET", i, device_name, KSF_NO_FLAGS); error != KS_OK)
{
if (KSERROR_CODE(error) != KSERROR_DEVICE_NOT_FOUND)
{
Universal::OutputErr(error, "KS_enumDevices", "Unable to query network device name!");
}
if (KSERROR_CODE(error) == KSERROR_DEVICE_NOT_FOUND && !i)
{
Universal::OutputTxt("No network adapters found");
return {};
}
break;
}
network_list.append(device_name);
}
return network_list;
}
void KitharaUser::SetNetworkIndex(const int index)
{
if (index < 0)
{
return;
}
network_index_ = index;
}
void KitharaUser::WaitForStop() const
{
while (true)
{
if (user_data_->is_finished == 1)
{
return;
}
if(!SendUdpData("Hello KRTS"))
{
Universal::OutputErr(KS_OK, "SendUdpData", "Unable to send data!");
}
Sleep(1000);
}
}
void KitharaUser::Stop() const
{
if (user_data_ != nullptr)
{
user_data_->is_finished = 1;
}
}
void KitharaUser::UnInit()
{
// 等待线程退出
future_.waitForFinished();
KSError error;
/* 卸载内核层DLL */
if (shared_mem_handle_ != NULL && user_data_->kernel_handle != NULL)
{
if (error = KS_execKernelFunctionEx(user_data_->kernel_handle, "ExitKernel", KS_INVALID_HANDLE, KS_INVALID_HANDLE, KSF_NO_FLAGS)
; error != KS_OK)
{
Universal::OutputErr(error, "KS_execKernelFunctionEx", "Error while deallocating resources on kernel level!");
return;
}
error = KS_freeKernel(user_data_->kernel_handle);
if (error != KS_OK)
{
Universal::OutputErr(error, "KS_freeKernel", "Unable to unload the kernel!");
}
}
/* 释放共享内存 */
if (shared_mem_handle_ != NULL)
{
error = KS_freeSharedMemEx(shared_mem_handle_, KSF_NO_FLAGS);
if (error != KS_OK)
{
Universal::OutputErr(error, "KS_freeSharedMemEx", "Unable to free the shared memory!");
}
else
{
user_data_ = nullptr;
}
}
}
void KitharaUser::RecevicePipeData()
{
KSError error = KS_OK;
char read_buffer[BUFFER_SIZE];
int length;
while (true)
{
if (user_data_->is_finished != 0)
{
break;
}
error = KS_waitForEvent(user_data_->receive_event_handle, KSF_NO_FLAGS, 5 * MS);
if (error != KS_OK) { continue; }
while (KS_OK == KS_getPipe(user_data_->pipe_handle, read_buffer, BUFFER_SIZE, &length, KSF_NO_FLAGS))
{
read_buffer[length] = '\0';
Universal::OutputTxt(read_buffer, false);
if (auto str = QString(read_buffer); !str.isEmpty())
{
emit SendData(str);
}
}
}
Universal::OutputTxt("Receiving thread has been finished.");
}
bool KitharaUser::SendUdpData(const QString &message) const
{
if (user_data_ == nullptr)
{
return false;
}
strcpy_s(user_data_->send_buffer, message.toStdString().c_str());
user_data_->send_length = (int)message.length();
if (const KSError error = KS_execKernelFunctionEx(user_data_->kernel_handle, "SendBufferContent", KS_INVALID_HANDLE, KS_INVALID_HANDLE, KSF_NO_FLAGS); error != KS_OK)
{
Universal::OutputErr(error, "SendBufferContent", "Error while sending!");
return false;
}
return true;
}
运行实例
稳定性测试
根据本次测试数据,系统抖动范围在0至30.60微秒之间,其中0-1微秒区间内抖动出现频率最高,占比达23.07%。整体来看,大部分抖动集中在低值区间,表明系统具有较好的时间稳定性和可预测性。测试过程中不同硬件的测试结果会产生较大差异。