2015-09-27 7 views
6

Stworzyłem prosty serwer przy użyciu programowania gniazd w języku C#, który otrzyma plik od strony klienta. Mój przykładowy segment kodu podano poniżej.Wysyłanie niektórych ograniczeń do klienta z serwera w C#

Chcę dodać pewne ograniczenia. Chcę ograniczyć rozmiar pliku (np. 4   KB lub 2KB) i dopuszczalnych formatów plików (takich jak .doc, .txt, .cpp itp.), Które zostaną wysłane do klienta tak szybko, jak klient łączy się z serwerem, aby klient mógł odpowiednio wysyłać pliki. Jak to zrobię?

Przykładowy segment kodu:

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... 

      } 
     } 
    } 
} 

Jakie dodatkowe linie będę musiał dodać do kodu wysłać ograniczenia do klienta?

+1

Aby ustawić limit rozmiaru pliku, po prostu dodaj całkowity licznik rozmiaru danych, np. "Int counter = 0; counter + = recv;". Następnie, jeśli limit został przekroczony, klient zostaje upuszczony z odpowiednim komunikatem. –

+0

Chcę tylko wysłać rozmiar pliku i dopuszczalnych formatów plików do klienta jako sson, jak klient łączy się, aby klient mógł wysyłać pliki odpowiednio @Alek Depler –

+0

Hm, to musisz stworzyć własny protokół klient-serwer. Zarówno klient, jak i serwer mogą wysyłać dane do siebie nawzajem, należy podzielić wszystkie dane według dwóch typów: instrukcji protokołu technicznego i samych danych. Odpowiedź "CodeCaster" jest poprawna. –

Odpowiedz

3

Wygląda na to, że popełniłeś klasyczny błąd gniazda. Podany kod i objaśnienie wydaje się zakładać obsadę gniazd w wiadomościach. One nie są. Użyty w ten sposób, używasz streaming internet sockets, który zapewnia strumień , a nie wiadomości.

Nie pokazujesz żadnego kodu, który faktycznie wysyła dane, więc domyślam się, że po prostu pompujesz dane pliku na drugą stronę i zamykasz połączenie. Jak inaczej będziesz wiedział, że udało ci się przenieść cały plik?

Ten zestaw reguł, które klient i serwer muszą przestrzegać, aby w sposób użyteczny wymieniać dane za pośrednictwem gniazd, nazywa się application protocol. Musisz będzie będzie musiał mieć jeden, w przeciwnym razie będziesz tylko wysyłanie danych do bóstwa $ wie, gdzie, i nie będziesz mieć nad nim żadnej kontroli. Oznacza to, że serwer i klient będą wiedzieli, co się dzieje, będą tylko wysyłać i odbierać dane i mieć nadzieję, że wszystko pójdzie dobrze. Więc nie ma "kilku linii", które musisz dodać do swojego kodu, będziesz musiał całkowicie go zrestrukturyzować.

Istnieje wiele sposobów definiowania protokołu aplikacji i wielu opcji do wyboru, więc pokażę ci dowolny: wyjaśnienie tekstowe wiadomości poprzedzonych identyfikatorem i długością ładunku (jeśli dotyczy), zarówno w nieokreślonych zmiennych numerycznych. Można na przykład wybrać czterobajtowe liczby całkowite z małych endianów.

Wiadomości w tym formacie są nazywane "Type/Length/Value" or TLV. więc określić te wiadomości:

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. 

Teraz wszystko, co wymagane jest wdrożenie tego protokołu w aplikacji serwera i klienta i gotowe.

Musisz także zdecydować, co zrobić, jeśli klient lub serwer nie przestrzega prototolu. Może na przykład wysłać wiadomość, której nie można przeanalizować, nieznany identyfikator wiadomości, długość komunikatu, którego nie chcesz obsługiwać, komunikat o niesłudze (FileUpload before IncomingFile) lub komunikat, który nie jest dostosuj komunikaty wysyłane wcześniej, tak jak klient przesyłający większy plik, niż serwer zgodził się na to, lub zaakceptował nieprawidłowe rozszerzenie. Musisz także myśleć o komunikatach "potwierdzenie" lub o odpowiedzi, takich jak serwer, który mówi klientowi "OK, śmiało, wyślij następną wiadomość".

Podsumowując, jest to szerokie pytanie o szerokim zakresie i niełatwo odpowiedzieć. Próbowałem odpowiedzieć na to w moim komentarzu do twojego pytania, które zostało usunięte. Tutaj masz odpowiedź.

Możesz dowiedzieć się więcej na ten temat w Internecie, na przykład Beej's Guide to Network Programming w powiązaniu z Giorgi (koniecznie przeczytaj cały przewodnik) i Stephen Cleary's blog.

4

Zasadniczo myślę, że przede wszystkim potrzebne są dwie rzeczy:

  • definiują protokół aplikacji jak zasugerowano w drugiej odpowiedzi

  • i uchwyt częściowy odczytu/pisze

Dla obsługi częściowy czyta (nie wiesz, ile takiej funkcji jest potrzebne dla write) możesz użyć funkcji podobnej do 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 jest tradycyjny Stream.Read() nie gwarantuje czytać jak wiele bajtów, jak to powiedział, metoda ta z drugiej strony, zapewni się czytać jak najwięcej bajtów, jak określono w data.Length parametru. Dlatego możesz użyć takiej funkcji, aby zaimplementować żądany protokół aplikacji.

Niektóre istotne informacje o takich protokołów aplikacji znajdziesz here zbyt


Ok to jest na przykład w jaki sposób serwer może wysłać limitu długości pliku i rozszerzenie pliku:

// 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 

Ale nadal będziesz potrzebował jakiegoś protokołu, inaczej powinieneś pozwolić klientowi odczytać "pełny" strumień i parsować te dane później, co nie jest banalne, jeśli dane nie mają ustalonej długości itp. w przeciwnym razie, w jaki sposób klient rozróżni, która część wiadomości jest tekstem, która jest liczbą całkowitą?

+0

Przekaż wiadomość, aby uzyskać link do przewodnika Beej. Każdy, kto choć trochę zainteresowany jest programowaniem sieci, powinien przeczytać ten przewodnik co najmniej raz. – CodeCaster

+0

@CodeCaster: Tak, rzeczywiście, dzięki. Ten przewodnik zawiera przydatne informacje. OP będzie musiał obsługiwać częściowe wysyłanie/odbiór i myśleć o jakimś protokole, jak sugerujesz, lub TLV, itp. –

+0

Protokół, który proponuję _jest_ TLV, AFAIK. :-) – CodeCaster