In che modo il server WebSocket gestisce più richieste di connessione in entrata?

Secondo qui :

L’intestazione Upgrade HTTP richiede che il server cambi il protocollo del livello applicazione da HTTP al protocollo WebSocket .

L’handshake del client ha stabilito una connessione HTTP-on-TCP tra IE10 e il server. Dopo che il server ha restituito la risposta 101, il protocollo a livello di applicazione passa da HTTP a WebSockets che utilizza la connessione TCP precedentemente stabilita.

HTTP è completamente fuori dall’immagine a questo punto. Utilizzando il leggero protocollo wire WebSocket, i messaggi possono ora essere inviati o ricevuti da entrambi gli endpoint in qualsiasi momento.

Quindi, la mia comprensione è che, dopo che il primo client ha terminato l’handshake con il server, la porta 80 del server sarà monopolizzata dal protocollo WebSocket. E l’ HTTP non funziona più su 80 porte .

Quindi, come potrebbe il secondo cliente scambiare l’handshake con il server. Dopo tutto l’handshake WebSocket è in formato HTTP.

AGGIUNGI 1

Grazie per tutte le risposte finora. Sono davvero d’aiuto.

Ora capisco che la stessa porta 80 del server è condivisa da più connessioni TCP . E questa condivisione è totalmente OK perché TCP connessioni TCP sono identificate da una tupla di 5 elementi come ha sottolineato Jan-Philip Gehrcke .

Vorrei aggiungere alcuni pensieri.

Sia WebSocket che HTTP sono semplicemente protocolli a livello di applicazione. Di solito entrambi si affidano al protocollo TCP come loro trasporto.

Perché scegliere la porta 80?

Il design WebSocket sceglie intenzionalmente la porta 80 del server sia per l’ handshake che per la comunicazione successiva . Penso che il progettista desideri rendere la comunicazione WebSocket simile alla normale comunicazione HTTP dal punto di vista del livello di trasporto (ovvero il numero di porta del server è ancora 80) . Ma secondo la risposta di jfriend00 , questo trucco non sempre ingannare le infrastrutture di rete.

Come passa il protocollo da HTTP a WebSocket ?

Da RFC 6455 – Protocollo WebSocket

Fondamentalmente è pensato per essere il più vicino ad esporre il TCP non elaborato allo script il più ansible, dati i limiti del Web. È inoltre progettato in modo tale che i suoi server possano condividere una porta con server HTTP, avendo la sua stretta di mano una richiesta di aggiornamento HTTP valida. Uno potrebbe concettualmente utilizzare altri protocolli per stabilire la messaggistica client-server, ma l’intento di WebSockets è quello di fornire un protocollo relativamente semplice che possa coesistere con HTTP e l’infrastruttura HTTP distribuita (come i proxy) e che sia il più vicino al TCP che è sicuro per utilizzare con tale infrastruttura considerazioni sulla sicurezza, con aggiunte mirate per semplificare l’uso e mantenere semplici le cose semplici (come l’aggiunta della semantica del messaggio).

Quindi penso di sbagliarmi sulla seguente affermazione:

La richiesta di handshake simula la richiesta HTTP ma la comunicazione che segue non lo fa. La richiesta di handshake arriva al server sulla porta 80. Poiché è 80 porte, il server la tratterà con il protocollo HTTP. Ed è per questo che la richiesta di handshake WebSocket deve essere in formato HTTP. Se è così, penso che il protocollo HTTP DEVE essere modificato / esteso per riconoscere quelle cose specifiche di WebSocket. Altrimenti non si renderà conto che dovrebbe cedere al protocollo WebSocket.

Penso che dovrebbe essere capito in questo modo:

La comunicazione WebSocket inizia con una richiesta HTTP valida da client a server. Quindi è il server che segue il protocollo HTTP per analizzare la richiesta di handshake e identificare l’accattonaggio per la modifica del protocollo. Ed è il server che cambia il protocollo. Quindi il protocollo HTTP non ha bisogno di cambiare. Il protocollo HTTP non ha nemmeno bisogno di sapere su WebSocket.

WebSocket e Comet

Quindi WebSocket è diverso dalle tecnologie Comet in quanto WebSoket non si limita nel regno HTTP corrente per risolvere il problema di comunicazione bidirezionale.

AGGIUNGI 2

Una domanda correlata: in che modo un browser stabilisce una connessione con un server Web su 80 porte? Dettagli?

Le altre risposte sono già utili. Voglio far notare che la tua domanda è molto buona e voglio rispondere dal punto di vista del coinvolgimento di listen() e accept() . Il comportamento di queste due chiamate di sistema dovrebbe essere sufficiente per rispondere alla tua domanda.

