Frage

Ich mag die TcpClient und TcpListener verwenden, um eine MP3-Datei über ein Netzwerk zu senden. Ich implementierte eine Lösung dieser Sockets, aber es gab einige Probleme, so dass ich eine neue / bessere Weise untersuchte eine Datei zu senden.

Ich erstelle ein Byte-Array, das wie folgt aussieht: length_of_filename | Dateiname | Datei

Dies sollte dann übertragen werden, um die oben genannten Klassen, noch auf der Serverseite das Byte-Array ich gelesen wird völlig verkorkste und ich bin mir nicht sicher, warum.

Die Methode, die ich verwende zu senden:

 public static void Send(String filePath)
    {
        try
        {
            IPEndPoint endPoint = new IPEndPoint(Settings.IpAddress, Settings.Port + 1);
            Byte[] fileData = File.ReadAllBytes(filePath);
            FileInfo fi = new FileInfo(filePath);

            List<byte> dataToSend = new List<byte>();
            dataToSend.AddRange(BitConverter.GetBytes(Encoding.Unicode.GetByteCount(fi.Name))); // length of filename
            dataToSend.AddRange(Encoding.Unicode.GetBytes(fi.Name)); // filename
            dataToSend.AddRange(fileData); // file binary data


            using (TcpClient client = new TcpClient())
            {
                client.Connect(Settings.IpAddress, Settings.Port + 1);

                // Get a client stream for reading and writing.
                using (NetworkStream stream = client.GetStream())
                {
                    // server is ready 
                    stream.Write(dataToSend.ToArray(), 0, dataToSend.ToArray().Length);
                }
            }

        }
        catch (ArgumentNullException e)
        {
            Debug.WriteLine(e);
        }
        catch (SocketException e)
        {
            Debug.WriteLine(e);
        }
    }
}

Dann auf der Serverseite sieht es wie folgt aus:

    private void Listen()
    {
        TcpListener server = null;
        try
        {
            // Setup the TcpListener
            Int32 port = Settings.Port + 1;
            IPAddress localAddr = IPAddress.Parse("127.0.0.1");

            // TcpListener server = new TcpListener(port);
            server = new TcpListener(localAddr, port);

            // Start listening for client requests.
            server.Start();

            // Buffer for reading data
            Byte[] bytes = new Byte[1024];
            List<byte> data;

            // Enter the listening loop.
            while (true)
            {
                Debug.WriteLine("Waiting for a connection... ");
                string filePath = string.Empty;

                // Perform a blocking call to accept requests.
                // You could also user server.AcceptSocket() here.
                using (TcpClient client = server.AcceptTcpClient())
                {
                    Debug.WriteLine("Connected to client!");
                    data = new List<byte>();

                    // Get a stream object for reading and writing
                    using (NetworkStream stream = client.GetStream())
                    {
                        // Loop to receive all the data sent by the client.
                        while ((stream.Read(bytes, 0, bytes.Length)) != 0)
                        {
                            data.AddRange(bytes);
                        }
                    }
                }

                int fileNameLength = BitConverter.ToInt32(data.ToArray(), 0);
                filePath = Encoding.Unicode.GetString(data.ToArray(), 4, fileNameLength);
                var binary = data.GetRange(4 + fileNameLength, data.Count - 4 - fileNameLength);

                Debug.WriteLine("File successfully downloaded!");

                // write it to disk
                using (BinaryWriter writer = new BinaryWriter(File.Open(filePath, FileMode.Append)))
                {
                    writer.Write(binary.ToArray(), 0, binary.Count);
                }
            }
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex);
        }
        finally
        {
            // Stop listening for new clients.
            server.Stop();
        }
    }

Kann jemand sehen etwas, das mir fehlt / falsch machen?

War es hilfreich?

Lösung

Die Korruption durch den folgenden Code auf dem Server verursacht wird:

// Loop to receive all the data sent by the client.
while ((stream.Read(bytes, 0, bytes.Length)) != 0)
{
    data.AddRange(bytes);
}

stream.Read nicht immer füllen die bytes Puffer. Es wird nicht gefüllt, wenn die TCP-Socket keine Daten mehr zur Verfügung hat, oder wenn das letzte Stück der Nachricht zu lesen (es sei denn, es ist ein Vielfaches der Puffergröße).

Der data.AddRange Aufruf fügt alles von bytes (unter der Annahme, dass es immer voll ist). Als Ergebnis wird dies am Ende gelegentlich Daten aus dem vorherigen Aufruf zum Hinzufügen stream.Read. Um dies zu beheben, müssen Sie die Anzahl von Bytes von Read zurück speichern und fügen Sie nur diese Anzahl von Bytes:

int length;

while ((length = stream.Read(bytes, 0, bytes.Length)) != 0)
{
    var copy = new byte[length];
    Array.Copy(bytes, 0, copy, 0, length);
    data.AddRange(copy);
}

Beachten Sie, dass Sie vielleicht Ihren Code restrukturieren Leistung und Speichernutzung zu verbessern (und wahrscheinlich auch leichter machen es als Folge zu lesen). Statt auf dem Client alle Daten in den Speicher zu lesen, bevor das Senden Sie einfach direkt an den NetworkStream schreiben kann. Auf dem Server müssen Sie nicht alles aus dem Strom in dem Speicher kopieren. Sie können die 4-Byte-Dateinamenlänge abgelesen und es entschlüsseln, dann lesen und die Dateinamen entschlüsseln und schließlich den Rest des Stroms kopiert direkt zu einem FileStream (die BinaryWriter ist nicht erforderlich).

Es ist auch erwähnenswert, dass Sie die Ausgabedatei mit FileMode.Append erstellen. Dies bedeutet, dass jede Datei auf die vorherige Kopie des gleichen Namen angehängt wird gesendet. Sie wollen stattdessen FileMode.Create verwenden, die überschrieben werden, wenn die Datei bereits vorhanden ist.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top