TcpListener Freezing on Reconnect - c#

I am using a TcpListener to receive messages. One of our clients is having an issue where the listener occasionally will not reconnect after receiving a message. My reconnect code is pretty basic, and straight from the TcpListener API.
tcpClientConnected = new ManualResetEvent(false);
server = new TcpListener(IPAddress.Any, Port);
server.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
server.Start();
while (isListening)
{
Parent.Log("******************** WAITING FOR A MESSAGE ********************", Verbose.Debug);
tcpClientConnected.Reset();
server.BeginAcceptTcpClient(new AsyncCallback(AcceptMessage), server);
tcpClientConnected.WaitOne(); // Wait for an incoming message
if(isListening)
Parent.Log("******************** CONNECTION RESET ********************", Verbose.Debug);
else
Parent.Log("******************** LISTENER DISCONNECTED ********************", Verbose.Debug);
}
Because of logging, I know that tcpClientConnected.Set() gets called. IsListening is still true, and the code loops back to BeginAcceptTcpClient. The first line of code in AcceptMessage writes to the log, and this is never hit. Therefore, I know that a new message is never received, and the server locks.
This customer can run for several days successfully, and then lock up. This is only happening with a single customer.In my AcceptMessage code, I make use of using statements:
TcpListener listener = (TcpListener)ar.AsyncState;
using (TcpClient client = listener.EndAcceptTcpClient(ar))
using (NetworkStream stream = client.GetStream())
I do not reference the listener after creating the client. In this code, I allow for multi-buffer messages, but I don't think anything in there is causing the issue.
My question is, why is BeginAcceptTcpClient not connecting, and is there anything that I can do to detect this and have it try again if needed?

Related

TcpClient claims it is connected altough the server is not running

I'm running a server on a linux kernel, which starts listening to a port and then crashes (this is not subject here). When I then try to establish a connection from some client using the following code, it looks as if everything is working: The TcpClient gets connected immediately and the send operation succeeds. However, I obviously will never get a response.
TcpClient tcpClient = new TcpClient();
tcpClient.Connect(new IPEndPoint(new IPAddress(new byte[] { 192,168,0,1 }), 123));
if (tcpClient.Connected)
{
Console.WriteLine("Connected");
client.NoDelay = true;
NetworkStream stream = tcpClient.GetStream();
stream.Write(new byte[] { 0 }, 0, 1);
stream.Flush();
Console.WriteLine("Sent");
}
How can I determine if the connection is actually open? When the client now tries to do send a command and waits for the response, it will block until the timeout.
The actual code is part of a wrapper around TcpClient which should handle the connection, send messages and receive the responses. It has no idea about the underlying protocol (so send anything and wait for a response seems not useful...)

UdpClient beginreceive how to detect when server is off

I have an application that is reading data from a Udp server on 32 different ports that I need to process. I'm using the UdpClient.BeginReceive that is calling itself because I want to listen all the time :
private void ProcessEndpointData(IAsyncResult result)
{
UdpClient client = result.AsyncState as UdpClient;
// points towards whoever had sent the message:
IPEndPoint source = new IPEndPoint(0, 0);
// schedule the next receive operation once reading is done:
client.BeginReceive(new AsyncCallback(this.ProcessEndpointData), client);
// get the actual message and fill out the source:
this.DecodeDatagram(new DatagrammeAscb()
{
Datagramme = this.ByteArrayToStructure<Datagram>(client.EndReceive(result, ref source))
});
}
When I stop the server side, the function is waiting for data (that is normal behavior). What I would like to do is to detect when the server is disconnected and then close all my clients.
I'm asking myself if I should use sockets class to have more controls or just maybe I'm missing something here.
Anyway thanks for your help.

Listen for additional requests on the same stream (TCPClient/SSLStream)?

