2015-12-15 16 views
5

sto cercando di imparare a utilizzare i socket in C# e ho un dubbio, sto usando un codice simile a questa:C# presa ricevere byte di lunghezza dell'array

byte[] data = new byte[64]; 
int length = 0; 
length = sock.Receive(data); 
//more code... 

Quindi, i dati byte[] è riempito con i dati ricevuti e lo spazio sinistro nell'array è riempito con 0s, lo byte[] è allocato in memoria completamente (tutti i 64 byte)? Se è così, c'è un modo per rendere lo byte[] della stessa dimensione dei dati effettivamente inviati?

+0

È possibile controllare 'calzino.Available' per vedere quanti dati sono già entrati dalla rete. Nota, potresti ottenere più dati in seguito. – ebyrob

+0

Sì, i 64 byte sono tutti allocati. Sono assegnati prima della chiamata di ricezione, quindi come si può sapere qual è la dimensione effettiva dei dati? Sarebbe come tagliare un pezzo di spago alla lunghezza giusta per avvolgere un pacchetto che non hai mai visto. Avresti bisogno di una sfera di cristallo. – phoog

risposta

1

È sufficiente utilizzare il valore restituito da Receive per capire quanti dati sono arrivati. Puoi accorciare il buffer usando Array.Resize se vuoi, ma normalmente sarebbe un segno che qualcosa non va.

Si noti inoltre che TCP è un flusso di byte e non conserva i limiti dei messaggi.

+0

Ho provato a utilizzare "byte [] dati = nuovo byte [1048576];" e l'utilizzo della CPU è passato da 0,4 a 2,7 e la memoria da 6 MB a 20 MB, quindi viene allocata. Il problema è che non so quale sia la dimensione dei dati ricevuti finché non la ricevo, e ho bisogno di avere un byte [] almeno della dimensione dei dati inviati prima di riceverli (o non li ho sapere come fare in entrambi i casi). L'unica soluzione che posso immaginare è che il client invii un numero massimo di dati e non di più. – null

+0

@ user3324670 Sapere cosa aspettarsi dal client è una parte importante della programmazione di rete. Inoltre, puoi leggere solo una parte dei dati disponibili e poi leggere di nuovo per ottenere il resto. (sotto e sopra la lettura è OK, basta riassemblare il messaggio una volta che ce l'hai) – ebyrob

+0

L'unico modo per sapere quanto sta arrivando è quello di farti dire dall'altra parte, ad esempio inviando un numero intero con quanti byte ora invia. Questo è un approccio comune. – usr

3

È possibile controllare sock.Available per vedere ciò che è già venuto a (finora)

byte[] data = new byte[sock.Available]; 
int length = sock.Receive(data); 
//more code... 

. Nota: Dal momento che si può o non può sapere che cosa è in arrivo il prossimo sulla rete di solito ha più senso leggere prima un'intestazione (con informazioni sulle dimensioni) o allocare più spazio del necessario e chiamare .Recieve() più volte fino al raggiungimento della fine di un record.

Nota: questo codice presuppone che tu sappia già che ci sono alcuni dati da ricevere e che hai aspettato abbastanza a lungo perché una certa quantità di dati utili sia pronta.

Se si sceglie di utilizzare le intestazioni di lunghezza, .Available può aiutare a evitare di leggere un'intestazione parziale e doverla riassemblare, il che è bello. (In questo caso, solo i messaggi di grandi dimensioni possono richiedere un riassemblaggio manuale)

+0

Non so come questo aiuti. Cosa succede se Disponibile è zero? – usr

+0

@usr Quindi non ci sono dati da leggere ... Inoltre, i byte disponibili possono cambiare tra lettura e controllo. – ebyrob

+0

Oh, questo è esattamente quello che stavo cercando, non sapevo che fosse disponibile: P, grazie. – null

2

Come indicato normalmente, è possibile che vengano restituiti meno byte, quindi è stato comunicato. Vedere una funzione di soluzione alternativa al di sotto della quale assicura che legge più byte come è stato detto - in pratica la dimensione del buffer passato. La funzione è da here.

/// Reads data into a complete array, throwing an EndOfStreamException 
/// if the stream runs out of data first, or if an IOException 
/// naturally occurs. 
/// </summary> 
/// <param name="stream">The stream to read data from</param> 
/// <param name="data">The array to read bytes into. The array 
/// will be completely filled from the stream, so an appropriate 
/// size must be given.</param> 
public static void ReadWholeArray (Stream stream, byte[] data) 
{ 
    int offset=0; 
    int remaining = data.Length; 
    while (remaining > 0) 
    { 
     int read = stream.Read(data, offset, remaining); 
     if (read <= 0) 
      throw new EndOfStreamException 
       (String.Format("End of stream reached with {0} bytes left to read", remaining)); 
     remaining -= read; 
     offset += read; 
    } 
} 

È possibile utilizzare questo metodo prima di leggere dire un intero 2 byte che dovrebbe rappresentare il numero di byte che seguiranno. Quindi leggi ancora una volta, tuttavia ora legge più byte come specificato in questo intero di due byte.

Ma per far funzionare tutto questo, è chiaro che il mittente deve prima inviare un intero di due byte che rappresenta la lunghezza dei dati che seguiranno, quindi i dati stessi.

Quindi in pratica si chiama sopra la funzione su una matrice di byte di dimensione due prima (per ottenere la lunghezza dei dati), e quindi su una matrice di byte con dimensioni come indicato in tale numero intero di 2 byte (per ottenere i dati).

È possibile utilizzare questo per leggere da NetworkStream. Altri reading su questo argomento.

+0

Potrei qualcosa di simile, basta leggere un 2byte e convertirlo in numero intero e quindi leggere la dimensione inviata – null

+0

@ user3324670: Sì, dovresti andare in quel modo; puoi usare la funzione sopra per leggere –

+0

Sono un po 'preoccupato per questo però, se qualcuno mandasse una dimensione che non è corretta, tutto si rovinerebbe (suppongo che se voglio che un server sia sicuro mi devo preoccupare di molti altre cose). – null

Problemi correlati