Sei interessato a come funziona TCP / IP!

Per la parte centrale della domanda non c’è davvero alcuna differenza a seconda di HTTP o WebSocket: il terreno comune è TCP su IP e questo è sufficiente per rispondere alla tua domanda. Tuttavia, ti meriti una risposta su come WebSocket si rapporta al TCP (ho cercato di approfondire un po ‘di più qui ): l’invio di una richiesta HTTP richiede una connessione TCP / IP stabilita tra due parti. In caso di un semplice browser Web / scenario server Web

  1. prima viene stabilita una connessione TCP tra entrambi (avviata dal client)
  2. quindi una richiesta HTTP viene inviata attraverso quella connessione TCP (dal client al server)
  3. quindi una risposta HTTP viene inviata attraverso la stessa connessione TCP (nell’altra direzione, dal server al client)

Dopo questo scambio, la connessione TCP sottostante non è più necessaria e solitamente viene distrutta / disconnessa. Nel caso di una richiesta di aggiornamento HTTP, la connessione TCP sottostante continua a vivere e la comunicazione WebSocket passa attraverso la stessa connessione TCP creata inizialmente (passaggio (1) sopra).

Come si può vedere, l’unica differenza tra WebSocket e HTTP standard è un passaggio in un protocollo di alto livello (da HTTP a WebSocket), senza modificare il canale di trasporto sottostante (una connessione TCP / IP).

Come gestire più tentativi di connessione IP attraverso lo stesso socket?

Questo è un argomento che una volta ho avuto difficoltà con me stesso e che molti non capiscono. Tuttavia, il concetto è in realtà molto semplice quando si capisce come funzionano le chiamate di sistema di base relative al socket fornite dal sistema operativo.

Innanzitutto, è necessario apprezzare che una connessione IP è definita in modo univoco da cinque informazioni:

IP: PORTA della macchina A e IP: PORTA della macchina B e il protocollo (TCP o UDP)

Ora, si pensa che gli oggetti socket rappresentino una connessione. Ma non è completamente vero. Possono rappresentare cose diverse: possono essere attivi o passivi. Un object socket in modalità passiva / ascolto fa qualcosa di molto speciale, ed è importante rispondere alla tua domanda. http://linux.die.net/man/2/listen dice:

listen () contrassegna il socket a cui fa riferimento sockfd come socket passivo, ovvero come socket che verrà utilizzato per accettare le richieste di connessione in ingresso usando accept (2).

Quindi, possiamo creare un socket passivo che ascolta le richieste di connessione in entrata. Per definizione, un tale socket non può mai rappresentare una connessione. Ascolta solo le richieste di connessione.

