Farik
Farik

Reputation: 25

Sending multiple files Client & Server

I have a Client and Server code for files sending. For some reason I need to receive at client and send from Server...

Everything work perfectly, in some cases all files sent and received perfectly. In another cases after sending a few files programm crashes. Don't understand where the problem...

Errors:

client colsole

server console

client

// client code
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;

using System.Net;
using System.Net.Sockets;
using System.Text;

class Client003
{
    const string destFilePath = @"..\..\..\";
    const int BufferSize = 1024;

    public static void StartReceiving()
    {
        // Data buffer for sending data.
        byte[] buffer;

        // FileStream to read data
        FileStream fileStream;
        int fileNameLen = 0;
        string fileName = "";
        long fileLen = 0;
        int NoOfPackets = 0;
        int receivedBytes = 0;
        int i, j;

        // Connect to a remote device.
        try
        {
            // Establish the remote endpoint for the socket.
            // This example uses port 11000 on the local computer.
            IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
            IPAddress ipAddress = ipHostInfo.AddressList[0];
            IPEndPoint remoteEP = new IPEndPoint(ipAddress, 11000);

            // Create a TCP/IP  socket.
            Socket receiver = new Socket(AddressFamily.InterNetwork,
                SocketType.Stream, ProtocolType.Tcp);

            // Connect the socket to the remote endpoint. Catch any errors.
            try
            {
                receiver.Connect(remoteEP);

                buffer = new byte[4];
                receiver.Receive(buffer, 4, 0);
                int filesNumber = BitConverter.ToInt32(buffer, 0);

                for (i = 0; i < filesNumber; i++)
                {
                    buffer = new byte[4];
                    receiver.Receive(buffer, 4, 0);
                    fileNameLen = BitConverter.ToInt32(buffer, 0);
                    // --
                    buffer = new byte[fileNameLen];
                    receiver.Receive(buffer, fileNameLen, 0);
                    fileName = Encoding.UTF8.GetString(buffer);
                    // --
                    buffer = new byte[8];
                    receiver.Receive(buffer, 8, 0);
                    fileLen = BitConverter.ToInt64(buffer, 0);
                    // --
                    NoOfPackets = Convert.ToInt32(Math.Ceiling(
                        Convert.ToDouble(fileLen) / Convert.ToDouble(BufferSize) ));
                    fileStream = new FileStream(destFilePath + fileName, FileMode.OpenOrCreate, FileAccess.Write);
                    receivedBytes = 0;
                    // --
                    for (j = 0; j < NoOfPackets; j++)
                    {
                        if (fileLen > BufferSize)
                        {
                            buffer = new byte[BufferSize];
                            receivedBytes = receiver.Receive(buffer, BufferSize, 0);
                            fileStream.Write(buffer, 0, receivedBytes);
                            fileLen -= BufferSize;
                        }
                        else
                        {
                            buffer = new byte[fileLen];
                            receivedBytes = receiver.Receive(buffer, (int)fileLen, 0);
                            fileStream.Write(buffer, 0, receivedBytes);
                        }
                    }
                    fileStream.Close();
                }
                // Release the socket.
                receiver.Shutdown(SocketShutdown.Both);
                receiver.Close();

            }
            catch (ArgumentNullException ane)
            {
                Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
            }
            catch (SocketException se)
            {
                Console.WriteLine("SocketException : {0}", se.ToString());
            }
            catch (Exception e)
            {
                Console.WriteLine("Unexpected exception : {0}", e.ToString());
            }

        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    public static int Main(String[] args)
    {
        StartReceiving();
        return 0;
    }
}

server

//server code
using System;
using System.IO;

using System.Net;
using System.Net.Sockets;
using System.Text;

using System.Collections.Generic;

class Server003
{
    public static void StartListening()
    {
        // Data buffer for incoming data.
        byte[] buffer;
        byte[] fileNameByte;
        byte[] fileNameLenByte;
        byte[] fileLenByte;

        // FileStream to write data
        FileStream fileStream;
        Int64 fileLen = 0;
        int NoOfPackets = 0;
        int readBytes = 0;
        int i;

        // Establish the local endpoint for the socket.
        // Dns.GetHostName returns the name of the 
        // host running the application.
        IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
        IPAddress ipAddress = ipHostInfo.AddressList[0];
        IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);

        // Create a TCP/IP socket.
        Socket listener = new Socket(AddressFamily.InterNetwork,
            SocketType.Stream, ProtocolType.Tcp);

        // Bind the socket to the local endpoint and 
        // listen for incoming connections.
        try
        {
            listener.Bind(localEndPoint);
            listener.Listen(10);

            // Start listening for connections.
            Console.WriteLine("Waiting for a connection...");
            // Program is suspended while waiting for an incoming connection.
            Socket handler = listener.Accept();

            Int32 filesNumber = binFilesNames.Count;
            byte[] filesNumberByte = BitConverter.GetBytes(filesNumber);
            handler.Send(filesNumberByte);
            // --
            foreach (string binName in binFilesNames)
            {
                fileNameByte = Encoding.UTF8.GetBytes(binName);
                fileNameLenByte = BitConverter.GetBytes(fileNameByte.Length);
                handler.Send(fileNameLenByte);
                handler.Send(fileNameByte);
                // --
                fileStream = new FileStream(sourceFilePath + binName, FileMode.Open, FileAccess.Read);
                fileLen = fileStream.Length;
                fileLenByte = BitConverter.GetBytes(fileLen);
                handler.Send(fileLenByte);
                // --
                NoOfPackets = Convert.ToInt32(Math.Ceiling(
                    Convert.ToDouble(fileLen) / Convert.ToDouble(BufferSize)));
                for (i = 0; i < NoOfPackets; i++)
                {
                    if (fileLen > BufferSize)
                    {
                        buffer = new byte[BufferSize];
                        // reeding data from file and writing it to the bytes "buffer"
                        readBytes = fileStream.Read(buffer, 0, BufferSize);
                        // send bytes from "buffer"
                        handler.Send(buffer, readBytes, SocketFlags.None);
                        fileLen -= BufferSize;
                    }
                    else
                    {
                        buffer = new byte[fileLen];
                        // reeding data from file and writing it to the bytes "buffer"
                        readBytes = fileStream.Read(buffer, 0, (int)fileLen);
                        // send bytes from "buffer"
                        handler.Send(buffer, readBytes, SocketFlags.None);
                    }
                }
                fileStream.Close();
            }
            // Release the socket.
            handler.Shutdown(SocketShutdown.Both);
            handler.Close();

        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }

        Console.WriteLine("\nPress ENTER to continue...");
        Console.Read();
    }


    public static List<string> GetFiles()
    {
        var dir = new DirectoryInfo(sourceFilePath);          // folder with files 
        var files = new List<string>();                 // List with file names 

        foreach (FileInfo file in dir.GetFiles("T*260000.bin"))
        {
            files.Add(Path.GetFileName(file.FullName));
        }

        return files;
    }

    public static int Main(String[] args)
    {
        binFilesNames = GetFiles();
        StartListening();

        return 0;
    }

    const string sourceFilePath = @"..\..\..\Binaries\";
    static List<string> binFilesNames;
    const int BufferSize = 1024;
}

UPD: I took into account the moments that pointed LB2. Here is the receive part and it works as it need:

while ((receivedBytes = receiver.Receive(buffer)) > 0)    // receive bytes to "buffer"
{
    var tmpBuff = buffer.Take(receivedBytes);   // takes first receivedBytes elements
    bufferList.AddRange(tmpBuff);
}

But I don't understand how sending work. When I send whole data at once - all ok, but when i trying to send partially it crashes:

This works and whole data sent:

handler.Send(buffer);

This one crashes:

int sentBytes = 0;
int sumSentBytes = 0;
do
{
    // send bytes from "buffer"
    sentBytes = handler.Send(buffer, sumSentBytes, BufferSize, SocketFlags.None);
    sumSentBytes += sentBytes;
}
while (sentBytes > 0);

So what is the best way to construct sending of large amounts of data (in my case about 20Mb, but it depends)?

Upvotes: 0

Views: 3379

Answers (2)

CodeCaster
CodeCaster

Reputation: 151586

I guess you get an exception:

ArgumentOutOfRangeException: size is greater than the length of buffer minus the value of the offset parameter.

You'll have to subtract the bytes already sent from the size parameter:

int bytesToSend = BufferSize - sumSentBytes;
sentBytes = handler.Send(buffer, sumSentBytes, bytesToSend, SocketFlags.None);

Upvotes: 1

LB2
LB2

Reputation: 4860

There are multiple bugs in the code to be able to pinpoint specifically where this particular came from. Here are a few things you should be aware and where code needs clean up:

