网络函数,用于在客户端之间建立连接并发送数据,可能的话会穿透 NAT。
注意:此 API 已弃用,且可能会从未来发行的 Steamworks SDK 中移除。 请转而使用
ISteamNetworkingSockets 或
ISteamNetworkingMessages。 请参见
Steam 网络 概览,以获取更多信息。
成员函数
SteamNetworking 的成员函数通过全局访问器函数
SteamNetworking() 调用。
AcceptP2PSessionWithUser
bool AcceptP2PSessionWithUser( CSteamID steamIDRemote );
| 名称 | 类型 | 描述 |
| steamIDRemote | CSteamID | 向我们发送了初始数据包的用户的 Steam ID。 |
这允许游戏指定是否接受传入的数据包。 需要在与远程主机建立真正的连接之前调用,让游戏有机会决定是否原意与远程用户通话。
如果一个您最近并未向其发送数据包的远程用户尝试先向您发送一个数据包,您的游戏会收到
P2PSessionRequest_t 回调。 该回调包含希望向您发送数据包的用户的 Steam ID。 响应回调时,您应该查看是否想与此用户通话(如用户是否与您在同一大厅内),如果您愿意,接受连接;否则,如您不想与此用户通话,只需忽略请求即可。 如该用户继续向您发送数据包,将会定期发起另一个
P2PSessionRequest_t 回调。 如您已对该用户调用了
SendP2PPacket,这会隐式接受会话请求。
注意,此函数只应在响应
P2PSessionRequest_t 回调时才能调用!
返回: bool
true, 表示成功;只有在
steamIDRemote 无效时为
false。
AllowP2PPacketRelay
bool AllowP2PPacketRelay( bool bAllow );
如果无法建立直接连接或 NAT 穿透,允许或禁止 P2P 连接回退到通过 Steam 服务器进行中继。
此函数只适用于设置此值后创建的连接,或在设置此值后需要自动重新连接的现有连接。
默认允许 P2P 数据包中继。
返回: bool
此函数将始终返回
true。
CloseP2PChannelWithUser
bool CloseP2PChannelWithUser( CSteamID steamIDRemote, int nChannel );
| 名称 | 类型 | 描述 |
| steamIDRemote | CSteamID | 要关闭与其连接的用户的 Steam ID。 |
| nChannel | int | 要关闭的通道。 |
在特定通道结束与用户的通话后,关闭该 P2P 通道。
关闭通向某个用户的所有通道后,与该用户当前打开的会话也会关闭,而来自该用户的新数据会触发新的
P2PSessionRequest_t 回调。
返回: bool
true; 表示通道成功关闭。否则,如果与该用户没有正在进行中的会话或通道,返回
false。
CloseP2PSessionWithUser
bool CloseP2PSessionWithUser( CSteamID steamIDRemote );
| 名称 | 类型 | 描述 |
| steamIDRemote | CSteamID | 要关闭与其连接的用户的 Steam ID。 |
应在结束与用户通信后调用此函数,可以释放后台所有分配给连接的资源。
如果远程用户再次尝试向您发送数据,将会发布新的
P2PSessionRequest_t 回调。
返回: bool
true; 表示会话成功关闭;否则,如果没有与
steamIDRemote 的连接,则返回
false。
CreateConnectionSocket
SNetSocket_t CreateConnectionSocket( uint32 nIP, uint16 nPort, int nTimeoutSec );
创建套接字,开始与远程目标进行连接。
这是基于伯克利套接字(Berkeley TCP socket)模型设计的一套旧版函数集中的一部分。 您应优先使用 P2P 函数,因为此类函数更可靠,而旧的函数最终会被移除。
返回: SNetSocket_tCreateListenSocket
SNetListenSocket_t CreateListenSocket( int nVirtualP2PPort, uint32 nIP, uint16 nPort, bool bAllowUseOfPacketRelay );
| 名称 | 类型 | 描述 |
| nVirtualP2PPort | int | |
| nIP | uint32 | |
| nPort | uint16 | |
| bAllowUseOfPacketRelay | bool | |
创建套接字,并侦听其他连接。
另一个客户端进行连接时,会触发
SocketStatusCallback_t 回调。
如果您有多个端口,nVirtualP2PPort 是客户端将连接至的唯一 ID。
它通常可以是 0,除非您想要多组连接。
unIP 是要绑定至的本地 IP 地址。
如果您只是想要默认的本地 IP,那么请传入 0。
unPort 是要使用的端口。
如果您不希望用户能够通过 IP/端口进行连接,但希望始终仅使用点对点连接,则传入 0。
这是基于伯克利套接字(Berkeley TCP socket)模型设计的一套旧版函数集中的一部分。 您应优先使用 P2P 函数,因为此类函数更可靠,而旧的函数最终会被移除。
返回: SNetListenSocket_tCreateP2PConnectionSocket
SNetSocket_t CreateP2PConnectionSocket( CSteamID steamIDTarget, int nVirtualPort, int nTimeoutSec, bool bAllowUseOfPacketRelay );
| 名称 | 类型 | 描述 |
| steamIDTarget | CSteamID | |
| nVirtualPort | int | |
| nTimeoutSec | int | |
| bAllowUseOfPacketRelay | bool | |
创建套接字,开始与远程目标进行连接。
可以通过已知的 Steam ID 连接(可以是客户端或游戏服务器),也可以直接连接至一个 IP 地址。
成功时将会触发 SocketStatusCallback_t 回调。
失败或超时的话则会触发 SocketStatusCallback_t 回调,且会通过 m_eSNetSocketState 提供失败代码。
这是基于伯克利套接字(Berkeley TCP socket)模型设计的一套旧版函数集中的一部分。您应优先使用 P2P 函数,因为此类函数更可靠,而旧的函数最终会被移除。
返回: SNetSocket_tDestroyListenSocket
bool DestroyListenSocket( SNetListenSocket_t hSocket, bool bNotifyRemoteEnd );
销毁侦听套接字将自动终止从该套接字生成的所有常规套接字。
这是基于伯克利套接字(Berkeley TCP socket)模型设计的一套旧版函数集中的一部分。 您应优先使用 P2P 函数,因为此类函数更可靠,而旧的函数最终会被移除。
返回: bool
DestroySocket
bool DestroySocket( SNetSocket_t hSocket, bool bNotifyRemoteEnd );
如果有与套接字的连接,断开此连接,并使句柄失效。
套接字上任何未读数据都会被丢弃。
如果设置了 bNotifyRemoteEnd,那么在远端确认断开连接前,不会完全销毁套接字。
这是基于伯克利套接字(Berkeley TCP socket)模型设计的一套旧版函数集中的一部分。您应优先使用 P2P 函数,因为此类函数更可靠,而旧的函数最终会被移除。
返回: bool
GetListenSocketInfo
bool GetListenSocketInfo( SNetListenSocket_t hListenSocket, uint32 *pnIP, uint16 *pnPort );
返回侦听套接字绑定至的本地端口。
如果套接字设置为只侦听 P2P 连接,则 *pnIP 与 *pnPort 将为 0。
这是基于伯克利套接字(Berkeley TCP socket)模型设计的一套旧版函数集中的一部分。 您应优先使用 P2P 函数,因为此类函数更可靠,而旧的函数最终会被移除。
返回: bool
GetMaxPacketSize
int GetMaxPacketSize( SNetSocket_t hSocket );
获取数据包最大字节量。
这是基于伯克利套接字(Berkeley TCP socket)模型设计的一套旧版函数集中的一部分。您应优先使用 P2P 函数,因为此类函数更可靠,而旧的函数最终会被移除。
返回: int
GetP2PSessionState
bool GetP2PSessionState( CSteamID steamIDRemote, P2PSessionState_t *pConnectionState );
在
P2PSessionState_t 结构体中填入有关连接的详细信息,如是否有使用中的连接;连接中排入队列里的字节数量;最后一个错误代码(如有);是否在使用中继服务器;远程用户的 IP 和端口(如已知)。
此函数应只用于调试。
返回: bool
true, 表示
pConnectionState 已填写;如果与指定用户无打开的会话,则返回
false。
示例:P2PSessionState_t p2pSessionState;
SteamNetworking()->GetP2PSessionState( steamIDremote, &p2pSessionState );
GetSocketConnectionType
ESNetSocketConnectionType GetSocketConnectionType( SNetSocket_t hSocket );
返回 true 以描述套接字最终如何连接。
这是基于伯克利套接字(Berkeley TCP socket)模型设计的一套旧版函数集中的一部分。 您应优先使用 P2P 函数,因为此类函数更可靠,而旧的函数最终会被移除。
返回: ESNetSocketConnectionTypeGetSocketInfo
bool GetSocketInfo( SNetSocket_t hSocket, CSteamID *pSteamIDRemote, int *peSocketStatus, uint32 *punIPRemote, uint16 *punPortRemote );
返回指定套接字的信息,填入指针的内容。
这是基于伯克利套接字(Berkeley TCP socket)模型设计的一套旧版函数集中的一部分。您应优先使用 P2P 函数,因为此类函数更可靠,而旧的函数最终会被移除。
返回: bool
IsDataAvailable
bool IsDataAvailable( SNetListenSocket_t hListenSocket, uint32 *pcubMsgSize, SNetSocket_t *phSocket );
检查与此侦听套接字连接的任何套接字中是否有数据。
如果没有剩余数据,返回 false。
在 *pcubMsgSize 中填入下一条消息的字节大小。
在 *phSocket 中填入含有数据的套接字。
这是基于伯克利套接字(Berkeley TCP socket)模型设计的一套旧版函数集中的一部分。 您应优先使用 P2P 函数,因为此类函数更可靠,而旧的函数最终会被移除。
返回: bool
IsDataAvailableOnSocket
bool IsDataAvailableOnSocket( SNetSocket_t hSocket, uint32 *pcubMsgSize );
如果没有剩余数据,返回 false。
在 *pcubMsgSize 填入下一条消息的字节大小。
这是基于伯克利套接字(Berkeley TCP socket)模型设计的一套旧版函数集中的一部分。您应优先使用 P2P 函数,因为此类函数更可靠,而旧的函数最终会被移除。
返回: bool
IsP2PPacketAvailable
bool IsP2PPacketAvailable( uint32 *pcubMsgSize, int nChannel = 0 );
| 名称 | 类型 | 描述 |
| pcubMsgSize | uint32 * | 返回数据包的大小。 |
| nChannel | int | 要检查其中是否有数据包可用的通道。 |
检查是否有 P2P 数据包可读,如有,获取消息大小。
应在您使用的每个通道中循环调用。 如有数据包可用,您应调用
ReadP2PPacket 获取数据包数据。
返回: bool
true, 表示数据包可用;否则,返回
false。
ReadP2PPacket
bool ReadP2PPacket( void *pubDest, uint32 cubDest, uint32 *pcubMsgSize, CSteamID *psteamIDRemote, int nChannel = 0 );
| 名称 | 类型 | 描述 |
| pubDest | void * | 以复制至此缓冲区的方式返回数据包数据。 |
| cubDest | uint32 | 分配给 pubDest 的大小。 应与 IsP2PPacketAvailable 返回的大小或您最大数据包的大小相同。 |
| pcubMsgSize | uint32 * | 返回数据包的大小。 |
| psteamIDRemote | CSteamID * | 返回发送此数据包的用户的 Steam ID。 |
| nChannel | int | 发送数据包的通道。 |
在另一位用户通过
SendP2PPacket 发送的数据包中进行读取操作。
如果
cubDest 缓冲区过小,无法容纳该数据包,则消息会截断。
该调用是非阻塞性的,如无数据可用,会返回 false。
在调用此函数前,您应调用
IsP2PPacketAvailable。
返回: bool
true, 表示成功读取数据包;如无数据包可用,则返回
false。
示例:uint32 msgSize = 0;
while ( SteamNetworking()->IsP2PPacketAvailable( &msgSize ) )
{
void *packet = malloc( msgSize );
CSteamID steamIDRemote;
uint32 bytesRead = 0;
if ( SteamNetworking()->ReadP2PPacket( packet, msgSize, &bytesRead, &steamIDRemote ) )
{
// 此处为消息发送代码
}
free( packet );
}
RetrieveData
bool RetrieveData( SNetListenSocket_t hListenSocket, void *pubDest, uint32 cubDest, uint32 *pcubMsgSize, SNetSocket_t *phSocket );
从与此侦听套接字连接的任何套接字中检索数据。
在 pubDest 中填入消息内容。
消息一直保持完整,且保持发送时的大小(也即以打包而非流式传输形式传送)。
如果 *pcubMsgSize < cubDest,则只写入部分数据。
如果无数据可用,返回 false。
在 *phSocket 中填入含有数据的套接字。
这是基于伯克利套接字(Berkeley TCP socket)模型设计的一套旧版函数集中的一部分。 您应优先使用 P2P 函数,因为此类函数更可靠,而旧的函数最终会被移除。
返回: bool
RetrieveDataFromSocket
bool RetrieveDataFromSocket( SNetSocket_t hSocket, void *pubDest, uint32 cubDest, uint32 *pcubMsgSize );
在 pubDest 中填入消息内容。
消息一直保持完整,且保持发送时的大小(也即以打包而非流式传输形式传送)。
如果 *pcubMsgSize < cubDest,则只写入部分数据。
如果无数据可用,返回 false。
这是基于伯克利套接字(Berkeley TCP socket)模型设计的一套旧版函数集中的一部分。您应优先使用 P2P 函数,因为此类函数更可靠,而旧的函数最终会被移除。
返回: bool
SendDataOnSocket
bool SendDataOnSocket( SNetSocket_t hSocket, void *pubData, uint32 cubData, bool bReliable );
发送数据。
必须是已连接的套接字的句柄。
数据全部通过 UDP 发送,因此发送大小限制为 1200 字节;超过这一限制后,许多路由器将开始丢弃数据包。
应谨慎使用可靠标志。尽管重发率相当高,
但依旧可能在接收数据时出现迟滞(类似于 TCP)。
返回: bool
SendP2PPacket
bool SendP2PPacket( CSteamID steamIDRemote, const void *pubData, uint32 cubData, EP2PSend eP2PSendType, int nChannel = 0 );
| 名称 | 类型 | 描述 |
| steamIDRemote | CSteamID | 要向其发送数据包的目标用户。 |
| pubData | const void * | 供数据包数据发送的原始字节数组。 此数据包最大大小由 eP2PSendType 定义。 |
| cubData | uint32 | pubData 的字节大小。 |
| eP2PSendType | EP2PSend | 指定您希望数据传输的方式,如可靠、不可靠、缓冲,等等。 |
| nChannel | int | 充当发送此数据包的虚拟端口的通道,允许您将消息经路由发送到不同的系统。 为了在另一端获取数据,需要在另一端用同一频道号调用ReadP2PPacket。 使用不同频道与同一用户通话仍旧会使用同一基础 P2P 连接,以节省资源。 如果使用主频道,或者不使用此功能,则将值设为 0。 |
给指定用户发送 P2P 数据包。
此 API 不产生会话,而是自动建立 NAT 穿透或 Steam 中继服务器连接。
注意: 在运行 NAT 穿透代码时,第一个数据包发送可能会延迟。
参见
EP2PSend ,了解发送数据包的不同方法。
您所发送的数据为任意类型,您可使用现成可用的系统,如
Protocol Buffers 或
Cap'n Proto,对数据包进行高效编码,或者您也可以创建自己的消息传送系统。
返回: bool
触发
P2PSessionRequest_t 回调。
true, 表示数据包发送成功。
请注意这并不意味着数据包已成功接收。如果超时 20 秒后用户仍无法收到数据包,会通过
P2PSessionConnectFail_t 回调发送错误提示。
false, 则表示出现以下情况之一:
- 数据包对于发送类型而言过大。
- 目标 Steam ID 无效。
- 排入队列等待发送的字节过多。
回调
以下是可以通过调用
SteamAPI_RunCallbacks 触发的回调。 其中许多回调会因为响应
ISteamNetworking 的成员函数而直接触发。
P2PSessionConnectFail_t
当数据包无法送至指定用户时调用。
此时队列中所有未发送的数据包将会被丢弃,如果继续尝试发送,则会试图重新建立连接(但如果再次失败,将会丢弃数据包)。
P2PSessionRequest_t
用户希望通过
SendP2PPacket 与我们在 P2P 通道通信。 响应时,如果您希望打开与用户之间的网络通道,需要调用
AcceptP2PSessionWithUser。
| 名称 | 类型 | 描述 |
| m_steamIDRemote | CSteamID | 希望与我们开始 P2P 会话的用户。 |
关联函数: SendP2PPacketSocketStatusCallback_t
套接字状态发生改变时调用,作为
CreateListenSocket 及
CreateP2PConnectionSocket 调用的一部分。
这是基于伯克利套接字(Berkeley TCP socket)模型设计的一套旧版函数集中的一部分。 您应优先使用 P2P 函数,因为此类函数更可靠,而旧的函数最终会被移除。
| 名称 | 类型 | 描述 |
| m_hSocket | SNetSocket_t | 用以与远程主机收发数据的套接字。 |
| m_hListenSocket | SNetListenSocket_t | 这是我们当时正在侦听的服务器套接字;如果为传出的连接则为 NULL。 |
| m_steamIDRemote | CSteamID | 这是我们已连接至的远程 Steam ID(若有) |
| m_eSNetSocketState | int | 套接字状态, ESNetSocketState |
结构体
以下为 ISteamNetworking 中的函数可能会返回和/或与之互动的结构体。
P2PSessionState_t
与指定用户的连接状态,由
GetP2PSessionState 返回。 此为后台信息,说明前一次调用
SendP2PPacket 发生的情况。 此函数通常不用于调试之外的目的。
| 名称 | 类型 | 描述 |
| m_bConnectionActive | uint8 | 我们与用户是否有开启中的活跃连接?(是为 true,否为 false。) |
| m_bConnecting | uint8 | 我们是否正尝试与用户建立连接?(是为 true,否为 false。) |
| m_eP2PSessionError | uint8 | 套接字上记录的最后错误。 会返回 EP2PSessionError。 |
| m_bUsingRelay | uint8 | 是通过 Steam 中继服务器进行连接吗?(是为 true,否为 false。) |
| m_nBytesQueuedForSend | int32 | 排入队列待向用户发送的字节数量。 |
| m_nPacketsQueuedForSend | int32 | 排入队列待向用户发送的数据包数量。 |
| m_nRemoteIP | uint32 | 若设置,为远程主机的 IP。 可以是 Steam 中继服务器。 仅用于与旧版验证 API 兼容。 |
| m_nRemotePort | uint16 | 若设置,为远程主机的端口。 可以是 Steam 中继服务器。 仅用于与旧版验证 API 兼容。 |
枚举
以下是经过定义来与 ISteamNetworking 一起使用的枚举。
EP2PSend
指定
SendP2PPacket 的发送类型。
通常而言,对于 UDP 式的数据包,您需要
k_EP2PSendUnreliable,而对于 TCP 式的数据包,您需要
k_EP2PSendReliable。
| 名称 | 值 | 描述 |
| k_EP2PSendUnreliable | 0 | 基础 UDP 发送。 数据包不能大于 1200 字节(MTU 的通常大小)。 可能会丢包,或乱序送达(但很少见)。 发送 API 确实对基础连接有一定了解,因此如果没有完成 NAT 穿透或已经识别到一个在连接上发生的调整,数据包将会被批处理,直至连接再次打开。 |
| k_EP2PSendUnreliableNoDelay | 1 | 同上,但如果基础 P2P 连接仍未建立,数据包会被丢弃。 如果将该类型用于发送给远程主机的第一个数据包上,几乎可以肯定数据包会丢失。 该类型仅对不应缓冲的数据(如语音负载数据包)有用。 |
| k_EP2PSendReliable | 2 | 可靠的消息发送。 最多可以在一条消息中发送 1 MB 数据。 可在后台对消息进行分片和重组,还可用滑动窗口高效发送大型数据块。 |
| k_EP2PSendReliableWithBuffering | 3 | 和上面一项一样,不过会对发送应用 Nagle 算法——发送任务将累积,直到达到当前的 MTU 大小(通常为 1200 字节左右,不过可能会改变),或是约 200ms 后为止(Nagle 算法)。 如果您想发送一系列较小的消息,但已将这些消息合并为单一的数据包,那么此选项会很有用。 由于可靠数据流全是有序的,您可以用 k_EP2PSendReliableWithBuffering 进行若干短小消息发送,然后使用常规的 k_EP2PSendReliable 来强制发送所有已缓冲的数据。 |
EP2PSessionError
SendP2PPacket 返回的可能的错误列表,将在
P2PSessionConnectFail_t 回调中发送。
| 名称 | 值 | 描述 |
| k_EP2PSessionErrorNone | 0 | 无错误。 |
| k_EP2PSessionErrorNotRunningApp | 1 | 目标用户并未运行相同游戏。 |
| k_EP2PSessionErrorNoRightsToApp | 2 | 本地用户不拥有正在运行的应用。 |
| k_EP2PSessionErrorDestinationNotLoggedIn | 3 | 目标用户未与 Steam 连接。 |
| k_EP2PSessionErrorTimeout | 4 | 连接超时,原因是目标用户未响应,也许他们未调用 AcceptP2PSessionWithUser。 企业防火墙也可将连接屏蔽(NAT 穿透并非防火墙穿透),请确保 UDP 端口 3478、4379 及 4380 在出站方向开放。 |
| k_EP2PSessionErrorMax | 5 | 未使用。 |
ESNetSocketConnectionType
描述套接字当前如何连接。 仅由旧版网络 API 使用。
| 名称 | 值 | 描述 |
| k_ESNetSocketConnectionTypeNotConnected | 0 | |
| k_ESNetSocketConnectionTypeUDP | 1 | |
| k_ESNetSocketConnectionTypeUDPRelay | 2 | |
ESNetSocketState
连接进程指示器,由
CreateP2PConnectionSocket 使用。
| 名称 | 值 | 描述 |
| k_ESNetSocketStateInvalid | 0 | |
| k_ESNetSocketStateConnected | 1 | 通信有效。 |
| k_ESNetSocketStateInitiated | 10 | 建立连接时的状态。 连接状态机已启动 |
| k_ESNetSocketStateLocalCandidatesFound | 11 | p2p 连接 我们找到了本地 IP 信息 |
| k_ESNetSocketStateReceivedRemoteCandidates | 12 | 已通过 Steam 后端接收到远程机器的 IP 信息。 |
| k_ESNetSocketStateChallengeHandshake | 15 | 直接连接 已从服务器接收到质询数据包。 |
| k_ESNetSocketStateDisconnecting | 21 | 失败状态 API 将连接关闭,我们正在告知另一端。 |
| k_ESNetSocketStateLocalDisconnect | 22 | API 已将连接关闭,我们已完成关闭。 |
| k_ESNetSocketStateTimeoutDuringConnect | 23 | 在尝试创建连接时超时。 |
| k_ESNetSocketStateRemoteEndDisconnected | 24 | 远端已断开与我们的连接。 |
| k_ESNetSocketStateConnectionBroken | 25 | 连接已断开。另一端已消失或本地网络连接断开。 |
Typedefs
以下是经过定义来与 ISteamNetworking 一起使用的 typedef。
| 名称 | 基类型 | 描述 |
| SNetListenSocket_t | uint32 | CreateListenSocket() |
| SNetSocket_t | uint32 | 套接字句柄 CreateP2PConnectionSocket() |
常量
以下是经过定义与 ISteamNetworking 一起使用的常量。
| 名称 | 类型 | 值 | 描述 |
| STEAMNETWORKING_INTERFACE_VERSION | const char * | "SteamNetworking005" | |