2012-01-26 13 views
7

Sto cercando di capire la classe 'SocketAsyncEventArgs' in C#. http://msdn.microsoft.com/en-us/library/system.net.sockets.socketasynceventargs.aspxC# SocketAsyncEventArgs gestione ricezione e invio dati

Sto seguendo questo tutorial: http://www.codeproject.com/Articles/83102/C-SocketAsyncEventArgs-High-Performance-Socket-Cod

Ora mi sono bloccato sul modo in cui ho esattamente dovrei elaborare i dati con il mio server. Quello che sto cercando di fare è usare un SocketAsyncEventArgs per un client connesso con uno spazio Buffer allocato di 512 byte nel BufferManager. Quindi quello che voglio fare è decodificare i dati byte [] nella mia propria classe personalizzata (ClientPacket) che contiene il byte [] per la decodifica e la lettura.

Questo è perfetto ma il mio server non sempre risponde con i dati la domanda è:

posso utilizzare 1 SocketAsyncEventArgs per la ricezione e anello intorno per elaborare ricevere i dati, quindi allocare un SocketAsyncEventArgs dalla piscina ogni volta Devo inviare quindi restituirlo al completamento?

E come sa SocketAsyncEventArgs quando la lettura è completa? (quando ha finito con il buffer byte [] prima di sovrascriverlo con nuovi dati) come quando viene restituito al pool quando viene eseguito se non rispondo?

risposta

8

Io uso solo un'istanza SocketAsyncEventArgs per tutte le mie esigenze. Ho semplicemente resettato il buffer tra ogni richiesta (impostandolo su un nuovo Byte []).

volta ho collegato e avere un riferimento alla presa, inizio ascoltando simili:

public void StartListening(SocketAsyncEventArgs e) 
{ 
    ResetBuffer(e); 
    e.Completed += SocketReceive; 

    socket.ReceiveAsync(e); 
} 

Ho una funzione di supporto che resetta il buffer:

private void ResetBuffer(SocketAsyncEventArgs e) 
{ 
    var buffer = new Byte[SocketBufferSize]; 

    e.SetBuffer(buffer, 0, SocketBufferSize); 
} 

Elaboro dati come:

private void SocketReceive(Object sender, SocketAsyncEventArgs e) 
{ 
    ProcessData(e.Buffer, 0, e.BytesTransferred); 

    ResetBuffer(e); 

    socket.ReceiveAsync(e); 
} 

In ProcessData, è possibile utilizzare l'array di byte necessario per inserire i dati . Io lo uso per creare un MemoryStream che ho poi deserializzare nella mia classe (simile a ClientPacket), come segue:

private void ProcessData(Byte[] data, Int32 count) 
{ 
    using (var stream = new MemoryStream(data, 0, count)) 
    { 
     var serializer = new XmlSerializer(typeof(ClientPacket)); 

     var packet = serializer.Deserialize(stream); 

     // Do something with the packet 
    } 
} 

quanto riguarda la tua ultima domanda. Il framework gestisce tutto ciò che ha a che fare con il protocollo TCP sottostante, ecc., Così puoi contare sul fatto che il gestore eventi venga chiamato ogni volta che ci sono dati da elaborare. Utilizza il valore e.BytesTransferred per indicare la quantità di dati effettivamente ricevuti che potrebbe essere inferiore ma non supererà mai la dimensione del buffer (SocketBufferSize nel mio codice). Se il messaggio era più grande della dimensione del buffer, l'infrastruttura TCP bufferizzerà i messaggi e li invierà in blocchi basati su SocketBufferSize (sollevando l'evento una volta per ogni blocco). Se si tratta di una preoccupazione, è sufficiente aumentare SocketBufferSize fino a quando la maggior parte del messaggio viene ricevuta in un blocco.

Lo svantaggio del chunking è che i messaggi possono essere uniti dall'infrastruttura, il che significa che potrebbe essere necessario un modo per dire quando il primo messaggio è terminato. Gli approcci tipici includono la prefazione del messaggio con un intero di 4 byte che indica la lunghezza del messaggio. Posso elaborare di più se necessario.

Spero che questo aiuti.

+0

Hai detto impostandolo su un nuovo byte [], ma sto condividendo un blocco buffer di grandi dimensioni su tutto SocketAsyncEventArgs, se leggo da quel buffer buffer in un pacchetto, il blocco del buffer potrebbe essere sovrascritto dal prossimo arrivo dati, anche se copio l'array byte [], non va usando il Buffer Block per inviare/ricevere dati? Inoltre, come posso inviare dati con lo stesso oggetto quando un'operazione di ricezione può avvenire in qualsiasi momento? –

+1

Sembra che tu stia assumendo una singola connessione socket tra 2 macchine. Non è possibile riutilizzare solo un singolo SocketAsyncEventArgs quando si gestiscono molte connessioni simultanee, il che è a mio parere la domanda. (E per cosa è stato creato SocketAsyncEventArgs). –

+0

grazie SonOfPirate, Sarebbe fantastico se tu possa elaborare di più sulla ricezione di grandi quantità di dati. soprattutto chiarire per favore se devo ri-chiamare ReceiveAsync ogni volta prima di raggiungere la fine; o Framework lo farà per me? –