So I have a client server model based off of using a TCPClient's stream and turning it into an SSLStream for security purposes, but each time the client wants to send something new to the server, it opens a new TCP connection to the server as the server ends the connection at the end. How would I go about listening for additional requests from the same stream? Not sure how and that's why I'm killing the stream at the end. Sorry if it's confusing, I can revise if not understandable. Thanks!
public void ServerListen()
{
TCPListener Server = new TCPListener(IPAddress.Any, 8001);
while (true)
{
Server.Start();
TCPClient TempClient = Server.AcceptTCPClient();
HandleRequest NewRequest = new HandleRequest(TempClient); // Send to a data handler class and open a separate thread to allow for additional clients to connect
}
}
public class HandleRequest
{
TCPClient WorkingClient;
public HandleRequest(TCPClient TempClient)
{
WorkingClient = TempClient;
(new Thread(new ThreadStart(DoWork))).Start();
}
public static void DoWork()
{
// Do Something Here With Data From Client
ProvideResponse(SomeData);
}
public static void ProvideResponse(object Data)
{
SSLStream SecureStream = new SSLStream(WorkingClient, false); // Kill inner stream after creating a secure connection
SecureStream.AuthenticateAsServer(MyCertificate, false, SslProtocols.Tls, true);
XmlSerializer XS = new XMLSerializer(typeof(someclass));
someclass TempObject = new someclass(){ InnerData = Data};
if (SecureStream.CanWrite)
{
XS.Serialize(SecureStream, TempObject);
}
SecureStream.Close();
}
}
SslStream simply wraps around another Stream. If you call AuthenticateAsServer() the other side should AuthenticateAsClient() and from that point on you can communicate over SSL. If either side fails to call this method, the SslStream will throw an exception.
If you close an SslStream constructed with the leaveInnerStreamOpen parameter set to true, you can then communicate directly over the underlying stream as if there never was an SslStream (and you can even send and receive directly to/from the underlying stream while the SslStream is still open).
In a typical scenario like HTTPS, client and server would enable SSL as soon as the connection is established, and continue using that for the duration of the connection. There's nothing stopping you though from closing the SslStream on both sides after a request/response, and recreating one for the next message - you'd just have to keep the "ssl state" synchronized between client and server.
As for your comment:
Once a TCP connection is established, you can send and receive data for as long as both sides stay connected. For example:
TcpClient client = TcpListener.AcceptTcpClient();
NetworkStream stream = client.GetStream();
while (true)
{
int bytes = stream.Read(...);
if (bytes == 0)
{
// other side has disconnected
stream.Close();
break;
}
// add incoming data to buffer, process messages
...
}
It's like talking to someone by writing text on a piece of paper you show to one another - you simply continue writing on the same piece of paper, and the other side can read while you write.
If you close the TcpClient after a request/response and open a new one using TcpListener.AcceptXxx(), you're throwing away each piece of paper after every message.
If I were you I'd play with these concepts (using the NetworkStream class) without the SslStream wrapper, until you feel you're doing the right thing. The SslStream layer can be added without any significant changes to code that uses NetworkStream.

How to know if the client call connection close on TcpListener?

I wrote simple application that using TcpListener.
The application is wait till some client will connect - and while the client is connected the application will listen to his sending stream.
In the code - i using while loop to check if the client is connected.
But event when i close the connection on the client side i get connected == true
But .. on the client close => i see that the server get byte stream with byte.length == 0
Code ...
private async void button1_Click(object sender, EventArgs e)
{
TcpListener tcpListener = new TcpListener(IPAddress.Any, 5501);
tcpListener.Start(1); // listen one client only
TcpClient client = await tcpListener.AcceptTcpClientAsync();
NetworkStream networkStream = client.GetStream();
while (client.Connected) // after connected => this is always true .. event if i close the connection on the client side
{
// do something ...
}
System.Console.WriteLine("No Connected");
}
TCP is a connection-oriented protocol, but the connection still is a virtual one - the only way to know that the other party is still connected is by successfully sending or receiving a message to/from it. This is why the Connected property may give false positives.
The 0-byte message means that the client has sent all their data and has closed (the send direction of) the socket. At that point the client still is connected, waiting for a 0-byte message back from the server (which is automatically sent when you close the server socket).
Of course in case of a network failure you would never receive that 0-byte message, but you would receive (eventually) a SocketException instead.
See this WinSock FAQ for more information about the shutdown process.

How can I unbind a socket in C#?

