How to find out which endpoint caused the SocketException, UdpClient - c#

I'm using a UdpClient at the server end and it is sending data to the client end (more than one client).
Suddenly the client stops listening on the udp port and the server gets hit with an SocketException, either when calling endRecieve or beginRecieve.
To my understanding this is because of an "ICMP Destination Unreachable" and it's just telling the server the port's closed. That's ok, but neither of the SocketExceptions tell me which endpoint it is from.
How can I know which endpoint is closed so the server stops sending to it and causing more SocketExceptions?
Or is there a way for Udpclient to stop throwing these SocketExceptions so I can make the clients timeout if they don't respond after so and so seconds.

I'm dealing with the same issue myself so I'll be interested to see if anyone comes up with a better solution, but for now I have a couple ideas:
I have a comm wrapper class (let's call it AsyncComm) around my sockets that is passed an exception handler delegate from its owner class when it's constructed. The exception handler delegate takes arguments of an exception and a reference to the AsyncComm instance that threw it. I then put
try
{
// Do stuff here
{
catch (Exception e)
{
CallExceptionHandlerDelegate(e, this);
}
in each of my async handler methods in AsyncComm so they can throw their exceptions up the chain. In my case, the exception handler uses the reference to the AsyncComm instance to call a method in the AsyncComm instance to tell it to reinitialize its socket. You can change that behavior to whatever you need to do to stop continuously getting SocketExceptions.
Regarding determining the end point the exception came from, the only idea I have right now is parsing the end point from the end of the SocketException.Message string, but that seems like quite a kludge.
Update: It is a kludge but it works. Parse code below, some of it taken from this question.
private IPEndPoint parseEndPointFromString(string input)
{
// Matches 1-255.1-255.1-255.1-255:0-65535. I think.
const string IPPortRegex = #"(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?):(6553[0-5]|655[0-2]\d|65[0-4]\d\d|6[0-4]\d{3}|[1-5]\d{4}|[1-9]\d{0,3}|0)";
Match match = Regex.Match(input, IPPortRegex);
if (match.Success)
{
string IPPortString = match.Value;
string[] ep = IPPortString.Split(':');
if (ep.Length != 2) throw new FormatException("Invalid endpoint format");
IPAddress ip;
if (!IPAddress.TryParse(ep[0], out ip))
{
throw new FormatException("Invalid IP address");
}
int port;
if (!int.TryParse(ep[1], out port))
{
throw new FormatException("Invalid port");
}
return new IPEndPoint(ip, port);
}
else
{
throw new FormatException("Invalid input string, regex could not find an IP:Port string.");
}
}

Related

How to ignore exception

I am using a UDP socket to send then receive a message.
So when I receive I set the timeout exception to 4 seconds...
sending_socket.ReceiveTimeout = 4000;
sending_socket.ReceiveFrom(ByteFromListener, ref receiving_end_point);
Now I get this exception (which I am expecting) : An unhandled exception of type 'System.Net.Sockets.SocketException' occurred in System.dll
Additional information: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
I wanted to know how can i ignore this exception?
Basicly I want the UDPSOCKET to listen for 4 seconds and if no answer then try to send a message again.. My code is the following (part of it)
IPEndPoint sending_end_point = new IPEndPoint(sendto, sendPort);
EndPoint receiving_end_point = new IPEndPoint(IPAddress.Any, 0);
Socket sending_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
text_to_send = ("hello");
byte[] send_buffer = Encoding.ASCII.GetBytes(text_to_send);
sending_socket.SendTo(send_buffer, sending_end_point);
Byte[] ByteFromListener = new byte[8000];
sending_socket.ReceiveTimeout = 4000;
sending_socket.ReceiveFrom(ByteFromListener, ref receiving_end_point);
string datafromreceiver;
datafromreceiver = Encoding.ASCII.GetString(ByteFromListener).TrimEnd('\0');
datafromreceiver = (datafromreceiver.ToString());
try
{
sending_socket.ReceiveFrom(ByteFromListener, ref receiving_end_point);
}
catch (SocketException ex) { }
Instead of checking for exception, I suggest that you use sending_socket.Available (Read on MSDN) property.
You can add a logic where you check for the time elapsed since you sent the data and then if Available is not yet true, try to send again. Something like below:
bool data_received = false;
do
{
DateTime dtSent;
sending_socket.SendTo(send_buffer, sending_end_point);
dtSent = DateTime.Now;
while(DateTime.Now - dtSent < TimeSpan.FromSeconds(4))
{
while(sending_socket.Available)
{
int bytes_available = sending_socket.Available;
// you can use bytes_available variable to create a buffer of the required size only.
//read data... and concatenate with previously received data, if required
data_received = true;
}
Thread.Sleep(100); // sleep for some time to let the data arrive
}
}while(!data_received);
The above code is only a simple sample logic. Kindly modify it as per your requirement.
I strongly suggest that you do not depend on exceptions to handle cases which you already know may happen. Exceptions are meant to handle those cases which cannot be known in advance and where there is no mechanism to check for.
Also, SocketException can be raised for other reasons like Endpoint was not available, connection get lost due to any reason. Exception should be handled for these scenarios so that your code can handle those scenarios properly.

TcpClient dispose order

I am writing a network layer on top of TCP and I am facing some troubles during my UnitTest phase.
Here is what I'm doing (My library is composed of multiple classes but I only show you the native instructions causing my problems, to limit the size of the post):
private const int SERVER_PORT = 15000;
private const int CLIENT_PORT = 16000;
private const string LOCALHOST = "127.0.0.1";
private TcpClient Client { get; set; }
private TcpListener ServerListener { get; set; }
private TcpClient Server { get; set; }
[TestInitialize]
public void MyTestInitialize()
{
this.ServerListener = new TcpListener(new IPEndPoint(IPAddress.Parse(LOCALHOST), SERVER_PORT));
this.Client = new TcpClient(new IPEndPoint(IPAddress.Parse(LOCALHOST), CLIENT_PORT));
this.ServerListener.Start();
}
// In this method, I just try to connect to the server
[TestMethod]
public void TestConnect1()
{
var connectionRequest = this.ServerListener.AcceptTcpClientAsync();
this.Client.Connect(LOCALHOST, SERVER_PORT);
connectionRequest.Wait();
this.Server = connectionRequest.Result;
}
// In this method, I assume there is an applicative error within the client and it is disposed
[TestMethod]
public void TestConnect2()
{
var connectionRequest = this.ServerListener.AcceptTcpClientAsync();
this.Client.Connect(LOCALHOST, SERVER_PORT);
connectionRequest.Wait();
this.Server = connectionRequest.Result;
this.Client.Dispose();
}
[TestCleanup]
public void MyTestCleanup()
{
this.ServerListener?.Stop();
this.Server?.Dispose();
this.Client?.Dispose();
}
First of all, I HAVE TO dispose the server first if I want to connect earlier to the server on the same port from the same endpoint:
If you run my tests like this, it will run successfully the first time.
The second time, it will throw an exception, in both tests, on the Connect method, arguing the port is already in use.
The only way I found to avoid this exception (and to be able to connect on the same listener from the same endpoint) is to provoke a SocketException within the Server by sending bytes to the disposed client twice (on the first sending, there is no problem, the exception is thrown only on the second sending).
I don't even need to Dispose the Server if I provoke an Exception ...
Why is the Server.Dispose() not closing the connection and freeing the port ??? Is there a better way to freeing the port than by provoking an Exception ?
Thanks in advance.
(Sorry for my English, I am not a native speaker)
Here is an example within a main fonction, to be checkout more easily:
private const int SERVER_PORT = 15000;
private const int CLIENT_PORT = 16000;
private const string LOCALHOST = "127.0.0.1";
static void Main(string[] args)
{
var serverListener = new TcpListener(new IPEndPoint(IPAddress.Parse(LOCALHOST), SERVER_PORT));
var client = new TcpClient(new IPEndPoint(IPAddress.Parse(LOCALHOST), CLIENT_PORT));
serverListener.Start();
var connectionRequest = client.ConnectAsync(LOCALHOST, SERVER_PORT);
var server = serverListener.AcceptTcpClient();
connectionRequest.Wait();
// Oops, something wrong append (wrong password for exemple), the client has to be disposed (I really want this behavior)
client.Dispose();
// Uncomment this to see the magic happens
//try
//{
//server.Client.Send(Encoding.ASCII.GetBytes("no problem"));
//server.Client.Send(Encoding.ASCII.GetBytes("oops looks like the client is disconnected"));
//}
//catch (Exception)
//{ }
// Lets try again, with a new password for example (as I said, I really want to close the connection in the first place, and I need to keep the same client EndPoint !)
client = new TcpClient(new IPEndPoint(IPAddress.Parse(LOCALHOST), CLIENT_PORT));
connectionRequest = client.ConnectAsync(LOCALHOST, SERVER_PORT);
// If the previous try/catch is commented, you will stay stuck here,
// because the ConnectAsync has thrown an exception that will be raised only during the Wait() instruction
server = serverListener.AcceptTcpClient();
connectionRequest.Wait();
Console.WriteLine("press a key");
Console.ReadKey();
}
You may need to restart Visual Studio (or wait some time) if you trigger the bug and the program refuse to let you connect.
Your port is already in use. Run netstat and see. You'll find ports still open in the TIME_WAIT state.
Because you have not gracefully closed the sockets, the network layer must keep these ports open, in case the remote endpoint sends more data. Were it to do otherwise, the sockets could receive spurious data meant for something else, corrupting the data stream.
The right way to fix this is to close the connections gracefully (i.e. use the Socket.Shutdown() method). If you want to include a test involving the remote endpoint crashing, then you'll need to handle that scenario correctly as well. For one, you should set up an independent remote process that you can actually crash. For another, your server should correctly accommodate the situation by not trying to use the port again until an appropriate time has passed (i.e. the port is actually closed and is no longer in TIME_WAIT).
On that latter point, you may want to consider actually using the work-around you've discovered: TIME_WAIT involves the scenario where the status of the remote endpoint is unknown. If you send data, the network layer can detect the failed connection and effect the socket cleanup earlier.
For additional insights, see e.g.:
Port Stuck in Time_Wait
Reconnect to the server
How can I forcibly close a TcpListener
How do I prevent Socket/Port Exhaustion?
(But do not use the recommendation found among the answers to use SO_REUSEADDR/SocketOptionName.ReuseAddress…all that does is hide the problem, and can result in corrupted data in real-world code.)

Client socket cannot connect but does not throw an SocketException

My asynchronous connect code is very rudimentary and is as followed:
private Socket _socket;
public void Connect(IPEndPoint remoteEndPoint, bool persistentConnection)
{
_logger.Trace("Attempting To Connect To " + remoteEndPoint.Address);
_remoteEndPoint = remoteEndPoint;
_persistentConnection = persistentConnection;
_socket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
_socket.BeginConnect(_remoteEndPoint, ConnectCallback, null);
}
The Connect() method is accompanied by ConnectCallback() which is the where the problem I will describe shortly occurs:
private void ConnectCallback(IAsyncResult asyncResult)
{
try
{
_socket.EndConnect(asyncResult);
_logger.Trace("Successfully Connected To " + _remoteEndPoint.Address);
}
catch (SocketException)
{
_logger.Trace("Failed To Connect To " + _remoteEndPoint.Address);
if (_persistentConnection)
{
Thread.Sleep(TimeSpan.FromSeconds(3));
Connect(_remoteEndPoint, true);
return;
}
}
_socketWriter.AssignSocket(_socket);
_socket.BeginReceive(..);
}
My networking code is encapsulated within a single assembly. Today I decided to reference the assembly from another applications and found the ConnectCallback method to behave very oddly.
I make a call to Connect() when the server application is not running. This means it is not physically possible for the connection to succeed. Because the remote end point is not available, I would expect EndConnect to throw an exception. Instead EndConnect appears to succeed because even though the socket is not really connected, my code proceeds to make a call to _socket.BeginReceive which of course, throws an exception because the socket is not connected.
What is especially bizarre is that if I place a break point on the opening try brace and step-through the call back code the exception is thrown and handled.
This happens on local host.
Why am I experiencing this behaviour and how can I ensure that EndConnect throws a SocketException is the connection cannot established consistently?
You only return from the catch if _persistentConnection is true. If not, you call BeginReceive() anyway.

Socket's state changes from Connected to Disconnected

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 });
}
}