  • Socket class is IDisposable and thus should be wrapped in using. (I don't know if this is full program, or just a snippet with a driver main(), but if you call StartReceiving enough times, it'll leak memory).
  • FileStream (that you have a in a for loop) is IDisposable and thus should be wrapped in using. (Call to .Close() may actually clean up enough, but still better to use using.)
  • Use of Socket.Receive() is incorrect. You cannot assume that you receive as many bytes as you requested. Receive() returns either 0 if connection is lost, or number of bytes (upto requested count) that are currently available in the receive buffer. So as you go through:

                buffer = new byte[fileNameLen];
                receiver.Receive(buffer, fileNameLen, 0);
                fileName = Encoding.UTF8.GetString(buffer);
                // --
                buffer = new byte[8];
                receiver.Receive(buffer, 8, 0);
                fileLen = BitConverter.ToInt64(buffer, 0);
    

... it is quite possible that you only read part of fileName bytes, get partial fileName, and then remainder bytes for filename are actually (incorrectly) interpreted as fileLen.

  • You correctly use receivedBytes to copy received bytes to file stream, but then you incorrectly decrement fileLen by BufferSize rather than receivedBytes, thus corrupting your file by possibly writing only part of the stream, in this part of the code:

                        receivedBytes = receiver.Receive(buffer, BufferSize, 0);
                        fileStream.Write(buffer, 0, receivedBytes);
                        fileLen -= BufferSize;
    
  • You keep reallocating new byte[] in a loop for each call to .Receive which is unnecessary. You can keep reusing the same buffer.

  • For the server code, exception screenshot that you posted has ? for the message (likly encoding issues). Please trap and post the actual message.

These are just a few things that I spotted by casual review. Whether some of these are the culprits, or there is some other issue is hard to ascertain with these issues present.

Upvotes: 1

Related Questions