Weird tcp connection scenario - c#

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));
}
}
}

Related

Client stops working after sending message and server doesn't wait for mutliple data to come

I've recently started learning about computer networks and decieded to try TCP/IP server and client. They both work, but I'm having issues with sending mutliple data to the server. I've made it to look like a chat service between clients but the server accepts only one client and closes the connection after the data is sent and the client for some reason stops responding after sending data to server (I think the problem comes from the server and not the client itself), no error message, only on the server side when I force close the client.
This is how my server looks like...
static void Main(string[] args)
{
//User can define port
Console.WriteLine("open a port:");
string userInputPort = Console.ReadLine();
//listening for connections
TcpListener listener = new TcpListener(System.Net.IPAddress.Any, Convert.ToInt32(userInputPort));
listener.Start();
Console.WriteLine("listening...");
while (true)
{
//waiting for client to connect to server
Console.WriteLine("Waiting for connection...");
//when user connects to server, server will accept any request
TcpClient client = listener.AcceptTcpClient();
Console.WriteLine("Client Accepted");
NetworkStream stream = client.GetStream();
StreamReader streamR = new StreamReader(client.GetStream());
StreamWriter streamW = new StreamWriter(client.GetStream());
while (true)
{
if(client.Connected)
{
if (stream.CanRead)
{
//buffer
byte[] buffer = new byte[1024];
stream.Read(buffer, 0, buffer.Length);
int recv = 0;
foreach (byte b in buffer)
{
if(b != 0)
{
recv++;
}
}
string request = Encoding.UTF8.GetString(buffer, 0, recv);
Console.WriteLine("request recived: " + request);
streamW.Flush();
}
}
}
}
}
}
}
and this is how the client looks like...
...
try
{
//try to connect
client = new TcpClient(textBoxIP.Text, Convert.ToInt32(textBoxPort.Text));
}
...
static void sendMessage(string message, TcpClient client)
{
int byteCount = Encoding.ASCII.GetByteCount(message);
byte[] sendData = new byte[byteCount];
sendData = Encoding.ASCII.GetBytes(message);
NetworkStream stream = client.GetStream();
stream.Write(sendData, 0, sendData.Length);
StreamReader streamReader = new StreamReader(stream);
string respone = streamReader.ReadLine();
stream.Close();
client.Close();
}
Like I said, I'm still learning about computer networking and any comment to this code will help!
Thank you
It helps if you give yourself some idea of what you're actually expecting from the code you're writing. It seems to me that you make a lot of automatic assumptions without actually making sure to put them in your code.
Your server can only ever at best accept a single client. Not one client at a time, but one ever. You never exit from your reading loop, so after the client disconnects, you end up in a wonderful infinite busy loop. Your intent was probably to serve another client when one disconnects, but that's not what you're doing.
You assume the server will send a response to the client. But you never actually send any response! For a client to read something, the server first must send something for the client to read.
You assume the string sent by the client will be zero-terminated, or that the target buffer for Read will be zeroed. If you want zero-termination, you have to send it yourself from the client - the StreamWriter certainly doesn't do that. Strings aren't zero-terminated as a rule - it's just one C-style way of representing strings in memory. You shouldn't assume anything about the contents of the buffer beyond what the return value from Read tells you was returned.
Those are issues with things you forgot to quite put in, presumably. Now to the incorrect assumptions on part of how TCP works. To keep clarity, I will tell the way it is, rather than the incorrect assumption.
A single write can result in multiple reads on the other side, and a single read can read data from multiple writes on the other side. TCP doesn't send (and receive) messages, it deals with streams. You need to add a messaging protocol on top of that if streams aren't good enough for you.
Read returns how many bytes were read. Use that to process the response, instead of looking for a zero. When Read returns a zero, it means the connection has been closed, and you should close your side as well. This is all that you need, instead of all the while (true), if (Connected) and if (CanRead) - loop until Read returns zero. Process data you get as it gets to you.
The TCP stream is a bit trickier to work with than most streams; it behaves differently enough that using helpers like StreamReader is dangerous. You have to do the work yourself, or get a higher-abstraction library to work with networking. TCP is very low level.
You cannot rely on getting a response to a Read. TCP uses connections, but it doesn't do anything to keep the connection alive on its own, or notice when it is down - it was designed for a very different internet than today's, and it can happily survive interruptions of service for hours - as long as you don't try to send anything. If the client disconnects abruptly, the server might never know.
You should also make sure to clean up all the native resources properly - it really helps to use using whenever possible. .NET will clean up eventually, but for things like I/O, that's often dangerously late.
while (true)
{
if(client.Connected)
{
if (stream.CanRead)
{
I don't see any code, that exits the outer while the loop if either client.Connected or stream.CanRead become false. So, when the client disconnects and they become false, it seems to me that the server just loops forever.
You should at least do all error handling (close all necessary streams) and break out of the loop.
As the next problem, you code can only have one client at a time. If the client is not actually closing the connection. I do not know for sure what the correct C# solution is, but i think it is spawning a separate thread for each connected client.

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.

TCPClient is not closed, and instead waits for a client to close it

i have few questions about programming a TcpListener.
First problem:
Once client is connected using browser, i see the request. it is all ok. but then i face the problem with writing. and client recieving that data. it basically never gets a reply from server. do i need that flush function ? how does it work ? and is there any others ways of doing it ?
Porblem number 2 which is even more weird. when i call client.close() client doesnt go anywhere. it is still there. browser is stillw ating for data. and when i kill connection in the browser, only then Tcp client gets closed and loop starts again.
namespace TestServer
{
class Program
{
public static void Main()
{
TcpListener server;
IPAddress addr = IPAddress.Parse("127.0.0.1");
server = new TcpListener(addr, 80);
server.Start();
byte[] buffer = new byte[1024];
while(true)
{
string data = null;
Console.WriteLine("Awaiting for connections");
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected...");
NetworkStream str = client.GetStream();
int msgCounter;
while ((msgCounter = str.Read(buffer, 0, buffer.Length)) != 0)
{
Console.WriteLine("Processing stream...");
data += System.Text.Encoding.ASCII.GetString(buffer, 0, msgCounter);
Console.WriteLine("Reciaved: {0}", System.Text.Encoding.ASCII.GetString(buffer, 0, msgCounter));
}
byte[] response = System.Text.Encoding.ASCII.GetBytes("200 OK");
str.Write(response, 0, response.Length);
str.Flush();
client.Close();
buffer = new byte[1024];
}
}
}
}
TCP as a bi-directional transport layer protocol does not denote any concept of the "client is done sending request" signal.
What it means for developers is that such signaling must be defined in the application (or any other higher level) protocol layer.
In your case it is declared by HTTP itself in the https://tools.ietf.org/html//rfc2616#section-5
So if you intend to implement an HTTP server you must parse the HTTP request that has a determined way to identify the end of the request (see the link above).
To summarise: you need to know somehow you've read the request entirely and you may start processing it and generating/sending the response.
I'd recommend you to start with a million times proven working MSDN example of TcpListener class. Additionally I can point to explicit wrong approach:
Do not recreate buffer, it is a waste of resources.
Do not use browser as a test client if you are working with TCP sockets. Any browser tries to correct somehow HTTP protocol errors and can do it in very unpredictable way. If you need HTTP level of debugging, use Fiddler, for lower levels - Microsoft Network Monitor, Wireshark of Netcat.
It could be useful to read some book about TCP/IP networking. Particularly, you will know, that there is not "close" operation or command for TCP connection by protocol definition, TcpClient just emulate it. Instead a peer can send "shutdown" to another one, it does mean it doesn't plan to send data anymore, but can read it. Connection can be considered as closed only after both peers have sent their "shutdown" and received "shutdown" from each other.

Detect closed network connection

I've written a number of small programs that communicate via TCP. I'm having endless issues with the system hanging because one program has closed its network connection, and the other end-point somehow fails to notice that it's now disconnected.
I was expecting doing I/O on a TCP connection that has been closed to throw some kind of I/O exception, but instead the program seems to just hang, waiting forever for the other end-point to reply. Obviously if the connection is closed, that reply is never coming. (It doesn't even seem to time out if you leave it for, say, twenty minutes.)
Is there some way I can force the remote end to "see" that I've closed the network connection?
Update: Here is some code...
public sealed class Client
{
public void Connect(IPAddress target)
{
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(ipAddress, 1177);
_stream = new NetworkStream(socket);
}
public void Disconnect()
{
_stream.Close();
}
}
public sealed class Server
{
public void Listen()
{
var listener = new TcpListener(IPAddress.Any, 1177);
listener.Start();
var socket = listener.AcceptSocket();
_stream = new NetworkStream(socket);
...
}
public void Disconnect()
{
socket.Shutdown(SocketShutdown.Both);
socket.Disconnect(false);
}
}
When an application closes a socket the right way, it sends a message containing 0 bytes. In some cases you may get a SocketException indicating something went wrong. In a third situation, the remote party is no longer connected (for instance by unplugging the network cable) without any communication between the two parties.
If that last thing happens, you'll have to write data to the socket in order to detect that you can no longer reach the remote party. This is why keep-alive mechanisms were invented - they check every so often whether they can still communicate with the other side.
Seeing the code you posted now: when using NetworkStream the Read operation on it would return a value of 0 (bytes) to indicate that the client has closed the connection.
The documentation is mentions both
"If no data is available for reading, the Read method returns 0."
and
"If the remote host shuts down the connection, and all available data has been received, the Read method completes immediately and return zero bytes."
in the same paragraph. In reality NetworkStream blocks if no data is available for reading while the connection is open.
Hi MathematicalOrchid,
You might find what you are looking for here:
http://blog.stephencleary.com/2009/05/detection-of-half-open-dropped.html
There is some great information there when it comes to working with TCP sockets and detecting half open connections.
You can also refer to this post which seems to have the same solution:
TcpClient communication with server to keep alive connection in c#?
-Dave
You are opening the socket, and assigning it to the stream. At the end of the process, you close the network stream, but not the socket.
For NetworkStream.Close() to close the underlying socket it must have the ownership parameters set to true in the constructor - See MSDN Docs at http://msdn.microsoft.com/en-us/library/te7e60bx.aspx.
This may result in the connection hanging as the underlying socket was not correctly closed.
Change
_stream = new NetworkStream(socket);
To
_stream = new NetworkStream(socket, true);
On a side note, if you do not require a maximum performance for your small app you should try using TCPClient instead - http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient%28v=vs.100%29.aspx. This is a wrapper around socket and it provides connection state checking facilities.

Tcp connection Keep alive

i am creating a client server application. the server is already design and in place waiting for connection from the client. Now in the client section i would like to keep the connection alive throughout th life of the application and the connection only closes when the main client application close's or shutdown or the server closes it.
Currently every 10 seconds Server closes the TCP connection.I tried with
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, true);
but it doesn't work for me..
Below is my code block
public TCPStreamDevice(string RemoteIPAddress, int RemotePort, string SourceIPAddress, int SourcePortNo)
{
mIpAddress = RemoteIPAddress;
mPort = RemotePort;
mClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
System.Net.IPEndPoint LocalEndPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Parse(SourceIPAddress), SourcePortNo);
mClient.Bind(LocalEndPoint);
mDataReceivedCallback = new AsyncCallback(DataReceivedTCPCallback_Handler);
mBuffer = new byte[1024];
Description = new DeviceDescription();
}
and in the handler I have:
private void DataReceivedTCPCallback_Handler(IAsyncResult ar)
{
try
{
Socket client = (Socket)ar.AsyncState;
int bytesReceived = client.EndReceive(ar);
if (bytesReceived > 0)
{
//to know transport level errors
//EngineInterface.reponseReceived(mBuffer, false);
ReceiveCallBackFunc(mBuffer, bytesReceived);
client.BeginReceive(mBuffer, 0, 1024, SocketFlags.None, DataReceivedTCPCallback_Handler, client);
}
else
{
//disconnect
/* when there is no datapacket means no TCP connection is alive now (how can i keep Tcp alive here) */
}
}
}
In the call to SetSocketOption(), KeepAlive is not valid at the SocketOptionLevel.Tcp level, instead use SocketOptionLevel.Socket.
SetSocketOption( SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true );
The comments and answer above are valid - sounds like a bad design choice to have a socket opened for the entire lifetime of the app AND expect things to work properly - you should build some sort of failsafe mechanism in case the connection gets dropped.
Back to keep-alives: You need them on both ends - server and client so check how the sockets are set up on both sides. I think that the default value for keep alives is 2 hours - that's a long time to wait for a keep-alive packet but it can be changed. Check Socket.IOControl method and use IOControlCode.KeepAliveValues with a structure that looks like this (unmanaged) http://msdn.microsoft.com/en-us/library/ms741621.aspx. More about control codes here: http://msdn.microsoft.com/en-us/library/system.net.sockets.iocontrolcode.aspx
The comment ("whrn there is no datapacket means no TCP connection") in your code is placed where you receive a disconnect (0 bytes) packet from the other side. There is no way to keep that connection alive because the other side choses to close it.
If the connection is being closed due to network issues, you would either get an exception, or it would seem as if the connection is valid but quiet.
Keep-alive mechanisms always work alongside with timeouts - the timeout enforces "if no data was received for x seconds, close the connection" where the keep-alive simply sends a dummy data packet to keep the timeout from occurring.
By implementing a protocol yourself (you're operating on the TCP/IP level) you only need to implement a keep-alive if you already have a timeout implemented on the other side.

Categories