我尝试使用SteamNetworkingSockets->ConnectP2P
连接两个对等点,这应该在两个对等点之间建立数据报中继。我的服务器使用CreateListenSocketP2P
,客户端使用ConnectP2P和SteamNetworkingIdentity。问题是客户端无法连接,我不知道原因。我运行服务器,API加载它,可以显示我的流ID,但连接拒绝。
#include <iostream>
#include <steam/steam_api.h>
#include <steam/isteamnetworking.h>
#include <steam/isteamfriends.h>
#include <steam/isteamnetworkingmessages.h>
#include <steam/isteamnetworkingsockets.h>
#include <steam/isteamnetworkingutils.h>
#include <thread>
#include <assert.h>
#define VALID_64_STEAMID 0xFFFFFFFFFFFFFFFF
bool g_bQuit = false;
class Client {
public:
SteamNetworkingIdentity sni;
ISteamNetworkingSockets* m_pInterface;
HSteamNetConnection m_hConnection;
Client() {
memset(&sni, 0, sizeof(SteamNetworkingIdentity));
sni.m_eType = k_ESteamNetworkingIdentityType_SteamID;
sni.SetSteamID64(VALID_64_STEAMID);
if (sni.IsInvalid()) {
printf("invalid id\n");
exit(0);
}
m_pInterface = SteamNetworkingSockets();
SteamNetworkingConfigValue_t opt;
opt.SetPtr(k_ESteamNetworkingConfig_Callback_ConnectionStatusChanged, (void*)SteamNetConnectionStatusChangedCallback);
m_hConnection = m_pInterface->ConnectP2P(sni, 0, 1, &opt);
if (m_hConnection == k_HSteamNetConnection_Invalid) {
printf(":failed to connect\n");
exit(0);
}
}
void Run() {
while (!g_bQuit) {
PollIncomingMessages();
PollConnectionStateChanges();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
void PollIncomingMessages() {
while (!g_bQuit)
{
ISteamNetworkingMessage* pIncomingMsg = nullptr;
int numMsgs = m_pInterface->ReceiveMessagesOnConnection(m_hConnection, &pIncomingMsg, 1);
if (numMsgs == 0)
break;
if (numMsgs < 0) {
printf("Fatal error on incoming messages\n");
exit(0);
}
printf("message received\n");
// We don't need this anymore.
pIncomingMsg->Release();
}
}
void OnSteamNetConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t* pInfo)
{
assert(pInfo->m_hConn == m_hConnection || m_hConnection == k_HSteamNetConnection_Invalid);
// What's the state of the connection?
switch (pInfo->m_info.m_eState)
{
case k_ESteamNetworkingConnectionState_None:
// NOTE: We will get callbacks here when we destroy connections. You can ignore these.
break;
case k_ESteamNetworkingConnectionState_ClosedByPeer:
case k_ESteamNetworkingConnectionState_ProblemDetectedLocally:
{
g_bQuit = true;
// Print an appropriate message
if (pInfo->m_eOldState == k_ESteamNetworkingConnectionState_Connecting)
{
// Note: we could distinguish between a timeout, a rejected connection,
// or some other transport problem.
printf("Unable to connect to host", pInfo->m_info.m_szEndDebug);
}
else if (pInfo->m_info.m_eState == k_ESteamNetworkingConnectionState_ProblemDetectedLocally)
{
printf("Lost connection to host", pInfo->m_info.m_szEndDebug);
}
else
{
// NOTE: We could check the reason code for a normal disconnection
printf("The host hath bidden us farewell. (%s)", pInfo->m_info.m_szEndDebug);
}
// Clean up the connection. This is important!
// The connection is "closed" in the network sense, but
// it has not been destroyed. We must close it on our end, too
// to finish up. The reason information do not matter in this case,
// and we cannot linger because it's already closed on the other end,
// so we just pass 0's.
m_pInterface->CloseConnection(pInfo->m_hConn, 0, nullptr, false);
m_hConnection = k_HSteamNetConnection_Invalid;
break;
}
case k_ESteamNetworkingConnectionState_Connecting:
// We will get this callback when we start connecting.
// We can ignore this.
break;
case k_ESteamNetworkingConnectionState_Connected:
printf("Connected to server OK");
break;
default:
// Silences -Wswitch
break;
}
}
static Client* s_pCallbackInstance;
static void SteamNetConnectionStatusChangedCallback(SteamNetConnectionStatusChangedCallback_t* pInfo)
{
s_pCallbackInstance->OnSteamNetConnectionStatusChanged(pInfo);
}
void PollConnectionStateChanges()
{
s_pCallbackInstance = this;
m_pInterface->RunCallbacks();
}
};
Client* Client::s_pCallbackInstance = nullptr;
int main(int argc, const char* argv[]) {
// insert code here...
if (!SteamAPI_Init()) {
printf("Failed to initialize Steamworks SDK\n");
exit(1);
}
// Get local user Steam ID
CSteamID localID = SteamUser()->GetSteamID();
printf("Local user Steam ID: %llu\n", localID.ConvertToUint64());
printf("%s\n", SteamFriends()->GetPersonaName());
ISteamNetworkingUtils* utils;
utils = SteamNetworkingUtils();
utils->InitRelayNetworkAccess();
printf("Running client\n");
//run client
Client c;
c.Run();
SteamAPI_Shutdown();
return 0;
}
它尝试连接,但随后在内部打印printf("Unable to connect to host", pInfo->m_info.m_szEndDebug);
// Print an appropriate message
if (pInfo->m_eOldState == k_ESteamNetworkingConnectionState_Connecting)
{
// Note: we could distinguish between a timeout, a rejected connection,
// or some other transport problem.
printf("Unable to connect to host", pInfo->m_info.m_szEndDebug);
}
我很困惑为什么这会失败,而且蒸汽ID是有效的0xFFFFFFFFFFFF只是一个占位符。
有没有人有使用SteamNetworkingSockets和SteamNetworkingIdentity的经验,可以对点对点连接有所帮助?
1条答案
按热度按时间b09cbbtk1#
我看到了两个可能导致代码失败的问题。如何分配SteamID和网络可用性。
我测试了你的代码,虽然我没有提供一个手动的CSteamID,而是使用了SteamFriends来收集两个独立账户之间可用好友的Steam ID,并且连接通过了。即使
sni.IsInvalid()
返回false,我也假设Steam的后端有一些安全措施来防止两个不知名的账户通信。还有一件事要注意,我不确定你使用的是哪个APP_ID。我们正在使用它进行测试,但我猜它是APP_ID 480,它在对等连接匹配方面有一些限制。但我是这样连接客户端和主机的,首先我确定两个对等体是朋友,然后我做了:
需要注意的是,在调用
m_pFriends->GetFriendByIndex
之前,你必须先调用m_pFriends->GetFriendCount(...)
,它们都需要使用位标志,有几个标志可以使用,但是那些请求成为朋友的人和那些你请求成为朋友的人是最常见的。你也可以比较朋友的名字s,而不必查找每个对等体的64位ID。这是通过m_pFriends->GetFriendPersonaName()
完成的。关于蒸汽文档的最后注解:
如果您知道将使用中继网络(例如,因为您预期进行P2P连接),请调用此函数以初始化中继网络。如果不调用此函数,初始化将延迟到您第一次使用需要访问中继网络的功能时,这将延迟第一次访问。
如果前一次尝试失败,你也可以调用这个函数来强制重试。执行任何需要访问中继网络的操作也会触发重试,所以调用这个函数从来都不是严格必要的,但是把它称为程序启动时间可能会很有用,如果预期访问中继网络。请使用GetRelayNetworkStatus或侦听SteamRelayNetworkStatus_t回调来了解初始化何时完成。通常初始化在几秒钟内完成。
这是非常重要的!在您的代码中,您没有检查GetRelayNetworkStatus的结果,而InitRelayNetworkAccess是一个非阻塞函数,可能需要几秒钟才能完成。您可能需要循环,直到您的状态可用。在我的示例中,我只是在线程上休眠了5秒钟,以查看它是否可用。