Related
How can I detect that a client has disconnected from my server?
I have the following code in my AcceptCallBack method
static Socket handler = null;
public static void AcceptCallback(IAsyncResult ar)
{
//Accept incoming connection
Socket listener = (Socket)ar.AsyncState;
handler = listener.EndAccept(ar);
}
I need to find a way to discover as soon as possible that the client has disconnected from the handler Socket.
I've tried:
handler.Available;
handler.Send(new byte[1], 0,
SocketFlags.None);
handler.Receive(new byte[1], 0,
SocketFlags.None);
The above approaches work when you are connecting to a server and want to detect when the server disconnects but they do not work when you are the server and want to detect client disconnection.
Any help will be appreciated.
Since there are no events available to signal when the socket is disconnected, you will have to poll it at a frequency that is acceptable to you.
Using this extension method, you can have a reliable method to detect if a socket is disconnected.
static class SocketExtensions
{
public static bool IsConnected(this Socket socket)
{
try
{
return !(socket.Poll(1, SelectMode.SelectRead) && socket.Available == 0);
}
catch (SocketException) { return false; }
}
}
Someone mentioned keepAlive capability of TCP Socket.
Here it is nicely described:
http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html
I'm using it this way: after the socket is connected, I'm calling this function, which sets keepAlive on. The keepAliveTime parameter specifies the timeout, in milliseconds, with no activity until the first keep-alive packet is sent. The keepAliveInterval parameter specifies the interval, in milliseconds, between when successive keep-alive packets are sent if no acknowledgement is received.
void SetKeepAlive(bool on, uint keepAliveTime, uint keepAliveInterval)
{
int size = Marshal.SizeOf(new uint());
var inOptionValues = new byte[size * 3];
BitConverter.GetBytes((uint)(on ? 1 : 0)).CopyTo(inOptionValues, 0);
BitConverter.GetBytes((uint)keepAliveTime).CopyTo(inOptionValues, size);
BitConverter.GetBytes((uint)keepAliveInterval).CopyTo(inOptionValues, size * 2);
socket.IOControl(IOControlCode.KeepAliveValues, inOptionValues, null);
}
I'm also using asynchronous reading:
socket.BeginReceive(packet.dataBuffer, 0, 128,
SocketFlags.None, new AsyncCallback(OnDataReceived), packet);
And in callback, here is caught timeout SocketException, which raises when socket doesn't get ACK signal after keep-alive packet.
public void OnDataReceived(IAsyncResult asyn)
{
try
{
SocketPacket theSockId = (SocketPacket)asyn.AsyncState;
int iRx = socket.EndReceive(asyn);
}
catch (SocketException ex)
{
SocketExceptionCaught(ex);
}
}
This way, I'm able to safely detect disconnection between TCP client and server.
This is simply not possible. There is no physical connection between you and the server (except in the extremely rare case where you are connecting between two compuers with a loopback cable).
When the connection is closed gracefully, the other side is notified. But if the connection is disconnected some other way (say the users connection is dropped) then the server won't know until it times out (or tries to write to the connection and the ack times out). That's just the way TCP works and you have to live with it.
Therefore, "instantly" is unrealistic. The best you can do is within the timeout period, which depends on the platform the code is running on.
EDIT:
If you are only looking for graceful connections, then why not just send a "DISCONNECT" command to the server from your client?
"That's just the way TCP works and you have to live with it."
Yup, you're right. It's a fact of life I've come to realize. You will see the same behavior exhibited even in professional applications utilizing this protocol (and even others). I've even seen it occur in online games; you're buddy says "goodbye", and he appears to be online for another 1-2 minutes until the server "cleans house".
You can use the suggested methods here, or implement a "heartbeat", as also suggested. I choose the former. But if I did choose the latter, I'd simply have the server "ping" each client every so often with a single byte, and see if we have a timeout or no response. You could even use a background thread to achieve this with precise timing. Maybe even a combination could be implemented in some sort of options list (enum flags or something) if you're really worried about it. But it's no so big a deal to have a little delay in updating the server, as long as you DO update. It's the internet, and no one expects it to be magic! :)
Implementing heartbeat into your system might be a solution. This is only possible if both client and server are under your control. You can have a DateTime object keeping track of the time when the last bytes were received from the socket. And assume that the socket not responded over a certain interval are lost. This will only work if you have heartbeat/custom keep alive implemented.
I've found quite useful, another workaround for that!
If you use asynchronous methods for reading data from the network socket (I mean, use BeginReceive - EndReceive methods), whenever a connection is terminated; one of these situations appear: Either a message is sent with no data (you can see it with Socket.Available - even though BeginReceive is triggered, its value will be zero) or Socket.Connected value becomes false in this call (don't try to use EndReceive then).
I'm posting the function I used, I think you can see what I meant from it better:
private void OnRecieve(IAsyncResult parameter)
{
Socket sock = (Socket)parameter.AsyncState;
if(!sock.Connected || sock.Available == 0)
{
// Connection is terminated, either by force or willingly
return;
}
sock.EndReceive(parameter);
sock.BeginReceive(..., ... , ... , ..., new AsyncCallback(OnRecieve), sock);
// To handle further commands sent by client.
// "..." zones might change in your code.
}
This worked for me, the key is you need a separate thread to analyze the socket state with polling. doing it in the same thread as the socket fails detection.
//open or receive a server socket - TODO your code here
socket = new Socket(....);
//enable the keep alive so we can detect closure
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
//create a thread that checks every 5 seconds if the socket is still connected. TODO add your thread starting code
void MonitorSocketsForClosureWorker() {
DateTime nextCheckTime = DateTime.Now.AddSeconds(5);
while (!exitSystem) {
if (nextCheckTime < DateTime.Now) {
try {
if (socket!=null) {
if(socket.Poll(5000, SelectMode.SelectRead) && socket.Available == 0) {
//socket not connected, close it if it's still running
socket.Close();
socket = null;
} else {
//socket still connected
}
}
} catch {
socket.Close();
} finally {
nextCheckTime = DateTime.Now.AddSeconds(5);
}
}
Thread.Sleep(1000);
}
}
The example code here
http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.connected.aspx
shows how to determine whether the Socket is still connected without sending any data.
If you called Socket.BeginReceive() on the server program and then the client closed the connection "gracefully", your receive callback will be called and EndReceive() will return 0 bytes. These 0 bytes mean that the client "may" have disconnected. You can then use the technique shown in the MSDN example code to determine for sure whether the connection was closed.
Expanding on comments by mbargiel and mycelo on the accepted answer, the following can be used with a non-blocking socket on the server end to inform whether the client has shut down.
This approach does not suffer the race condition that affects the Poll method in the accepted answer.
// Determines whether the remote end has called Shutdown
public bool HasRemoteEndShutDown
{
get
{
try
{
int bytesRead = socket.Receive(new byte[1], SocketFlags.Peek);
if (bytesRead == 0)
return true;
}
catch
{
// For a non-blocking socket, a SocketException with
// code 10035 (WSAEWOULDBLOCK) indicates no data available.
}
return false;
}
}
The approach is based on the fact that the Socket.Receive method returns zero immediately after the remote end shuts down its socket and we've read all of the data from it. From Socket.Receive documentation:
If the remote host shuts down the Socket connection with the Shutdown method, and all available data has been received, the Receive method will complete immediately and return zero bytes.
If you are in non-blocking mode, and there is no data available in the protocol stack buffer, the Receive method will complete immediately and throw a SocketException.
The second point explains the need for the try-catch.
Use of the SocketFlags.Peek flag leaves any received data untouched for a separate receive mechanism to read.
The above will work with a blocking socket as well, but be aware that the code will block on the Receive call (until data is received or the receive timeout elapses, again resulting in a SocketException).
Above answers can be summarized as follow :
Socket.Connected properity determine socket state depend on last read or receive state so it can't detect current disconnection state until you manually close the connection or remote end gracefully close of socket (shutdown).
So we can use the function below to check connection state:
bool IsConnected(Socket socket)
{
try
{
if (socket == null) return false;
return !((socket.Poll(5000, SelectMode.SelectRead) && socket.Available == 0) || !socket.Connected);
}
catch (SocketException)
{
return false;
}
//the above code is short exp to :
/* try
{
bool state1 = socket.Poll(5000, SelectMode.SelectRead);
bool state2 = (socket.Available == 0);
if ((state1 && state2) || !socket.Connected)
return false;
else
return true;
}
catch (SocketException)
{
return false;
}
*/
}
Also the above check need to care about poll respone time(block time)
Also as said by Microsoft Documents : this poll method "can't detect proplems like a broken netwrok cable or that remote host was shut down ungracefuuly".
also as said above there is race condition between socket.poll and socket.avaiable which may give false disconnect.
The best way as said by Microsoft Documents is to attempt to send or recive data to detect these kinds of errors as MS docs said.
The below code is from Microsoft Documents :
// This is how you can determine whether a socket is still connected.
bool IsConnected(Socket client)
{
bool blockingState = client.Blocking; //save socket blocking state.
bool isConnected = true;
try
{
byte [] tmp = new byte[1];
client.Blocking = false;
client.Send(tmp, 0, 0); //make a nonblocking, zero-byte Send call (dummy)
//Console.WriteLine("Connected!");
}
catch (SocketException e)
{
// 10035 == WSAEWOULDBLOCK
if (e.NativeErrorCode.Equals(10035))
{
//Console.WriteLine("Still Connected, but the Send would block");
}
else
{
//Console.WriteLine("Disconnected: error code {0}!", e.NativeErrorCode);
isConnected = false;
}
}
finally
{
client.Blocking = blockingState;
}
//Console.WriteLine("Connected: {0}", client.Connected);
return isConnected ;
}
//and heres comments from microsoft docs*
The socket.Connected property gets the connection state of the Socket as of the last I/O operation. When it returns false, the Socket was either never connected, or is no longer connected.
Connected is not thread-safe; it may return true after an operation is aborted when the Socket is disconnected from another thread.
The value of the Connected property reflects the state of the connection as of the most recent operation.
If you need to determine the current state of the connection, make a nonblocking, zero-byte Send call. If the call returns successfully or throws a WAEWOULDBLOCK error code (10035), then the socket is still connected; //otherwise, the socket is no longer connected .
Can't you just use Select?
Use select on a connected socket. If the select returns with your socket as Ready but the subsequent Receive returns 0 bytes that means the client disconnected the connection. AFAIK, that is the fastest way to determine if the client disconnected.
I do not know C# so just ignore if my solution does not fit in C# (C# does provide select though) or if I had misunderstood the context.
Using the method SetSocketOption, you will be able to set KeepAlive that will let you know whenever a Socket gets disconnected
Socket _connectedSocket = this._sSocketEscucha.EndAccept(asyn);
_connectedSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, 1);
http://msdn.microsoft.com/en-us/library/1011kecd(v=VS.90).aspx
Hope it helps!
Ramiro Rinaldi
i had same problem , try this :
void client_handler(Socket client) // set 'KeepAlive' true
{
while (true)
{
try
{
if (client.Connected)
{
}
else
{ // client disconnected
break;
}
}
catch (Exception)
{
client.Poll(4000, SelectMode.SelectRead);// try to get state
}
}
}
This is in VB, but it seems to work well for me. It looks for a 0 byte return like the previous post.
Private Sub RecData(ByVal AR As IAsyncResult)
Dim Socket As Socket = AR.AsyncState
If Socket.Connected = False And Socket.Available = False Then
Debug.Print("Detected Disconnected Socket - " + Socket.RemoteEndPoint.ToString)
Exit Sub
End If
Dim BytesRead As Int32 = Socket.EndReceive(AR)
If BytesRead = 0 Then
Debug.Print("Detected Disconnected Socket - Bytes Read = 0 - " + Socket.RemoteEndPoint.ToString)
UpdateText("Client " + Socket.RemoteEndPoint.ToString + " has disconnected from Server.")
Socket.Close()
Exit Sub
End If
Dim msg As String = System.Text.ASCIIEncoding.ASCII.GetString(ByteData)
Erase ByteData
ReDim ByteData(1024)
ClientSocket.BeginReceive(ByteData, 0, ByteData.Length, SocketFlags.None, New AsyncCallback(AddressOf RecData), ClientSocket)
UpdateText(msg)
End Sub
You can also check the .IsConnected property of the socket if you were to poll.
I am trying to have a server allow TCP connections and and echo out any newline delimited messages being sent. I want multiple clients to be able to connect one after another, maintaining the same server socket. Here's my code:
TcpClient client;
while (true) {
Console.Write("Waiting for connection... ");
client = listener.AcceptTcpListener();
nStream = client.GetStream();
sReader = new StreamReader(nStream);
Console.WriteLine("Connected!");
while (client.Connected) {
string line = sReader.ReadLine();
Console.WriteLine(line);
}
Console.WriteLine("#Client Disconnected")
}
Unfortunately, when the remote client disconnects, it never escapes the "while (client.Connected)" loop. Instead I get an infinite write to STDOUT.
Basically, the property that you're using TcpClient.Connection does not do what you think it does. From the MSDN documentation:
http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.connected.aspx
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.
The gist is that the property TcpClient.Connection was not updated after the host disconnected but before your server blocked waiting to read another line from the stream. You need a more reliable way to detect if the connection is active before you block.
Turns out, this question has been asked before. So, I borrowed the answer from here and adapted it to the format that you're using in the OP.
https://stackoverflow.com/a/8631090
static void Main(string[] args)
{
TcpClient client = new TcpClient();
TcpListener listener = new TcpListener(IPAddress.Loopback, 60123);
listener.Start();
while (true)
{
Console.WriteLine("Waiting for connection...");
client = listener.AcceptTcpClient();
Console.WriteLine("Connection found");
StreamReader reader = new StreamReader(client.GetStream());
string line = string.Empty;
while (TestConnection(client))
{
line = reader.ReadLine();
Console.WriteLine(line);
}
Console.WriteLine("Disconnected");
}
}
private static bool TestConnection(TcpClient client)
{
bool sConnected = true;
if (client.Client.Poll(0, SelectMode.SelectRead))
{
if (!client.Connected) sConnected = false;
else
{
byte[] b = new byte[1];
try
{
if (client.Client.Receive(b, SocketFlags.Peek) == 0)
{
// Client disconnected
sConnected = false;
}
}
catch { sConnected = false; }
}
}
return sConnected;
}
This works for me when I test it, and the reason that it works is that you cannot tell if the connection is closed until you attempt to read or write from it. You can do that by blindly trying to read/write and then handling the IO exceptions that come when the socket is closed, or you can do what this tester method is doing and peek to see if the connection is closed.
Hope this helps you
EDIT:
It should be noted that this may or may not be the most efficient way to check if the connection is closed, but it is purely to illustrate that you must check the connection yourself on the server side by reading/writing instead of relying on TcpClient.Connection.
EDIT 2:
My sample doesn't clean up old resources very well, apologies to anyone who had an OCD reaction.
I am connecting to a remote server in C# via a socket and sending data across, upon disconnect I try to re-establish the connection by creating a new socket and reinitialising it.
This works for me when I test by pulling out the ethernet cable and reconnecting it a few mins later, but occasionally (every few hours maybe) I get the one of two exceptions while connected and cannot reconnect...
System.Net.Sockets.SocketException: An established connection was aborted by the software in your host machine
.......
System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
If I restart the application everything works fine once again, so im curious as to why creating a new socket doesnt work. Am I missing an initialisation somewhere perhaps? Any ideas? I use the same method for connection each time:
public static bool OpenConnection(string siteName)
{
bool success;
IPEndPoint ip = new IPEndPoint(IPAddress.Parse(serverIp), Convert.ToInt16(serverRemotePort));
try
{
client = null;
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Console.WriteLine("Try to connect to the server ..." + ip.Address.ToString());
client.Connect(ip);
Console.WriteLine("Connection established");
//Send the nameSite first
string nameSite = EncryptString(siteName, pwd, initVector) + "*";
byte[] dataSite = new byte[100];
dataSite = Encoding.ASCII.GetBytes(nameSite);
client.Send(dataSite, dataSite.Length, SocketFlags.None);
Console.WriteLine("NameSite send");
success = true;
}
catch (SocketException e)
{
success = false;
Console.WriteLine("Unable to connect to the server : " + e.StackTrace);
}
return success;
}
I try to reconnect as follows in the catch, count is incrementing with each iteration of a while loop.
if (count % 20 == 0)
{
try
{
if (OpenConnection(siteName))
connected = true;
EventLog.WriteEntry("Connection re-established.");
}
catch (SocketException socketEx)
{
Console.WriteLine("Reconnection failed. Storing data locally. \n\n " + socketEx);
EventLog.WriteEntry("Reconnection failed. Storing data locally. \n\n " + socketEx);
}
}
The constructor simply initialises the IP and Port No. Why is it that certain types of disconnect prevent me from reconnecting without a restart, any ideas?
Do you ever call Dispose() on client to clean it up?
Try adding the call to Dispose() before you null out the client in your OpenConnection method
client.Dispose();
client = null;
After looking at the documentation for Socket on the MSDN, the Disconnect method seems like it also might solve your problem. However, I'm not sure where in your code it should go since the question shows a portion of the logic.
I'm going to setup a small client/server server in TCP/IP mode, I use VS2010,C# to develop my apps, I've googled a lot and could find some source codes, but none of them work in internet, I can get some answers in my own local system, i.e. I run my server, then listen for my own localhost (127.0.0.1) then send some data (for example using telnet), it works fine but when I do the same over internet I get nothing! I want to use port 80, as I want to send/receive http data, I have tested several source codes, here is the last code I have used (and it works on localhost with telnet)
//server code:
form_load()
IPAddress localAddress = IPAddress.Parse("127.0.0.1");
Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipEndpoint = new IPEndPoint(localAddress, 80);
// Bind the socket to the end point
listenSocket.Bind(ipEndpoint);
// Start listening, only allow 1 connection to queue at the same time
listenSocket.Listen(1);
listenSocket.BeginAccept(new AsyncCallback(ReceiveCallback), listenSocket);
Console.WriteLine("Server is waiting on socket {0}", listenSocket.LocalEndPoint);
// Start being important while the world rotates
while (true)
{
Console.WriteLine("Busy Waiting....");
Thread.Sleep(2000);
}
public static void ReceiveCallback(IAsyncResult AsyncCall)
{
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
Byte[] message = encoding.GetBytes("I am a little busy, come back later!");
Socket listener = (Socket)AsyncCall.AsyncState;
Socket client = listener.EndAccept(AsyncCall);
Console.WriteLine("Received Connection from {0}", client.RemoteEndPoint);
client.Send(message);
Console.WriteLine("Ending the connection");
client.Close();
listener.BeginAccept(new AsyncCallback(ReceiveCallback), listener);
}
send data (client), of course I haven't used this code, is it right?
public static string SendData()
{
TcpClient client = new TcpClient();
client.Connect(IP, 80);
StreamWriter sw = new StreamWriter(client.GetStream());
StreamReader sr = new StreamReader(client.GetStream());
//if statement evalutes to see if the user has selected to update the server
//" " = update server
//"" = do not update the server
//if (updateData.Equals(""))
//{
// space = "";
//}
//else if (!updateData.Equals(""))
//{
// space = " ";
//}
//Refrences stream writer, username variable passed in from GUI
//space variable provides update function: "" = dont update. " " = update database.
sw.WriteLine("h");
sw.Flush();
//data send back from the server assigned to string variable
//string recieved = sr.ReadLine();
return "";
}
I'm going to have the server code in my Server (winserver 2008R2) but currently test it in normal PCs, what am I doing wrong? I want to send some http packet from a random system (with a random IP) to my server (which I know its IP), what should I do? is it possible with tcp/ip or I should do something else?
is it related to static IP? should I certainly have static IP? my web server has a static IP but my clients do not, is it a problem?
I think I have some problem in defining ports and IPs, how should I set them? my server has a specific IP, but I don't know IP of my clients, would you please explain it to me step by step?
thanks
The two most common problems in this scenario:
Ensure your server's router is using port forwarding to forward HTTP requests from the router to the server.
Ensure you are connecting to the server's public IP address, not its local network address.
In C# to use a TcpClient or generally to connect to a socket how can I first check if a certain port is free on my machine?
more info:
This is the code I use:
TcpClient c;
//I want to check here if port is free.
c = new TcpClient(ip, port);
Since you're using a TcpClient, that means you're checking open TCP ports. There are lots of good objects available in the System.Net.NetworkInformation namespace.
Use the IPGlobalProperties object to get to an array of TcpConnectionInformation objects, which you can then interrogate about endpoint IP and port.
int port = 456; //<--- This is your value
bool isAvailable = true;
// Evaluate current system tcp connections. This is the same information provided
// by the netstat command line application, just in .Net strongly-typed object
// form. We will look through the list, and if our port we would like to use
// in our TcpClient is occupied, we will set isAvailable to false.
IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();
foreach (TcpConnectionInformation tcpi in tcpConnInfoArray)
{
if (tcpi.LocalEndPoint.Port==port)
{
isAvailable = false;
break;
}
}
// At this point, if isAvailable is true, we can proceed accordingly.
You're on the wrong end of the Intertube. It is the server that can have only one particular port open. Some code:
IPAddress ipAddress = Dns.GetHostEntry("localhost").AddressList[0];
try {
TcpListener tcpListener = new TcpListener(ipAddress, 666);
tcpListener.Start();
}
catch (SocketException ex) {
MessageBox.Show(ex.Message, "kaboom");
}
Fails with:
Only one usage of each socket address (protocol/network address/port) is normally permitted.
When you set up a TCP connection, the 4-tuple (source-ip, source-port, dest-ip, dest-port) has to be unique - this is to ensure packets are delivered to the right place.
There is a further restriction on the server side that only one server program can bind to an incoming port number (assuming one IP address; multi-NIC servers have other powers but we don't need to discuss them here).
So, at the server end, you:
create a socket.
bind that socket to a port.
listen on that port.
accept connections on that port.
and there can be multiple connections coming in (one per client).
On the client end, it's usually a little simpler:
create a socket.
open the connection.
When a client opens the connection, it specifies the ip address and port of the server. It can specify its source port but usually uses zero which results in the system assigning it a free port automatically.
There is no requirement that the destination IP/port be unique since that would result in only one person at a time being able to use Google, and that would pretty well destroy their business model.
This means you can even do such wondrous things as multi-session FTP since you set up multiple sessions where the only difference is your source port, allowing you to download chunks in parallel. Torrents are a little different in that the destination of each session is usually different.
And, after all that waffling (sorry), the answer to your specific question is that you don't need to specify a free port. If you're connecting to a server with a call that doesn't specify your source port, it'll almost certainly be using zero under the covers and the system will give you an unused one.
Thanks for this tip. I needed the same functionality but on the Server side to check if a Port was in use so I modified it to this code.
private bool CheckAvailableServerPort(int port) {
LOG.InfoFormat("Checking Port {0}", port);
bool isAvailable = true;
// Evaluate current system tcp connections. This is the same information provided
// by the netstat command line application, just in .Net strongly-typed object
// form. We will look through the list, and if our port we would like to use
// in our TcpClient is occupied, we will set isAvailable to false.
IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
IPEndPoint[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpListeners();
foreach (IPEndPoint endpoint in tcpConnInfoArray) {
if (endpoint.Port == port) {
isAvailable = false;
break;
}
}
LOG.InfoFormat("Port {0} available = {1}", port, isAvailable);
return isAvailable;
}
TcpClient c;
//I want to check here if port is free.
c = new TcpClient(ip, port);
...how can I first check if a certain port is free on my machine?
I mean that it is not in use by any other application.
If an application is using a port others can't use it until it becomes free. – Ali
You have misunderstood what's happening here.
TcpClient(...) parameters are of server ip and server port you wish to connect to.
The TcpClient selects a transient local port from the available pool to communicate to the server. There's no need to check for the availability of the local port as it is automatically handled by the winsock layer.
In case you can't connect to the server using the above code fragment, the problem could be one or more of several. (i.e. server ip and/or port is wrong, remote server not available, etc..)
thanks for the #jro answer. I had to tweak it for my usage. I needed to check if a port was being listened on, and not neccessarily active. For this I replaced
TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();
with
IPEndPoint[] objEndPoints = ipGlobalProperties.GetActiveTcpListeners();.
I iterated the array of endpoints checking that my port value was not found.
To answer the exact question of finding a free port (which is what I needed in my unit tests) in dotnet core 3.1 I came up this
public static int GetAvailablePort(IPAddress ip) {
TcpListener l = new TcpListener(ip, 0);
l.Start();
int port = ((IPEndPoint)l.LocalEndpoint).Port;
l.Stop();
Log.Info($"Available port found: {port}");
return port;
}
note: based the comment by #user207421 about port zero I searched and found this and slightly modified it.
string hostname = "localhost";
int portno = 9081;
IPAddress ipa = (IPAddress) Dns.GetHostAddresses(hostname)[0];
try
{
System.Net.Sockets.Socket sock = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
sock.Connect(ipa, portno);
if (sock.Connected == true) // Port is in use and connection is successful
MessageBox.Show("Port is Closed");
sock.Close();
}
catch (System.Net.Sockets.SocketException ex)
{
if (ex.ErrorCode == 10061) // Port is unused and could not establish connection
MessageBox.Show("Port is Open!");
else
MessageBox.Show(ex.Message);
}
From the available ports I would exclude:
active TCP connections
active TCP listeners
active UDP listeners
With the following import:
using System.Net.NetworkInformation;
You can use the following function to check if a port is available or not:
private bool isPortAvailable(int myPort)
{
var availablePorts = new List<int>();
var properties = IPGlobalProperties.GetIPGlobalProperties();
// Active connections
var connections = properties.GetActiveTcpConnections();
availablePorts.AddRange(connections);
// Active tcp listners
var endPointsTcp = properties.GetActiveTcpListeners();
availablePorts.AddRange(endPointsTcp);
// Active udp listeners
var endPointsUdp = properties.GetActiveUdpListeners();
availablePorts.AddRange(endPointsUdp);
foreach (int p in availablePorts){
if (p == myPort) return false;
}
return true;
}
I give you a similar function for those who use VB.NET:
Imports System.Net.NetworkInformation
Private Function isPortAvailable(ByVal myPort As Integer) As Boolean
Dim props As IPGlobalProperties = IPGlobalProperties.GetIPGlobalProperties()
' ignore active connections
Dim tcpConnInfoArray() As TcpConnectionInformation = props.GetActiveTcpConnections()
For Each tcpi As Net.NetworkInformation.TcpConnectionInformation In tcpConnInfoArray
If tcpi.LocalEndPoint.Port = myPort Then
Return False
End If
Next tcpi
' ignore active TCP listeners
Dim activeTcpListeners() As Net.IPEndPoint = props.GetActiveTcpListeners
For Each tcpListener As Net.IPEndPoint In activeTcpListeners
If tcpListener.Port = myPort Then
Return False
End If
Next tcpListener
' ignore active UPD listeners
Dim activeUdpListeners() As Net.IPEndPoint = props.GetActiveUdpListeners
For Each udpListener As Net.IPEndPoint In activeUdpListeners
If udpListener.Port = myPort Then
Return False
End If
Next udpListener
Return True
End Function
netstat! That's a network command line utility which ships with windows. It shows all current established connections and all ports currently being listened to. You can use this program to check, but if you want to do this from code look into the System.Net.NetworkInformation namespace? It's a new namespace as of 2.0. There's some goodies there. But eventually if you wanna get the same kind of information that's available through the command netstat you'll need to result to P/Invoke...
Update: System.Net.NetworkInformation
That namespace contains a bunch of classes you can use for figuring out things about the network.
I wasn't able to find that old pice of code but I think you can write something similar yourself. A good start is to check out the IP Helper API. Google MSDN for the GetTcpTable WINAPI function and use P/Invoke to enumerate until you have the information you need.
If I'm not very much mistaken, you can use System.Network.whatever to check.
However, this will always incur a race condition.
The canonical way of checking is try to listen on that port. If you get an error that port wasn't open.
I think this is part of why bind() and listen() are two separate system calls.
ipGlobalProperties.GetActiveTcpConnections() doesn't return connections in Listen State.
Port can be used for listening, but with no one connected to it the method described above will not work.
You say
I mean that it is not in use by any
other application. If an application
is using a port others can't use it
until it becomes free.
But you can always connect to a port while others are using it if something's listening there. Otherwise, http port 80 would be a mess.
If your
c = new TcpClient(ip, port);
fails, then nothing's listening there. Otherwise, it will connect, even if some other machine/application has a socket open to that ip and port.
Be aware the time window between you make check and the moment you try to make connection some process may take the port - classical TOCTOU. Why don't you just try to connect? If it fails then you know the port is not available.
You don't have to know what ports are open on your local machine to connect to some remote TCP service (unless you want to use a specific local port, but usually that is not the case).
Every TCP/IP connection is identified by 4 values: remote IP, remote port number, local IP, local port number, but you only need to know remote IP and remote port number to establish a connection.
When you create tcp connection using
TcpClient c;
c = new TcpClient(remote_ip, remote_port);
Your system will automatically assign one of many free local port numbers to your connection. You don't need to do anything.
You might also want to check if a remote port is open. but there is no better way to do that than just trying to connect to it.
public static bool TestOpenPort(int Port)
{
var tcpListener = default(TcpListener);
try
{
var ipAddress = Dns.GetHostEntry("localhost").AddressList[0];
tcpListener = new TcpListener(ipAddress, Port);
tcpListener.Start();
return true;
}
catch (SocketException)
{
}
finally
{
if (tcpListener != null)
tcpListener.Stop();
}
return false;
}
Check for error code 10048
try
{
TcpListener tcpListener = new TcpListener(ipAddress, portNumber);
tcpListener.Start();
}
catch(SocketException ex)
{
if(ex.ErrorCode == 10048)
{
MessageBox.Show("Port " + portNumber + " is currently in use.");
}
return;
}
I simply needed to verify if a port was available for listening. Condensing #Melloware example above to a one-liner as static method strictly for the purpose of indicating if the port is available works for me (.NET6).
using System.Net.NetworkInformation;
namespace MyNamespace
{
public static class NetworkValidation
{
public static bool IsListeningPortAvailable(int port) =>
!IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners().Any(x => x.Port == port);
}
}
Implementation as simple console app:
using MyNamespace;
int port = 5000;
var available = NetworkValidation.IsListeningPortAvailable(port);
Console.WriteLine($"Port:{port} available == {available}");
test_connection("ip", port);
public void test_connection(String hostname, int portno) {
IPAddress ipa = (IPAddress)Dns.GetHostAddresses(hostname)[0];
try {
System.Net.Sockets.Socket sock = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
sock.Connect(ipa, portno);
if (sock.Connected == true) {
MessageBox.Show("Port is in use");
}
sock.Close();
}
catch (System.Net.Sockets.SocketException ex) {
if (ex.ErrorCode == 10060) {
MessageBox.Show("No connection.");
}
}
}
try this, in my case the port number for the created object wasn't available so I came up with this
IPEndPoint endPoint;
int port = 1;
while (true)
{
try
{
endPoint = new IPEndPoint(IPAddress.Any, port);
break;
}
catch (SocketException)
{
port++;
}
}