Question

What I'm trying to do is to received a large number of bytes (about 5MB data) sent from the client side

Below is the code where data(byte[]) is received

    byte[] receivedBytesRaw = new byte[4000];
 //first, initialize network stream
 NetworkStream stream = client.GetStream();
    //The bytesNeeded is the size of bytes which is a protocol sent by the client side indicating the size of byte which will be sent
    int bytesNeeded = 4000;
    int bytesReceived = 0;
    do
    {
        int bytesRead = stream.Read(receivedBytesRaw, bytesReceived, bytesNeeded - bytesReceived);
        networkValidation.addBytesToList(receivedBytesRaw, ref receivedBytes);
        bytesReceived += bytesRead;
    } while (bytesReceived < bytesNeeded);

But now I'm stuck on a problem:

Everytime when data arrives, the do while loop loops for the first time, and the return value (i) is 26, then it loops again, this time, when it goes to " i = stream.Read(receivedBytesRaw, 0, receivedBytesRaw.Length);", the program seems waiting for the client side to send data and have no response, also, when I check "receivedBytesRaw", the data was incomplete, only the first 13 bytes was received, the remaining space in the byte array remains null, and the stream.DataAvailable is false

Why the server side received incomplete data? Note: when I try to send small data (a string), it's ok

=====================================================================

Edited

Below is the client side code which sends data:

   private int sendData(byte[] dataSend, string IP, int portNumber)
    {
        TcpClient clientSide = new TcpClient();
        int result = -1;
        try
        {
            clientSide.Connect(IP, portNumber);
        }
        catch (Exception ex)
        {
            return 2;
        }
        NetworkStream netStream = clientSide.GetStream();
        if (netStream.CanWrite)
        {
            byte[] replyMsg = new byte[1024];

            netStream.Write(dataSend, 0, dataSend.Length);
            netStream.Flush();
            result = 0;
        }
        else
        {
            result = 1;
        }
        return result;
    }
Était-ce utile?

La solution

Because it's a stream, and can be partial received. Are you sure you are always receiving packages with te size of 2048 bytes?

     int i = 0;
     int bytesNeeded = 200;
     int bytesReceived = 0;
     do
      {
        //read byte from client
        int bytesRead = stream.Read(receivedBytesRaw, bytesReceived, bytesNeeded-bytesReceived);
        bytesReceived += bytesRead;
        // merge byte array to another byte array
      } while (bytesReceived < bytesNeeded);

I think you need a frame protocol, try create a protocol like, writing the size of the data that follows.

example: (psuedo)

void SendData(byte[] data)
{
    // get the 4 bytes of a int value.
    byte[] dataLength = BitConverter.GetBytes(data.Lenght);
    // write the length to the stream.
    stream.Write(dataLength, 0, dataLength.Length);
    // write the data bytes.
    stream.Write(data, 0, data.Length);
}

void Receive()
{
    // read 4 bytes from the stream.
    ReadBuffer(buffer, 4);
    // convert those 4 bytes to an int.
    int dataLength = BitConverter.ToInt32(buffer, 0);
    // read bytes with dataLength as count.
    ReadBuffer(buffer, dataLength);    
}

// read until the right amount of bytes are read.
void ReadBuffer(byte[] buffer, int length)
{
    int i = 0;
    int bytesNeeded = length;
    int bytesReceived = 0;
    do
    {
        //read byte from client
        int bytesRead = stream.Read(buffer, bytesReceived, bytesNeeded-bytesReceived);
        bytesReceived += bytesRead;
        // merge byte array to another byte array
    } while (bytesReceived < bytesNeeded);   //  <- you should do this async.
}

This is just an example..

Autres conseils

Another solution you could try is using async reads. I made a class that reads until all bytes are read. If it isn't a problem that the complete file is read, you could try this:

Example:

This example show that you can read a simple protocol. ReadPacket handles a length + data message. So the sender will first send an int value containing the length of data that follows. The StartReading method reads a filename and the filedata. It will store up to 10mb max filesize. But this isn't originally designed for receiving files.

const int MaxFileSize = 10 * 1024 * 1024;

private void Example()
{
    Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    socket.Connect("localhost", 12345);

    StartReading(socket);
}

private void StartReading(Socket socket)
{
    ReadPacket(socket, (filenameData) =>
    {
        if (filenameData.Count == 0)
        {
            // disconnected
            return;
        }

        // parse the filename
        string filename = Encoding.UTF8.GetString(filenameData.Array, filenameData.Offset, filenameData.Count);
        Trace.WriteLine("Receiving file :" + filename);

        ReadPacket(socket, (fileData) =>
        {
            if (fileData.Count == 0)
            {
                // disconnected
                return;
            }

            Trace.WriteLine("Writing file :" + filename);

            // write to the file
            using (FileStream stream = new FileStream(filename, FileMode.Create, FileAccess.Write))
                stream.Write(fileData.Array, fileData.Offset, fileData.Count);

            // start waiting for another packet.
            StartReading(socket);
        });
    });
}

private void ReadPacket(Socket socket, Action<ArraySegment<byte>> endRead)
{
    // read header. (length of data) (4 bytes)
    EasySocketReader.ReadFromSocket(socket, 4, (headerBufferSegment) =>
    {
        // if the ReadFromSocket returns 0, the socket is closed.
        if (headerBufferSegment.Count == 0)
        {
            // disconnected;
            endRead(new ArraySegment<byte>());
            return;
        }

        // Get the length of the data that follows
        int length = BitConverter.ToInt32(headerBufferSegment.Array, headerBufferSegment.Offset);

        // Check the length
        if (length > MaxFileSize)
        {
            // disconnect
            endRead(new ArraySegment<byte>());
            return;
        }

        // Read bytes specified in length.
        EasySocketReader.ReadFromSocket(socket, length, (dataBufferSegment) =>
        {
            // if the ReadFromSocket returns 0, the socket is closed.
            if (dataBufferSegment.Count == 0)
            {
                endRead(new ArraySegment<byte>());
                return;
            }

            endRead(dataBufferSegment);
        });

    });

}

The EasySocketReader class can be found on my blog: http://csharp.vanlangen.biz/network-programming/async-sockets/asyncsocketreader/

The original EasyPacketReader can be found here: http://csharp.vanlangen.biz/network-programming/async-sockets/easypacketreader/

For the sending part, you could use something like this:

private void SendFile(Socket socket, string filename)
{
    byte[] filenameData = Encoding.UTF8.GetBytes(filename);
    socket.Send(BitConverter.GetBytes(filenameData.Length));
    socket.Send(filenameData);

    int fileSize;
    byte[] fileData;

    using (FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read))
    {
        fileSize = (int)stream.Length;

        if (fileSize > MaxFileSize)
            throw new ArgumentOutOfRangeException("File too big");

        fileData = new byte[fileSize];

        stream.Read(fileData, 0, fileSize);
    }

    socket.Send(BitConverter.GetBytes(fileSize));
    socket.Send(fileData);
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top