Ahhh, se tutti fossero così bravi!!!
Esattamente così si fa!
Il linger riguarda il periodo di sconnessione e cosa deve fare il socket per chiudere. Se il timeout è troppo breve, o zero, la sconnessione avviene immediatamente, ed eventuali dati in fase di trasmissione sono semplicemente persi. Con un linger normale o alto, si permette al client di ricevere tutti i dati come se fosse ancora aperta la connessione. Il valore di 2 secondi normalmente è sufficiente, ma su modem lenti, o linee intasate, parte dei dati potrebbe andare perso, che ha diversi effetti collaterali, soprattutto per i trasferimenti binari, come FTP.
Un effetto è che si riceve un file non completo, che è fastidioso, perché si deve riprendere lo scaricamento, sperando che vada a buon fine. Alcuni provider, come il mio, troncano la connessione in questo modo, e file di grossi dimensioni (parlo di 10-20 MB) sono semplicemente da evitare.
Per pagine web non è così grave, perché i tag di chiusura pagina sono opzionali, e di regola si vede il contenuto anche se manca un pezzo.
Un linger timeout di 5 secondi è molto user-friendly, anche per modem da 9600 bps o meno, ma richiede maggiori risorse, e siti molto battuti potrebbero rallentarsi parecchio, però solo se si tratta di migliaia di utenti contemporanei. Quindi c'è da fare una scelta e trovare una buona via di mezzo.
Per trovarla, normalmente si misura il traffico e/o la velocità di trasmissione e si aggiusta il linger al momento della chiusura con la funzione 'select', credo. Ma conosco ben pochi che si fanno la fatica di fare i conteggio dei dati in uscita e calcolare l'aggiustamento. Sono due righe di codice, e se lo facessero tutti, l'Internet sarebbe davvero bello da usare. Mi sa, molti non sanno neanche come si fa...
Ed ecco come:
la procedura che manda via i dati, legge il timer (GetTickCount) e salva il valore sullo stack. Poi scrive, e quando ha finito, legge di nuovo il tempo trascorso, e sottrae da questo il valore di prima. Risultato: millisecondi per la quantità di dati inviati. Poi calcoli il rapporto per 1024 byte e lo metti su una variabile globalmente accessibile, in quanto rispecchia la velocità attuale di invio. Non succede nulla di grave se questo viene sovrasscritto da altri thread nello stesso tempo, sarà +/- uguale.
Alla chiusura del socket leggi quanti dati sono ancora in coda, ossia i dati che invii prima di chiudere, e imposti il linger prendendo: rapporto * kB = lingertimeout.
Se hai un server grosso, puoi snellire tutto, inviando sempre blocchi di dati non superiori a 1 kB, quindi, con un thread dedicato aggiorni il lingertimeout per tutti i socket in circolazione, usando l'idle time del sistema, quindi a alla più bassa priorità che esiste. Questo richiede che tieni un array dove sono gli handle dei socket, e il thread spazzola questo array. Se questo array fosse poi un ring-buffer, la gestione sarebbe ottima.
Ora ti ho messo una pulce nell'orecchio, e ti ho raccontato i trucchi del mestiere, ma per un semplice server 1:1 o 1:10, non vale la pena di pensare in grande. Comunque è un bellisimo studio, soprattutto del ring-buffer, che è anche ideale per inviare grandi quantità di dati senza problemi di collisione fra thread di diversa velocità, come ad esempio la lettura da disco e l'invio dati via Internet.
Giovanni
---
http://www.y2ksw.com/vbulletin