Search code examples
c#networkstreamtcpsocket

NetworkStream cuts off first 4 bytes when reading


I ran into a strange problem. When I'm trying to send the file via a TCP socket, the first 4 bytes of sended information cuts off.

That is sending and receives pieces of code.

Client side

for (var i = 0; i < fileContentByte.Length; i += buffer.Length)
{
    var size = (i + buffer.Length > fileContentByte.Length) ? fileContentByte.Length - i : buffer.Length;
    clientSocket.Write(fileContentByte, i, size);
}

Server side

using(var file = File.Create("C:\\test\\"+fileName.Substring(0, fileName.IndexOf('\0'))))
while(bytesReceived < numberOfBytes && (count = clientStream.Read(buffer, 0, buffer.Length)) > 0)
{
    file.Write(buffer, 0, count);
    bytesReceived += count;
}

Here is link on full code - http://pastebin.com/VwTgTxgb


Solution

  • You're doing something very strange here.

    First of all, retrieval of file name can be greatly simplified down to Path.GetFileName() call.

    Second, are you sure ASCII will suffice?

    Third, reading the entire file into memory is OK-ish for a proof-of-concept project, but be ready to switch to streaming operations.

    Fourth, your protocol is somewhat wonky. When sending variable-size payload, it is required to first tell the receiving party exactly how much bytes are you going to send. This is exactly what you don't do when sending file name.

    Here's a snippet to get you started:

    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    
    namespace FolderSync
    {
        class Program
        {
            static void Main()
            {
                var server = new Server();
                server.Start();
    
                new Client().TransmitFile(
                    new IPEndPoint(IPAddress.Loopback, 35434), 
                    @"f:\downloads\ubuntu-14.04.3-desktop-amd64.iso");
    
                Console.ReadLine();
    
                server.Stop();
            }
        }
    
        class Server
        {
            private readonly TcpListener tcpListener;
    
            public Server()
            {
                tcpListener = new TcpListener(IPAddress.Loopback, 35434);
            }
    
            public void Start()
            {
                tcpListener.Start();
                tcpListener.BeginAcceptTcpClient(AcceptTcpClientCallback, null);
            }
    
            public void Stop()
            {
                tcpListener.Stop();
            }
    
            private void AcceptTcpClientCallback(IAsyncResult asyncResult)
            {
                //
                // Big fat warning: http://stackoverflow.com/a/1230266/60188
    
                tcpListener.BeginAcceptTcpClient(AcceptTcpClientCallback, null);
    
                using(var tcpClient = tcpListener.EndAcceptTcpClient(asyncResult))
                using(var networkStream = tcpClient.GetStream())
                using(var binaryReader = new BinaryReader(networkStream, Encoding.UTF8))
                {
                    var fileName = binaryReader.ReadString();
                    var length = binaryReader.ReadInt64();
    
                    var mib = length / 1024.0 / 1024.0;
                    Console.WriteLine("Receiving '{0}' ({1:N1} MiB)", fileName, mib);
    
                    var stopwatch = Stopwatch.StartNew();
    
                    var fullFilePath = Path.Combine(Path.GetTempPath(), fileName);
                    using(var fileStream = File.Create(fullFilePath))
                        networkStream.CopyTo(fileStream);
    
                    var elapsed = stopwatch.Elapsed;
    
                    Console.WriteLine("Received in {0} ({1:N1} MiB/sec)", 
                        elapsed, mib / elapsed.TotalSeconds);
                }
            }
        }
    
        class Client
        {
            public void TransmitFile(IPEndPoint endPoint, string fileFullPath)
            {
                if(!File.Exists(fileFullPath)) return;
    
                using(var tcpClient = new TcpClient())
                {
                    tcpClient.Connect(endPoint);
    
                    using(var networkStream = tcpClient.GetStream())
                    using(var binaryWriter = new BinaryWriter(networkStream, Encoding.UTF8))
                    {
                        var fileName = Path.GetFileName(fileFullPath);
                        Debug.Assert(fileName != null, "fileName != null");
    
                        //
                        // BinaryWriter.Write(string) does length-prefixing automatically
                        binaryWriter.Write(fileName);
    
                        using(var fileStream = File.OpenRead(fileFullPath))
                        {
                            binaryWriter.Write(fileStream.Length);
                            fileStream.CopyTo(networkStream);
                        }
                    }
                }
            }
        }
    }