I am trying to create an asynchronous methode to verify if i can connect with an host Through TCP. It seem like i am not releasing correctly all the memory i use.
I'm i forgetting something ?
My Connection Indicator is :
Bool CanConnectToHost = false;
My Function is :
private async void TryToConnectToHost()
{
// host IP Address and communication port
string ipAddress = Properties.Settings.Default.HostIPaddr;
int port = 9100;
//Try to Connect with the host
try
{
TcpClient client = new TcpClient();
await client.ConnectAsync(ipAddress, port);
//Verify if connected succesfully
if (client.Connected)
{
//Connection with host
CanConnectToHost = true;
}
else
{
// No connection with host
CanConnectToHost = false;
}
//Close Connection
client.Close();
}
catch (Exception exception)
{
//Do Something
}
}
Thx a lot
I don't think you need to care about memory here. What you probably observe is that the Garbage Collection doesn't bother to clean up all memory immediatly after your method is finished. It will do so eventually when it has time or your process starts to run out of free memory.
TcpClient.ConnectAsync() throws a SocketException if the connection cannot be established. So your code has the flaw that in case of that exception, you don't set your CanConnectToHost correctly (though it is false by initialization).
I recommend to use using here. That also has the advantage that Close() will also be called in case of the exception. And Close() will also free any resources used by the TcpClient immediatly and not only if GC starts to work.
Your code with using:
private async void TryToConnectToHost()
{
// host IP Address and communication port
string ipAddress = Properties.Settings.Default.HostIPaddr;
int port = 9100;
//Try to Connect with the host
try
{
using (TcpClient client = new TcpClient())
{
await client.ConnectAsync(ipAddress, port);
CanConnectToHost = client.Connected; // no need for if
}
}
catch (Exception exception)
{
CanConnectToHost = false;
}
}
Related
Punching the UDP network works and works. However, when it comes to TCP, it's possible that I'm writing something wrong but I'm not a beginner programmer, or maybe I don't understand something.
Of course, I'll shorten a bit, we assume that we already have something as trivial as connection to an external server :)
Packet synchronization between threads as well as their creation, queuing, serialization, sending raw bytes and much more I skip because it is about the element of creating TCP sockets and not what works.
We will use the TcpListener class for the server.
public void InitializeServer(IPAddress address, int port)
{
try
{
// 127.0.0.1 accept only local connections, 0.0.0.0 is open for whole internet connections
listener = new TcpListener(address, port);
socket = listener.Server;
// Enable NAT Translation
listener.AllowNatTraversal(true);
// Start listening for example 10 client requests.
listener.Start(listenQueue);
Debug.Log($"[L{socket.LocalEndPoint}]Server start... ", EDebugLvl.Log);
OnServerInitialize(true);
// Enter the listening loop.
StartListener();
}
catch (SocketException e)
{
Debug.LogError($"SocketException: {e}", EDebugLvl.Error);
OnServerInitialize(false);
}
}
We start listening
private void StartListener()
{
Debug.Log("\nWaiting for a connection... ");
listener.BeginAcceptTcpClient(AcceptCallback, listener);
}
When the server receives the connection, we create a new socket
private void AcceptCallback(IAsyncResult ar)
{
TcpListener server = (TcpListener)ar.AsyncState;
TcpClient newClient = null;
try
{
newClient = server.EndAcceptTcpClient(ar);
}
catch (Exception e)
{
Debug.LogError(e.ToString());
}
if (newClient != null && newClient.Connected)
{
//...
client.StartRead();
}
//Loop
StartListener();
}
We create a new socket at the client and try to establish a connection
public void Connect(IPEndPoint remote, IPEndPoint bind = null, bool reuseAddress = false)
{
if (bind == null)
{
client = new TcpClient();
}
else
{
client = new TcpClient(bind);
}
socket = client.Client;
if (reuseAddress)
{
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, reuseAddress);
//It throws me a error SocketOption so im comment this.
//socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseUnicastPort, reuseAddress);
}
client.BeginConnect(remote.Address, remote.Port, ConnectCallback, null);
}
The connection works without any problems and data transfer.
Unfortunately, here as we know, we must start a new socket listening on the same address and port that was created when connecting to the server. I do this for every client.
public void StartHost(Client server)
{
if (server != null && server.socket.Connected)
{
IPEndPoint localHost = (IPEndPoint)server.socket.LocalEndPoint;
InitializeHost(localHost.Address, localHost.Port);
}
}
public void InitializeHost(IPAddress address, int port, bool reuse = false)
{
try
{
listener = new TcpListener(address, port);
socket = listener.Server;
if (reuse)
{
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseUnicastPort, true);
}
// Enable NAT Translation
listener.AllowNatTraversal(true);
// Start listening for example 10 client requests.
listener.Start(listenQueue);
Debug.Log($"\n[L{socket.LocalEndPoint}]Host start... ", EDebugLvl.Log);
OnServerInitialize(true);
// Enter the listening loop.
StartListener();
}
catch (SocketException e)
{
Debug.LogError($"SocketException: {e}", EDebugLvl.Error);
OnServerInitialize(false);
}
}
private void StartListener()
{
Debug.Log("\nWaiting for a connection... ");
listener.BeginAcceptTcpClient(AcceptCallback, listener);
}
private void AcceptCallback(IAsyncResult ar)
{
TcpListener server = (TcpListener)ar.AsyncState;
TcpClient newClient = null;
try
{
newClient = server.EndAcceptTcpClient(ar);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
if (newClient != null && newClient.Connected)
{
//...
client.StartRead();
}
//Loop
StartListener();
}
So, as they write everywhere ... client "B" sends a packet to the server that wants to establish a connection, the server sends information to the client "A" about the client "B" and vice versa
Then they both try to connect with the new socket? No problem...
public void Connect(IPEndPoint remote, IPEndPoint bind = null, bool reuseAddress = false)
{
if (bind == null)
{
client = new TcpClient();
}
else
{
client = new TcpClient(bind);
}
socket = client.Client;
if (reuseAddress)
{
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, reuseAddress);
//socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseUnicastPort, reuseAddress);
}
client.BeginConnect(remote.Address, remote.Port, ConnectCallback, null);
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
client.EndConnect(ar);
}
catch (Exception e)
{
Debug.LogError(e.ToString(), EDebugLvl.ConnectionError);
}
if (client.Connected)
{
Debug.Log($"[P{socket.RemoteEndPoint}, L{socket.LocalEndPoint}]Connected", EDebugLvl.ConnectionLog);
stream = new NetworkStream(socket, FileAccess.ReadWrite, true);
StartRead();
}
ConnectedComplete(this, socket.Connected);
}
No matter how many times I try, the connection is rejected ... the addresses match everywhere and yet it does not work, so I have nothing to write about in this case, especially since UDP works for me.
What I wrote only works on the same NAT network. Unfortunately, I noticed that on the same NAT created two connections. One is the result of trying to connect the new socket A to B and the other is the result of receiving a new connection from B to A, so each client has one unnecessary socket connected by a local address. So all NAT TCP / IP Punch NAT doesn't work for me. I can actually use UDP but I really need TCP. I have been sitting on it for several months in my free time but nowhere can I find an example from the code and not the theory of which there is a lot.
I accumulated a lot of knowledge for 8 years and from 2 I write applications using sockets and finally I need to punch the net.
Why won't I use the ready solution? I need my own which is fully open using only UDP and TCP because some target devices only support these protocols. I also used the Socket class but this one did not give me a working copy.
Maybe someone will be able to help me for which I would be very grateful and certainly the post will also help others understand this.
Regards
Octavian
NAT hole punching only works with UDP, and even that is a hack.
NAT firewall implementations will start tracking a TCP stream when they see the initial SYN packet leaving the network. To capture incoming TCP streams you need to create an incoming rule on the router, there's no way around this. If the router supports UPnP, you can ask it to create that rule for you dynamically.
Since UDP doesn't have a SYN packet equivalent, routers will start tracking the stream on any outgoing packet. This is why NAT hole punching works. If both end points are behind NAT and just assume that the link will work. Both can just start sending UDP packets to each other. The routers will add the connection state, and map the incoming packets to each endpoint.
TcpClient tcp = new TcpClient();
bool failed = false;
IAsyncResult connection = tcp.BeginConnect(host, port, null, null);
if (!connection.AsyncWaitHandle.WaitOne(_connectTimeout))
{
failed = true;
if (tcp.Client.Connected)
{
tcp.GetStream().Close();
tcp.Close();
}
}
else
{
if (!tcp.Connected)
{
failed = true;
if (tcp.Client.Connected)
{
tcp.GetStream().Close();
}
tcp.Close();
}
}
return tcp;
The code above is what I call to connect to a host, port of a proxy.
The WaitOne is essentially a timeout. If it returns false, it's timed out.
My question here, is am I calling Close/Dispose/GetStream().Close etc properly on each condition? From what I can tell I should be using EndConnect here with the connection variable but wherever I try to place it, it gives me a SocketException saying the target machine refused connection, yet its either not connected anyway or it IS connected already.
This resolved my question (It's an edit by me of another solution, credit below):
TcpClient tcp = new TcpClient();
#region Try connect
IAsyncResult ar = tcp.BeginConnect(host, port, (ari) => {
TcpClient tcpi = (TcpClient)ari.AsyncState;
try {
tcpi.EndConnect(ari);
} catch { }
if (tcpi.Connected) {
return; //return IAsyncResult and waitone will be true
}
//otherwise it will close the tcpi and never return, causing the timeout to kickin.
tcpi.Close();
}, tcp);
#endregion
#region If timed out, or not connected return null
if (!ar.AsyncWaitHandle.WaitOne(_connectTimeout, false) || !tcp.Connected) {
return null; //this is my use case, you might want to do something different
}
#endregion
return tcp;
Credit for linking another similar question:
#JeroenMostert
Credit for original solution on the similar question:
#Adster
I'm currently developing a autodiscover feature for SNMP printer monitor software. I need a helper method, which is executed from several threads each checking an ip in a range, to determine if a device at a certain ip address, is responding to port 9100, to establish that it in fact is a printer, before sending an SNMP request to it.
I've ended up with the following method, however im unaware if this is the correct approach, and if it by convention is correct use of the Close() method in this context (I can see that Dispose(), Disconnect() and Shutdown() methods are also available, so which to use?). Furthermore i need to set a timeout value of max. 5 seconds, so the threads won't linger for too long, before presenting a result. My code so far:
private bool GetTCPPrinterResponse(IPAddress _ip)
{
int port = 9100;
bool isResponsive = false;
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
s.Connect(_ip, port);
isResponsive = true;
}
catch (SocketException)
{
isResponsive = false;
}
finally
{
s.Close();
}
return isResponsive;
}
After method edit:
private bool GetTCPPrinterResponse(IPAddress _ip)
{
int port = 9100;
bool isResponsive = false;
using (Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
s.ReceiveTimeout = 3000;
s.SendTimeout = 3000;
try
{
s.Connect(_ip, port);
isResponsive = true;
}
catch (SocketException)
{
isResponsive = false;
}
}
return isResponsive;
}
Setting of Timeout properties, has no effect.
That is the correct way to check if a computer/printer is online at a certain IP on a certain Port.
You should call the dispose method to release the memory being used by the object.
Socket class implements IDisposable, so it would be best if you use using and not worry about calling dispose because using does it for you.
using(Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
//...
}
Socket class has properties ReceiveTimeout and SendTimeout.
There is no need to use multi-threading for this. You're tying up threads that will end up waiting for the I/O operation to complete anyway. Instead, why not use asynchronous I/O?
public async Task<Tuple<IPAddress, bool>> GetResponse(IPAddress address)
{
using (var client = new TcpClient(AddressFamily.InterNetwork))
{
var connectTask = client.ConnectAsync(address, 80);
await Task.WhenAny(connectTask, Task.Delay(5000));
if (connectTask.IsCompleted)
return Tuple.Create(address, true);
else
return Tuple.Create(address, false);
}
}
This can further be improved - the timeout mechanism is somewhat wasteful (Task.Delay uses a timer, not really necessary), but it's easy to write, understand and use, and it doesn't unnecessarily waste threads.
The call would then be something like this:
Task<Tuple<IPAddress, bool>>[] tasks =
new []
{
GetResponse(Dns.GetHostAddresses("www.google.com").First()),
GetResponse(Dns.GetHostAddresses("www.microsoft.com").First()),
GetResponse(Dns.GetHostAddresses("www.yahoo.com").First()),
GetResponse(Dns.GetHostAddresses("www.altavista.com").First()),
};
Task.WhenAll(tasks).Wait();
foreach (var t in tasks)
t.Result.Dump(); // t.Result has the IP address and status
This will wait for all of the devices to respond (or timeout). Of course, there's nothing preventing you from doing this in a more interactive fashion - you could just as easily update the UI with the data as it comes back.
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 need to poll a server, which is running some propriatary software, to determine if this service is running. Using wireshark, I've been able to narrow down the TCP port its using, but it appears that the traffic is encrypted.
In my case, its a safe bet that if the server is accepting connections (i.e. telnet serverName 1234) the service is up and all is OK. In other words, I don't need do any actual data exchange, just open a connection and then safely close it.
I'm wondering how I can emulate this with C# and Sockets. My network programming basically ends with WebClient, so any help here is really appreciated.
The process is actually very simple.
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
try
{
socket.Connect(host, port);
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.ConnectionRefused)
{
// ...
}
}
}
Just use TcpClient try to connect to the server, TcpClient.Connect will throw an exception if the connection fails.
bool IsListening(string server, int port)
{
using(TcpClient client = new TcpClient())
{
try
{
client.Connect(server, port);
}
catch(SocketException)
{
return false;
}
client.Close();
return true;
}
}
I've used the following code. There is one caveat ... in a high transaction environment, the client's available ports may run out as the sockets are not released by the OS at the same rate they are released by the .NET code.
If anyone's got a better idea, please post. I've seen snowball issues arise where the server can no longer make outgoing connections. I'm working on a better solution ...
public static bool IsServerUp(string server, int port, int timeout)
{
bool isUp;
try
{
using (TcpClient tcp = new TcpClient())
{
IAsyncResult ar = tcp.BeginConnect(server, port, null, null);
WaitHandle wh = ar.AsyncWaitHandle;
try
{
if (!wh.WaitOne(TimeSpan.FromMilliseconds(timeout), false))
{
tcp.EndConnect(ar);
tcp.Close();
throw new SocketException();
}
isUp = true;
tcp.EndConnect(ar);
}
finally
{
wh.Close();
}
}
}
catch (SocketException e)
{
LOGGER.Warn(string.Format("TCP connection to server {0} failed.", server), e);
isUp = false;
}
return isUp;
Use the TcpClient class to connect the server.