TcpClient connection status issue on Network Down - c#

I have a TcpClient which i am connecting to the machine and everything is working fine.Now one extra step i want to monitor the connection status on very 60 seconds by the help of timer.As per the basic research of the topic i got to know that there is no direct way to test it .So i tried to get it by the response of the recent message sent to the machine when the application goes out of the network.
Here is the code..
// Find out whether the socket is connected to the remote host.
//Send a message to Machine
try
{
byte[] notify = Encoding.ASCII.GetBytes("Hello");
stream.Write(notify, 0, notify.Length);
}catch { }
//Check if it reached to machine or failed
bool getConnectionStatus = client.Connected;
if (getConnectionStatus == true)
{
//Do nothing
}
else
{
//Stop the thread
_shutdownEvent.WaitOne(0);
_thread.Abort();
//Start Again
_thread = new Thread(DoWork);
_thread.Start();
}
But the most astonishing thing that is happening in this case is that if the machine is out of the network then also while writing the first time it is able to write and and that's why connection status is coming as connected although it is out of the network.Second time when it is trying to send data it is failing and like expected status is disconnected.
The main problem that i am facing is that once it is disconnected from the network why it is able to send the data .Due to this i loosing all the buffer data which is stored in the machine by that time when network goes off.
Please help me..

Under the hood, the Write operation just sends the data to the network layer; you may get a "success" result before an attempt is made to transmit the data. The network layer may even delay sending the data for a while if the data is small, in an attempt to send one batch of a few messages at once.
What Alex K. said with a few words is that the most reliable way to check a network connection is to wait for a response. If no such response is received within a certain amount of time, the connection is lost.
Lets say you keep using "Hello" and the server should respond with "Yeah!". On the client side, you could extend your current code with:
try
{
byte[] notify = Encoding.ASCII.GetBytes("Hello");
stream.Write(notify, 0, notify.Length);
byte[] notifyResult = new byte[5];
int bytesRead = stream.Read(notifyResult, 0, 5);
if (bytesRead == 0)
{
// No network error, but server has disconnected
}
// Arriving here, notifyResult should contain ASCII "Yeah!"
}
catch (SocketException)
{
// Network error
}
On the server, you should recognize the "Hello" being sent, and simply respond with "Yeah!". I don't know what your server currently does, but it could be something similar to:
switch (receivedMessage)
{
case "Hello":
stream.Write(Encoding.ASCII.GetBytes("Yeah!"), 0, 5);
break;
}
Note that you should consider wrapping your messages in information packets, ie:
<Message Type> <Message> <Terminator Character>
ie. "KHello\n"
Or
<Size of Message> <Message Type> <Message>
ie. "0005KHello"
Where message type 'K' is a Keep-alive message, the newline "\n" the terminator character and "0005" the message length excluding the message type.
This way the server will always be able to tell whether it has received the full message, and the message type could indicate whether "Hello" was sent as data or as a keep-alive packet.

Related

Why does my connection drop when the client doesn't send any more data?

