2012-06-05 9 views
5

Ho una libreria di terze parti che funge da server HTTP. Gli passo un indirizzo e una porta, che poi usa per ascoltare le connessioni in entrata. Questa libreria ascolta in modo tale da non ricevere l'uso esclusivo della porta e dell'indirizzo a cui è destinata. Di conseguenza, posso ascoltare sulla stessa porta più volte.Come si verifica se una porta TCP è già in ascolto?

Ho bisogno di eseguire più istanze di questo server HTTP nello stesso processo. Ogni istanza ha una porta predefinita, ma se quella porta non è disponibile, dovrebbe utilizzare la successiva porta disponibile. Questo è il mio problema; Posso finire con due server HTTP in ascolto sulla stessa porta.

Non riesco a cambiare il codice del server HTTP e il server HTTP non mi avviserà se non è in grado di ascoltare sulla porta che gli ho dato, quindi devo essere in grado di verificare se una porta è già in uso prima di avviare ogni server HTTP . Ho provato a verificare se una porta è già in ascolto collegando il mio socket con SO_REUSEADDR impostato su FALSE e SO_EXCLUSIVEADDRUSE impostato su TRUE, ma le chiamate di bind e di ascolto hanno esito positivo quando un server HTTP esistente è già in ascolto su quella porta.

In che modo questo server HTTP raggiunge questo effetto e come posso controllare accuratamente se una porta viene ascoltata in questo modo?

+0

C'è un motivo per utilizzare questa particolare libreria di server HTTP? Dato che è rotto, e non hai abbastanza controllo su di esso o accesso per capire cosa sta facendo per farlo funzionare, il passaggio sembrerebbe una buona idea. – abarnert

+0

Per curiosità, quale libreria è? –

+0

"Questa libreria ascolta in modo tale da non ricevere l'uso esclusivo della porta e dell'indirizzo a cui è associato". Questo non è possibile in TCP. L'unica forma di condivisione delle porte che è possibile in TCP è vincolante per diversi indirizzi IP locali e lo stesso numero di porta. È necessario riesaminare e quindi riformulare la domanda. – EJP

risposta

4

Il metodo rapido e sporco sarebbe provare a connect() alla porta su localhost. Se la chiamata connect() ha esito positivo, significa che la porta è attualmente in ascolto (da chiunque abbia ricevuto la connessione). Se la chiamata di connessione fallisce (in particolare con ECONNREFUSED), si può essere certi che nessuno stia ascoltando su quella porta.

Naturalmente, c'è una condizione di competizione qui: nulla è davvero l'arresto di un altro programma da picchiata e afferrare la porta subito dopo è stato eseguito il test di cui sopra, ma prima di andare in giro per il legame con il porto da soli. Quindi dovresti prendere il risultato del test più di un suggerimento di una regola assoluta, e (si spera) avere un qualche modo di gestirlo se in seguito scoprirai che la porta è in uso dopotutto.

+0

Il suo codice di test previsto avrà esattamente la stessa condizione di gara (o, piuttosto, avrebbe la stessa condizione di gara se funzionasse ...). E davvero, non c'è modo di evitarlo, visto il suo design. – abarnert

+0

(Quanto sopra sta spiegando perché ti ho dato +1 nonostante le condizioni della gara, non in disaccordo con la tua risposta o qualcosa del genere.) – abarnert

2

Utilizzare un numero porta di 0. Il sistema operativo sceglierà una porta libera.

+0

Non ho accesso al server HTTP socket interno, quindi se passo 0 come porta, non posso recuperare la porta che il sistema operativo ha dato. –

+0

Quindi associare un socket utilizzando la porta 0, utilizzare 'getsockaddr' per rilevare il numero di porta selezionato, inizializzare un server HTTP utilizzando la stessa porta e quindi chiudere il socket temporaneo. –

1

http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621(v=vs.85).aspx spiega come interagiscono le diverse opzioni.

Non ci avete dato abbastanza informazioni per dirci esattamente cosa sta succedendo nel vostro caso d'uso, ma posso lavorare attraverso un caso d'uso arbitrario che sembrerebbe quello che state vedendo.

Diciamo che sei su Windows 2003 o successivo, e il tuo NIC primario è 10.0.0.1, e tutto è in esecuzione con lo stesso account utente.

La prima istanza della tua app si presenta e il tuo codice di prova tenta di associare 10.0.0.1:12345 con SO_EXCLUSIVEADDREUSE. Certo che funziona.

Si chiude il socket, quindi si dice al server HTTP di ascoltare la porta 12345. Si lega 0.0.0.0:12345 con SO_REUSEADDR, che ovviamente funziona.

Ora viene visualizzata una seconda istanza dell'app e il codice di test tenta di associare 10.0.0.1:12345 con SO_EXCLUSIVEADDREUSE. Secondo il grafico nell'articolo MSDN, funziona.

Si chiude il socket, quindi si dice al server HTTP di ascoltare la porta 12345. Esso associa 0.0.0.0:12345 con SO_REUSEADDR, che funziona.

Se questo è il problema, supponendo che non sia possibile ottenere il server HTTP per associare un indirizzo specifico, è possibile risolvere le cose utilizzando 0.0.0.0 nel proprio codice di test.(Naturalmente se è una delle altre centinaia di possibili problemi, quella soluzione non funzionerà.)

Se non si conoscono le opzioni socket, indirizzo, ecc. Il server HTTP sta usando, e non avere il sorgente, basta eseguirlo nel debugger e interrompere le chiamate rilevanti.

Problemi correlati