我正在就一个涉及虚幻引擎和 Quiche 库的项目寻求帮助。
背景: 我一直致力于将 Quiche 库集成到虚幻引擎中,以开发一个可以连接到 Quic 服务器的客户端。到目前为止,我已经成功地将 Quiche 库集成到虚幻引擎中,并在虚幻引擎中编写了一个简单的 UDP 客户端,以使用虚幻的套接字功能发送和接收消息。此外,我还使用 Quiche 库开发了一个 C 客户端来了解其工作原理,并且这两个客户端都运行良好。
问题: 然而,当我尝试使用 Quiche 库在虚幻引擎中编写客户端时,我在握手过程中遇到了问题。我可以看到客户端向 Quic 服务器发送初始数据包,但之后我无法取得任何进展。建立握手似乎存在障碍。我是虚幻引擎和乳蛋饼库的新手,我已经为此苦苦挣扎了一段时间。
代码:
头文件:
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
#include <Interfaces/IPv4/IPv4Endpoint.h>
#include <Networking/Public/Common/UdpSocketBuilder.h>
#include <Interfaces/IPv4/IPv4Address.h>
#include <Sockets/Public/IPAddress.h>
#include <SocketSubsystem.h>
#include <Sockets.h>
#include "quiche_api.h"
class RDNCPPTEST_API FRdnCppTestModule : public IModuleInterface
{
public:
int init();
int send();
int recv(quiche_recv_info* recvInfo);
void driver();
private:
FSocket* socket;
ISocketSubsystem* SocketSubsystem;
FIPv4Address ip;
quiche_config* config;
quiche_conn* conn;
struct sockaddr localAddr;
struct sockaddr peerAddr;
const char* host = "172.27.224.121"; // Hard code the IP for now
};
Cpp文件:
#include "RdnCppTest.h"
#define LOCTEXT_NAMESPACE "FRdnCppTestModule"
#define MAX_DATAGRAM_SIZE 1500
#define LOCAL_CONN_ID_LEN 16
int FRdnCppTestModule::init()
{
/*UNREAL*/
SocketSubsystem = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM);
socket = SocketSubsystem->CreateSocket(NAME_DGram, "mySocket", false);
if (!socket)
{
UE_LOG(LogTemp, Log, TEXT("Error creating socket."));
return -1;
}
UE_LOG(LogTemp, Log, TEXT("Socket successfully created."));
socket->SetNonBlocking();
TSharedPtr <FInternetAddr> serveraddr = SocketSubsystem->CreateInternetAddr();
FIPv4Address::Parse("172.27.224.121", ip);
serveraddr->SetIp(ip.Value);
serveraddr->SetPlatformPort(8080);
bool connected = socket->Connect(*serveraddr);
if (!connected)
{
UE_LOG(LogTemp, Log, TEXT("Error in socket connection"));
return -1;
}
UE_LOG(LogTemp, Log, TEXT("Socket successfully connected to server IP"));
/* QUICHE */
quiche_enable_debug_logging([](const char* line, void* argp) {
UE_LOG(LogTemp, Log, TEXT("Quiche: %s"), UTF8_TO_TCHAR(line));
},
nullptr
);
config = quiche_config_new(0xbabababa);
if (config == NULL)
{
UE_LOG(LogTemp, Log, TEXT("Failed to create config."));
return -1;
}
UE_LOG(LogTemp, Log, TEXT("Config created."));
quiche_config_set_application_protos(config,
(uint8_t*)"\x0ahq-interop\x05hq-29\x05hq-28\x05hq-27\x08http/0.9", 38);
quiche_config_set_max_idle_timeout(config, 5000);
quiche_config_set_max_recv_udp_payload_size(config, MAX_DATAGRAM_SIZE);
quiche_config_set_max_send_udp_payload_size(config, MAX_DATAGRAM_SIZE);
quiche_config_set_initial_max_data(config, 10000000);
quiche_config_set_initial_max_stream_data_bidi_local(config, 1000000);
quiche_config_set_initial_max_stream_data_bidi_remote(config, 1000000);
quiche_config_set_initial_max_streams_bidi(config, 100);
quiche_config_set_initial_max_streams_uni(config, 100);
quiche_config_set_disable_active_migration(config, true);
uint8_t scid[QUICHE_MAX_CONN_ID_LEN] = {};
for (size_t i = 0; i < QUICHE_MAX_CONN_ID_LEN; ++i)
scid[i] = static_cast<unsigned char>(i);
size_t scid_len = sizeof(scid);
memset(&localAddr, 0, sizeof(localAddr));
struct sockaddr_in* localIPv4Addr = (struct sockaddr_in*)&localAddr;
localIPv4Addr->sin_family = AF_INET;
localIPv4Addr->sin_addr.s_addr = inet_addr("127.0.0.1");
unsigned short localPort = socket->GetPortNo();
localIPv4Addr->sin_port = htons(8080);
size_t localIPv4Len = sizeof(localIPv4Addr);
memset(&peerAddr, 0, sizeof(peerAddr));
struct sockaddr_in* peerIPv4Addr = (struct sockaddr_in*)&peerAddr;
peerIPv4Addr->sin_family = AF_INET;
peerIPv4Addr->sin_addr.s_addr = inet_addr(host);
peerIPv4Addr->sin_port = htons(8080);
size_t peerIPv4Len = sizeof(peerIPv4Addr);
conn = quiche_connect(host, (const uint8_t*)scid, scid_len,
&localAddr, sizeof(localAddr),
&peerAddr, sizeof(peerAddr),
config);
if (conn == nullptr)
{
UE_LOG(LogTemp, Log, TEXT("Quiche Connect Error"));
return -1;
}
UE_LOG(LogTemp, Log, TEXT("Quiche Connect Successful"));
return 0;
}
int FRdnCppTestModule::send()
{
int err = 0;
int32 bytesSent = 0;
static uint8_t send_buffer[1350];
quiche_send_info send_info;
while (true)
{
/*QUICHE PACKET WRITE*/
ssize_t quichePacketWrite = quiche_conn_send(conn, send_buffer, sizeof(send_buffer), &send_info);
if (quichePacketWrite == QUICHE_ERR_DONE)
{
UE_LOG(LogTemp, Log, TEXT("Nothing to send from quiche."));
break;
}
if (quichePacketWrite < 0)
{
UE_LOG(LogTemp, Log, TEXT("Failed to create packet from quiche."));
err = -1;
break;
}
UE_LOG(LogTemp, Log, TEXT("Packet write from quiche successful. Bytes written: %zd"), quichePacketWrite);
/*UNREAL SOCKET*/
bool sent = socket->Send(send_buffer, sizeof(send_buffer), bytesSent);
if (!sent)
{
UE_LOG(LogTemp, Log, TEXT("Failed to send packet over the socket."));
err = -1;
break;
}
UE_LOG(LogTemp, Log, TEXT("Bytes sent over the socket: %d"), bytesSent);
}
return err;
}
int FRdnCppTestModule::recv(quiche_recv_info* recvInfo)
{
int err = 0;
int32 bytesRead = 0;
static uint8_t recvBuffer[65535];
while (true)
{
err = 0;
bool received = socket->Recv(recvBuffer, sizeof(recvBuffer), bytesRead, ESocketReceiveFlags::None);
if (!received)
{
UE_LOG(LogTemp, Log, TEXT("Read error from socket. Error Value: %d"), bytesRead);
err = -1;
break;
}
if (!bytesRead)
{
UE_LOG(LogTemp, Log, TEXT("Nothing to read from the socket"));
break;
}
UE_LOG(LogTemp, Log, TEXT("Successfully read from the socket. Bytes read: %d"), bytesRead);
ssize_t quichePacketRead = quiche_conn_recv(conn, recvBuffer, sizeof(recvBuffer), recvInfo);
if (quichePacketRead < 0)
{
UE_LOG(LogTemp, Log, TEXT("Error processing packet in quiche. Error: %zd"), quichePacketRead);
err = -1;
break;;
}
UE_LOG(LogTemp, Log, TEXT("Packet successfully processed. Bytes processed: %zd"), quichePacketRead);
}
return err;
}
void FRdnCppTestModule::driver()
{
int err = 0;
bool protos_sent = false;
/* Initializing Local Addr and Peer Addr */
/*struct sockaddr localAddr;
struct sockaddr peerAddr;
socklen_t localAddrLength = sizeof(localAddr);
memset(&localAddr, 0, localAddrLength);
socklen_t peerAddrLength = sizeof(peerAddr);
memset(&peerAddr, 0, peerAddrLength);*/
if (init() < 0) // Socket construction and quiche initialization
{
UE_LOG(LogTemp, Log, TEXT("Error in the init function."));
return;
}
quiche_recv_info recvInfo =
{
(struct sockaddr*)&peerAddr,
sizeof(peerAddr),
(struct sockaddr*)&localAddr,
sizeof(localAddr),
};
/* Main Loop */
while (true)
{
err = send();
if (err)
{
UE_LOG(LogTemp, Log, TEXT("Error in the send function!"));
break;
}
err = recv(&recvInfo);
if (err)
{
UE_LOG(LogTemp, Log, TEXT("Error in the receive function!"));
break;
}
if (quiche_conn_is_established(conn) && !protos_sent)
{
const uint8_t* app_proto;
size_t app_proto_len;
quiche_conn_application_proto(conn, &app_proto, &app_proto_len); // Returns the negotiated ALPN
UE_LOG(LogTemp, Log, TEXT("Connection Established and ALPN negotiated."));
const static uint8_t r[] = "GET /index.html\r\n";
if (quiche_conn_stream_send(conn, 4, r, sizeof(r), true) < 0)
{
UE_LOG(LogTemp, Log, TEXT("Failed to send request."));
break;
}
UE_LOG(LogTemp, Log, TEXT("Request sent after ALPN negototiation."));
protos_sent = true;
}
if (quiche_conn_is_established(conn))
{
UE_LOG(LogTemp, Log, TEXT("Connection established successfully!"));
// TODO: Send data over a stream
}
if (quiche_conn_is_closed(conn))
{
UE_LOG(LogTemp, Log, TEXT("Connection Closed."));
break;
}
}
quiche_conn_free(conn);
quiche_config_free(config);
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FRdnCppTestModule, RdnCppTest)
虚幻客户端输出:
LogTemp: Socket successfully created.
LogTemp: Socket successfully connected to server IP
LogTemp: Config created.
LogTemp: Quiche Connect Successful
LogTemp: Quiche: quiche::tls: 000102030405060708090a0b0c0d0e0f10111213 write message lvl=Initial len=277
LogTemp: Quiche: quiche: 000102030405060708090a0b0c0d0e0f10111213 tx pkt Initial version=babababa dcid=f30a9f1d527d83397b803de36f65c9ac scid=000102030405060708090a0b0c0d0e0f10111213 len=281 pn=0 src:127.0.0.1:8080 dst:172.27.224.121:8080
LogTemp: Quiche: quiche: 000102030405060708090a0b0c0d0e0f10111213 tx frm CRYPTO off=0 len=277
LogTemp: Quiche: quiche::recovery: 000102030405060708090a0b0c0d0e0f10111213 timer=998.2987ms latest_rtt=0ns srtt=None min_rtt=0ns rttvar=166.5ms loss_time=[None, None, None] loss_probes=[0, 0, 0] cwnd=15000 ssthresh=18446744073709551615 bytes_in_flight=344 app_limited=true congestion_recovery_start_time=None Rate { delivered: 0, delivered_time: Instant { t: 563857.6140141s }, first_sent_time: Instant { t: 563857.6140141s }, end_of_app_limited: 1, last_sent_packet: 0, largest_acked: 0, rate_sample: RateSample { delivery_rate: 0, is_app_limited: false, interval: 0ns, delivered: 0, prior_delivere
d: 0, prior_time: None, send_elapsed: 0ns, ack_elapsed: 0ns, rtt: 0ns } } pacer=Pacer { enabled: true, capacity: 15000, used: 0, rate: 0, last_update: Instant { t: 563857.6140141s }, next_time: Instant { t: 563857.6140141s }, max_datagram_size: 1500, last_packet_size: None, iv: 0ns, max_pacing_rate: None } hystart=window_end=None last_round_min_rtt=18446744073709551615.999999999s current_round_min_rtt=18446744073709551615.999999999s css_baseline_min_rtt=18446744073709551615.999999999s rtt_sample_count=0 css_start_time=None css_round_count=0 cubic={ k=0 w_max=0 }
LogTemp: Packet write from quiche successful. Bytes written: 1200
LogTemp: Bytes sent over the socket: 1350
LogTemp: Nothing to send from quiche.
LogTemp: Read error from socket. Error Value: 0
LogTemp: Error in the receive function!
服务器端输出:
172.27.224.1
version negotiation
sent 47 bytes
Trying again, recv would block
请注意,我使用的服务器是乳蛋饼存储库中的示例服务器: https://github.com/cloudflare/quiche/blob/master/quiche/examples/server.c
您完全缺少进行握手的事件循环。如果可能的话,尝试运行和调试示例服务器和客户端程序。