So I have a server which accepts incoming connections and then grabs the TcpClient in order to get the stream so that data can be send and received though that stream.
As for right now I'm only trying to read the data, and it works perfectly! The only issue is that, if I send data as the client to the server, the server then interprets the data just as it should, it reads every single bit just the way it's intended. But if the packet doesnt send anymore data within the next 50 - 60 seconds, the server throws this exception
Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host..
As soon as the client is connected the server enters a loop and starts reading data like so
while (isConnected)
{
var packetOpCode = nr.ReadByte();
var packetSize = Constants.INCOMING_SIZES[packetOpCode];
NetPacket packet;
/* i.e 127 */
packetSize = nr.ReadByte();
var payload = nr.ReadBytes(packetSize);
packet = new NetPacket
{
OpCode = packetOpCode,
Length = packetSize,
Payload = payload
};
_packets.Add(packet);
/* If anything here crashes, then treat it as a faulty packet and disconnect the user. */
Console.WriteLine(
$"#: {_id} Queue: [{_packets.Count}] - Packet with ID: {packet.OpCode} added. ");
File.AppendAllText("Log.txt",
$"#: {_id} Queue: [{_packets.Count}] - Packet with ID: {packet.OpCode} added. \n");
}
where nr is a instance of my NetReader class
public class NetReader : BinaryReader
{
private readonly NetworkStream _ns;
public NetReader(NetworkStream ns) : base(ns)
{
_ns = ns;
base.BaseStream.ReadTimeout = System.Threading.Timeout.Infinite;
}
}
And all I'm doing on the client is
Connect To Server
Create a byte[] and send it through that connection by doing Client.Send(..);
So it's only sending one packet and then it's idling, the application doesn't exit or anything, it just doesn't send anymore data.
client.Connect("127.0.0.1", portNumber);
PacketBuilder builder = new PacketBuilder();
builder.AddOpCode(4);
builder.AddByte(4);
builder.AddString("Test");
var packet = builder.GetByteArray();
client.Client.Send(packet, packet.Length, SocketFlags.None);
The packet looks like this 4 4 54 65 73 74
Since the server is looping, trying to read more data once it's read the first packet, the second iteration it will get stuck on this line var packetOpCode = nr.ReadByte(); since it's a blocking call.
It's almost as if there is a timeout somewhere, but I can't figure out what making the connection drop.
Why am I getting the exception on the server? Is there a hidden timeout somewhere?
TCP does not timeout, unless its implementation specifically implements a timeout.
An established TCP connection that doesn't send any data for 100 years is still an established TCP connection.
So long as each end still exists, there is no reason for either end to send a packet to the other, they can each just sit there waiting FOREVER.
So:
Servers and/or Clients can close idle connections to free up resources.
Firewalls and NAT devices can expunge state information so that your connection no longer works when you come to use it again.
Firewalls and NAT devices can also fake close an idle tcp connection, by sending a RST to the client or server.
From what you have explained, it sounds like the server is closing the connection because it has not seen any data, thus it is freeing resources.
Check your server implementation.

Determine broken connection in TCP server

I wrote a tcp server, each time a client connection accepted, the socket instance returned by Accept or EndAccept which is called handler and many other information gathered in object called TcpClientConnection, I need to determine whether a connection is connected or not at some specific interval times, the Socket.Connected property is not reliable and according to the documentation i should use the Poll method with SelectRead option to do it.
with a test scenario i unplug the client cable, and wait for broken alarm which is built upon the handler.Poll(1, SelectMode.SelectRead), it should return true but never it happened.
This is a fundamentally caused by the way the TCP and IP protocols work. The only way to detect if a connection is disconnected is to send some data over the connection. The underlying TCP protocol will cause acknowledgements to be sent from the receiver back to the sender thereby allowing a broken connection to be detected.
These articles provide some more information
Do I need to heartbeat to keep a TCP connection open?
http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html
According to the documentation of Socket.Poll:
This method cannot detect certain kinds of connection problems, such as a broken network cable, or that the remote host was shut down ungracefully. You must attempt to send or receive data to detect these kinds of errors.
In another words - Poll is useful for checking if some data arrived and are available to your local OS networking stack.
If you'd need to detect the connection issues you need to call blocking read (e.g. Socket.Receive)
You can also build a simple initialization miniprotocol to exchange some agreed 'hello' back and forth message.
Here is a simplified example how you can do it:
private bool VerifyConnection(Socket socket)
{
byte[] b = new byte[1];
try
{
if (socket.Receive(b, 0, 1, SocketFlags.None) == 0)
throw new SocketException(System.Convert.ToInt32(SocketError.ConnectionReset));
socket.NoDelay = true;
socket.Send(new byte[1] { SocketHelper.HelloByte });
socket.NoDelay = false;
}
catch (Exception e)
{
this._logger.LogException(LogLevel.Fatal, e, "Attempt to connect (from: [{0}]), but encountered error during reading initialization message", socket.RemoteEndPoint);
socket.TryCloseSocket(this._logger);
return false;
}
if (b[0] != SocketHelper.HelloByte)
{
this._logger.Log(LogLevel.Fatal,
"Attempt to connect (from: [{0}]), but incorrect initialization byte sent: [{1}], Ignoring the attempt",
socket.RemoteEndPoint, b[0]);
socket.TryCloseSocket(this._logger);
return false;
}
return true;
}

Weird tcp connection scenario

