I have created a TCP listener to receive data from a port. And I created a NetworkStream to read the coming data.
NetworkStream stream = new NetworkStream(TCPSocket);
Byte[] bytes = new Byte[128];
int i;
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
string msg = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("received: {0}", msg);
}
What I want to do is, if there is no data coming for 10 minutes, I want to close the stream. How can I do this? I have tried to use timer with creating a thread to call stream.close() after sometime, but nothing worked before it receive any data. Thanks in advance!
Try using:
stream.ReadTimeOut = 600000;
it is in milliseconds.
I am trying to receive data at my server of any length through tcp connection. First my client sends length of data to server through stream.write then it send the actual data.
At Client I receive the length and loop until whole the data is received successfully.
The problem is: "I receive 0 size on the server no matters what the length of data is". I tried to figure out the issue but could not get where the problem is. Any kind of help/hint would be appreciated.
Server Side Code:
byte[] lengthOfData = new byte[2048];
byte[] buffer;
try
{
stream = client.GetStream();
eventLog1.WriteEntry("Size of 1st = "+stream.Read(lengthOfData,0,lengthOfData.Length));
int numBytesToRead = ByteArraySerializer.BytesArrayToInt(lengthOfData);
eventLog1.WriteEntry("number of bytes to read= "+numBytesToRead);
buffer = new byte[numBytesToRead+10];
int numBytesRead = 0;
do
{
int n = stream.Read(buffer, numBytesRead, 10);
numBytesRead += n;
numBytesToRead -= n;
eventLog1.WriteEntry("number of bytes read= " + numBytesRead);
} while (numBytesToRead > 0);
}
catch (Exception e) // Called automatically when Client Diposes or disconnects unexpectedly
{
eventLog1.WriteEntry("Connection Closes: "+e.ToString());
lock (connectedClients)
{
connectedClients.Remove(client);
}
client.Close();
break;
}
Client Side Code
byte[] command = ByteArraySerializer.Serialize<Command>(cmd);
byte[] sizeOfData = ByteArraySerializer.IntToBytesArray(command.Length);
stream.Write(sizeOfData, 0, sizeOfData.Length);
Console.WriteLine("Size of Data = "+command.Length);
stream.Write(command, 0, command.Length);
Change the following line at server
byte[] lengthOfData = new byte[2048];
to
byte[] lengthOfData = new byte[sizeof(int)];
The issue was that the read at server was supposed to read only 4 bytes integer whereas it was reading other data as well which was getting written after writing the length of data. We are supposed to read only 4 bytes if we want to get the length of data(integer).
i am trying to send raw image from server to client using sockets in NETMF, but with no success.
Here is my server side code, i am sending an image byte[] array using a chunks method, because of buffer size limitations in NETMF:
if (serverSocket.IsConnected)
{
Byte[] bytesToSend = capturedata;
Byte[] outboundBuffer = new byte[512];
int incomingOffset = 0;
while (incomingOffset < bytesToSend.Length)
{
int length = System.Math.Min(outboundBuffer.Length, bytesToSend.Length - incomingOffset);
Array.Copy(bytesToSend, incomingOffset, outboundBuffer, 0, length);
incomingOffset += length;
// Transmit outbound buffer
serverSocket.SendBinary(outboundBuffer);
}
Here is my client side code. I am trying to prepare image from memorystream and show it in picturebox:
public static void ReadCallback(IAsyncResult ar)
{
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
handler = state.workSocket;
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
memorystream.Write(state.buffer, 0, bytesRead);
if (bytesRead<=0)
{
PICTUREBOX_CAPTURED_IMAGE.Image = new System.Drawing.Bitmap(memorystream);// Here is an ArgumentException
}
else
{
// Not all data received. Get more.
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
}
I dont know what the matter, but it seems like the server side chunks buffers not completely writes to memorystream on client side, because Byte[] bytesToSend = capturedata; all the time is about 12540 bytes, but when i start to investigate this value on clientside memory stream capacity is about 3500-4600 bytes. And i think because of it i have an Argument Exception when i am trying to make a Bitmap image from stream in this line of code:
if (bytesRead<=0)
{
PICTUREBOX_CAPTURED_IMAGE.Image = new System.Drawing.Bitmap(memorystream);// Here is an ArgumentException
}
Help me please to find out what am i doing wrong?
I've been struggling with this and can't find a reason why my code is failing to properly read from a TCP server I've also written. I'm using the TcpClient class and its GetStream() method but something is not working as expected. Either the operation blocks indefinitely (the last read operation doesn't timeout as expected), or the data is cropped (for some reason a Read operation returns 0 and exits the loop, perhaps the server is not responding fast enough). These are three attempts at implementing this function:
// this will break from the loop without getting the entire 4804 bytes from the server
string SendCmd(string cmd, string ip, int port)
{
var client = new TcpClient(ip, port);
var data = Encoding.GetEncoding(1252).GetBytes(cmd);
var stm = client.GetStream();
stm.Write(data, 0, data.Length);
byte[] resp = new byte[2048];
var memStream = new MemoryStream();
int bytes = stm.Read(resp, 0, resp.Length);
while (bytes > 0)
{
memStream.Write(resp, 0, bytes);
bytes = 0;
if (stm.DataAvailable)
bytes = stm.Read(resp, 0, resp.Length);
}
return Encoding.GetEncoding(1252).GetString(memStream.ToArray());
}
// this will block forever. It reads everything but freezes when data is exhausted
string SendCmd(string cmd, string ip, int port)
{
var client = new TcpClient(ip, port);
var data = Encoding.GetEncoding(1252).GetBytes(cmd);
var stm = client.GetStream();
stm.Write(data, 0, data.Length);
byte[] resp = new byte[2048];
var memStream = new MemoryStream();
int bytes = stm.Read(resp, 0, resp.Length);
while (bytes > 0)
{
memStream.Write(resp, 0, bytes);
bytes = stm.Read(resp, 0, resp.Length);
}
return Encoding.GetEncoding(1252).GetString(memStream.ToArray());
}
// inserting a sleep inside the loop will make everything work perfectly
string SendCmd(string cmd, string ip, int port)
{
var client = new TcpClient(ip, port);
var data = Encoding.GetEncoding(1252).GetBytes(cmd);
var stm = client.GetStream();
stm.Write(data, 0, data.Length);
byte[] resp = new byte[2048];
var memStream = new MemoryStream();
int bytes = stm.Read(resp, 0, resp.Length);
while (bytes > 0)
{
memStream.Write(resp, 0, bytes);
Thread.Sleep(20);
bytes = 0;
if (stm.DataAvailable)
bytes = stm.Read(resp, 0, resp.Length);
}
return Encoding.GetEncoding(1252).GetString(memStream.ToArray());
}
The last one "works", but it certainly looks ugly to put a hard-coded sleep inside the loop considering that sockets already support read timeouts! Do I need to setup some property(ies) on the TcpClient of the NetworkStream? Does the problem resides in the server? The server don't close the connections, it is up to the client to do so. The above is also running inside the UI thread context (test program), maybe it has something to do with that...
Does someone know how to properly use NetworkStream.Read to read data until no more data is available? I guess what I'm wishing for is something like the old Win32 winsock timeout properties... ReadTimeout, etc. It tries to read until the timeout is reached, and then return 0... But it sometimes seem to return 0 when data should be available (or on the way.. can Read return 0 if is available?) and it then blocks indefinitely on the last read when data is not available...
Yes, I'm at a loss!
Networking code is notoriously difficult to write, test and debug.
You often have lots of things to consider such as:
what "endian" will you use for the data that is exchanged (Intel x86/x64 is based on little-endian) - systems that use big-endian can still read data that is in little-endian (and vice versa), but they have to rearrange the data. When documenting your "protocol" just make it clear which one you are using.
are there any "settings" that have been set on the sockets which can affect how the "stream" behaves (e.g. SO_LINGER) - you might need to turn certain ones on or off if your code is very sensitive
how does congestion in the real world which causes delays in the stream affect your reading/writing logic
If the "message" being exchanged between a client and server (in either direction) can vary in size then often you need to use a strategy in order for that "message" to be exchanged in a reliable manner (aka Protocol).
Here are several different ways to handle the exchange:
have the message size encoded in a header that precedes the data - this could simply be a "number" in the first 2/4/8 bytes sent (dependent on your max message size), or could be a more exotic "header"
use a special "end of message" marker (sentinel), with the real data encoded/escaped if there is the possibility of real data being confused with an "end of marker"
use a timeout....i.e. a certain period of receiving no bytes means there is no more data for the message - however, this can be error prone with short timeouts, which can easily be hit on congested streams.
have a "command" and "data" channel on separate "connections"....this is the approach the FTP protocol uses (the advantage is clear separation of data from commands...at the expense of a 2nd connection)
Each approach has its pros and cons for "correctness".
The code below uses the "timeout" method, as that seems to be the one you want.
See http://msdn.microsoft.com/en-us/library/bk6w7hs8.aspx. You can get access to the NetworkStream on the TCPClient so you can change the ReadTimeout.
string SendCmd(string cmd, string ip, int port)
{
var client = new TcpClient(ip, port);
var data = Encoding.GetEncoding(1252).GetBytes(cmd);
var stm = client.GetStream();
// Set a 250 millisecond timeout for reading (instead of Infinite the default)
stm.ReadTimeout = 250;
stm.Write(data, 0, data.Length);
byte[] resp = new byte[2048];
var memStream = new MemoryStream();
int bytesread = stm.Read(resp, 0, resp.Length);
while (bytesread > 0)
{
memStream.Write(resp, 0, bytesread);
bytesread = stm.Read(resp, 0, resp.Length);
}
return Encoding.GetEncoding(1252).GetString(memStream.ToArray());
}
As a footnote for other variations on this writing network code...when doing a Read where you want to avoid a "block", you can check the DataAvailable flag and then ONLY read what is in the buffer checking the .Length property e.g. stm.Read(resp, 0, stm.Length);
Setting the underlying socket ReceiveTimeout property did the trick. You can access it like this: yourTcpClient.Client.ReceiveTimeout. You can read the docs for more information.
Now the code will only "sleep" as long as needed for some data to arrive in the socket, or it will raise an exception if no data arrives, at the beginning of a read operation, for more than 20ms. I can tweak this timeout if needed. Now I'm not paying the 20ms price in every iteration, I'm only paying it at the last read operation. Since I have the content-length of the message in the first bytes read from the server I can use it to tweak it even more and not try to read if all expected data has been already received.
I find using ReceiveTimeout much easier than implementing asynchronous read... Here is the working code:
string SendCmd(string cmd, string ip, int port)
{
var client = new TcpClient(ip, port);
var data = Encoding.GetEncoding(1252).GetBytes(cmd);
var stm = client.GetStream();
stm.Write(data, 0, data.Length);
byte[] resp = new byte[2048];
var memStream = new MemoryStream();
var bytes = 0;
client.Client.ReceiveTimeout = 20;
do
{
try
{
bytes = stm.Read(resp, 0, resp.Length);
memStream.Write(resp, 0, bytes);
}
catch (IOException ex)
{
// if the ReceiveTimeout is reached an IOException will be raised...
// with an InnerException of type SocketException and ErrorCode 10060
var socketExept = ex.InnerException as SocketException;
if (socketExept == null || socketExept.ErrorCode != 10060)
// if it's not the "expected" exception, let's not hide the error
throw ex;
// if it is the receive timeout, then reading ended
bytes = 0;
}
} while (bytes > 0);
return Encoding.GetEncoding(1252).GetString(memStream.ToArray());
}
As per your requirement, Thread.Sleep is perfectly fine to use because you are not sure when the data will be available so you might need to wait for the data to become available. I have slightly changed the logic of your function this might help you little further.
string SendCmd(string cmd, string ip, int port)
{
var client = new TcpClient(ip, port);
var data = Encoding.GetEncoding(1252).GetBytes(cmd);
var stm = client.GetStream();
stm.Write(data, 0, data.Length);
byte[] resp = new byte[2048];
var memStream = new MemoryStream();
int bytes = 0;
do
{
bytes = 0;
while (!stm.DataAvailable)
Thread.Sleep(20); // some delay
bytes = stm.Read(resp, 0, resp.Length);
memStream.Write(resp, 0, bytes);
}
while (bytes > 0);
return Encoding.GetEncoding(1252).GetString(memStream.ToArray());
}
Hope this helps!
This is a continuation of the this question. I am new to network programming, so I am just writing small sample stuff to gain understanding, but somewhat struggling with explaining results.
It seems setting NetworkStream.ReceiveTimeout is not working correctly when client that was supposed to be sending data simply closes before sending all the expected data.
Here is the sample code:
public static void Main(string[] args)
{
TcpListener listener = new TcpListener(IPAddress.Any, 10001);
listener.Start();
ThreadPool.QueueUserWorkItem(WriterThread);
using (TcpClient client = listener.AcceptTcpClient())
using (NetworkStream stream = client.GetStream())
{
client.ReceiveTimeout = (int)new TimeSpan(0, 0, 2).TotalMilliseconds;
stream.ReadTimeout = (int)new TimeSpan(0, 0, 2).TotalMilliseconds;
ReceiveMessage(stream, 1024);
}
listener.Stop();
Console.WriteLine("Done.");
Console.ReadKey(true);
}
private static void WriterThread(object state)
{
using (TcpClient client = new TcpClient())
{
client.Connect(new IPEndPoint(IPAddress.Loopback, 10001));
using (NetworkStream stream = client.GetStream())
{
byte[] bytes = Encoding.ASCII.GetBytes("obviously less than 1024 bytes");
stream.Write(bytes, 0, bytes.Length);
Thread.Sleep(10000); // comment out
}
}
}
private static byte[] ReceiveMessage(Stream stream, int length)
{
byte[] buffer = new byte[length];
int bufferFill = 0;
while (true)
{
bufferFill += stream.Read(buffer, bufferFill, buffer.Length - bufferFill);
if (buffer.Length == bufferFill)
return buffer;
Thread.Sleep(100);
}
}
This version works correctly triggering exception on the stream.Read() call. However If I comment out Thread.Sleep(10000), the client closes connection, but listener fails to recognize it. Main thread gets stuck inside the while(true) loop. The stream.Read() keeps returning zero, but no exception thrown.
Is this normal? If so how am I expected to handle abnormal client disconnections?
Yes, this sounds normal. There is no receive- or read timeout because the client has disconnected. This means that no more data is available for reading and the stream will return 0 immediately just as documented.
I would modify your ReceiveMessage method to something like the following:
private static byte[] ReceiveMessage(Stream stream, int length)
{
byte[] buffer = new byte[length];
int bufferFill = 0;
while (true)
{
int bytesRead = stream.Read(buffer, bufferFill, buffer.Length - bufferFill);
if (bytesRead == 0)
throw new Exception("No more data available.");
bufferFill += bytesRead;
if (buffer.Length == bufferFill)
return buffer;
Thread.Sleep(100);
}
}
Clearly if the stream.Read() call returns 0 before we have received all the expected bytes there must have been some form of disconnection or similar. Either way we will never get any more data from the stream.
Edit: The Stream class has no notion of a "message". The Read method blocks until more data becomes available if none is already in the buffer. It will however return 0 when no more data can be received, which in this case means the connection is closed.