TCP Communication-Asynchronous Read Loop doesn't end - c#

I am using Asynchronous TCP server/client communication. I have noticed in my log that the same client reconnects several times. However, it never shows that it was disconnected. My code has logging for both connection and disconnection. So why does readAsync stay in loop while the client has disconnected? Here is the code for your reference:
private async Task Accept(TcpClient client)
{
//get client information
string clientEndPoint = GetClientIPAddress(client);
log.Info("Client connected at " + clientEndPoint); //same client is connected several times in log
await Task.Yield ();
try
{
using (client)
using (NetworkStream stream = client.GetStream ())
{
byte[] dataReceived = new byte [100];
while (await stream.ReadAsync(dataReceived, 0, dataReceived.Length) != 0) //read input stream - 0=>end of stream is reached
{
//pass on data for processing
var task = ProcessData(dataReceived);
}
}
log.Info("Closing client connection " + clientEndPoint);//this line is never reached in log
if (client.Connected)
client.Close();
} //end try
catch (Exception ex)
{
log.Error(ex.Message);
log.Info("Closing client connection " + clientEndPoint);
if (client.Connected)
client.Close();
}

It looks like you may have a half-open problem. You should periodically write data to determine whether the socket is still connected; reads can detect graceful shutdowns but not half-open scenarios.
I describe the half-open problem more on my blog.

Did you check if TCP keep alive is set? That should detect if connection is broken.
Also, check if you got zero length bytes on receive, this means that connection is closed.
Edit: Keep Alive is standard method to check if connection is active, this means that one side sends small chunks of data to the other side periodically: http://en.wikipedia.org/wiki/Keepalive.
Many components have this feature already implemented. I've never used TcpClient class, but it must be some wrapper class for Socket over TCP and, as doc states, this class have exposed underlaying Socket (you can use Socket class for TCP also, but never mind). And this Socket have method SetSocketOption. So try:
client.Socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, true);

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.

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.

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

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.

.Net Socket doesn't respond to remote disconnect?

I'm writing a small (C#) client application that sends data using a TCP/IP connection to a remote server. I'm using the standard .Net TcpClient object and want to leave the connection open from the client end as I am regularly submitting data packets to the server. However, it is possible that the server may close the connection, in which case I need to know to re-connect before sending my next packet.
Using Wireshark, I can see (only) the following dialogue when the server terminates the connection:
server >>> FIN, ACK ACK <<< client
What I do not see is my client responding with a FIN of its own, to complete the connection shutdown. The result is that my client program only finds out that the connection is down after sending the next data packet.
Is there any way I can set up TcpClient or its underlying Socket so as to complete the disconnect, and provide some feedback so that my client code knows to re-connect before sending the next packet?
Added in response to comment below:
My sending code is very simple - the object that maintains the TcpClient and NetworkStream member variables, has a member function containing (essentially) the following:
bool sent = false;
byte[] buffer = Encoding.UTF8.GetBytes(dataString);
while (!sent)
{
try
{
m_outStream.Write(buffer, 0, buffer.Length);
sent = true;
}
catch (Exception ex)
{
if (m_outStream != null) { m_outStream.Dispose(); }
m_client = new TcpClient(AddressFamily.InterNetwork);
m_client.Connect(ipAddress, ipPort);
m_outStream = m_client.GetStream();
}
}
With m_client and m_outStream initialized, this simply performs a single pass every time. Then using Wireshark I can see the server send a packet with flags FIN, ACK to which the client responds with ACK.
The next time I call my function, the data is sent out with PSH, ACK, and the server responds with RST, ACK but does not read the incoming data. No exception is raised by the client.
Then I call my function a second time, and an exception is raised causing the connection to be re-started.
In general you should be able to use the Connected property on the TcpCient instance:
See here:
http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.connected.aspx
However:
Because the Connected property only reflects the state of the
connection as of the most recent operation, you should attempt to send
or receive a message to determine the current state. After the message
send fails, this property no longer returns true. Note that this
behavior is by design. You cannot reliably test the state of the
connection because, in the time between the test and a send/receive,
the connection could have been lost. Your code should assume the
socket is connected, and gracefully handle failed transmissions.
Try the following to make sure the Connected flag holds the most recent state:
var tcpClient = new TcpClient ();
tcpClient.Connect();
var stream = tcpClient.GetStream();
// buffer size need to be > 0
int[] buffer = new int[1];
stream.Read(buffer, 0, 0);
if(!tcpClient.Connected)
// do something
Based on decompilation it should be possible to read 0 bytes from a stream, at least there is no check in the .NET Framework TcpClient that prevents this. However it might not be aloud in the external code that is called from the framework to actually read from the network stream.
Be sure to Dispose of both the TcpClient and the Stream after your done, disposing the TcpClientdoes not dispose of the Stream so you need todo this manually, afterwards all resources are freed up (after GC).
From MSDN TcpClient.Connected property:
Type: System.Boolean
true if the Client socket was connected to a remote resource as of the most recent operation; otherwise, false.
This means, you would have to send some data to the server to detect the broken connection. Reading does not work, as you read from the buffer.
See my answer on a related question (https://stackoverflow.com/a/25680975/2505186),
linking the answer of someone else, where a suitable way is described to detect the connection status:
How to check if TcpClient Connection is closed?
Important for you:
The client does not close the connection automatically, when the server does so. The connection is in CLOSE_WAIT state then at the client side and in FIN_WAIT2 state at the server side. See the related section in the wikipedia article Transmission Control Protocol. Using the code from the linked answer above, you can detect that the connection is about to get closed. Further, you can finish the closing procedure then and reopen it if needed.
The method I use for detecting connected status is this one.
static class SocketExtensions
{
/// <summary>
/// Extension method to tell if the Socket REALLY is closed
/// </summary>
/// <param name="socket"></param>
/// <returns></returns>
public static bool IsConnected(this Socket socket)
{
try
{
return !(socket.Poll(1, SelectMode.SelectRead) && socket.Available == 0);
}
catch (SocketException) { return false; }
}
}
When I want to shutdown the connection, I call the following. Closing the underlying stream, and then the client object on top.
I enclose it in trys and catches to ensure that an attempt at closing them is attempted on each.
Note: PeerStream in this case is the NetworkStream (from Client.GetStream())
/// <summary>
/// Method will disconnect this peer forcefully
/// </summary>
public void Disconnect()
{
try
{
PeerStream.Close();
}
catch (Exception ee)
{
}
try
{
_client.Client.Disconnect(false);
}
catch (Exception ee)
{
}
}
I have found a partial answer to my question that solves the immediate problem.
While I still don't know if I can get my TcpClient to complete the disconnection, I can reliably discover whether the socket has disconnected using the following code:
if (m_client.Client.Poll(1000, SelectMode.SelectRead)
&& (m_client.Client.Available == 0))
{
// Connection has gone - reconnect!
m_client = new TcpClient(AddressFamily.InterNetwork);
m_client.Connect(ipAddress, ipPort);
}
else
{
// Connection is good, nothing to do
}

Categories