I am using TCP as a mechanism for keep alive here is my code:
Client
TcpClient keepAliveTcpClient = new TcpClient();
keepAliveTcpClient.Connect(HostId, tcpPort);
//this 'read' is supposed to blocked till a legal disconnect is requested
//or till the server unexpectedly dissapears
int numberOfByptes = keepAliveTcpClient.GetStream().Read(new byte[10], 0, 10);
//more client code...
Server
TcpListener _tcpListener = new TcpListener(IPAddress.Any, 1000);
_tcpListener.Start();
_tcpClient = _tcpListener.AcceptTcpClient();
Tracer.Write(Tracer.TraceLevel.INFO, "get a client");
buffer = new byte[10];
numOfBytes = _tcpClient.GetStream().Read(buffer, 0, buffer.Length);
if(numOfBytes==0)
{
//shouldn't reach here unless the connection is close...
}
I put only the relevant code... Now what that happens is that the client code is block on read as expected, but the server read return immediately with numOfBytes equals to 0, even if I retry to do read on the server it return immediately... but the client read is still block! so in the server side I think mistakenly that the client is disconnected from the server but the client thinks it connected to the server... someone can tell how it is possible? or what is wrong with my mechanism?
Edit: After a failure I wrote to the log these properties:
_tcpClient: _tcpClient.Connected=true
Socket: (_tcpClient.Client properties)
_tcpClient.Client.Available=0
_tcpClient.Client.Blocking=true
_tcpClient.Client.Connected=true
_tcpClient.Client.IsBound=true
Stream details
_tcpClient.GetStream().DataAvailable=false;
Even when correctly implemented, this approach will only detect some remote server failures. Consider the case where the intervening network partitions the two machines. Then, only when the underlying TCP stack sends a transport level keep-alive will the system detect the failure. Keepalive is a good description of the problem. [Does a TCP socket connection have a “keep alive”?] 2 is a companion question. The RFC indicates the functionality is optional.
The only certain way to reliably confirm that the other party is still alive is to occasionally send actual data between the two endpoints. This will result in TCP promptly detecting the failure and reporting it back to the application.
Maybe something that will give clue: it happens only when 10 or more clients
connect the server the same time(the server listen to 10 or more ports).
If you're writing this code on Windows 7/8, you may be running into a connection limit issue. Microsoft's license allows 20 concurrent connections, but the wording is very specific:
[Start->Run->winver, click "Microsoft Software License Terms"]
3e. Device Connections. You may allow up to 20 other devices to access software installed on the licensed computer to use only File Services, Print Services, Internet Information Services and Internet Connection Sharing and Telephony Services.
Since what you're doing isn't file, print, IIS, ICS, or telephony, it's possible that the previous connection limit of 10 from XP/Vista is still enforced in these circumstances. Set a limit of concurrent connections to 9 in your code temporarily, and see if it keeps happening.
The way I am interpretting the MSDN remarks it seems that behavior is expected. If you have no data the Read the method returns.
With that in mind I think what I would try is to send data at a specified interval like some of the previous suggestions along with a "timeout" of some sort. If you don't see the "ping" within your designated interval you could fail the keepalive. With TCP you have to keep in mind that there is no requirement to deem a connection "broken" just because you aren't seeing data. You could completely unplug the network cables and the connection will still be considered good up until the point that you send some data. Once you send data you'll see one of 2 behaviors. Either you'll never see a response (listening machine was shutdown?) or you'll get an "ack-reset" (listening machine is no longer listening on that particular socket)
https://msdn.microsoft.com/en-us/library/vstudio/system.net.sockets.networkstream.read(v=vs.100).aspx
Remarks:
This method reads data into the buffer parameter and returns the number of bytes successfully read. If no data is available for reading, the Read method returns 0. The Read operation reads as much data as is available, up to the number of bytes specified by the size parameter. If the remote host shuts down the connection, and all available data has been received, the Read method completes immediately and return zero bytes.
As I can see you are reading data on both sides, server and client. You need to write some data from the server to the client, to ensure that your client will have something to read. You can find a small test program below (The Task stuff is just to run the Server and Client in the same program).
class Program
{
private static Task _tcpServerTask;
private const int ServerPort = 1000;
static void Main(string[] args)
{
StartTcpServer();
KeepAlive();
Console.ReadKey();
}
private static void StartTcpServer()
{
_tcpServerTask = new Task(() =>
{
var tcpListener = new TcpListener(IPAddress.Any, ServerPort);
tcpListener.Start();
var tcpClient = tcpListener.AcceptTcpClient();
Console.WriteLine("Server got client ...");
using (var stream = tcpClient.GetStream())
{
const string message = "Stay alive!!!";
var arrayMessage = Encoding.UTF8.GetBytes(message);
stream.Write(arrayMessage, 0, arrayMessage.Length);
}
tcpListener.Stop();
});
_tcpServerTask.Start();
}
private static void KeepAlive()
{
var tcpClient = new TcpClient();
tcpClient.Connect("127.0.0.1", ServerPort);
using (var stream = tcpClient.GetStream())
{
var buffer = new byte[16];
while (stream.Read(buffer, 0, buffer.Length) != 0)
Console.WriteLine("Client received: {0} ", Encoding.UTF8.GetString(buffer));
}
}
}

