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);
Related
I am using TcpListener class to create a TCP socket on a certain IP and port in my machine. The code I use is as follows :
tcpListener = new TcpListener("192.168.0.110", 8005);
try
{
tcpListener.Start();
}
catch (Exception e)
{
Console.WriteLine(e);
return;
}
This works fine. I want to use a check thread to check the status of the listener.
private void CheckConnections()
{
while (true)
{
if (_tcpListener.Server.IsBound)
{
Console.WriteLine(_tcpListener.Active);
Console.WriteLine("IsBound : True");
}
else
{
Console.WriteLine(_tcpListener.Active);
Console.WriteLine("IsBound : False");
}
Thread.Sleep(2000);
}
}
When I change the IP of my machine manually from adapter settings, for example from "192.168.0.110" to "192.168.0.105", in the "netstat -ano" command I still see that the " 192.168.0.110:8005" is in Listening state. Also I could not find a way to subscribe to this change from my code. So my question is how to handle IP change on server side socket? Is there a way that I can get IP change information from the socket itself?
Sockets remain in listening state for a while after being closed. This is deliberate and is due to the way sockets have been designed. it doesn't mean your code is still listening, it means the O/S is listening and it will eventually go away.
As for the second part of the question, you can listen to the NotifyAddrChange notification, close your socket, and reopen on the new address.
Here is an article on how to do it.
https://www.codeproject.com/Articles/35137/How-to-use-NotifyAddrChange-in-C
I'm not sure if this is what you want.
Try to use TcpListener(IPAddress.Any, 8005);
This will accept any IPAddress so you don't have to change it on code everytime.
Unless you want to change it while the program is running, that will be a little bit more complicated. You would have to close the socket and change the IP.
in one of my projects I have implemented a small HTTP server to stream the video data of a connected webcam. For this task I'm utilizing the System.Net.Sockets.TcpListener from .NET Framework 4.5, which listens to a pre-configured endpoint and uses the AcceptSocketAsync() mtehod to wait for incomming requests. You can see the relevant code parts below:
this.server = new TcpListener(endpoint);
this.server.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, new LingerOption(true, 0));
this.server.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
this.server.Start();
...
this.listenTask = Task.Factory.StartNew(this.Listen);
...
private async void Listen()
{
try
{
while (this.server.Server.IsBound)
{
Socket socket = await this.server.AcceptSocketAsync();
if (socket == null)
{
break;
}
Task.Factory.StartNew(() => this.ClientThread(socket));
}
}
catch (ObjectDisposedException)
{
Log.Debug("Media HttpServer closed.");
}
}
This works fine, when I start the application and the HTTP server is started for the first time. However, when I stop the HTTP server (done via CheckBox in the settings of the application) the unverlying listening socket is sometimes not closed. When I check for the state of the sockets via console (netstat -ano) I can see that the socket is still in state LISTENING. The resulting problem is, when I restart the HTTP server again I get an System.Net.Sockets.SocketException with the message "Only one usage of each socket address is normally permitted", which is not surprising.
The relevant code part for stopping the HTTP server is as follows:
...
if (this.server != null)
{
if (this.server.Server != null)
{
if (this.server.Server.Connected)
{
this.server.Server.Shutdown(SocketShutdown.Both);
this.server.Server.Disconnect(true);
}
this.server.Server.Close();
}
this.server.Stop();
}
...
I also keep track of my open connections and close them after finishing the transmission of data and when stopping the server. None of the connection sockets stays opened, so I believe only the listening socket should be relevant for this problem.
I already tried various combinations/orders of the Shutdown(), Disconnect(), Close() and Stop() methods when stopping the server, as well as setting/unsetting several options when starting the server like Linger and ReuseAddress, which sometimes seemed to fix the problem at first, but then a few days later the problem occurred again.
I also tried to "force" the listening socket to close when stopping the server using GetTcpTable(...) and SetTcpEntry(...) from iphlpapi.dll, as described in this question: How to close a TCP connection by port?
Unfortunately, this approach did not work for me (it change anything about the state of the listening socket at all).
As I'm a little bit clueless of what else I could do, I'm asking here if somebody has an idea of what might cause the discribed problem or how to solve it. Any help would be greatly appreciated.
Kind regards,
Chris
You should almost always leave TcpListener.Server alone. It's there so you can set socket options on it, not use it for control purposes.
So your Listen should be:
private async void Listen()
{
try
{
while (true)
{
Socket socket = await this.server.AcceptSocketAsync();
if (socket == null)
{
break;
}
Task.Run(() => this.ClientThread(socket));
}
}
catch (ObjectDisposedException)
{
Log.Debug("Media HttpServer closed.");
}
}
(assuming you do actually want one thread per client, an architecture I do not recommend in general).
When you're ready to stop, just stop:
if (this.server != null)
{
this.server.Stop();
}
If you do not have any special requirement, it is suggested to make use of TcpListener class and its methods only or if you have such requirement, do not use TcpListener and start with the Raw socket.
TcpListener class is self sufficient to provide method like
Start(), AcceptTcpClient() and Stop().
You can create a List<TcpClient> and loop through each client and call client.close() after calling Stop() on the TcpListener instance.
A very good example of client server communication is on MSDN:
http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener(v=vs.110).aspx
Regards
On server socket, shutdown & disconnect is not needed for listening sockets. Those calls are needed only for connected sockets. Replace the socket stop with below code:
if (this.server != null)
{
if (this.server.Server != null)
{
this.server.Server.Close();
this.server.Server = NULL;
}
}
I would dispose of your socket connections once you have closed them. The documentation says they should be disposed after closed but personally I like to say when to dispose of anything that use the IDisposable interface.
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.
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.
I have a server that listens for a connection on a socket:
public class Server
{
private Socket _serverSocket;
public Server()
{
_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_serverSocket.Bind(new IPEndPoint(IPAddress.Any, 1234));
_serverSocket.Listen(1);
}
public void Start()
{
_serverSocket.BeginAccept(HandleAsyncConnectionMethod, null);
}
public void Stop()
{
//????? MAGIC ?????
}
//... rest of code here
}
What is the correct (clean) way to close down the socket?
Is it sufficient to call:
_serverSocket.Disconnect(true);
in the Stop() method? or is there other work that needs to happen to close the connection cleanly?
TCP connection termination correctly involves a four-way handshake. You want both ends to inform the other that they're shutting down and then acknowledge each other's shutdown.
Wikipedia explains the process: http://en.wikipedia.org/wiki/Transmission_Control_Protocol#Connection_termination
This post explains how to make it happen in C#: http://vadmyst.blogspot.com/2008/04/proper-way-to-close-tcp-socket.html
2 ways to close it properly without exceptions
1) create temporary connecting socket and connect it to listening one so it could have its handler triggered then just finish it with normal EndAccept and after that close both.
2) just Close(0) listening socket which will result in false shot to its callback, if you then look into your listening socket you will see that its state is "closed" and "disposed". This is why calling EndAccept would cause exception. You may just ignore it and do not call EndAccept. Listening socket will go down immediately without timeout.
Since you are listening for incoming TCP connections, you could use System.Net.Sockets.TcpListener which does have a Stop() method. It does not have asynchronous operations though.
The cleanest way to have Accept call break immediately is to call _serverSocket.Dispose();
Any other call to methods in the like of Shutdown or Disconnect will throw an exception.
First, you need to make sure you're keeping track of any client sockets that were created in the process of BeginAccept. Shut those down first using the Socket.Shutdown() and Socket.Close() methods. Once those have all been shut down then do the same on the listening socket itself.
That should handle it...but if you need to make absolutely sure, you could always kill it with fire:
Not for sockets, but same idea applies., which is to close it in every way possible, then finally set the socket to null.
You should use Socket.Shutdown() and then Socket.Close(). Socket.Disconnect() is usually only used if you intend on reconnecting the same socket.