2015-09-27 21 views
6

Ho creato un semplice server utilizzando la programmazione socket in C# che riceverà un file dal lato client. Il mio segmento di codice di esempio è riportato di seguito.Invio di alcuni vincoli al client dal server in C#

Desidero aggiungere alcune restrizioni. Voglio limitare le dimensioni del file (ad esempio 4   KB o 2   KB) e i formati di file consentiti (come .doc, .txt, .cpp, ecc.) Che verranno inviati al client non appena il client si connette al server in modo che il client possa inviare i file di conseguenza. Come lo farò?

Esempio segmento di codice:

using System; 
using System.Collections.Generic; 
using System.Net; 
using System.Net.Sockets; 
using System.IO; 
using System.Text; 

namespace FileTransfer 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      // Listen on port 1234 

      TcpListener tcpListener = new TcpListener(IPAddress.Any, 1234); 
      tcpListener.Start(); 

      Console.WriteLine("Server started"); 

      //Infinite loop to connect to new clients 
      while (true) 
      { 
       // Accept a TcpClient 
       TcpClient tcpClient = tcpListener.AcceptTcpClient(); 
           Console.WriteLine("Connected to client"); 
       byte[] data = new byte[1024]; 
       NetworkStream ns = tcpClient.GetStream(); 
       int recv = ns.Read(data, 0, data.Length); 
       StreamReader reader = new StreamReader(tcpClient.GetStream()); 

       //Will add some lines to add restrictions... 

      } 
     } 
    } 
} 

Quali linee aggiuntive verranno devo aggiungere al codice di inviare le restrizioni al cliente?

+1

Per limitare le dimensioni del file basta aggiungere il contatore delle dimensioni totali dei dati, come "contatore = = 0; contatore + = recv;". Quindi, se il limite è superato, rilasciare il client con il messaggio appropriato. –

+0

Voglio solo inviare la dimensione del file e i formati di file consentiti al client come sson come il client si connette in modo che il client possa inviare file di conseguenza @Alek Depler –

+0

Hm, quindi è necessario creare il proprio protocollo client-server. Sia il client che il server possono inviare dati tra loro, è necessario suddividere tutti i dati di due tipi: le istruzioni del protocollo tecnico e i dati stessi. La risposta di "CodeCaster" è corretta –

risposta

3

Sembra che tu stia commettendo il classico errore di presa. Il codice e la spiegazione forniti sembrano supporre che i socket gestiscano i messaggi. Non sono. Se utilizzato in questo modo, stai utilizzando streaming internet sockets, che fornisce uno stream , non i messaggi.

Non viene visualizzato alcun codice che trasmette l'invio effettivo, quindi suppongo che si limitino a pompare i dati di un file sull'altro lato e si chiuda la connessione. In quale altro modo saprai di aver trasferito con successo un intero file?

Questo insieme di regole che client e server devono seguire per scambiare utilmente i dati tramite socket è chiamato application protocol. È deve averne uno, altrimenti si invierà solo dati a $ deity sa dove, e non si avrà alcun controllo su di esso. Ciò significa che il server o il client sapranno cosa sta succedendo, invieranno e riceveranno i dati e sperano che tutto vada bene. Quindi non ci sono "poche righe" che devi aggiungere al tuo codice, dovrai ristrutturarlo interamente.

Ci sono molti modi per definire un protocollo di applicazione e molte opzioni tra cui scegliere, quindi vi mostrerò un arbitrario: una spiegazione testuale dei messaggi che hanno come prefisso un ID e una lunghezza del payload (se applicabile), sia in variabili numeriche non specificate. Ad esempio, è possibile scegliere interi interi senza segno a quattro byte little-endian.

I messaggi in questo formato sono noti come "Type/Length/Value" or TLV. Così definiamo questi messaggi:

ID Name   Direction   Description     Payload 
1 ServerHello Server -> Client The server sends this message None. 
            to every connecting client. Or maybe server or 
                    protocol version. 
2 MaxUpload Server -> Client Sent after the ServerHello. Maximum upload size 
                    in bytes. 
3 AllowedExts Server -> Client Allowed upload extensions,  The allowed extensions. 
            comma-separated. Sent after 
            MaxUpload message. 
10 IncomingFile Client -> Server There's a file coming.   The file name. 
11 FileUpload Client -> Server The file to upload.   The file data. 
            Sent after IncomingFile. 

Ora tutto quello che serve è quella di implementare questo protocollo di applicazione in server e client e il gioco è fatto.

È inoltre necessario decidere cosa fare se un client o un server non aderisce al prototipo. Ad esempio, può inviare un messaggio che non è possibile analizzare, un ID messaggio sconosciuto, una lunghezza messaggio che non si desidera supportare, un messaggio fuori ordine (FileUpload before IncomingFile) o un messaggio che non è conformare i messaggi inviati in precedenza, come un client che carica un file più grande di quanto il server abbia detto che accetterebbe o un'estensione non valida. Devi anche pensare a "conferma" o messaggi di risposta, come il server che dice al cliente "OK, vai avanti, invia il messaggio successivo".

Tutto sommato, si tratta di una molto ampia domanda e non ha risposto facilmente. Ho cercato di dirlo nel mio commento alla tua domanda, che è stata rimossa. Quindi qui hai la tua risposta.

È possibile ottenere ulteriori informazioni a riguardo sul Web, ad esempio Beej's Guide to Network Programming come collegato a Giorgi (assicurarsi di leggere l'intera guida) e Stephen Cleary's blog.

4

Fondamentalmente penso soprattutto avete bisogno di due cose:

  • definiscono protocollo di applicazione come suggerito in altra risposta

  • e gestire lettura parziale/scrive

Per la gestione letture parziali (Non sono sicuro di quanto sia necessaria tale funzione per write) è possibile utilizzare la funzione below:

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; 
    } 
} 

Thing è tradizionale Stream.Read() non garantisce di leggere tanti byte come hai detto che, questo metodo d'altra parte, farà in modo di aver letto tanti byte come specificato nel data.Length parametro. Quindi è possibile utilizzare tale funzione per implementare il protocollo dell'applicazione desiderato.

Alcuni informazioni relative a tali protocolli applicativi troverete here troppo


Ok questo è per esempio come il server potrebbe inviare limite di lunghezza del file e l'estensione del file:

// Send string 
string ext = ".txt"; 
byte [] textBytes = Encoding.ASCII.GetBytes(ext); 
ns.Write(textBytes, 0, textBytes.Length); 

// Now, send integer - the file length limit parameter 
int limit = 333; 
byte[] intBytes = BitConverter.GetBytes(limit); 
ns.Write(intBytes, 0, intBytes.Length); // send integer - mind the endianness 

Ma avrai comunque bisogno di un qualche tipo di protocollo altrimenti dovresti lasciare che il client legga il flusso "completo" e analizzare questi dati in un secondo momento, il che non è banale se i dati non hanno una lunghezza fissa ecc. altrimenti, in che modo il client distinguerà quale parte del messaggio è testo, quale numero intero?

+0

Avere un upvote per il collegamento alla guida di Beej. Chiunque sia anche lontanamente interessato alla programmazione di rete dovrebbe aver letto questa guida almeno una volta. – CodeCaster

+0

@CodeCaster: Sì, davvero, grazie. Questa guida contiene informazioni utili. L'OP dovrà gestire i messaggi di invio/ricezione parziali e pensare a qualche protocollo, come suggerisci tu, o TLV, ecc. –

+0

Il protocollo che suggerisco _is_ TLV, AFAIK. :-) – CodeCaster

Problemi correlati