C# client unable to trigger server back to back

I have a Kinect sensor connected to a PC and my application that is requesting frames over a TCP connection that is residing on another PC. My problem is that I am unable to trigger two requests and get frames back to back.
This is the code on the server side which is connected to the sensor:
while(running)
{
if (networkStreamReceive.DataAvailable)
{
byte[] clientRequest = new byte[8];
networkStreamReceive.Read(clientRequest, 0, clientRequest.Length);
string clientData = System.Text.Encoding.ASCII.GetString(clientRequest);
clientData = clientData.Substring(0, clientData.IndexOf("$"));
if (clientData == "1")
{
// Process sensor data.
// Takes about 5-15 ms.
}
}
}
On the client side, it makes a request as follows:
NetworkStream serverStreamSend = clientSocketSend.GetStream();
//Send the request.
byte[] outStream = System.Text.Encoding.ASCII.GetBytes("1$");
serverStreamSend.Write(outStream, 0, outStream.Length);
Thread.Sleep(800); // Works for 1000ms and above.
serverStreamSend.Write(outStream, 0, outStream.Length);
receivedFrame = receiveFrame();
receivedFrame = receiveFrame();
where receiveFrame reads the data from the stream.
This only works if I add a sleep of at least a second on the client side. If I remove that sleep, I see that the client is able to fire both the requests, but is stuck reading the second receiveFrame.
On the server side, I see the first trigger come in, but the second one does not come through. I am unable to understand why this is so when the time to process the sensor data is only about 10-15ms.
The second one did come through, but your code doesn't notice because you aren't checking the return value of the Read() method to see just how much data was actually available.
When the client is sending the requests quickly enough, they get combined into a single transmission and both requests are available in a single call to Read(). But your code will check only the first request in that transmission and will throw away the second one.
Assuming the $ character is a delimiter for your protocol, you should change your server side so that the server continues to read data from the received buffer all the way to the end, treating each $-delimited section as a single request.
If the $ character isn't a delimiter, then you're going to need to decide what you will use for a delimiter and include that your protocol.

TCPClient - stops receiving data after some time

I have wrote a code to listen data on particular port in TCP mode.
Now the problem here is that the below code receives some data from the remote and after sometime it does not receive anything
I have check the wireshark and data is coming over there
I have check the TCPView, port (2-3 entries of same port is there) is open with the application but few port status stays as "ESTABLISHED" and one port is saying "LISTENING"
If i am checking the wireshark for missign data detail, then i found that remote IP-Port pair is stated as "ESTABLISHED" in TCPView but it cannot write anything in log file
My question is why the no data received in my application. Is there anything wrong in the code? I have tried every option which google can provide but there is no luck.
TcpListener tcpListenerDeviceResponse = new TcpListener(new IPEndPoint(IPAddress.Parse(localIP), 6005));
tcpListenerDeviceResponse.Start();
while (true)
{
using (TcpClient client = tcpListenerDeviceResponse.AcceptTcpClient())
{
// Get a stream object for reading and writing
using (NetworkStream stream = client.GetStream())
{
Socket skSource = client.Client;
int i;
var data2 = new byte[client.ReceiveBufferSize];
// Loop to receive all the data sent by the client.
while ((i = stream.Read(data2, 0, data2.Length)) != 0)
{
// Translate data bytes to a ASCII string.
string strResponse = System.Text.Encoding.ASCII.GetString(data2, 0, i);
// Insert the data in log text file
// process data
}
stream.Close();
}
// Shutdown and end connection
client.Close();
}
}
tcpListenerDeviceResponse.Stop();
One Reason could be Timeout!
Assuming Transmitting socket doesn't send data for more than Receiving socket's timeout, it will result in Timeout Error and will break the while loop and Close the socket.
This MSDN link might help you!
Also, I would suggest you to close the socket only if it is breaking while for other reasons except Timeout. If Timeout occurs, Go on reading again.

Categories