Gaurav123
Gaurav123

Reputation: 5219

How to make sure that stream is read completely?

I am using Network Stream, TcpListener and Sockets.

I want to make sure that all the data from sender is received by receiver.

I have below code for receiver

private void StartReciever()
{
    util.LoadSettings();

    string tcpIpAddress = util.svrSettings["IpAddress"];
    string port = util.svrSettings["Port"];
    string outDir = util.svrSettings["isOutput"];

    new Thread(
    () =>
    {
        if (!File.Exists(util.settingFile))
            Logger("Please setup the services first.");
        else
        {
            try
            {
                IPAddress ipAddress = IPAddress.Parse(tcpIpAddress);
                TcpListener tcpListener = new TcpListener(ipAddress, Convert.ToInt32(port));

                tcpListener.Start();

                Logger("\nWaiting for a client to connect...");

                //blocks until a client connects
                Socket socketForClient = tcpListener.AcceptSocket();

                Logger("\nClient connected");

                //Read data sent from client
                NetworkStream networkStream = new NetworkStream(socketForClient);
                int bytesReceived, totalReceived = 0;

                string fileName = "testing.txt";

                byte[] receivedData = new byte[10000];
                do
                {
                    bytesReceived = networkStream.Read
                        (receivedData, 0, receivedData.Length);
                    totalReceived += bytesReceived;
                    Logger("Progress of bytes recieved: " + totalReceived.ToString());
                    if (!File.Exists(fileName))
                    {
                        using (File.Create(fileName)) { };
                    }

                    using (var stream = new FileStream(fileName, FileMode.Append))
                    {
                        stream.Write(receivedData, 0, bytesReceived);
                    }

                }
                while (bytesReceived != 0);
                Logger("Total bytes read: " + totalReceived.ToString());

                socketForClient.Close();
                Logger("Client disconnected...");

                tcpListener.Stop();
            }
            catch (Exception ex)
            {
                // Error : "Only one usage of each socket address (protocol/network address/port) is normally permitted"     
                Logger("There is some error: " + ex.Message); 
            }
        }
    }).Start();
}

How can I make sure that my code after do-while loop executes ?

Sender Code:

private static void SendData(string tcpIpAddress, string port, string filename)
{
    new Thread(
      () =>
      {
          TcpClient tcpClient = new TcpClient(tcpIpAddress, Convert.ToInt32(port));
          //const int bufsize = 8192;
          const int bufsize = 10000;
          var buffer = new byte[bufsize];
          NetworkStream networkStream = tcpClient.GetStream();

          using (var readFile = File.OpenRead(filename))
          {
              int actuallyRead;
              while ((actuallyRead = readFile.Read(buffer, 0, bufsize)) > 0)
              {
                  networkStream.Write(buffer, 0, actuallyRead);
              }
          }
      }).Start();
}

Upvotes: 1

Views: 100

Answers (2)

usr
usr

Reputation: 171246

How can I make sure that my code after do-while loop executes?

Here, it's easy because you can close the connection on the sender which will cause the receiver to read zero bytes and terminate the loop.

In fact you forgot to clean up the sender. Dispose of all resources. This fixes the problem.

Your code would benefit from the Code Review SE. I see about a dozen issues immaterial to this question. Would be a great way for you to improve yourself.

For example you can replace the copy loops with Stream.Copy.

Upvotes: 3

James
James

Reputation: 9985

The usual way I've seen this done to prepend the data being sent with the number of bytes about to be sent. That way the receiver knows that the packet has been read. Even if the network gets interrupted or the sender sends something else without a break.

Note that doing this you can also read the first 8 bytes (or 4 if an Int32 will do the job) before allocating the read buffer which can help optimise the buffer size

Another common way of doing it is with a specific terminator, but then you have to guarantee that whatever you're sending cannot contain that terminator

Upvotes: 0

Related Questions