I'm having some problems reusing a server socket in a test application I've made. Basically, I have a program that implements both the client side and the server side. I run two instances of this program for testing purposes, one instance starts to host and the other connects. This is the listening code:
private void Listen_Click(object sender, EventArgs e)
{
try
{
server = new ConnectionWrapper();
HideControls();
alreadyReset = false;
int port = int.Parse(PortHostEdit.Text);
IPEndPoint iep = new IPEndPoint(IPAddress.Any, port);
server.connection.Bind(iep); // bellow explanations refer to this line in particular
server.connection.Listen(1);
server.connection.BeginAccept(new AsyncCallback(OnClientConnected), null);
GameStatus.Text = "Waiting for connections on port " + port.ToString();
}
catch (Exception ex)
{
DispatchError(ex);
}
}
private void OnClientConnected(IAsyncResult iar)
{
try
{
me = Player.XPlayer;
myTurn = true;
server.connection = server.connection.EndAccept(iar); // I will only have one client, so I don't care for the original listening socket.
GameStatus.Text = server.connection.RemoteEndPoint.ToString() + " connected";
StartServerReceive();
}
catch (Exception ex)
{
DispatchError(ex);
}
}
This works fine the first time. However, after a while (when my little game ends), I call Dispose() on the server object, implemented like this:
public void Dispose()
{
connection.Close(); // connection is the actual socket
commandBuff.Clear(); // this is just a StringBuilder
}
I also have this in the object constructor:
public ConnectionWrapper()
{
commandBuff = new StringBuilder();
connection = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
connection.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
}
I get no error when I click the Listen button a second time. The client side connects just fine, however my server side does not detect the client connection a second time, which basically renders the server useless anyway. I'm guessing it's connecting to the old, lingering socket, but I have no idea why this is happening to be honest. Here's the client connection code:
private void Connect_Click(object sender, EventArgs e)
{
try
{
client = new ConnectionWrapper();
HideControls();
alreadyReset = false;
IPAddress ip = IPAddress.Parse(IPEdit.Text);
int port = int.Parse(PortConnEdit.Text);
IPEndPoint ipe = new IPEndPoint(ip, port);
client.connection.BeginConnect(ipe, new AsyncCallback(OnConnectedToServer), null);
}
catch (Exception ex)
{
DispatchError(ex);
}
}
If I do netstat -a in CMD, I see that the port I use is still bound and its state is LISTENING, even after calling Dispose(). I read that this is normal, and that there's a timeout for that port to be "unbound".
Is there a way I can force that port to unbind or set a very short timeout until it automatically gets unbound? Right now, it only gets unbound when I exit the program. Maybe I'm doing something wrong in my server? If so, what could that be? Why does the client connect fine, yet the server side doesn't detect it a second time?
I could make the socket always listen, not dispose it, and use a separate socket to handle the server connection, which would probably fix it, but I want other programs to be able to use the port between successive play sessions.
I remember seeing another question asking this, but there was no satisfactory answer for my case there.
There may be a couple of reasons why the port would stay open, but I think you should be able to resolve your issue by using an explicit LingerOption on the socket:
LingerOption lo = new LingerOption(false, 0);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lo);
This basically turns the socket shutdown into an abortive shutdown instead of a graceful shutdown. If you want it to be graceful but just not wait as long, then use true in the constructor and specify a small but nonzero value for the timeout.
I just noticed this line, which is almost undoubtedly part of your problem:
server.connection = server.connection.EndAccept(iar); // I will only have one client, so I don't care for the original listening socket.
The comment you've written here is, well, wrong. Your wrapper class really shouldn't allow connection to be written to at all. But you cannot simply replace the listening socket with the client socket - they're two different sockets!
What's going to happen here is that (a) the listening socket goes out of scope and therefore never gets explicitly closed/disposed - this will happen at a random time, possibly at a nasty time. And (b) the socket that you do close is just the client socket, it will not close the listening socket, and so it's no wonder that you're having trouble rebinding another listening socket.
What you're actually witnessing isn't a socket timeout, it's the time it takes for the garbage collector to realize that the listening socket is dead and free/finalize it. To fix this, you need to stop overwriting the listening socket; the Dispose method of your wrapper class should dispose the original listening socket, and the client socket should be tracked separately and disposed whenever you are actually done with it.
In fact, you should really never need to rebind another listening socket at all. The listening socket stays alive the whole time. The actual connection is represented by just the client socket. You should only need to dispose the listening socket when you finally shut down the server.
I agree with the previous answer, you should also "shutdown" to allow any existing activity to complete and then close the socket flagging it for reuse...
socket.Shutdown(SocketShutdown.Both);
socket.Disconnect(true);

Categories