Sending big files in socket programming c# [duplicate]

倾然丶 夕夏残阳落幕 提交于 2019-12-06 00:21:44

The problem is that you ignore the return value from Receive(). There is no guarantee what-so-ever that your buffer will be completely filled.

The return value tells you how much data that the socket actually read from the network. Adjust your receiving code so it's taken into account. Same goes for the send. If the internal socket buffer gets full it will report less bytes sent than you have requested to send.

Other than that, I suggest you start to give your variables meaningful names. Your code is not very readable as is.

Here is a better receive routine:

var fileBuffer = new byte[size];
var receiveBuffer = new byte[2048];
var bytesLeftToReceive = size;
var fileOffset = 0;

while (bytesLeftToReceive > 0)
{
    //receive
    var bytesRead = client.Receive(receiveBuffer);
    if (bytesRead == 0) 
        throw new InvalidOperationException("Remote endpoint disconnected");

    //if the socket is used for other things after the file transfer
    //we need to make sure that we do not copy that data
    //to the file
    int bytesToCopy = Math.Min(bytesRead, bytesLeftToReceive);

    // copy data from our socket buffer to the file buffer.
    Buffer.BlockCopy(receiveBuffer, 0, bytesLeftToReceive, fileBuffer, fileOffset);

    //move forward in the file buffer
    fileOffset += bytesToCopy;

    //update our tracker.
    bytesLeftToReceive -= bytesToCopy;
}

However, since you are transferring large files, isn't it better to write it directly to a file stream?

var stream = File.Create(@"C:\path\to\file.dat");
var receiveBuffer = new byte[2048];
var bytesLeftToReceive = size;

while (bytesLeftToReceive > 0)
{
    //receive
    var bytesRead = client.Receive(receiveBuffer);
    if (bytesRead == 0) 
        throw new InvalidOperationException("Remote endpoint disconnected");

    //if the socket is used for other things after the file transfer
    //we need to make sure that we do not copy that data
    //to the file
    int bytesToCopy = Math.Min(bytesRead, bytesLeftToReceive);

    // write to file
    stream.Write(receiveBuffer, 0, bytesToCopy);

    //update our tracker.
    bytesLeftToReceive -= bytesToCopy;
}

On the send side I would do something like this:

// read directly from the file to reduce memory usage.
var fileName = @"....";
using (var file = File.OpenRead(fileName))
{
    var sendBuffer = new byte[2048];
    var fileSize = BitConverter.GetBytes((int)file.Length);
    server.Send(fileSize, fileSize.Length, SocketFlags.None);

    var bytesLeftToTransmit = fileSize;
    while (bytesLeftToTransmit > 0)
    {
        var dataToSend = file.Read(sendBuffer, 0, sendBuffer.Length);
        bytesLeftToTransmit -= dataToSend;

        //loop until the socket have sent everything in the buffer.
        var offset=0;
        while (dataToSend > 0)
        {
            var bytesSent = socket.Send(sendBuffer, offset, dataToSend);
            dataToSend -= bytesSent;
            offset += bytesSent;
        }
    }
}

Finally you have a Socket.SendFile which have been optimized to send files. You can invoke it at any time for an open socket.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!