Documentazione di Steamworks
Interfaccia ISteamNetworkingSockets
API di rete simile ai socket Berkeley, ma destinata ai giochi.

  • È un'API orientata alla connessione (come TCP, non UDP). Durante l'invio e la ricezione dei messaggi, il peer viene identificato utilizzando un handle di connessione.
  • A differenza di TCP, è orientata ai messaggi, non allo stream (i limiti tra i messaggi sono mantenuti dall'API).
  • Sono supportati sia i messaggi attendibili sia quelli non attendibili.
  • I messaggi più grandi sono suddivisi in più pacchetti, mentre i messaggi più piccoli sono combinati in meno pacchetti.
  • Una robusta strategia ACK/di riassemblaggio/di ritrasmissione.
  • Crittografia e autenticazione avanzate. Quando un giocatore si collega, hai la certezza che, se un determinato ID di Steam viene autenticato, chiunque abbia accesso a quell'account personale abbia autorizzato la connessione. L'intercettazione e la manomissione necessitano di intrusione nel processo protetto da VAC, mentre la personificazione necessita dell'accesso al computer del bersaglio.
  • Supporta le connessioni inoltrate attraverso la rete di Valve. Ciò impedisce il rilevamento degli indirizzi IP e protegge giocatori e server di gioco dagli attacchi.
  • Supporta anche la connettività standard su UDP semplice utilizzando IPv4 o IPv6.

Documentazione correlata:
  • Rete di Steam: panoramica sulle diverse API di rete.
  • ISteamNetworkingUtils: utility per misurare il ping e stimare la latenza tra i peer.
  • steamnetworkingtypes: vari tipi e utility.
  • Steam Datagram Relay: un servizio che trasmette il traffico di gioco sulla backbone di Valve. Impedisce il rilevamento degli indirizzi IP e in molti casi migliora i tempi di ping e la qualità di connessione.
  • ISteamNetworkingMessages è un'interfaccia in stile UDP. Invece di stabilire subito una connessione, è possibile inviare e ricevere messaggi specificando il peer di destinazione per ogni chiamata di invio. Le prestazioni rimangono invariate poiché vengono ancora usate le stesse connessioni, ma i processi di creazione e timeout di inattività delle connessioni avvengono in modo automatico. Inoltre, il tuo livello di controllo sulla connessione sarà limitato e non riceverai così tante informazioni sul suo stato.

Su github è disponibile una versione open source di questa API. Puoi utilizzarla per qualsiasi scopo. Per utilizzare la rete di Valve devi essere un partner di Steam e usare la versione presente nell'SDK di Steamworks.

Le funzioni membro per ISteamNetworkingSockets vengono chiamate dalla funzione di accesso globale SteamNetworkingSockets().

Gestione delle connessioni

CreateListenSocketIP

HSteamListenSocket CreateListenSocketIP( const SteamNetworkingIPAddr &localAddress, int nOptions, const SteamNetworkingConfigValue_t *pOptions );

Crea un socket del "server" che resta in ascolto dei client a cui collegarsi chiamando ConnectByIPAddress sul normale protocollo UDP (IPv4 o IPv6).

È necessario selezionare una porta locale specifica sulla quale restare in ascolto e impostarla come campo della porta dell'indirizzo locale.

Solitamente si imposta la porzione IP dell'indirizzo su zero, (SteamNetworkingIPAddr::Clear()). Questo significa che non effettuerai alcuna associazione a un'interfaccia locale particolare (corrisponde a INADDR_ANY in codice socket semplice). Inoltre, se possibile, il socket sarà associato in modalità "dual stack", il che significa che può accettare sia i client IPv4 che IPv6. Se desideri veramente associare a un'interfaccia particolare, imposta l'indirizzo locale sull'IP IPv4 o IPv6 appropriato.

Se devi impostare delle opzioni di configurazione iniziali, passale qui. Vedi SteamNetworkingConfigValue_t per ulteriori informazioni sul motivo per cui questa procedura è preferibile all'impostazione delle opzioni "subito" dopo la creazione.

Quando un client tenta di collegarsi, verrà pubblicata una SteamNetConnectionStatusChangedCallback_t. La connessione sarà nello stato k_ESteamNetworkingConnectionState_Connecting.

ConnectByIPAddress

HSteamNetConnection ConnectByIPAddress( const SteamNetworkingIPAddr &address, int nOptions, const SteamNetworkingConfigValue_t *pOptions );

Crea una connessione e inizia a comunicare con un "server" tramite UDP all'indirizzo IPv4 o IPv6 specificato. L'host remoto deve essere in ascolto con una chiamata corrispondente a ISteamnetworkingSockets::CreateListenSocketIP sulla porta specificata.

Sarà attivata una callback SteamNetConnectionStatusChangedCallback_t quando avviamo la connessione e quindi un'altra al timeout o all'avvenuta connessione.

Se l'identità del server non è stata configurata, il suo indirizzo di rete sarà l'unica identità utilizzata. In alternativa, l'host di rete può fornire un'identità specifica per la piattaforma con o senza un certificato valido per autenticare tale identità. Questi dettagli saranno contenuti in SteamNetConnectionStatusChangedCallback_t, spetta all'applicazione decidere se consentire la connessione.

Se devi impostare delle opzioni di configurazione iniziali, passale qui. Vedi SteamNetworkingConfigValue_t per ulteriori informazioni sul motivo per cui questa procedura è preferibile all'impostazione delle opzioni "subito" dopo la creazione.

CreateListenSocketP2P

HSteamListenSocket CreateListenSocketP2P( int nLocalVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions );

Simile a CreateListenSocketIP, ma i client si collegheranno utilizzando ConnectP2P. La connessione sarà trasmessa attraverso la rete di Valve.

nLocalVirtualPor specifica in che modo i client possono collegarsi a questo socket utilizzando ConnectP2P. È molto comune per le applicazioni avere un solo socket di ascolto; in questo caso, usa zero. Se devi aprire più socket di ascolto e i client sono in grado di collegarsi a uno di essi, nLocalVirtualPort deve essere un numero intero basso (<1000) univoco per ogni socket di ascolto creato.

Se stai ascoltando su un server dedicato in un centro dati noto, puoi ascoltare utilizzando questa funzione anziché createHostedDedicatedServerListenSocket, per consentire ai client di connettersi senza ticket. Qualsiasi utente che possiede l'app e ha effettuato l'accesso a Steam potrà tentare di connettersi al tuo server. Inoltre, un tentativo di connessione potrebbe richiedere al client di essere connesso a Steam e questo rappresenterebbe un'altra possibile fonte di errore. Quando vengono utilizzati i ticket, una volta ottenuto il ticket, un client può connettersi al tuo server anche se si è disconnesso da Steam o Steam è offline.

Se procedi in questo modo, probabilmente ti conviene chiamare ISteamNetworkingUtils::InitRelayNetworkAccess quando l'app viene inizializzata.

Se devi impostare delle opzioni di configurazione iniziali, passale qui. Vedi SteamNetworkingConfigValue_t per ulteriori informazioni sul motivo per cui questa procedura è preferibile all'impostazione delle opzioni "subito" dopo la creazione.

ConnectP2P

HSteamNetConnection ConnectP2P( const SteamNetworkingIdentity &identityRemote, int nRemoteVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions );
Inizia la connessione a un peer che viene identificato tramite un identificatore specifico per la piattaforma. Questo usa il servizio di rendezvous predefinito, che dipende dalla piattaforma e dalla configurazione della libreria (ad esempio, su Steam attraversa il back-end di Steam). Il traffico viene inoltrato sulla rete Steam Datagram Relay.

Se procedi in questo modo, probabilmente ti conviene chiamare ISteamNetworkingUtils::InitRelayNetworkAccess quando l'app viene inizializzata.

Se devi impostare delle opzioni di configurazione iniziali, passale qui. Vedi SteamNetworkingConfigValue_t per ulteriori informazioni sul motivo per cui questa procedura è preferibile all'impostazione delle opzioni "subito" dopo la creazione.

AcceptConnection

EResult AcceptConnection( HSteamNetConnection hConn );

Accetta una connessione in arrivo che è stata ricevuta su un socket di ascolto.

Quando viene ricevuto un tentativo di connessione (magari dopo che sono stati scambiati alcuni pacchetti handshake per impedire lo spoofing di base), viene creato un oggetto interfaccia di connessione nello stato k_ESteamNetworkingConnectionState_Connecting e viene pubblicato un SteamNetConnectionStatusChangedCallback_t. A questo punto, l'applicazione DEVE accettare o chiudere la connessione (non può ignorarla). Se la connessione viene accettata, passa nello stato connessa o nello stato di ricerca del percorso, a seconda del tipo di connessione.

A questo punto è necessario intervenire entro un paio di secondi, perché l'accettazione della connessione è ciò che permette di inviare la risposta che segnala al client che è collegato. Se ritardi l'azione, dal punto di vista del client questo corrisponde a una mancata risposta da parte della rete e il client potrebbe interrompere il tentativo di connessione con un timeout. In altre parole, il client non riesce a distinguere tra un ritardo causato da problemi di rete e uno causato dall'applicazione.

Questo significa che, se la tua applicazione non elabora le callback per più di alcuni secondi (ad esempio, mentre sta caricando una mappa), esiste la probabilità che un client tenti di connettersi durante tale intervallo e non ci riesca a causa del timeout.

Se l'applicazione non risponde tempestivamente al tentativo di connessione e non riceviamo più le comunicazioni dal client, il timeout del tentativo di connessione
scadrà localmente, passando la connessione nello stato k_ESteamNetworkingConnectionState_ProblemDetectedLocally. Il client può anche chiudere la connessione prima che venga accettata ed è anche possibile una transizione a k_ESteamNetworkingConnectionState_ClosedByPeer, a seconda dell'esatta sequenza degli eventi.

Restituisce:
  • k_EResultInvalidParam se l'handle non è valido.
  • k_EResultInvalidState se la connessione non è nello stato corretto (ricorda che lo stato della connessione potrebbe cambiare tra il momento in cui la notifica viene pubblicata nella coda e quello in cui viene ricevuta dall'applicazione).

Una nota sulle opzioni di configurazione della connessione. Se hai bisogno di alcune opzioni di configurazione comuni a tutte le connessioni accettate su un socket specifico in ascolto, considera la configurazione delle opzioni sul socket di ascolto, in quanto queste opzioni vengono ereditate automaticamente. Se hai davvero bisogno di impostare opzioni specifiche, puoi impostarle sulla connessione prima di accettarla.

CloseConnection

bool CloseConnection( HSteamNetConnection hPeer, int nReason, const char *pszDebug, bool bEnableLinger );

Si disconnette dall'host remoto e invalida l'handle di connessione. Tutti i dati non letti sulla connessione vengono scartati.

nReason è un codice definito dell'applicazione che sarà ricevuto sull'altro lato e registrato (quando possibile) nell'analisi di back-end. Il valore deve provenire da un intervallo limitato (vedi ESteamNetConnectionEnd). Se non devi comunicare alcuna informazione all'host remoto e non vuoi che l'analisi sia in grado di distinguere tra interruzioni della connessione "normali" ed "eccezionali", puoi passare zero; in questo caso sarà utilizzato il valore generico di k_ESteamNetConnectionEnd_App_Generic.

pszDebug è una stringa diagnostica leggibile dall'utente che sarà ricevuta dall'host remoto e registrata (quando possibile) nell'analisi di back-end.

Facoltativamente, puoi impostare il socket in uno stato di "attesa", che fa in modo che la connessione tenti di recapitare gli eventuali messaggi attendibili in uscita rimanenti prima di chiudere la connessione. In caso contrario, tutti i dati attendibili non inviati vengono scartati. In qualsiasi caso, una volta chiusa la connessione non avrai più visibilità sullo stato della connessione o dei messaggi. In alcuni casi, questo è accettabile. Se non lo è, devi aspettare per chiudere la connessione. Ricorda che si tratta di un protocollo dell'applicazione, non un protocollo del kernel come il TCP. Devi quindi assicurarti che l'applicazione resti in esecuzione abbastanza a lungo da eliminare i dati.

Se la connessione è già terminata (k_ESteamNetworkingConnectionState_ClosedByPeer o k_ESteamNetworkingConnectionState_ProblemDetectedLocally) e stai semplicemente liberando l'oggetto connessione, nReason, pszDebug e bEnableLinger vengono ignorati.

CloseListenSocket

bool CloseListenSocket( HSteamListenSocket hSocket );

Distrugge un socket di ascolto. Tutte le connessioni che sono state accettate sul socket di ascolto vengono chiuse forzatamente.

CreateSocketPair

bool CreateSocketPair( HSteamNetConnection *pOutConnection1, HSteamNetConnection *pOutConnection2, bool bUseNetworkLoopback, const SteamNetworkingIdentity *pIdentity1, const SteamNetworkingIdentity *pIdentity2 );

Crea una coppia di connessioni che comunicano tra loro, ovvero una connessione loopback. Questo è molto utile per i test o per consentire al codice client/server di funzionare anche quando stai eseguendo un "server" locale.

Le due connessioni saranno poste immediatamente in stato collegato e nessuna callback sarà pubblicata immediatamente. A questo punto, se chiudi una delle connessioni, l'altra connessione riceverà una callback, proprio come se stesse comunicando sulla rete. Devi chiudere *entrambi* i lati per liberare completamente le risorse!

Per impostazione predefinita vengono utilizzati i buffer interni, aggirando completamente la rete, la suddivisione dei messaggi in pacchetti, la crittografia, la copia del carico utile, ecc. Questo significa che, per impostazione predefinita, i pacchetti di loopback non simuleranno un ritardo o una perdita. Se passi true per bUseNetworkLoopback farai in modo che la coppia di socket invii i pacchetti tramite il dispositivo di loopback della rete locale (127.0.0.1) sulle porte effimere. In questo caso il ritardo e la perdita di pacchetti fittizi sono supportati e il tempo CPU viene dedicato alla crittografia e alla decodifica.

Se desideri assegnare un'identità specifica a una delle connessioni, puoi passare un'identità particolare. In caso contrario, se passi nullptr la rispettiva connessione assumerà un'identità generica "localhost". Se usi un loopback di rete reale, questo potrebbe essere tradotto nella porta di loopback effettivamente associata. In caso contrario, la porta sarà zero.

Invio e ricevimento di messaggi

SendMessageToConnection

EResult SendMessageToConnection( HSteamNetConnection hConn, const void *pData, uint32 cbData, int nSendFlags );
Invia un messaggio all'host remoto sulla connessione specificata.

nSendFlags determina le garanzie di recapito che saranno fornite, quando i dati devono essere memorizzati nel buffer, ecc. Ad esempio:
  • k_nSteamNetworkingSend_Unreliable
  • k_nSteamNetworkingSend_Reliable
  • k_nSteamNetworkingSend_NoNagle
  • k_nSteamNetworkingSend_NoDelay

Ricorda che la semantica utilizzata per i messaggi non è esattamente uguale alla semantica di un socket di "flusso" standard. (SOCK_STREAM) Per un normale socket di flusso, i limiti tra blocchi non sono considerati rilevanti e le dimensioni dei blocchi di dati scritti non corrisponderanno necessariamente a quelle dei blocchi restituiti dalle letture sull'altro lato. L'host remoto potrebbe leggere un blocco parziale, oppure più blocchi potrebbero essere uniti. Per la semantica dei messaggi qui utilizzata, tuttavia, le dimensioni corrisponderanno. Ogni chiamata di invio corrisponderà a una chiamata di lettura uno-a-uno andata a buon fine sull'host remoto. Se stai convertendo un codice esistente orientato al flusso nella semantica dei messaggi attendibili, il tuo codice dovrebbe funzionare ugualmente, poiché la semantica dei messaggi attendibili è più rigida di quella di flusso. L'unico problema riguarda le prestazioni: mantenere le dimensioni di ogni messaggio comporta un sovraccarico; quindi, se il tuo codice invia molti piccoli blocchi di dati, le prestazioni ne soffriranno. Qualsiasi codice basato sui socket di flusso che non scrive blocchi eccessivamente piccoli funzionerà senza bisogno di modifiche.

pOutMessageNumber è un puntatore opzionale per ricevere il numero di messaggio assegnato al messaggio stesso, se l'invio è avvenuto con successo.

Restituisce:
  • k_EResultInvalidParam: handle di connessione non valido, oppure il singolo messaggio è troppo grande. (Vedi k_cbMaxSteamNetworkingSocketsMessageSizeSend)
  • k_EResultInvalidState: la connessione è in uno stato non valido
  • k_EResultNoConnection: la connessione è terminata
  • k_EResultIgnored: hai utilizzato k_nSteamNetworkingSend_NoDelay e il messaggio è stato eliminato perché non eravamo pronti a inviarlo.
  • k_EResultLimitExceeded: c'erano già troppi dati da inviare in coda. (Vedi k_ESteamNetworkingConfig_SendBufferSize)

SendMessages

void SendMessages( int nMessages, SteamNetworkingMessage_t *const *pMessages, int64 *pOutMessageNumberOrResult );
Invia uno o più messaggi senza copiare il payload del messaggio. Questo è il modo più efficiente di inviare messaggi. Per usare questa funzione devi prima allocare un oggetto messaggio usando ISteamNetworkingUtils::AllocateMessage (non dichiararne uno sullo stack o dovrai allocarne uno).

Dovresti compilare il payload del messaggio. Puoi lasciargli allocare il buffer automaticamente e poi compilare il payload, oppure se hai già un buffer allocato puoi puntare m_pData sul tuo buffer e impostare la callback alla funzione appropriata per liberarlo. Ricorda che se usi il tuo buffer, questo DEVE restare valido fino all'esecuzione della callback. Ricorda inoltre che la tua callback può essere eseguita in qualunque momento da qualsiasi thread (anche prima della restituzione di SendMessager!), quindi DEVE essere rapida e sicura.

Inoltre è OBBLIGATORIO compilare:
  • m_conn - l'handle della connessione a cui inviare il messaggio
  • m_nFlags - maschera di bit dei contrassegni k_nSteamNetworkingSend_xxx.

Tutti gli altri campi sono attualmente riservati e non devono essere modificati.

La libreria assumerà la proprietà delle strutture dei messaggi. Questi possono essere modificati o diventare non validi in qualsiasi momento, quindi non devi leggerli dopo averli passati a questa funzione.

pOutMessageNumberOrResult è una matrice facoltativa che, per ogni messaggio, riceverà il numero che è stato assegnato al messaggio se l'invio è andato a buon fine. Se l'invio non riesce, nella matrice viene inserito un valore EResult negativo. Ad esempio, la matrice conterrà -k_EResultInvalidState se la connessione era in stato non valido. Vedi SendMessageToConnection per i possibili codici di errore.

FlushMessagesOnConnection

EResult FlushMessagesOnConnection( HSteamNetConnection hConn );
Svuota tutti i messaggi in attesa sul timer di Nagle e li invia alla prima opportunità di trasmissione (spesso significa adesso).

Se il Nagle è abilitato (è attivo per impostazione predefinita), chiamando SendMessageToConnection il messaggio verrà memorizzato nel buffer, fino alla scadenza del Nagle prima di essere inviato, per unire i messaggi piccoli nello stesso pacchetto. (Vedi k_ESteamNetworkingConfig_NagleTime)

Restituisce:
  • k_EResultInvalidParam: handle di connessione non valido
  • k_EResultInvalidState: la connessione è in uno stato non valido
  • k_EResultNoConnection: la connessione è terminata
  • k_EResultIgnored: non eravamo (ancora) collegati, quindi questa operazione non ha alcun effetto.

ReceiveMessagesOnConnection

int ReceiveMessagesOnConnection( HSteamNetConnection hConn, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages );
Raccoglie i prossimi messaggi disponibili dalla connessione, se presenti. Restituisce il numero di messaggi restituiti nella tua matrice, fino a nMaxMessages.
Se l'handle di connessione non è valido, restituisce -1. Se non sono disponibili dati, restituisce 0.

L'ordine dei messaggi restituiti nella matrice è irrilevante. I messaggi attendibili saranno ricevuti nello stesso ordine in cui sono stati inviati (e con le stesse dimensioni. Vedi SendMessageToConnection per informazioni su questa sottile differenza da un socket di flusso).

I messaggi non attendibili possono essere eliminati oppure recapitati in ordine sparso l'uno rispetto all'altro o rispetto ai messaggi attendibili.

Se vengono restituiti dei messaggi, DEVI chiamare SteamNetworkingMessage_t::Release() su ciascuno di essi per liberare le risorse quando hai finito. È sicuro mantenere attivo l'oggetto per un po' (metterlo in una coda, ecc.) e puoi chiamare Release() da qualsiasi thread.

Controllo efficiente di molte connessioni


Un gruppo di controllo è un insieme di connessioni che si possono controllare efficacemente. In questa API, "controllare" una connessione significa recuperarne tutti i messaggi in sospeso. Non è disponibile un'API per "controllare" lo stato della connessione, come i socket BSD.

CreatePollGroup

HSteamNetPollGroup CreatePollGroup()
Crea un nuovo gruppo di controllo.

Dovresti eliminare il gruppo di controllo quando hai finito di usare DestroyPollGroup.

DestroyPollGroup

bool DestroyPollGroup( HSteamNetPollGroup hPollGroup )
Elimina un gruppo di controllo creato con CreatePollGroup.

Se sono presenti connessioni nel gruppo di controllo, verranno rimosse dal gruppo e lasciate in uno stato per cui non faranno parte di alcun gruppo di controllo. Restituisce "false" se viene passato un handle per un gruppo di controllo non valido.

SetConnectionPollGroup

bool SetConnectionPollGroup( HSteamNetConnection hConn, HSteamNetPollGroup hPollGroup );

Assegna una connessione a un gruppo di controllo. Tieni presente che la connessione potrebbe appartenere solo a un singolo gruppo di controllo. Aggiungere una connessione a un gruppo di controllo la rimuove implicitamente da ogni altro gruppo di controllo di cui faceva parte.

Puoi passare k_HSteamNetPollGroup_Invalid per rimuovere una connessione dal suo gruppo di controllo attuale senza aggiungerla a uno nuovo.

Se sulla connessione sono presenti messaggi ricevuti in sospeso, sarà effettuato un tentativo di aggiungerli alla coda dei messaggi per il gruppo di controllo nell'ordine approssimativo che sarebbe stato utilizzato se la connessione avesse fatto parte del gruppo di controllo nel momento in cui il messaggio è stato ricevuto.

Restituisce false se l'handle della connessione o del gruppo di controllo non sono validi (e non k_HSteamNetPollGroup_Invalid).

ReceiveMessagesOnPollGroup

int ReceiveMessagesOnPollGroup( HSteamNetPollGroup hPollGroup, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages );

Uguale a ReceiveMessagesOnConnection, ma restituirà i prossimi messaggi disponibili su qualunque connessione del gruppo di controllo. Esamina SteamNetworkingMessage_t::m_conn per conoscere la connessione. (SteamNetworkingMessage_t::m_nConnUserData potrebbe essere di aiuto).

L'ordine di consegna dei messaggi tra diverse connessioni sarà di solito uguale all'ordine in cui è stato ricevuto l'ultimo pacchetto che ha completato il messaggio. Ma non è una vera garanzia, soprattutto per i pacchetti ricevuti non appena una connessione viene assegnata a un gruppo di controllo.

L'ordine di consegna dei messaggi sulla stessa connessione è ben stabilito e sono presenti le stesse garanzie citate in ReceiveMessagesOnConnection. (Ma i messaggi non sono raggruppati per connessione, quindi non appariranno necessariamente in ordine consecutivo nell'elenco; potrebbero essere intercalati con messaggi di altre connessioni.)

Informazioni di connessione

GetConnectionInfo

bool GetConnectionInfo( HSteamNetConnection hConn, SteamNetConnectionInfo_t *pInfo );
Restituisce informazioni di base sullo stato ad alto livello della connessione.
Restituisce false se l'handle di connessione non è valido.

GetConnectionRealTimeStatus

eResult getConnectionRealTimeStatus (HSteamNetConnection HConn, SteamNetConnectionRealTimeStatus_T *pStatus, int nLanes, SteamNetConnectionRealTimeLaneStatus_t *Planes);

Restituisce un piccolo insieme di informazioni sullo stato in tempo reale della connessione e sullo stato della coda per ogni corsia.

pStatus potrebbe essere NULL se non sono le informazioni desiderate. (Ad esempio, ti interessano solo le informazioni sulla corsia.)

Nel campo, nLanes indica la lunghezza della matrice pLanes, che può essere 0 se non si desidera ricevere dati sulla corsia. È consentito che sia inferiore al numero totale di corsie configurate.

pLanes punta a un array che riceverà informazioni specifiche sulla corsia. Può essere NULL se non è necessario.

Valore restituito:
  • k_EResultNoConnection - l'handle di connessione non è valido o la connessione è stata chiusa.
  • k_eResultInvalidParam - nLanes è errato

GetDetailedConnectionStatus

int GetDetailedConnectionStatus( HSteamNetConnection hConn, char *pszBuf, int cbBuf );
Restituisce statistiche di connessione molto dettagliate in formato di testo diagnostico. Utile per salvare un file di dump su un registro, ecc. Il formato di queste informazioni è soggetto a cambiamenti.

Restituisce:
  • -1: errore (handle di connessione non valido)
  • 0: OK, il tuo buffer è stato riempito e '\0'-terminato
  • >0: il tuo buffer era nullptr, oppure era troppo piccolo e il testo è stato troncato. Riprova con un buffer di almeno N byte.

SetConnectionUserData

bool SetConnectionUserData( HSteamNetConnection hPeer, int64 nUserData );

Imposta i dati utente della connessione. I dati vengono utilizzati nelle posizioni seguenti:

È necessario impostarli come atomici quando viene creata la connessione? Vedi k_ESteamNetworkingConfig_ConnectionUserData.

ATTENZIONE: presta *molta attenzione* quando utilizzi il valore fornito nelle strutture di callback. Le callback vengono inserite in una coda e il valore che riceverai nella callback corrisponde ai dati utente validi nel momento in cui la callback è stata inserita nella coda. Possono verificarsi impercettibili situazioni di corsa se
non capisci questo!

Se i messaggi in arrivo per questa connessione sono inseriti nella coda, il campo dei dati utente viene aggiornato, in modo che quando si ricevono messaggi (ad esempio con ReceiveMessagesOnConnection), questi abbiano sempre i dati utente più recenti. Per cui le insidiose situazioni di corsa che possono verificarsi con le callback non si applicano nei casi di recupero dei messaggi.

Restituisce false se l'handle non è valido.

GetConnectionUserData

int64 GetConnectionUserData( HSteamNetConnection hPeer );
Recupera i dati utente della connessione. Restituisce -1 se l'handle non è valido o se non hai impostato alcun dato utente sulla connessione.

SetConnectionName

void SetConnectionName( HSteamNetConnection hPeer, const char *pszName );
Imposta un nome per la connessione, utilizzata prevalentemente per il debugging.

GetConnectionName

bool GetConnectionName( HSteamNetConnection hPeer, char *pszName, int nMaxLen );
Recupera il nome della connessione nel buffer, che è di almeno nMaxLen byte. Restituisce false se l'handle non è valido.

ConfigureConnectionLanes

EResult ConfigureConnectionLanes( HSteamNetConnection hConn, int nNumLanes, const int *pLanePriorities, const uint16 *pLaneWeights );

Configura più flussi di messaggi in uscita ("corsie") su una connessione e controlla i blocchi head-of-line tra di essi. I messaggi all'interno di una determinata corsia vengono sempre inviati in base all'ordine nella coda, ma i messaggi provenienti da corsie diverse potrebbero essere inviati in ordine sparso. Ogni corsia ha una propria sequenza numerica di messaggio. Al primo messaggio inviato su ogni corsia sarà assegnato il numero 1.

Ogni corsia ha una determinata "priorità". Le corsie con priorità inferiore verranno elaborate solo quando tutte le corsie con priorità più alta saranno vuote. Solo l'ordine dei valori di priorità è rilevante, non la grandezza. I valori numerici più alti hanno la priorità su quelli inferiori.

A ciascuna corsia viene inoltre assegnato un peso, che indica quanta larghezza di banda sarà approssimativamente usata da quella corsia rispetto alle altre con la stessa priorità. (Questo presuppone che la corsia resti occupata. Una corsia inattiva non accumula "crediti" da spendere dopo che un messaggio è stato messo in coda). Questo valore va inteso solo come proporzione rispetto ad altre corsie con la stessa priorità. Quanto alle corsie con priorità diverse, prevarrà lo specifico ordine di priorità e la relazione tra i rispettivi pesi non sarà rilevante. Pertanto, se una corsia ha un valore di priorità univoco, il valore del peso per quella corsia non ha importanza.

Esempio: 3 corsie con priorità { 0, 10, 10 } e pesi {(NA), 20, 5}. I messaggi inviati nella prima saranno sempre spediti per primi, prima dei messaggi nelle altre due corsie. Il suo valore di peso è irrilevante, poiché non ci sono altre corsie con priorità pari a 0. La seconda e la terza corsia condivideranno la larghezza di banda, con un rapporto indicativo di 4:1. I pesi { NA, 4, 1 } saranno equivalenti.

Note:
  • Al momento, alcuni codici hanno un costo in termini di prestazioni proporzionale al numero di corsie, per cui mantieni il numero di corsie al minimo. Tre o giù di lì vanno bene, >otto sono troppe. Il numero massimo di corsie su Steam è pari a 255, un numero molto elevato e non consigliato!
  • Il valore di priorità di una corsia può corrispondere a qualunque numero intero. Solo l'ordine conta, non il valore assoluto.
  • I pesi devono avere valori positivi e, a causa dei dettagli di implementazione, sono limitati a valori a 16 bit. Solo le proporzioni contano, non le grandezze in termini assoluti.
  • I messaggi inviati su un indice di corsia diverso da 0 provocano un leggero sovraccarico sulla rete. Di conseguenza, per massimizzare l'efficienza della rete la corsia 0 dovrebbe essere quella "più usata", indipendentemente dalle priorità o dai pesi.
  • Una connessione ha una singola corsia per impostazione predefinita. È corretto chiamare questa funzione con NNumLanes=1, anche se inutile, poiché in tal caso i valori di priorità e di peso sono irrilevanti.
  • Sebbene sia possibile riconfigurare le corsie di connessione in qualunque momento, non è consentito ridurre il numero di corsie.
  • La riconfigurazione delle corsie potrebbe riavviare il bilanciamento della condivisione della larghezza di banda. In genere chiamerai questa funzione una volta verso l'inizio della connessione, eventualmente dopo aver scambiato alcuni messaggi.
  • Per assegnare a tutte le corsie la stessa priorità, puoi usare pLanePriorities=NULL.
  • Se vuoi che tutte le corsie con la stessa priorità condividano equamente la larghezza di banda, o se i valori di priorità sono irrilevanti perché non ci sono due corsie con lo stesso valore di priorità, puoi usare pLaneWeights=NULL.
  • Le priorità e i pesi determinano l'ordine in cui i messaggi vengono INVIATI in rete. NON C'È ALCUNA GARANZIA sull'ordine di RICEZIONE dei messaggi! A causa della perdita dei pacchetti, della consegna fuori ordine e dei piccoli dettagli relativi alla serializzazione dei pacchetti, è comunque possibile che i messaggi vengano ricevuti leggermente fuori ordine! L'*unica* vera garanzia è che i messaggi *affidabili* sulla *stessa corsia* saranno consegnati nell'ordine in cui sono stati spediti.
  • Ogni host configura le corsie in relazione ai pacchetti che invia; le corsie per l'invio in una direzione non hanno alcuna relazione con le corsie nella direzione opposta.

Valore restituito:
  • k_EResultNoConnection - bad hConn
  • k_EResultInvalidParam - Numero di corsie non valido, pesi sbagliati oppure si è provato a ridurre il numero di corsie
  • k_EResultInvalidState - La connessione è già persa, ecc.

Vedi anche:
  • SteamNetworkingMessage_t::m_idxLane

Varie

GetListenSocketAddress

bool GetListenSocketAddress( HSteamListenSocket hSocket, SteamNetworkingIPAddr *address );

Restituisce l'IP locale e la porta alla quale è associato un socket di ascolto creato utilizzando CreateListenSocketIP.

Possono essere restituiti indirizzi IPv6/IPv4 specifici se associ il socket a una particolare interfaccia.
Un indirizzo IPv6 di ::0 significa "qualsiasi IPv4 o IPv6"
.
Un indirizzo IPv6 di ::ffff:0000:0000 significa "qualsiasi IPv4".

NOTA: non è questo il modo per risalire al tuo IP pubblico a cui i client possono connettersi.
Prova con ISteamGameServer::GetPublicIP.

Restituisce false se l'handle non è valido oppure se le informazioni non sono disponibili per quel tipo di socket di ascolto.

GetIdentity

bool GetIdentity( SteamNetworkingIdentity *pIdentity );
Ottiene l'identità assegnata a questa interfaccia.

Ad esempio, su Steam è l'ID di Steam dell'utente; per l'interfaccia del server di gioco è l'ID di Steam assegnato al server di gioco. Restituisce false e imposta il risultato su un'identità non valida se ancora non ne conosciamo l'identità. (Ad esempio, il server di gioco non ha effettuato l'accesso. Su Steam, l'utente conoscerà il proprio ID di Steam anche se non ha effettuato l'accesso a Steam.)

InitAuthentication

ESteamNetworkingAvailability InitAuthentication();

Indica la nostra disponibilità a partecipare alle comunicazioni autenticate. Se non siamo ancora pronti, verranno intraprese delle azioni per ottenere i certificati necessari (compreso un certificato per noi, nonché tutti i certificati CA necessari per autenticare i peer).

Puoi chiamare questa funzione al momento dell'inizializzazione del programma se sai che farai connessioni autenticate, in modo da essere già pronto quando verranno tentate tali connessioni. (Ricorda che, essenzialmente, tutte le connessioni necessitano di autenticazione, ad eccezione delle normali connessioni UDP con l'autenticazione disabilitata utilizzando k_ESteamNetworkingConfig_IP_AllowWithoutAuth.) Se non chiami questa funzione, aspetteremo finché non viene utilizzata una funzionalità che necessita di queste risorse.

Puoi chiamare questa funzione anche per forzare un nuovo tentativo qualora si sia verificato un errore. Quando un tentativo fallisce, non effettueremo automaticamente un nuovo tentativo. Da questo punto di vista, il comportamento del sistema dopo un tentativo fallito è uguale a quello precedente al primo tentativo: la richiesta di una comunicazione autenticata o la chiamata a questa funzione farà in modo che il sistema tenti di acquisire le risorse necessarie.

Puoi utilizzare GetAuthenticationStatus o restare in ascolto di SteamNetAuthenticationStatus_t per monitorare lo stato.

Restituisce il valore corrente che sarebbe stato restituito da GetAuthenticationStatus.

GetAuthenticationStatus

ESteamNetworkingAvailability GetAuthenticationStatus( SteamNetAuthenticationStatus_t *pDetails );

Interroga la nostra disponibilità a partecipare alle comunicazioni autenticate. Una callback SteamNetAuthenticationStatus_t viene pubblicata non appena questo stato cambia, ma puoi usare questa funzione per interrogarla in qualsiasi momento.

Viene restituito il valore di SteamNetAuthenticationStatus_t::m_eAvail. Se vuoi solo questo stato di alto livello, puoi passare NULL per pDetails. Se vuoi maggiori dettagli, passa non-NULL per riceverli.

Server di gioco che utilizzano Steam Datagram Relay

Le funzioni seguenti sono utilizzate quando il server di gioco si trova in un centro dati conosciuto a Valve e il traffico di gioco sta sfruttando la rete Steam Datagram Relay. Per maggiori informazioni, vedi Steam Datagram Relay.

ReceivedRelayAuthTicket

bool ReceivedRelayAuthTicket( const void *pvTicket, int cbTicket, SteamDatagramRelayAuthTicket *pOutParsedTicket );

Effettua questa chiamata quando ricevi un ticket dal tuo sistema back-end/di ricerca delle partite. Inserisce il ticket in una cache persistente e, facoltativamente, restituisce il ticket analizzato.

Per maggiori dettagli, vedi stamdatagram_gamecoordinator.h.

FindRelayAuthTicketForServer

int FindRelayAuthTicketForServer( const SteamNetworkingIdentity &identityGameServer, int nRemoteVirtualPort, SteamDatagramRelayAuthTicket *pOutParsedTicket );

Cerca un ticket nella cache per comunicare con il server sulla porta virtuale specificata. Se lo trova, restituisce il numero di secondi fino alla scadenza del ticket e, facoltativamente, il ticket elaborato completo. Restituisce 0 se non abbiamo alcun ticket.

In genere è utile semplicemente per confermare di avere un ticket, prima di chiamare ConnectToHostedDedicatedServer per collegarsi al server.

ConnectToHostedDedicatedServer

HSteamNetConnection ConnectToHostedDedicatedServer( const SteamNetworkingIdentity &identityTarget, int nRemoteVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions );

Chiamata client per collegarsi a un server ospitato in un centro dati di Valve, sulla porta virtuale specificata. Devi avere inserito nella cache un ticket per questo server, altrimenti questo tentativo di connessione non andrà a buon fine! Se non emetti ticket personalizzati, per connetterti a un server dedicato tramite SDR in modalità ticket automatico usa ConnectP2P. (Il server deve essere configurato per consentire questo tipo di connessione in ascolto utilizzando CreateListenSocketP2P.)

Potresti chiederti perché i ticket vengono memorizzati in una cache invece di essere semplicemente passati qui come argomento. Lo scopo è rendere robusta la riconnessione a un server di gioco, anche se il computer client perde la connessione a Steam o al back-end centrale, oppure se l'applicazione viene riavviata o si arresta, ecc.

Se procedi in questo modo, probabilmente ti conviene chiamare ISteamNetworkingUtils::InitRelayNetworkAccess quando l'app viene inizializzata.

Se devi impostare delle opzioni di configurazione iniziali, passale qui. Vedi SteamNetworkingConfigValue_t per ulteriori informazioni sul motivo per cui questa procedura è preferibile all'impostazione delle opzioni "subito" dopo la creazione.

GetHostedDedicatedServerPort

uint16 GetHostedDedicatedServerPort();
Restituisce il valore della variabile di ambiente SDR_LISTEN_PORT. Questo è il server UDP sul quale il tuo server resterà in ascolto. Viene configurata automaticamente negli ambienti di produzione.

Nell'ambiente di sviluppo dovrai impostarla manualmente. Vedi Steam Datagram Relay per maggiori informazioni su come configurare gli ambienti di sviluppo.

GetHostedDedicatedServerPOPID

SteamNetworkingPOPID GetHostedDedicatedServerPOPID();
Restituisce 0 se SDR_LISTEN_PORT non è impostata. In caso contrario, restituisce il centro dati nel quale è in esecuzione il server. Sarà k_SteamDatagramPOPID_dev in un ambiente non di produzione.

GetHostedDedicatedServerAddress

EResult GetHostedDedicatedServerAddress( SteamDatagramHostedAddress *pRouting );
Restituisce informazioni sul server ospitato. Contiene il PoPID del server e informazioni di instradamento opache che possono essere utilizzate dai relè per inviare il traffico al tuo server.

Dovrai inviare queste informazioni al tuo back-end e inserirle nei ticket, in modo che i relè sappiano come inoltrare il traffico dai client al tuo server. Per maggiori informazioni, vedi SteamDatagramRelayAuthTicket.

Ricorda inoltre che le informazioni di instradamento sono contenute in SteamDatagramGameCoordinatorServerLogin; quindi, se possibile, è preferibile utilizzare SteamNetworkingSockets::GetGameCoordinatorServerLogin per inviare queste informazioni al servizio di coordinazione del gioco e, contemporaneamente, anche per accedere in modo sicuro.

k_EResultOK viene restituito quando un'uscita va a buon fine.

Uscita non riuscita:
  • Viene restituito un valore diverso da k_EResultOK.
  • k_EResultInvalidState: non siamo configurati per restare in ascolto di SDR (SDR_LISTEN_SOCKET non è impostata).
  • k_EResultPending: non abbiamo (ancora) le informazioni di autenticazione necessarie. (Vedi GetAuthenticationStatus.) Se usi variabili di ambiente per pre-recuperare la configurazione di rete, questi dati dovrebbero essere sempre disponibili immediatamente.
  • Un messaggio di debugging diagnostico non localizzato sarà collocato in m_data e descriverà la causa dell'errore.

NOTA: il blob restituito non è crittografato. Invialo al tuo back-end, ma non condividerlo direttamente con i client.

CreateHostedDedicatedServerListenSocket

HSteamListenSocket CreateHostedDedicatedServerListenSocket( int nLocalVirtualPort, int nOptions, const SteamNetworkingConfigValue_t *pOptions );
Crea un socket di ascolto sulla porta virtuale specificata. La porta UDP fisica da utilizzare sarà determinata dalla variabile di ambiente SDR_LISTEN_PORT. Se una porta UDP non è configurata, questa chiamata non andrà a buon fine.

Ricorda che questa chiamata DEVE essere effettuata attraverso l'interfaccia SteamGameServerNetworkingSockets().

Questa funzione deve essere usata quando si utilizza la libreria del generatore di ticket per emettere i propri ticket. I client che si connettono al server su questa porta virtuale avranno bisogno di un ticket e devono connettersi utilizzando ConnectToHostedDedicatedServer.

Se devi impostare delle opzioni di configurazione iniziali, passale qui. Vedi SteamNetworkingConfigValue_t per ulteriori informazioni sul motivo per cui questa procedura è preferibile all'impostazione delle opzioni "subito" dopo la creazione.

GetGameCoordinatorServerLogin

EResult GetGameCoordinatorServerLogin( SteamDatagramGameCoordinatorServerLogin *pLoginInfo, int *pcbSignedBlob, void *pBlob );

Genera un blob di autenticazione che può essere utilizzato per accedere in modo sicuro al back-end, utilizzando SteamDatagram_ParseHostedServerLogin. (Vedi steamdatagram_gamecoordinator.h)

Prima di chiamare la funzione:
  • Popola i dati dell'applicazione in pLoginInfo (m_cbAppData e m_appData). Puoi lasciare non inizializzati tutti gli altri campi.
  • *pcbSignedBlob contiene la dimensione del buffer presso pBlob. Deve essere almeno k_cbMaxSteamDatagramGameCoordinatorServerLoginSerialized.

Quando un'uscita va a buon fine:
  • Viene restituito k_EResultOK
  • Tutti i campi rimanenti di pLoginInfo saranno compilati.
  • *pcbSignedBlob contiene la dimensione del blob serializzato che è stato inserito in pBlob.

Uscita non riuscita:
  • Viene restituito un valore diverso da k_EResultOK.
  • k_EResultNotLoggedOn: non hai (ancora) effettuato l'accesso.
  • Vedi ISteamNetwrokingSockets::GetHostedDedicatedServerAddress per altri potenziali valori restituiti in caso di errore.
  • Un messaggio di debugging diagnostico non localizzato sarà collocato in pBlob e descriverà la causa dell'errore.

Funziona firmando il contenuto di SteamDatagramGameCoordinatorServerLogin con il certificato emesso per questo server. Negli ambienti di sviluppo non è un problema se non hai un certificato. (Dovrai abilitare l'accesso di sviluppo non sicuro in SteamDatagram_ParseHostedServerLogin.)
In caso contrario, avrai bisogno di un certificato firmato.

NOTA: il blob di instradamento restituito qui non è crittografato. Invialo al back-end e non condividerlo direttamente con i client.

Sistema di falsi indirizzi IP


Un "falso indirizzo IP" è essenzialmente un identificatore temporaneo, arbitrario e un valido indirizzo IPv4. Lo scopo di questo sistema è di semplificare l'integrazione con il codice esistente che identifica gli host utilizzando indirizzi IPv4. Il falso indirizzo IP è esclusivamente un identificatore e non sarà mai utilizzato per inviare o ricevere pacchetti su internet.

I falsi indirizzi IP sono auspicabilmente progettati per andare oltre il codice esistente nel modo più trasparente possibile, entrando in conflitto il meno possibile con indirizzi "veri" che potrebbero essere in uso sulle reti (sia Internet che LAN) nello stesso codice. Al momento provengono dall'intervallo 169.254.0.0/16 e il numero di porta è sempre >1024. In ogni caso, questo è soggetto a cambiamenti! Non avanzare ipotesi in merito a questi indirizzi, altrimenti il codice potrebbe non funzionare in futuro. In particolare, dovresti utilizzare funzioni come ISteamNetworkingUtils::IsFakeIP per stabilire se un indirizzo IP è uno di quelli "falsi" usati da questo sistema.

BeginAsyncRequestFakeIP

bool BeginAsyncRequestFakeIP( int nNumPorts );

Inizia il processo asincrono di allocazione di un falso indirizzo IPv4 che altri peer possono utilizzare per contattarci tramite P2P. Gli indirizzi IP restituiti da questa funzione sono univoci a livello globale per un determinato appID.

nNumPorts è il numero di porte che intendi prenotare. Ciò è utile per lo stesso motivo per cui l'ascolto su più porte UDP è utile per diversi tipi di traffico. Poiché queste allocazioni provengono da uno spazio dei nomi globale, esiste un limite relativamente rigoroso al numero massimo di porte che è possibile richiedere (al momento della stesura di questo articolo, il limite è 4). *Non* è garantito che le assegnazioni delle porte abbiano un ordine o una relazione particolare! *Non* dare per scontato che siano contigui, anche se in pratica può verificarsi spesso.

Restituisce false se una richiesta era già in corso, true se è stata avviata una nuova richiesta. Al completamento della richiesta verrà pubblicata una SteamNetworkingFakeIPResult_t.

Per i server di gioco, *devi* chiamarla dopo aver inizializzato l'SDK ma prima di iniziare l'accesso. Steam deve sapere in anticipo che verrà utilizzato un falso indirizzo IP. Ovunque il tuo IP pubblico apparirebbe normalmente (come il browser del server), verrà sostituito dal FakeIP e la porta fittizia all'indice 0. La richiesta viene effettivamente inserita nella coda fino al completamento dell'accesso, quindi non è necessario attendere il completamento dell'allocazione prima di effettuare l'accesso. A eccezione di errori banali che possono essere rilevati localmente (ad esempio, "parametro non valido"), una callback SteamNetworkingFakeIPResult_T (andata o meno a buon fine) verrà pubblicata solo dopo che abbiamo effettuato l'accesso. Inoltre, si presume che l'allocazione del falso indirizzo IP sia essenziale per il funzionamento della tua applicazione, quindi l'errore non verrà segnalato fino a quando non saranno stati effettuati *diversi* tentativi. Questo processo potrebbe durare diversi minuti. È *caldamente raccomandato* trattare come fatale la mancata riuscita dell'operazione.

Per comunicare utilizzando un'API orientata alla connessione (stile TCP):
  • Il server crea un socket di ascolto utilizzando createListenSocketP2PFakeIP
  • Il client si connette utilizzando ConnectByIPAddress, passando il falso indirizzo IP.
  • La connessione si comporterà prevalentemente come una connessione P2P. Le identità che appaiono in SteamNetConnectionInfo_t saranno quelle del falso indirizzo IP finché la vera identità non sarà nota; a quel punto sarà la vera identità. Se SteamNetConnectionInfo_T: :M_AddrRemote è valido, sarà un vero indirizzo IPv4 di una connessione con NAT punching. In caso contrario, non sarà valido.

Per comunicare utilizzando un sendto/recv ad hoc da un'API (stile UDP), utilizza CreateFakeUDPPort.

GetFakeIP

void GetFakeIP( int idxFirstPort, SteamNetworkingFakeIPResult_t *pInfo );

Restituisce informazioni sul falso indirizzo IP e sulle porte che ci sono state assegnate, se presenti. iDXFirstPort è attualmente riservato e deve essere zero. Controlla e verifica SteamNetworkingFakeIPResult_t::m_eResult

CreateListenSocketP2PFakeIP

HSteamListenSocket CreateListenSocketP2PFakeIP( int idxFakePort, int nOptions, const SteamNetworkingConfigValue_t *pOptions );

Crea un socket di ascolto che ascolta le connessioni P2P inviate al nostro falso indirizzo IP. Un peer può avviare connessioni a questo socket di ascolto chiamando ConnectByIPAddress.

iDxFakePort si riferisce all'*indice* della porta fittizia richiesta, non al numero di porta effettivo. Ad esempio, passa 0 per fare riferimento alla prima porta nella prenotazione. Devi chiamarla solo dopo aver chiamato BeginAsyncRequestFakeIP. Tuttavia, non è necessario attendere il completamento della richiesta prima di creare il socket di ascolto.

GetRemoteFakeIPForConnection

EResult GetRemoteFakeIPForConnection( HSteamNetConnection hConn, SteamNetworkingIPAddr *pOutAddr );

Se la connessione è stata avviata utilizzando il sistema del "falso indirizzo IP", possiamo ottenere un indirizzo IP per l'host remoto. Se l'host remoto aveva un falso indirizzo IP globale al momento in cui è stata stabilita la connessione, questa funzione restituirà tale IP globale. In caso contrario, verrà allocato e restituito un falso indirizzo IP univoco a livello locale dallo spazio degli indirizzi del falso indirizzo IP locale.

L'allocazione dei falsi indirizzi IP locali tenta di assegnare gli indirizzi in modo coerente. Se vengono effettuate più connessioni verso lo stesso host remoto, *probabilmente* restituiranno lo stesso indirizzo IP falso. In ogni caso, poiché lo spazio dei nomi è limitato, ciò non può essere garantito.

In caso di errore, restituisce:
  • k_EResultInvalidParam: handle di connessione non valido.
  • k_eResultIPNotFound: questa connessione non è stata effettuata utilizzando il sistema del falso indirizzo IP.

CreateFakeUDPPort

ISteamNetworkingFakeUDPPort *CreateFakeUDPPort( int idxFakeServerPort );

Ottiene un'interfaccia che può essere utilizzata come una porta UDP per inviare/ricevere datagrammi a un falso indirizzo IP. Questo ha lo scopo di semplificare il porting del codice esistente basato su UDP per sfruttare l'SDR.

idxFakeServerPort si riferisce all'*indice* della porta allocata utilizzando BeginAsyncRequestFakeIP ed è utilizzato per creare le porte "server". Puoi chiamarla prima che l'allocazione sia completata. Tuttavia, qualsiasi tentativo di inviare pacchetti fallirà finché l'allocazione non avrà esito positivo. Quando il peer riceve i pacchetti inviati da questa interfaccia, l'indirizzo di origine del pacchetto sarà il falso indirizzo IP univoco a livello globale. Se chiami questa funzione più volte e passi lo stesso indice di porta falso (non negativo), verrà restituito lo stesso oggetto e questo oggetto non viene conteggiato come riferimento.

Per creare una porta "client" (ad esempio, l'equivalente di una porta UDP effimera), passa -1. In questo caso, verrà restituito un oggetto distinto per ogni chiamata. Quando il peer riceve i pacchetti inviati da questa interfaccia, assegna un falso indirizzo IP dal proprio spazio dei nomi controllato localmente.

Strutture di callback

SteamNetConnectionStatusChangedCallback_t

Questa callback viene pubblicata ogni volta che una connessione viene creata, terminata o cambia stato. Il campo m_info conterrà una descrizione completa della connessione al momento della modifica e della pubblicazione della callback. In particolare, m_info.m_eState conterrà il nuovo stato della connessione.

In genere sarà necessario rimanere in ascolto di questa callback per sapere quando:
  • Una nuova connessione arriva su un socket di ascolto. m_info.m_hListenSocket sarà impostato, m_eOldState = k_ESteamNetworkingConnectionState_None e m_info.m_eState = k_ESteamNetworkingConnectionState_Connecting. Vedi AcceptConnection.
  • Una connessione che hai avviato è stata accettata dall'host remoto. m_eOldState = k_ESteamNetworkingConnectionState_Connecting e m_info.m_eState = k_ESteamNetworkingConnectionState_Connected. Alcune connessioni potrebbero prima effettuare la transizione a k_ESteamNetworkingConnectionState_FindingRoute.
  • Una connessione è stata rifiutata attivamente o chiusa dall'host remoto. m_eOldState = k_ESteamNetworkingConnectionState_Connecting o k_ESteamNetworkingConnectionState_Connected e m_info.m_eState = k_ESteamNetworkingConnectionState_ClosedByPeer. m_info.m_eEndReason e m_info.m_szEndDebug conterranno ulteriori dettagli. NOTA: al ricevimento di questa callback, devi sempre interrompere la connessione utilizzando CloseConnection per liberare le risorse locali (in questo caso i dettagli passati alla funzione non sono utilizzati, poiché la connessione è già chiusa.)
  • È stato rilevato un problema con la connessione, che è stata chiusa dall'host locale. L'errore più comune è il timeout, ma può essere causato anche da altri errori di configurazione o autenticazione. m_eOldState = k_ESteamNetworkingConnectionState_Connecting o k_ESteamNetworkingConnectionState_Connected e m_info.m_eState = k_ESteamNetworkingConnectionState_ProblemDetectedLocally. m_info.m_eEndReason e m_info.m_szEndDebug conterranno ulteriori dettagli. NOTA: al ricevimento di questa callback, devi sempre interrompere la connessione utilizzando CloseConnection per liberare le risorse locali. (in questo caso i dettagli passati alla funzione non sono utilizzati, poiché la connessione è già chiusa.)

Ricorda che le callback vengono pubblicate in una coda e le connessioni di rete possono cambiare in qualsiasi momento. È possibile che la connessione abbia già cambiato stato prima che tu finisca di elaborare questa callback.

Ricorda anche che le callback vengono pubblicate quando le connessioni sono create e interrotte dalle tue chiamate API.

struct SteamNetConnectionStatusChangedCallback_t { /// Handle di connessione HSteamNetConnection m_hConn; /// Informazioni di connessione complete SteamNetConnectionInfo_t m_info; /// Stato precedente. (Lo stato corrente si trova in m_info.m_eState) ESteamNetworkingConnectionState m_eOldState; };

SteamNetAuthenticationStatus_t


Una struttura utilizzata per descrivere la nostra disponibilità a partecipare a una comunicazione crittografata e autenticata. A questo scopo, abbiamo bisogno di:
  • L'elenco di certificati CA attendibili che potrebbero essere pertinenti a questa applicazione.
  • Un certificato valido emesso da una CA.

Questa callback viene pubblicata ogni volta che cambia il nostro stato di disponibilità.

struct SteamNetAuthenticationStatus_t { /// Stato ESteamNetworkingAvailability m_eAvail; /// Stato in lingua inglese non localizzato. Solo a scopi di /// diagnostica/debugging. char m_debugMsg[]; };

Segnalazione P2P personalizzata

Segnalazione è un termine che si riferisce ai messaggi di incontro inviati tramite un canale attendibile con bassa larghezza di banda e latenza elevata, utilizzato dai peer per negoziare una connessione P2P. Steam ti mette a disposizione un servizio di segnalazione. Tuttavia, in alcuni casi può essere utile crearne uno personalizzato. Ad esempio, se uno o entrambi i peer non sono su Steam, è possibile usare SteamNetworkingSockets per realizzare connessioni P2P con un sistema di segnalazione personalizzato. Puoi usare un ICE per attraversare il NAT e usare i server STUN/TURN standard, altrimenti in base alla tua situazione, la rete di relè SDR e il backbone di Valve potrebbero non essere disponibili. Non esitare a contattarci se necessiti di ulteriori informazioni su queste API.