Andiamo su accept() ( http://linux.die.net/man/2/accept ):

La chiamata di sistema accept () viene utilizzata con i tipi di socket basati su connessione (SOCK_STREAM, SOCK_SEQPACKET). Estrae la prima richiesta di connessione sulla coda delle connessioni in sospeso per il socket di ascolto, sockfd, crea un nuovo socket connesso e restituisce un nuovo descrittore di file riferito a quel socket. Il socket appena creato non è nello stato di ascolto. Il socket sockfd originale non è influenzato da questa chiamata.

Questo è tutto ciò che dobbiamo sapere per rispondere alla tua domanda. accept() non modifica lo stato del socket passivo creato in precedenza. Restituisce un socket attivo (connesso) (tale socket rappresenta quindi i cinque stati di informazioni sopra indicati – semplice, giusto?). Di solito, questo object socket attivo appena creato viene quindi trasferito su un altro processo o thread o semplicemente ” quadro” che si occupa della connessione. Dopo che accept() ha restituito questo object socket connesso, accept() può essere chiamato di nuovo sul socket passivo, e ancora e ancora – qualcosa che è noto come accept loop . Ma chiamare accept() richiede tempo, giusto? Non può mancare le richieste di connessione in entrata? Vi sono altre informazioni essenziali nel testo della guida appena citato: c’è una coda di richieste di connessione in sospeso! Viene gestito automaticamente dallo stack TCP / IP del sistema operativo. Ciò significa che mentre accept() può gestire solo le richieste di connessione in entrata uno alla volta , nessuna richiesta in ingresso verrà ignorata anche quando sono in arrivo ad alta velocità o (quasi-) simultaneamente. Si potrebbe dire che il comportamento di accept() limita la frequenza delle richieste di connessione in entrata che la macchina può gestire. Tuttavia, questa è una chiamata di sistema veloce e, in pratica, altre limitazioni colpiscono in primo luogo – di solito quelle relative alla gestione di tutte le connessioni che sono state accettate finora .

La cosa relativamente semplice che sembra mancare qui è che ogni connessione a un server (in particolare al tuo server HTTP qui) crea il proprio socket e quindi gira su quel socket. Ciò che accade su un socket è completamente indipendente da ciò che accade su qualsiasi altro socket attualmente connesso. Quindi, quando un socket viene commutato al protocollo webSocket, ciò non cambia ciò che accade ad altre connessioni socket attuali o in entrata. Quelli decidono da soli come saranno trattati.

Quindi, i socket aperti possono utilizzare il protocollo webSocket mentre altre connessioni in ingresso possono essere richieste o richieste HTTP regolari per creare una nuova connessione webSocket.

Quindi, puoi avere questo tipo di sequenza:

  1. Il client A si connette al server sulla porta 80 con richiesta HTTP per avviare una connessione webSocket. Questo processo crea un socket tra i due.
  2. Il server risponde sì, all’aggiornamento alla richiesta webSocket e sia il client che il server scambiano il protocollo per questo socket solo con il protocollo webSocket.
  3. Il Cliente A e il Server iniziano a scambiare pacchetti usando il protocollo webSocket e continuano a farlo per le prossime ore.
  4. Il client B si collega allo stesso server sulla porta 80 con una normale richiesta HTTP. Questo processo crea un nuovo socket tra i due.
  5. Server vede la richiesta in arrivo è una normale richiesta HTTP e invia la risposta.
  6. Quando il client B riceve la risposta, il socket viene chiuso.
  7. Il client C si connette allo stesso server sulla porta 80 con una richiesta HTTP per l’aggiornamento a un webSocket.
  8. Il server risponde sì, all’aggiornamento alla richiesta webSocket e sia il client che il server scambiano il protocollo per questo socket solo con il protocollo webSocket.
  9. A questo punto, ci sono due socket aperti che utilizzano il protocollo webSocket che può comunicare e il server sta ancora accettando nuove connessioni che possono essere richieste HTTP regolari o possono essere richieste per un aggiornamento al protocollo webSocket.

In ogni momento, il server accetta ancora nuove connessioni sulla porta 80 e quelle nuove connessioni possono essere richieste HTTP regolari o possono essere richieste HTTP che sono una richiesta per l’aggiornamento al protocollo webSocket (e quindi avviare una connessione webSocket). E mentre tutto questo accade, le connessioni webSocket che sono già state stabilite comunicano tramite il proprio socket usando il protocollo webSocket.

Lo schema di connessione e comunicazione webSocket è stato progettato molto attentamente per avere queste caratteristiche:

  1. Non è stata richiesta una nuova porta. La porta in ingresso (più comunemente la porta 80) potrebbe essere utilizzata sia per le richieste HTTP regolari sia per le comunicazioni webSocket.
  2. Poiché non era richiesta alcuna nuova porta, le modifiche ai firewall o altre infrastrutture di rete non erano “normalmente” richieste. Come risulta, questo non è sempre il caso perché alcuni proxy o cache che si aspettano il traffico HTTP potrebbero dover essere modificati per gestire (o evitare) il traffico del protocollo webSocket.
  3. Lo stesso processo server potrebbe facilmente gestire sia le richieste HTTP che le richieste webSocket.
  4. I cookie HTTP e / o altri mezzi di autenticazione basati su HTTP potrebbero essere utilizzati durante l’installazione di una connessione webSocket.

Risposte alle tue ulteriori domande:

1) Perché scegliere 80 come porta predefinita? Il progettista desidera rendere la comunicazione WebSocket simile alla normale comunicazione HTTP dal punto di vista del livello di trasporto? (cioè la porta del server è la buona vecchia 80).

Sì, vedi i miei punti 1-4 immediatamente sopra. webSockets può essere stabilito su canali HTTP esistenti in modo che generalmente non richiedano modifiche all’infrastruttura di rete. Aggiungerei a questi punti che non è necessario alcun nuovo processo server o server in quanto un server HTTP esistente può semplicemente avere il supporto webSocket aggiunto ad esso.

2) Sto cercando di immaginare come avviene lo spostamento del protocollo sul server. Immagino ci siano diversi moduli software per gestire i traffici HTTP o WebSocket. Il primo server utilizza il modulo HTTP per gestire le normali richieste HTTP. Quando trova una richiesta di aggiornamento, passerà a utilizzare il modulo WebSocket.