debugging sockets and DLL's

First question now answered if you want to skip to the bottom..
I'm developing comms between PDA's on .net 2.0 and our servers. Can't use WCF or I would have.
The comms model is like this:
And fortunately i've found working code form http://aviadezra.blogspot.com/2008/07/code-sample-net-sockets-multiple.html - that's where the image above comes from too.
The example app has messages from each client being broadcast to all other clients. I would like to be able to send a message from one client to another specific client. To do this i've modified the client app to have a from-ID and To-ID which is sent as part of the message.
Note: At this stage i'm doing proof of concept - i'll work on things like message headers (lengths, versions etc later).
From the project each client connection is handled by:
private void OnClientConnection(IAsyncResult asyn)
{
if (m_Closed)
{
return;
}
try
{
Socket clientSocket = m_socket.EndAccept(asyn);
RaiseClientConnected(clientSocket);
ConnectedClient connectedClient = new ConnectedClient(clientSocket);
connectedClient.MessageRecived += OnMessageRecived;
connectedClient.Disconnected += OnClientDisconnection;
connectedClient.StartListen();
long key = clientSocket.Handle.ToInt64();
if (m_clients.ContainsKey(key))
{
Debug.Fail(string.Format(
"Client with handle key '{0}' already exist!", key));
}
m_clients[key] = connectedClient;
// create the call back for any client connections...
m_socket.BeginAccept(new AsyncCallback(OnClientConnection), null);
}
catch (ObjectDisposedException odex)
{
Debug.Fail(odex.ToString(),
"OnClientConnection: Socket has been closed");
}
catch (Exception sex)
{
Debug.Fail(sex.ToString(),
"OnClientConnection: Socket failed");
}
}
Class connectedClient holds the socket for that client.
When I send a message from client I do a lookup to see if that's in my list of sockets:
if (ListIDSocket.ContainsKey(ToID))
{
PublishMessage(listLog, "ToID Found");
SendAll = false;
}
ListIDSocket is:
private Dictionary<string, Socket> ListIDSocket = new Dictionary<string, Socket>();
Then..
if (SendAll)
m_ServerTerminal.DistributeMessage(buffer);
else
m_ServerTerminal.SendToSocket(ToID, socket, buffer);
So if message is to anyone, call DistributeMessage; if to single user, call SendToSocket.
The code in m_ServerTerminal is:
public void DistributeMessage(byte[] buffer)
{
try
{
foreach (ConnectedClient connectedClient in m_clients.Values)
{
connectedClient.Send(buffer);
}
}
catch (SocketException se)
{
Debug.Fail(se.ToString(), string.Format(
"Buffer could not be sent"));
}
}
public void SendToSocket(string ToID, Socket DestSocket, byte[] buffer)
{
DistributeMessage(buffer); // This line works
ConnectedClient ToClient;
long keyval = DestSocket.Handle.ToInt64();
if (m_clients.ContainsKey(keyval))
{
ToClient = (ConnectedClient)m_clients[keyval];
try
{
ToClient.Send(buffer); // Nothing is received
}
catch (SocketException se)
{
Debug.Fail(se.ToString(), se.Message);
}
// DistributeMessage(buffer); // This code here doesn't work
}
}
DistributeMessage works fine. For debugging purposes i've included a call to DistributeMessage in my SendToSocket and this works if it's at the top.
If I move it down after I try writing to to the socket, it doesn't.
I don't get an exception on either way.
As it stands now, client gets one message when it should get two - one from DistributeMessage and one from SendToSocket.
The code for connectedclient.Send is:
public void Send(byte[] buffer)
{
if (m_clientSocket == null)
{
throw new Exception("Can't send data. ConnectedClient is Closed!");
}
m_clientSocket.Send(buffer);
}
Questions:
I can't see anything that i'm doing substantially different with my new code to existing but the socket isn't being written to. Can anyone spot anything obvious ? Is this something to do with sockets, handles and references to them ?
EDIT: Bug found, whilst I was looking up to see if the socket existed, I was passing in the socket of the sender not receiver. I'll fix this.
Debugging DLL's I'd still like to know about though..
Secondly, the project is setup with the socket handling in it's own DLL called Communication.Sockets.Core. I've never built DLL's before and i'm having trouble debugging. Can't use normal debug points in code - I resorted to creating a form to display instead.
Any tips on how to debug DLL's ?
I'm still fairly new to C#; just on 1 year.
TIA,
Andrew

Categories

Resources