Sunday, August 8, 2010

Info: Network Stream Length is not available at Server to read buffer from Client

In general, CLIENT writes the array of bytes or buffer and SERVER reads this buffer, but the problem is, lets say CLIENT writes X length of Array of bytes but as Network stream does not support length property therefore SERVER has no idea that how many bytes are written by CLIENT, therefore at server level its quite difficult to initialize the buffer to read. So, the best approach I think is to read data accurately without data loss , it to Read data in chunks till the end to Stream is reached in this way we can ensure the full data read also can keep the memory usage flat.

CODE SAMPLE :

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;


namespace TCPServer
{
class Program
{
static void Main(string[] args)
{
try
{
IPAddress ipAd = IPAddress.Parse("192.168.1.7");
// use local m/c IP address, and
// use the same in the client

// Initializes the Listener
TcpListener myList = new TcpListener(ipAd, 8002);

// Start Listeneting at the specified port
myList.Start();
Console.WriteLine("The server is running at port 8002...Waiting for a connection.....");

TcpClient cl = myList.AcceptTcpClient();
Console.WriteLine("Connection accepted");

Stream ns = cl.GetStream();
byte[] b = Utilities.ReadFully(ns, 0);

Console.WriteLine("Recieved...");
TRGRequest tTRGRequest = (TRGRequest)Utilities.Deserialize(b);

#region Send Ack

ASCIIEncoding asen = new ASCIIEncoding();
byte[] ack = asen.GetBytes("The string was recieved by the server.");
ns.Write(ack, 0, ack.Length);
Console.WriteLine("\nSent Acknowledgement");

#endregion

cl.Close();
ns.Close();
myList.Stop();
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine("Error..... " + e.StackTrace);
}
}
}


public class Utilities
{
public static object Deserialize(byte[] bytes)
{
BinaryFormatter bFormatter = new BinaryFormatter();
using (MemoryStream strm = new MemoryStream())
{
strm.Write(bytes, 0, bytes.Length);
strm.Seek(0, SeekOrigin.Begin);
return (object)bFormatter.Deserialize(strm);
}
}



///
/// Reads data from a stream until the end is reached. The
/// data is returned as a byte array. An IOException is
/// thrown if any of the underlying IO calls fail.
///

/// The stream to read data from
/// The initial buffer length
public static byte[] ReadFully(Stream stream, int initialLength)
{
// If we've been passed an unhelpful initial length, just
// use 32K.
if (initialLength < 1)
{
initialLength = 32768;
}

byte[] buffer = new byte[initialLength];
int read = 0;

int chunk;
while ((chunk = stream.Read(buffer, read, buffer.Length - read)) > 0)
{
read = read + chunk;

// If we've reached the end of our buffer, check to see if there's
// any more information
if (read == buffer.Length)
{
int nextByte = stream.ReadByte();

// End of stream? If so, we're done
if (nextByte == -1)
{
return buffer;
}

// Nope. Resize the buffer, put in the byte we've just
// read, and continue
byte[] newBuffer = new byte[buffer.Length * 2];
Array.Copy(buffer, newBuffer, buffer.Length);
newBuffer[read] = (byte)nextByte;
buffer = newBuffer;
read = read + 1;
}
else
{
//return buffer;
// Buffer is now too big. Shrink it.
byte[] ret = new byte[read];
Array.Copy(buffer, ret, read);
return ret;
}

}
byte[] ret1 = new byte[read];
Array.Copy(buffer, ret1, read);
return ret1;
}
}
}

No comments:

Post a Comment