增强P2P连接的可靠性,添加用户信息管理和连接重试机制
This commit is contained in:
@@ -35,6 +35,13 @@ ISteamNetworkingSockets* m_pInterface = nullptr;
|
|||||||
bool forwarding = false;
|
bool forwarding = false;
|
||||||
std::unique_ptr<TCPServer> server;
|
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
|
// New variables for multiple connections and TCP clients
|
||||||
std::vector<HSteamNetConnection> connections;
|
std::vector<HSteamNetConnection> connections;
|
||||||
std::map<HSteamNetConnection, TCPClient*> clientMap;
|
std::map<HSteamNetConnection, TCPClient*> clientMap;
|
||||||
@@ -43,11 +50,23 @@ int localPort = 0;
|
|||||||
bool g_isHost = false;
|
bool g_isHost = false;
|
||||||
bool g_isClient = 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
|
// Callback function for connection status changes
|
||||||
void OnSteamNetConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t *pInfo)
|
void OnSteamNetConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t *pInfo)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(clientMutex);
|
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)
|
if (pInfo->m_eOldState == k_ESteamNetworkingConnectionState_None && pInfo->m_info.m_eState == k_ESteamNetworkingConnectionState_Connecting)
|
||||||
{
|
{
|
||||||
// Incoming connection, accept it
|
// Incoming connection, accept it
|
||||||
@@ -55,7 +74,19 @@ void OnSteamNetConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t
|
|||||||
connections.push_back(pInfo->m_hConn);
|
connections.push_back(pInfo->m_hConn);
|
||||||
g_hConnection = pInfo->m_hConn; // Keep for backward compatibility if needed
|
g_hConnection = pInfo->m_hConn; // Keep for backward compatibility if needed
|
||||||
g_isConnected = true;
|
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
|
// 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)
|
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
|
// Client connected successfully
|
||||||
g_isConnected = true;
|
g_isConnected = true;
|
||||||
std::cout << "Connected to host" << std::endl;
|
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)
|
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;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Remove from userMap
|
||||||
|
userMap.erase(pInfo->m_hConn);
|
||||||
// Cleanup TCP Client
|
// Cleanup TCP Client
|
||||||
if (clientMap.count(pInfo->m_hConn)) {
|
if (clientMap.count(pInfo->m_hConn)) {
|
||||||
clientMap[pInfo->m_hConn]->disconnect();
|
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 << "Cleaned up TCP Client for connection" << std::endl;
|
||||||
}
|
}
|
||||||
std::cout << "Connection closed" << 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;
|
CSteamID hostSteamID = pCallback->m_steamIDFriend;
|
||||||
if (!g_isHost && !g_isConnected) {
|
if (!g_isHost && !g_isConnected) {
|
||||||
g_isClient = true;
|
g_isClient = true;
|
||||||
|
g_hostSteamID = hostSteamID;
|
||||||
|
g_retryCount = 0;
|
||||||
|
g_currentVirtualPort = 0;
|
||||||
SteamNetworkingIdentity identity;
|
SteamNetworkingIdentity identity;
|
||||||
identity.SetSteamID(hostSteamID);
|
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) {
|
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
|
// Start TCP Server
|
||||||
server = std::make_unique<TCPServer>(8888);
|
server = std::make_unique<TCPServer>(8888);
|
||||||
if (!server->start()) {
|
if (!server->start()) {
|
||||||
@@ -125,6 +188,10 @@ int main() {
|
|||||||
|
|
||||||
m_pInterface = SteamNetworkingSockets();
|
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
|
// Initialize GLFW
|
||||||
if (!glfwInit()) {
|
if (!glfwInit()) {
|
||||||
std::cerr << "Failed to initialize GLFW" << std::endl;
|
std::cerr << "Failed to initialize GLFW" << std::endl;
|
||||||
@@ -187,6 +254,21 @@ int main() {
|
|||||||
// Poll networking
|
// Poll networking
|
||||||
m_pInterface->RunCallbacks();
|
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
|
// Receive messages from Steam and forward to TCP server
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(clientMutex);
|
std::lock_guard<std::mutex> lock(clientMutex);
|
||||||
@@ -241,11 +323,14 @@ int main() {
|
|||||||
hListenSock = m_pInterface->CreateListenSocketP2P(0, 0, nullptr);
|
hListenSock = m_pInterface->CreateListenSocketP2P(0, 0, nullptr);
|
||||||
if (hListenSock != k_HSteamListenSocket_Invalid) {
|
if (hListenSock != k_HSteamListenSocket_Invalid) {
|
||||||
g_isHost = true;
|
g_isHost = true;
|
||||||
|
std::cout << "Created listen socket for hosting game room" << std::endl;
|
||||||
// Set Rich Presence
|
// Set Rich Presence
|
||||||
std::string connectStr = std::to_string(SteamUser()->GetSteamID().ConvertToUint64());
|
std::string connectStr = std::to_string(SteamUser()->GetSteamID().ConvertToUint64());
|
||||||
SteamFriends()->SetRichPresence("connect", connectStr.c_str());
|
SteamFriends()->SetRichPresence("connect", connectStr.c_str());
|
||||||
SteamFriends()->SetRichPresence("status", "主持游戏房间");
|
SteamFriends()->SetRichPresence("status", "主持游戏房间");
|
||||||
std::cout << "Hosting game room. Connection string: " << connectStr << std::endl;
|
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));
|
ImGui::InputText("主机Steam ID", joinBuffer, IM_ARRAYSIZE(joinBuffer));
|
||||||
@@ -253,11 +338,15 @@ int main() {
|
|||||||
uint64 hostID = std::stoull(joinBuffer);
|
uint64 hostID = std::stoull(joinBuffer);
|
||||||
CSteamID hostSteamID(hostID);
|
CSteamID hostSteamID(hostID);
|
||||||
g_isClient = true;
|
g_isClient = true;
|
||||||
|
g_hostSteamID = hostSteamID;
|
||||||
|
g_retryCount = 0;
|
||||||
|
g_currentVirtualPort = 0;
|
||||||
// Connect to host
|
// Connect to host
|
||||||
SteamNetworkingIdentity identity;
|
SteamNetworkingIdentity identity;
|
||||||
identity.SetSteamID(hostSteamID);
|
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) {
|
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
|
// Connection initiated, wait for callback to confirm
|
||||||
std::cout << "Connecting to host..." << std::endl;
|
std::cout << "Connecting to host..." << std::endl;
|
||||||
// Start TCP Server
|
// Start TCP Server
|
||||||
@@ -305,6 +394,27 @@ int main() {
|
|||||||
ImGui::Text("连接的好友: %d", (int)connections.size());
|
ImGui::Text("连接的好友: %d", (int)connections.size());
|
||||||
ImGui::Text("活跃的TCP客户端: %d", (int)clientMap.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();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user