Diverse architetture server gestiranno la divisione tra i pacchetti webSocket e le richieste HTTP in modo diverso. In alcuni casi, le connessioni webSocket potrebbero persino essere inoltrate a un nuovo processo. In altri casi, potrebbe trattarsi semplicemente di un gestore di eventi diverso nello stesso processo registrato per il traffico di pacchetti in entrata sul socket, che è ora passato al protocollo webSocket. Ciò dipende interamente dall’architettura del server Web e da come sceglie di elaborare il traffico webSocket. Uno sviluppatore che implementa l’estremità server di un’app webSocket probabilmente selezionerà un’implementazione WebSocket esistente compatibile con la loro particolare architettura di server Web e quindi scriverà il codice che funziona all’interno di tale framework.

Nel mio caso, ho selezionato la libreria socket.io che funziona con node.js (che è la mia architettura del server). Quella libreria mi fornisce un object che supporta eventi per i nuovi webSocket di collegamento e quindi una serie di altri eventi per leggere i messaggi in arrivo o inviare messaggi in uscita. I dettagli della connessione webSocket iniziale sono gestiti dalla libreria e non devo preoccuparmi di nulla. Se voglio richiedere l’autenticazione prima che la connessione sia stabilita, la libreria socket.io ha un modo per me di collegarlo. Posso quindi ricevere messaggi da qualsiasi client, inviare messaggi a qualsiasi singolo client o trasmettere informazioni a tutti i client. Lo uso principalmente per la trasmissione per mantenere alcune informazioni in una pagina Web “live” in modo che la visualizzazione della pagina web sia sempre attuale. Ogni volta che il valore cambia sul server, trasmetto il nuovo valore a tutti i client connessi.

Per rispondere alla tua domanda: le connessioni Websocket e HTTP simultanee alla porta 80 vengono gestite …

Esattamente allo stesso modo vengono gestite le connessioni HTTP simultanee alla porta 80!

Ciò significa: su un handshake TCP soddisfacente, il servizio di ascolto su serviceip: 80 procede a generare un nuovo processo o thread e passa tutte le comunicazioni per quella connessione ad esso (o semplicemente serve la richiesta eseguendo il callback associato a quell’evento come asincrono nodejs fa, come giustamente ha fatto notare jfriend00).

Quindi attende o gestisce la prossima richiesta in entrata in coda.

Se vuoi sapere quale parte HTTP 1.1 e la richiesta UPGRADE giocano su tutto questo, questo articolo MSDN su di esso lascia molto chiaro:

Il protocollo WebSocket ha due parti: un handshake per stabilire la connessione aggiornata, quindi il trasferimento dati effettivo. Innanzitutto, un client richiede una connessione web socket utilizzando le intestazioni “Aggiornamento: websocket” e “Connessione: Aggiornamento”, insieme ad alcune intestazioni specifiche del protocollo per stabilire la versione utilizzata e impostare un handshake. Il server, se supporta il protocollo, risponde con le stesse intestazioni “Upgrade: websocket” e “Connection: Upgrade” e completa l’handshake. Una volta completata correttamente l’handshake, inizia il trasferimento dei dati.

Solitamente i servizi Websocket non sono integrati nel server Web, quindi non sono pensati per l’ascolto nella porta 80, ma sono accessibili solo grazie all’invio trasparente del server Web. Il server Web Apache lo fa usando mod_proxy_wstunnel .

Naturalmente è anche ansible avere un server Web con un’implementazione di socket Web incorporata: Apache Tomcat , ad esempio.

La cosa principale qui è: il protocollo Websocket non è HTTP. Serve a uno scopo diverso. Si tratta di un protocollo di comunicazione a livello di applicazione indipendente anch’esso costruito su TCP (sebbene TCP non sia necessario per il requisito, ma un protocollo per il livello di trasporto che si adatta ai requisiti del protocollo del livello dell’applicazione Websockets).

Un servizio Websocket è un servizio PARALLEL che funziona con un servizio di server web.

Utilizza il protocollo Websocket, per il quale i moderni browser Web supportano, implementando la parte client dell’interfaccia.

Si imposta o si crea un servizio Websocket per stabilire connessioni persistenti non HTTP tra client Websocket (in genere browser Web) e quel servizio.

Il vantaggio principale è: Il servizio Websocket può INVIARE un messaggio al client ogni volta che è necessario (“uno dei tuoi amici è connesso!” “La tua squadra ha appena segnato un objective!”), Invece di dover aspettare la RICHIESTA esplicita del cliente per un aggiornamento.

È ansible stabilire una connessione persistente utilizzando HTTP 1.1, ma HTTP non è pensato per qualcosa di diverso dal servire un set di risorse SU RICHIESTA e quindi chiudere la connessione.

