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.
Related
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;
}
}
I am trying to implement a simple TCP server and I basically copied the example on MSDN sans a couple of lines and tried to make it work. I have an external client trying to connect already.
This is my code:
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPEndPoint localEP = new IPEndPoint(ipHostInfo.AddressList[0], 4001);
Socket listener = new Socket(localEP.Address.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
try
{
listener.Bind(localEP);
listener.Listen(1000);
while (true)
{
listener.BeginAccept(new AsyncCallback(AcceptCnxCallback), listener);
}
}
catch (Exception e)
{
//Log here
}
This is my callback:
private void AcceptCnxCallback(IAsyncResult iar)
{
MensajeRecibido msj = new MensajeRecibido();
Socket server = (Socket)iar.AsyncState;
msj.workSocket = server.EndAccept(iar);
}
And this is the information of one of the incoming packages:
TCP:[SynReTransmit #1727889]Flags=......S., SrcPort=57411, DstPort=4001, PayloadLen=0, Seq=673438964, Ack=0, Win=5840 ( Negotiating scale factor 0x4 ) = 5840
Source: 10.0.19.65 Destination: 10.0.19.59
I basically have two issues:
If I use the while loop I get an OutOfMemoryException
I never do manage to connect to the client
Any tips on either of the two problems? Thank you in advance!
Your problem is, that you use asynchronous calls all the time. There is no wait mechanism or similar, so generally you are just creating new asynchronous callbacks in an infinite loop.
For a basic TCP I would recommend to use the simple approach and use the synchronous methods.
Accept() is blocking, so the program flow will stop until there is an ingoing connection.
while (true)
{
Socket s = listener.Accept();
buffer = new byte[BUFFER_SIZE];
s.Receive(buffer);
//Do something
s.Send(...);
}
Noe that this is just a basic example. If you want to keep your connection you might consider a new Thread for each accepted Socket, that continoues with receiving and sending data.
First problem
You are using an infinite loop to call an async method.
try it like this:
listener.BeginAccept(new AsyncCallback(AcceptCnxCallback), listener);
//add your code here (this part will be executed wile the listner is waiting for a connection.
while (true)
{
Thread.Sleep(100);
}
and change the Callbackmethod to:
private void AcceptCnxCallback(IAsyncResult iar)
{
MensajeRecibido msj = new MensajeRecibido();
Socket server = (Socket)iar.AsyncState;
msj.workSocket = server.EndAccept(iar);
//call again the listener after you get a message
listener.BeginAccept(new AsyncCallback(AcceptCnxCallback), listener);
}
I have a C# application that receives UDP data from a remote host. I find that sometimes my socket receives nothing and I cant seem to find any clues as to why!
Wireshark tells me my data is being sent from the remote device correctly. I cant seem to get why sometimes I can receive fine, and sometimes I can't.
I don't get any exceptions, but OnRecieve never gets called
Here is my code in case it helps:
class cUdpRx
{
private Thread rxThread = null;
private Socket UdpSocket;
private IPEndPoint localEp;
byte[] byData;
//rxbytes event
public delegate void OnRxBytesEventHandler(byte[] rxBuf);
public event OnRxBytesEventHandler OnRxBytesEvent;
/// <summary>
/// Creates the udp socket
/// </summary>
/// <param name="Port"></param>
/// <returns></returns>
public bool CreateSocket(int Port)
{
try
{
byData = new byte[1500]; //create our buffer
UdpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
UdpSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
localEp = new IPEndPoint(IPAddress.Any,Port);
UdpSocket.Bind(localEp);
UdpSocket.BeginReceive(byData,0,byData.Length, SocketFlags.None, new AsyncCallback(OnRecieve), UdpSocket);
return true; //seemed to work ok
}
catch
{
Dispose();
return false; //something went wrong, abort
}
}
private void OnRecieve(IAsyncResult iar)
{
byte[] rxData;
int nBytesRec = 0;
Socket socket = (Socket)iar.AsyncState;
try //in case something else has already disposed of the socket
{
nBytesRec = socket.EndReceive(iar);
}
catch
{
Debug.WriteLine("cant access udp rx socket");
}
try
{
if (nBytesRec > 0)
{
rxData = new byte[nBytesRec];
Array.Copy(byData, rxData, nBytesRec); //copy exact data into new array
OnRxBytesEvent(rxData);
}
if(!killThreads)
UdpSocket.BeginReceive(byData, 0, byData.Length, SocketFlags.None, new AsyncCallback(OnRecieve), UdpSocket);
}
catch(SocketException se)
{
Debug.WriteLine(se.ToString());
}
}
Any help would be really appreciated as its stopping me from going forward with my project. Thanks
UPDATE
It seems like using IPAdress.any is the problem. If I change:
localEp = new IPEndPoint(IPAddress.Any,Port);
to
localEp = new IPEndPoint(IPAddress.Parse("192.168.0.33"),Port);
where 192.168.0.33 is the IP address of my computer, it receives data every time.
Can anyone explain why?
It is quite useful to use IPAddress.any and receive from both wireless and wired connections.
IPAddress.any is equivalent to 0.0.0.0 and according to MSDN it should receive on all network interfaces.
The usual cause of such problems is not processing packets fast enough. They fill up socket receive buffer and kernel starts dropping them.
Increase socket receive buffer size to accommodate traffic bursts.
Remove everything non-essential from the fast socket reading path.
Consider simple iterative approach bellow instead of working against thread pool:
rxData = new byte[nBytesRec];
while ( !time_to_stop ) {
int len = socket.Receive( rxData );
OnRxBytesEvent( rxData, len );
}
Your code comments mention multicast. Note that you need to add explicit group membership for that, and the fact that you join a multicast group on an interface (either explicitly or as decided via routing table), so if you want to listen for multicast data on two interfaces you need two sockets.
I just got the same problem and resolve it by set timeTolive to big data.
_client = new UdpClient();
_client.Client.Bind(new IPEndPoint(IPAddress.Any, targetURI.Port));
_client.JoinMulticastGroup(IPAddress.Parse(targetURI.Host) , 250);
timeToLive = 250, it works.
timeToLive = 50 , works or not work alternate happened.
timeToLive = none or 0, not work.
I have two applications, one connects to another via TCP Socket. I was having an issue and after a long troubleshooting I begun to think the root cause is due to the disconnection of the Socket, aka the Socket.state changes to Disconnected.
The reasons I came to above conclusion are just purely from reading the codes and analyze them. I need to prove that is the case and therefore my question is have you ever came accross this type of issue that the socket actually keep getting disconnected even after trying to connect to them?
Below is my Connect code, I have a loop that constantly check for the socket's state itself, if I detect the state is "Disconnected" I call this Connect() function again. Upon each and every time I call Connect() I noticed my socket state is back to Connected again.
So my questions are:
1. Have you seen this behavior yourself before?
2. Do you see any problem in me calling multiple Connect() again and again?
3. Is there a way to simulate this type of socket disconnections? I tried but I can't set the Socket.Connected flag.
public override void Connect()
{
try
{
sState = Defs.STATE_CONNECTING;
// send message to UI
string sMsg = "<Msg SocketStatus=\"" + sState + "\" />";
HandleMessage(sMsg);
// Create the socket object
sSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
string sIP = "";
// Define the Server address and port
if (Validate.IsIPAddress(sServer.ToString()))
{
sIP = sServer.ToString();
}
else
{
IPHostEntry iphost = Dns.GetHostEntry(sServer.ToString());
sIP = iphost.AddressList[0].ToString();
}
IPEndPoint epServer = new IPEndPoint(IPAddress.Parse(sIP), 1234);
// Connect to Server non-Blocking method
sSock.Blocking = false;
AsyncCallback onconnect = new AsyncCallback(OnConnect);
sSock.BeginConnect(epServer, onconnect, sSock);
}
catch (Exception ex)
{
LogException(new Object[] { ex });
}
}
For this question, I'm running windows 7 64 bit, .net framework 3.5
What I really want to know is
Is there a way to unbind/release a port that has been bound?
When I set the socketoption reuse address I am able to bind to the port but I never receive data using that address/port?
I'm looking at what ports are bound using netstat -apd udp
The test code I'm using is below, normally I would not close the port after receiving one packet.
EndPoint endpoint = new IPEndPoint(state.IPAddress, state.Port);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,ProtocolType.Udp);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
socket.Bind(endpoint);
ReadStateObject stateObject = new ReadStateObject();
stateObject.socket = socket;
stateObject.Port = state.Port;
stateObject.IPAddress = state.IPAddress;
stateObject.BurstDataReceivedEvent = state.BurstDataReceivedEvent;
stateObject.shutdownRequested = state.StopRequestedEvent;
socket.BeginReceiveFrom(stateObject.buffer,
0,
stateObject.buffer.Length,
SocketFlags.None, // Was 0 which is likely the same enumeration but this is clearer
ref endpoint,
new AsyncCallback(BurstUdpListener.SocketBeginReceiveAsyncCallback),
stateObject);
// wait for read to complete... or the thread to be asked to stop
while (stateObject.readFinished.WaitOne(100, false) == false)
{
// has this thread been requested to stop? if so, cancel the pending read
if (state.StopRequestedEvent.WaitOne(1, false) == true)
{
stop = true;
break;
}
}
socket.Shutdown(SocketShutdown.Both);
socket.Close();
socket = null;
private static void SocketBeginReceiveAsyncCallback(IAsyncResult ar)
{
if (ar.IsCompleted)
{
ReadStateObject state = ar.AsyncState as ReadStateObject;
if (state != null)
{
if (state.shutdownRequested.WaitOne(1, false))
return;
EndPoint endpoint = new IPEndPoint(state.IPAddress, state.Port);
int bytesReceived = state.socket.EndReceiveFrom(ar, ref endpoint); // for some reason throws error here on changes to settings
if (state.BurstDataReceivedEvent != null)
{
state.BurstDataReceivedEvent(null, new BurstDataReceivedEventArgs(state.buffer, bytesReceived));
}
state.readFinished.Set();
}
}
}
The port should be released when close() is called, so it sounds like either close() is not being called or it is not succeeding.
Remove the shutdown() call as that does not really apply to UDP.
Check the error return of close() to make sure both that it is being called and that it is returning success.