XNSim/XNServices/XNUDPService/XNUDPService.cpp

230 lines
6.3 KiB
C++
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "XNUDPService.h"
#include "XNUDPService_p.h"
#include <XNCore/XNServiceManager.h>
#include <XNCore/XNDDSManager.h>
#include <fstream>
#include <sstream>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <XNCore/XNByteArray.h>
XN_SERVICE_INITIALIZE(XNUDPService)
XNUDPService::XNUDPService() : XNServiceObject(new XNUDPServicePrivate())
{
}
XNUDPService::~XNUDPService()
{
T_D();
if (d->udpSocket >= 0) {
close(d->udpSocket);
d->udpSocket = -1;
}
};
XNUDPService::XNUDPService(PrivateType *p) : XNServiceObject(p)
{
}
void XNUDPService::Initialize()
{
XNServiceObject::Initialize();
T_D();
if (d->_initialType == 0) {
// 读取配置文件
std::ifstream file(GetXmlPath());
if (!file.is_open()) {
LOG_WARNING("无法打开配置文件:%1使用默认值", GetXmlPath().c_str());
d->localPort = 12345;
d->targetHost = "127.0.0.1";
d->targetPort = 54321;
return;
}
std::stringstream buffer;
buffer << file.rdbuf();
std::string content = buffer.str();
file.close();
// 简单的XML解析
size_t udpPos = content.find("<UDP>");
if (udpPos != std::string::npos) {
size_t localPortPos = content.find("<LocalPort>", udpPos);
size_t targetHostPos = content.find("<TargetHost>", udpPos);
size_t targetPortPos = content.find("<TargetPort>", udpPos);
if (localPortPos != std::string::npos) {
size_t endPos = content.find("</LocalPort>", localPortPos);
d->localPort =
std::stoi(content.substr(localPortPos + 11, endPos - localPortPos - 11));
}
if (targetHostPos != std::string::npos) {
size_t endPos = content.find("</TargetHost>", targetHostPos);
d->targetHost = content.substr(targetHostPos + 12, endPos - targetHostPos - 12);
}
if (targetPortPos != std::string::npos) {
size_t endPos = content.find("</TargetPort>", targetPortPos);
d->targetPort =
std::stoi(content.substr(targetPortPos + 12, endPos - targetPortPos - 12));
}
} else {
LOG_WARNING("未找到UDP配置, 使用默认值");
d->localPort = 12345;
d->targetHost = "127.0.0.1";
d->targetPort = 54321;
}
} else {
try {
if (d->_otherParams.contains("LocalPort")) {
d->localPort = d->_otherParams["LocalPort"].get<int>();
}
if (d->_otherParams.contains("TargetHost")) {
d->targetHost = d->_otherParams["TargetHost"].get<std::string>();
}
if (d->_otherParams.contains("TargetPort")) {
d->targetPort = d->_otherParams["TargetPort"].get<int>();
}
LOG_INFO("UDP配置: 本地端口:%1, 目标主机:%2, 目标端口:%3", d->localPort, d->targetHost,
d->targetPort);
} catch (const std::exception &e) {
LOG_WARNING("解析JSON参数失败: %1, 使用默认值", e.what());
d->localPort = 12345;
d->targetHost = "127.0.0.1";
d->targetPort = 54321;
}
}
}
void XNUDPService::PrepareForExecute()
{
XNServiceObject::PrepareForExecute();
T_D();
// 初始化UDP socket
d->udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (d->udpSocket < 0) {
LOG_WARNING("无法创建UDP socket");
return;
}
// 设置非阻塞模式
int flags = fcntl(d->udpSocket, F_GETFL, 0);
fcntl(d->udpSocket, F_SETFL, flags | O_NONBLOCK);
// 绑定本地端口
struct sockaddr_in localAddr;
memset(&localAddr, 0, sizeof(localAddr));
localAddr.sin_family = AF_INET;
localAddr.sin_addr.s_addr = INADDR_ANY;
localAddr.sin_port = htons(d->localPort);
if (bind(d->udpSocket, (struct sockaddr *)&localAddr, sizeof(localAddr)) < 0) {
LOG_WARNING("UDP socket 绑定失败, 端口:%d", d->localPort);
close(d->udpSocket);
d->udpSocket = -1;
return;
}
RegisterRTEventHandler("SendUDPData",
std::bind(&XNUDPService::SendData, this, std::placeholders::_1));
}
void XNUDPService::HandleIncomingData()
{
T_D();
if (d->udpSocket < 0)
return;
char buffer[65536];
struct sockaddr_in senderAddr;
socklen_t senderLen = sizeof(senderAddr);
while (true) {
ssize_t bytesRead = recvfrom(d->udpSocket, buffer, sizeof(buffer), 0,
(struct sockaddr *)&senderAddr, &senderLen);
if (bytesRead <= 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
break; // 没有更多数据
}
LOG_WARNING("读取UDP socket失败");
break;
}
if (bytesRead <= 8) {
LOG_WARNING("UDP 数据包小于8字节");
continue;
}
// 将数据转换为XNByteArray
XNByteArray datagram;
datagram.resize(bytesRead);
memcpy(datagram.data(), buffer, bytesRead);
if (datagram[0] != 0xa6) {
LOG_WARNING("UDP 数据包头无效, 头:%1", datagram[0]);
continue;
}
if (datagram[5] != 0x00) {
LOG_WARNING("UDP 数据包传输方向错误, 方向:%1", datagram[5]);
continue;
}
uint16_t dataSize = ((uint16_t)datagram[6] << 8) | (uint16_t)datagram[7];
if (dataSize != bytesRead) {
LOG_WARNING("UDP 数据包大小无效, 大小:%d, 实际大小:%zd", dataSize, bytesRead - 8);
continue;
}
uint8_t planeHeader = datagram[1];
uint8_t ataHeader = datagram[2];
uint8_t modelHeader = datagram[3];
uint8_t structHeader = datagram[4];
if (planeHeader == 0xc0) { //C909数据
if (ataHeader == 0x04) { //ATA04章节数据
if (modelHeader == 0x00 && structHeader == 0x00) { //气动输入数据
TriggerRTEvent("C909::ATA04::AeroInput", datagram);
continue;
} else if (modelHeader == 0x01 && structHeader == 0x00) { //地操输入数据
TriggerRTEvent("C909::ATA04::GhInput", datagram);
continue;
} else if (modelHeader == 0x02 && structHeader == 0x00) { //质量输入数据
TriggerRTEvent("C909::ATA04::WbInput", datagram);
continue;
}
}
} else {
TriggerRTEvent("ReceiveUDPData", datagram);
}
}
}
void XNUDPService::SendData(const std::any &data)
{
T_D();
if (d->udpSocket < 0) {
LOG_WARNING("UDP socket not initialized");
return;
}
struct sockaddr_in targetAddr;
memset(&targetAddr, 0, sizeof(targetAddr));
targetAddr.sin_family = AF_INET;
targetAddr.sin_port = htons(d->targetPort);
inet_pton(AF_INET, d->targetHost.c_str(), &targetAddr.sin_addr);
XNByteArray packet = std::any_cast<XNByteArray>(data);
ssize_t bytesSent = sendto(d->udpSocket, packet.data(), packet.size(), 0,
(struct sockaddr *)&targetAddr, sizeof(targetAddr));
if (bytesSent < 0) {
LOG_WARNING("Failed to send UDP datagram: %s", strerror(errno));
}
}