Fino a poco tempo fa, prima che il supporto di Websockets fosse disponibile in tutti i principali browser, c’erano solo due possibilità per implementare aggiornamenti in tempo reale su un’applicazione web:

  • Implementazione di richieste di polling lunghe AJAX, che è un processo doloroso e inefficiente.

  • Utilizzo / creazione di un plug-in del browser (ad esempio un plug-in di supporto dell’applet Java) per poter stabilire una connessione non HTTP con il servizio di aggiornamenti, che è più efficiente ma anche più doloroso del polling lungo.

In termini di porta di ascolto condivisa del servizio (che può essere una qualsiasi porta TCP e non deve nemmeno essere aperta su Internet, poiché la maggior parte dei server Web supporta l’inoltro trasparente delle connessioni socket Web), funziona esattamente come qualsiasi altro TCP servizio: il servizio si limita ad ascoltarlo e quando l’handshake TCP è terminato, esiste un socket TCP affinché il servizio possa comunicare con il client.

Come al solito, tutte le connessioni a un servizio in ascolto su un particolare socket TCP (server_ip: service_TCP_port) saranno differenziate quando viene assegnato un unico client_ip: client_TCP_port pair, il client_TCP_port scelto casualmente dal client tra le porte TCP disponibili).

Se si è ancora in dubbio sul passaggio del protocollo dell’applicazione HTTP-> Websocket che avviene sull’handshave della connessione Websocket e su come non ha nulla a che fare con la connessione TCP sottostante, rimando alla risposta di Jan-Philip Gehrcke , che è molto chiara un istruttivo e probabilmente quello che stavi effettivamente cercando.

È un concetto abbastanza semplice, quindi lasciatemi tentare di descriverlo in termini semplici nel caso qualche altra anima perduta voglia coglierla senza dover leggere tutte quelle lunghe spiegazioni.

Connessioni multiple

  1. Il server Web inizia ad ascoltare le connessioni. Questo succede:

    • Il processo principale del server Web apre un socket passivo nello stato di listen sulla porta 80 , ad esempio 9.9.9.9:80 ( 9.9.9.9 è l’IP del server e 80 è la porta).
  2. Il browser effettua una richiesta alla porta 80 sul server. Questo succede:

    • Il sistema operativo (in breve OS) alloca una porta in uscita casuale sul client, ad esempio: 1.1.1.1:6747 ( 1.1.1.1 è l’IP del client e 6747 è la porta casuale).

    • Il sistema operativo invia un pacchetto di dati con l’indirizzo di origine 1.1.1.1:6747 e l’indirizzo di destinazione 9.9.9.9:80 . Passa attraverso vari router e switch e arriva al server di destinazione.

  3. Il server riceve il pacchetto. Questo succede:

    • Il sistema operativo del server vede che l’indirizzo di destinazione del pacchetto è uno dei propri indirizzi IP e in base alla porta di destinazione lo passa all’applicazione associata alla porta 80 .

    • Il processo principale del server Web accetta la connessione creando un nuovo socket attivo. Quindi di solito genera un nuovo processo figlio, che prende il socket attivo. La presa passiva rimane aperta per accettare nuove connessioni in entrata.

Ora ogni pacchetto inviato dal server al client avrà quegli indirizzi:

  • fonte: 9.9.9.9:1553 ; destinazione: 1.1.1.1:80

E ogni pacchetto inviato dal client al server avrà quegli indirizzi:

  • fonte: 1.1.1.1:80 ; destinazione: 9.9.9.9:1553

HTTP -> handshake WebSocket

HTTP è un protocollo basato su testo. Vedi il wiki HTTP per l’elenco dei comandi disponibili. Il browser invia uno di questi comandi e il server Web risponde di conseguenza.

WebSocket non è basato su HTTP. È un protocollo binario in cui più flussi di messaggi possono essere inviati contemporaneamente in entrambe le direzioni (modalità full-duplex). Per questo motivo non sarebbe ansible stabilire una connessione WebSocket direttamente senza introdurre un nuovo standard HTTP, come ad esempio HTTP / 2 . Ma ciò sarebbe ansible solo se:

  1. Verbi / richieste HTTP supportati da WebSocket

  2. C’era una nuova porta dedicata diversa da 80 per la comunicazione specifica di WebSocket.

Il primo non rientrava nel campo di applicazione del protocollo e il secondo avrebbe interrotto l’infrastruttura Web esistente. Poiché un client / browser può stabilire più connessioni HTTP con lo stesso server, il passaggio da HTTP a WebSocket è il migliore dei due mondi: mantenere la stessa porta 80 ma consentire un protocollo diverso da HTTP. L’interruttore avviene tramite l’ handshake del protocollo avviato dal client.