Question

Je veux utiliser la TcpClient et TcpListener pour envoyer un fichier mp3 sur un réseau. Je mis en œuvre une solution de ce en utilisant les sockets, mais il y avait quelques problèmes, donc je suis étudie une nouvelle / meilleure façon d'envoyer un fichier.

Je crée un tableau d'octets qui ressemble à ceci: length_of_filename | nom | fichier

Cela devrait ensuite être transmis à l'aide des classes mentionnées ci-dessus, mais sur le côté serveur du tableau d'octets que je lis est complètement foiré et je ne sais pas pourquoi.

La méthode que j'utilise pour envoyer:

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

Ensuite, du côté du serveur, il se présente comme suit:

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

Quelqu'un peut-il voir quelque chose que je manque / faire le mal?

Était-ce utile?

La solution

La corruption est causée par le code suivant sur le serveur:

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

stream.Read remplira pas toujours le tampon de bytes. Il ne sera pas remplie si le socket TCP n'a pas plus de données, ou lors de la lecture du dernier morceau du message (à moins qu'il soit un multiple exact de la taille de la mémoire tampon).

L'appel data.AddRange ajoute tout de bytes (en faisant l'hypothèse qu'il est toujours plein). En conséquence, cela finira par ajouter de temps en temps les données de l'appel précédent à stream.Read. Pour y remédier, vous devez stocker le nombre d'octets renvoyés par Read et ajouter que ce nombre d'octets:

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

Notez que vous pouvez restructurer votre code pour améliorer les performances et l'utilisation mémoire (et sans doute faire plus facile à lire la suite). Au lieu de lire toutes les données en mémoire sur le client avant de vous envoyer pouvez simplement écrire directement au NetworkStream. Sur le serveur, vous n'avez pas besoin de copier tout du flux dans la mémoire. Vous pouvez lire la longueur du nom de fichier de 4 octets et le décoder, puis lire et décoder le nom du fichier et enfin copier le reste du cours d'eau directement à un FileStream (le BinaryWriter est inutile).

Il est également intéressant de noter que vous créez le fichier de sortie avec FileMode.Append. Cela signifie que chaque fichier envoyé sera ajouté à la copie précédente du même nom. Vous pouvez utiliser FileMode.Create à la place, qui remplacera si le fichier existe déjà.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top