增强P2P连接的可靠性,添加用户信息管理和连接重试机制

This commit is contained in:
Ayndpa
2025-11-18 18:28:52 +08:00
parent 0f76252c16
commit 3b85a5f3bb

View File

@@ -35,6 +35,13 @@ ISteamNetworkingSockets* m_pInterface = nullptr;
bool forwarding = false;
std::unique_ptr<TCPServer> server;
// Connection config for improved P2P reliability
SteamNetworkingConfigValue_t g_connectionConfig[2];
int g_retryCount = 0;
const int MAX_RETRIES = 3;
CSteamID g_hostSteamID;
int g_currentVirtualPort = 0;
// New variables for multiple connections and TCP clients
std::vector<HSteamNetConnection> connections;
std::map<HSteamNetConnection, TCPClient*> clientMap;
@@ -43,11 +50,23 @@ int localPort = 0;
bool g_isHost = false;
bool g_isClient = false;
// User info structure
struct UserInfo {
CSteamID steamID;
std::string name;
int ping;
bool isRelay;
};
std::map<HSteamNetConnection, UserInfo> userMap;
// Callback function for connection status changes
void OnSteamNetConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t *pInfo)
{
std::lock_guard<std::mutex> lock(clientMutex);
std::cout << "Connection status changed: " << pInfo->m_info.m_eState << std::endl;
std::cout << "Connection status changed: " << pInfo->m_info.m_eState << " for connection " << pInfo->m_hConn << std::endl;
if (pInfo->m_info.m_eState == k_ESteamNetworkingConnectionState_ProblemDetectedLocally) {
std::cout << "Connection failed: " << pInfo->m_info.m_szEndDebug << std::endl;
}
if (pInfo->m_eOldState == k_ESteamNetworkingConnectionState_None && pInfo->m_info.m_eState == k_ESteamNetworkingConnectionState_Connecting)
{
// Incoming connection, accept it
@@ -55,7 +74,19 @@ void OnSteamNetConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t
connections.push_back(pInfo->m_hConn);
g_hConnection = pInfo->m_hConn; // Keep for backward compatibility if needed
g_isConnected = true;
std::cout << "Accepted incoming connection" << std::endl;
std::cout << "Accepted incoming connection from " << pInfo->m_info.m_identityRemote.GetSteamID().ConvertToUint64() << std::endl;
// Add user info
SteamNetConnectionInfo_t info;
SteamNetConnectionRealTimeStatus_t status;
if (m_pInterface->GetConnectionInfo(pInfo->m_hConn, &info) && m_pInterface->GetConnectionRealTimeStatus(pInfo->m_hConn, &status, 0, nullptr)) {
UserInfo userInfo;
userInfo.steamID = pInfo->m_info.m_identityRemote.GetSteamID();
userInfo.name = SteamFriends()->GetFriendPersonaName(userInfo.steamID);
userInfo.ping = status.m_nPing;
userInfo.isRelay = (info.m_idPOPRelay != 0);
userMap[pInfo->m_hConn] = userInfo;
std::cout << "Incoming connection details: ping=" << status.m_nPing << "ms, relay=" << (info.m_idPOPRelay != 0 ? "yes" : "no") << std::endl;
}
// Removed: Create TCP Client here - now lazy connect on first message
}
else if (pInfo->m_eOldState == k_ESteamNetworkingConnectionState_Connecting && pInfo->m_info.m_eState == k_ESteamNetworkingConnectionState_Connected)
@@ -63,6 +94,18 @@ void OnSteamNetConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t
// Client connected successfully
g_isConnected = true;
std::cout << "Connected to host" << std::endl;
// Add user info
SteamNetConnectionInfo_t info;
SteamNetConnectionRealTimeStatus_t status;
if (m_pInterface->GetConnectionInfo(pInfo->m_hConn, &info) && m_pInterface->GetConnectionRealTimeStatus(pInfo->m_hConn, &status, 0, nullptr)) {
UserInfo userInfo;
userInfo.steamID = pInfo->m_info.m_identityRemote.GetSteamID();
userInfo.name = SteamFriends()->GetFriendPersonaName(userInfo.steamID);
userInfo.ping = status.m_nPing;
userInfo.isRelay = (info.m_idPOPRelay != 0);
userMap[pInfo->m_hConn] = userInfo;
std::cout << "Outgoing connection details: ping=" << status.m_nPing << "ms, relay=" << (info.m_idPOPRelay != 0 ? "yes" : "no") << std::endl;
}
}
else if (pInfo->m_info.m_eState == k_ESteamNetworkingConnectionState_ClosedByPeer || pInfo->m_info.m_eState == k_ESteamNetworkingConnectionState_ProblemDetectedLocally)
{
@@ -78,6 +121,8 @@ void OnSteamNetConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t
++it;
}
}
// Remove from userMap
userMap.erase(pInfo->m_hConn);
// Cleanup TCP Client
if (clientMap.count(pInfo->m_hConn)) {
clientMap[pInfo->m_hConn]->disconnect();
@@ -86,6 +131,21 @@ void OnSteamNetConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t
std::cout << "Cleaned up TCP Client for connection" << std::endl;
}
std::cout << "Connection closed" << std::endl;
// Retry connection if client and retries left
if (g_isClient && !g_isConnected && g_retryCount < MAX_RETRIES) {
g_retryCount++;
g_currentVirtualPort++;
SteamNetworkingIdentity identity;
identity.SetSteamID(g_hostSteamID);
HSteamNetConnection newConn = m_pInterface->ConnectP2P(identity, g_currentVirtualPort, 2, g_connectionConfig);
if (newConn != k_HSteamNetConnection_Invalid) {
g_hConnection = newConn;
std::cout << "Retrying connection attempt " << g_retryCount << " with virtual port " << g_currentVirtualPort << std::endl;
} else {
std::cerr << "Failed to initiate retry connection" << std::endl;
}
}
}
}
@@ -93,11 +153,14 @@ void SteamFriendsCallbacks::OnGameRichPresenceJoinRequested(GameRichPresenceJoin
CSteamID hostSteamID = pCallback->m_steamIDFriend;
if (!g_isHost && !g_isConnected) {
g_isClient = true;
g_hostSteamID = hostSteamID;
g_retryCount = 0;
g_currentVirtualPort = 0;
SteamNetworkingIdentity identity;
identity.SetSteamID(hostSteamID);
g_hConnection = m_pInterface->ConnectP2P(identity, 0, 0, nullptr);
g_hConnection = m_pInterface->ConnectP2P(identity, g_currentVirtualPort, 2, g_connectionConfig);
if (g_hConnection != k_HSteamNetConnection_Invalid) {
std::cout << "Joined game room via invite from " << hostSteamID.ConvertToUint64() << std::endl;
std::cout << "Joined game room via invite from " << hostSteamID.ConvertToUint64() << ", attempting connection with virtual port " << g_currentVirtualPort << std::endl;
// Start TCP Server
server = std::make_unique<TCPServer>(8888);
if (!server->start()) {
@@ -125,6 +188,10 @@ int main() {
m_pInterface = SteamNetworkingSockets();
// Initialize connection config for better P2P reliability
g_connectionConfig[0].SetInt32(k_ESteamNetworkingConfig_TimeoutInitial, 10000); // 10 seconds initial timeout
g_connectionConfig[1].SetInt32(k_ESteamNetworkingConfig_NagleTime, 0); // Disable Nagle for UDP
// Initialize GLFW
if (!glfwInit()) {
std::cerr << "Failed to initialize GLFW" << std::endl;
@@ -187,6 +254,21 @@ int main() {
// Poll networking
m_pInterface->RunCallbacks();
// Update user info
{
std::lock_guard<std::mutex> lock(clientMutex);
for (auto conn : connections) {
SteamNetConnectionInfo_t info;
SteamNetConnectionRealTimeStatus_t status;
if (m_pInterface->GetConnectionInfo(conn, &info) && m_pInterface->GetConnectionRealTimeStatus(conn, &status, 0, nullptr)) {
if (userMap.count(conn)) {
userMap[conn].ping = status.m_nPing;
userMap[conn].isRelay = (info.m_idPOPRelay != 0);
}
}
}
}
// Receive messages from Steam and forward to TCP server
{
std::lock_guard<std::mutex> lock(clientMutex);
@@ -241,11 +323,14 @@ int main() {
hListenSock = m_pInterface->CreateListenSocketP2P(0, 0, nullptr);
if (hListenSock != k_HSteamListenSocket_Invalid) {
g_isHost = true;
std::cout << "Created listen socket for hosting game room" << std::endl;
// Set Rich Presence
std::string connectStr = std::to_string(SteamUser()->GetSteamID().ConvertToUint64());
SteamFriends()->SetRichPresence("connect", connectStr.c_str());
SteamFriends()->SetRichPresence("status", "主持游戏房间");
std::cout << "Hosting game room. Connection string: " << connectStr << std::endl;
} else {
std::cerr << "Failed to create listen socket for hosting" << std::endl;
}
}
ImGui::InputText("主机Steam ID", joinBuffer, IM_ARRAYSIZE(joinBuffer));
@@ -253,11 +338,15 @@ int main() {
uint64 hostID = std::stoull(joinBuffer);
CSteamID hostSteamID(hostID);
g_isClient = true;
g_hostSteamID = hostSteamID;
g_retryCount = 0;
g_currentVirtualPort = 0;
// Connect to host
SteamNetworkingIdentity identity;
identity.SetSteamID(hostSteamID);
g_hConnection = m_pInterface->ConnectP2P(identity, 0, 0, nullptr);
g_hConnection = m_pInterface->ConnectP2P(identity, g_currentVirtualPort, 2, g_connectionConfig);
if (g_hConnection != k_HSteamNetConnection_Invalid) {
std::cout << "Attempting to connect to host " << hostSteamID.ConvertToUint64() << " with virtual port " << g_currentVirtualPort << std::endl;
// Connection initiated, wait for callback to confirm
std::cout << "Connecting to host..." << std::endl;
// Start TCP Server
@@ -305,6 +394,27 @@ int main() {
ImGui::Text("连接的好友: %d", (int)connections.size());
ImGui::Text("活跃的TCP客户端: %d", (int)clientMap.size());
}
ImGui::Separator();
ImGui::Text("用户列表:");
if (ImGui::BeginTable("UserTable", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
ImGui::TableSetupColumn("名称");
ImGui::TableSetupColumn("延迟 (ms)");
ImGui::TableSetupColumn("连接类型");
ImGui::TableHeadersRow();
{
std::lock_guard<std::mutex> lock(clientMutex);
for (const auto& pair : userMap) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%s", pair.second.name.c_str());
ImGui::TableNextColumn();
ImGui::Text("%d", pair.second.ping);
ImGui::TableNextColumn();
ImGui::Text("%s", pair.second.isRelay ? "中继" : "直连");
}
}
ImGui::EndTable();
}
ImGui::End();
}