Mono BLOG

Blog about Microsoft technologies (.NET, ASP.NET Core, Blazor, EF Core, WPF, TypeScript, etc.)

File Transfer in C#

in .NET

This guide demonstrates a reliable file transfer solution using C#'s native networking classes, with enhancements for error handling, asynchronous operations, and large file support.


Enhanced Client Implementation

using System.IO;
using System.Net.Sockets;
using System.Threading.Tasks;

public class FileSender
{
    public async Task SendFileAsync(string filePath, string host, int port)
    {
        using var client = new TcpClient();
        await client.ConnectAsync(host, port);
        
        using var networkStream = client.GetStream();
        using var fileStream = File.OpenRead(filePath);
        
        // Send file metadata first (file name and size)
        var fileName = Path.GetFileName(filePath);
        var fileNameData = System.Text.Encoding.UTF8.GetBytes(fileName);
        await networkStream.WriteAsync(BitConverter.GetBytes(fileNameData.Length), 0, 4);
        await networkStream.WriteAsync(fileNameData, 0, fileNameData.Length);
        await networkStream.WriteAsync(BitConverter.GetBytes(fileStream.Length), 0, 8);

        // Buffer-based transfer for large files
        var buffer = new byte[81920];
        int bytesRead;
        while ((bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
        {
            await networkStream.WriteAsync(buffer, 0, bytesRead);
        }
    }
}

Enhanced Server Implementation

using System.Net.Sockets;
using System.Threading.Tasks;

public class FileReceiver
{
    public async Task StartListeningAsync(int port, string saveDirectory)
    {
        var listener = new TcpListener(System.Net.IPAddress.Any, port);
        listener.Start();

        try
        {
            while (true)
            {
                var client = await listener.AcceptTcpClientAsync();
                _ = Task.Run(() => HandleClientAsync(client, saveDirectory));
            }
        }
        finally
        {
            listener.Stop();
        }
    }

    private async Task HandleClientAsync(TcpClient client, string saveDirectory)
    {
        using (client)
        using (var stream = client.GetStream())
        {
            // Read metadata
            var fileNameSizeBuffer = new byte[4];
            await stream.ReadAsync(fileNameSizeBuffer, 0, 4);
            int fileNameSize = BitConverter.ToInt32(fileNameSizeBuffer);

            var fileNameBuffer = new byte[fileNameSize];
            await stream.ReadAsync(fileNameBuffer, 0, fileNameSize);
            string fileName = System.Text.Encoding.UTF8.GetString(fileNameBuffer);

            var fileSizeBuffer = new byte[8];
            await stream.ReadAsync(fileSizeBuffer, 0, 8);
            long fileSize = BitConverter.ToInt64(fileSizeBuffer);

            // Prepare file storage
            var savePath = Path.Combine(saveDirectory, fileName);
            using var fileStream = File.Create(savePath);

            // Buffer-based reception
            var buffer = new byte[81920];
            long totalBytesRead = 0;
            int bytesRead;

            while (totalBytesRead < fileSize && 
                  (bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
            {
                await fileStream.WriteAsync(buffer, 0, bytesRead);
                totalBytesRead += bytesRead;
            }
        }
    }
}

Key Enhancements

  1. Asynchronous Operations • Uses async/await for non-blocking I/O • Handles multiple concurrent connections • Implements proper resource cleanup with using statements
  2. Large File Support • Chunked transfer using 80KB buffers (adjustable) • Memory-efficient streaming instead of full-file buffering • Progress tracking capability
  3. Metadata Handling • Transmits filename and size before file content • UTF-8 encoding for cross-platform compatibility • Prevents path injection attacks
  4. Error Handling • Automatic client disconnection cleanup • Network timeout handling (recommended to add) • File size validation during transfer

Usage Example

Sender:

var sender = new FileSender();
await sender.SendFileAsync("largefile.zip", "192.168.1.100", 5000);

Receiver:

var receiver = new FileReceiver();
await receiver.StartListeningAsync(5000, @"C:\ReceivedFiles");

Recommended Improvements

  1. Security Enhancements • Add SSL/TLS encryption • Implement file checksum verification • Add authentication mechanism
  2. Performance Optimization • Implement compression during transfer • Adjust buffer size based on network conditions • Add parallel chunk transfer support
  3. Diagnostics • Add transfer progress reporting • Implement cancellation support • Add logging for error tracking

Comparison Table: Native vs Enhanced Implementation

FeatureBasic ImplementationEnhanced Version
Large File Support
Async Operations
Metadata Handling
Memory Efficiency
Concurrent Connections
Error HandlingPartial

This implementation provides a foundation for reliable file transfers while maintaining flexibility for customization. For production use, consider implementing additional security measures and error recovery mechanisms.