(Apparently) Gracefully Closed UDPClient leaves the socket blocked - c#

The following code, despite apparently closing the UDP Socket, leaves it hanging and unable to reconnect to the same address / port.
These are the class variables I use:
Thread t_listener;
List<string> XSensAvailablePorts;
private volatile bool stopT_listener = false;
volatile UdpClient listener;
IPEndPoint groupEP;
I create and launch a new thread with a method which will handle the Socket connection and listening:
private void startSocketButton_Click(object sender, RoutedEventArgs e)
{
stopT_listener = false;
closeSocketButton.IsEnabled = true;
startSocketButton.IsEnabled = false;
t_listener = new Thread(UDPListener);
t_listener.Name = "UDPListenerThread";
t_listener.Start();
}
The method is the following (I use a time-out on the Receive in order to not leave it blocked if nothing is being sent on the socket and a Stop is being issued):
private void UDPListener()
{
int numberOfPorts = XSensAvailablePorts.Count();
int currAttempt = 0;
int currPort = 0;
bool successfullAttempt = false;
while (!successfullAttempt && currAttempt < numberOfPorts)
{
try
{
currPort = Int32.Parse(XSensAvailablePorts[currAttempt]);
listener = new UdpClient(currPort);
successfullAttempt = true;
}
catch (Exception e)
{
currAttempt++;
}
}
if (successfullAttempt)
{
//timeout = 2000 millis
listener.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 2000);
//Tried with and without, no change: listener.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
statusTB.Dispatcher.BeginInvoke((Action)delegate() { statusTB.Text = "Connected on port:" + currPort; });
groupEP = new IPEndPoint(IPAddress.Parse("143.225.85.130"), currPort);
byte[] receive_byte_array;
try
{
while (!stopT_listener)
{
try
{
receive_byte_array = listener.Receive(ref groupEP);
if (receive_byte_array.Length == 0 || receive_byte_array == null)
continue;
ParseData(receive_byte_array, samplingDatagramCounter);
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.TimedOut)
continue;
}
}
}
catch (Exception e)
{
Debug.Print(e.Message);
}
finally
{
if (listener != null)
{
listener.Client.Shutdown(SocketShutdown.Both);
listener.Close();
}
}
}
statusTB.Dispatcher.BeginInvoke((Action)delegate() { statusTB.Text = "Not Connected"; });
return;
}
I order the thread / socket to stop with this method:
private void closeSocketButton_Click(object sender, RoutedEventArgs e)
{
stopT_listener = true;
closeSocketButton.IsEnabled = false;
startSocketButton.IsEnabled = true;
t_listener.Join();
if (listener.Client != null)
{
listener.Client.Shutdown(SocketShutdown.Both);
listener.Close();
}
if (t_listener.IsAlive)
{
t_listener.Abort();
statusTB.Text = "Aborted";
}
else
statusTB.Text = "Not Connected";
}
Despite checking in debug that the socket has been closed, if I retry to connect to the same port, I am unable to do so because it raises a SocketException saying that only one usage of port/address is normally permitted.

I put code you provided in a simple form to run it and... I cannot directly reproduce your problem. I haven't send any data to the client though, but as far as I understand it shouldn't change anything as it's UDP and we're investigating (re)opening socket, not transmitting data.
When clicking Start/Stop buttons the socket is always properly opened and closed, reopening works as intended.
For me the only way to force the SocketException you mentioned was to introduce some obvious misuse of socket logic:
Run two instances of application and click Start in both.
Remove BOTH occurrences of Shutdown and Close (Stop doesn't close socket).
Running app, opening socket, closing the app without closing socket, running app again, trying to open socket.
Only changes I made in your code was removing ParseData(...) line and adding some ports to XSensAvailablePorts list.
Can you check if the port is still open after you apparently close it? You can use netstat -an, or an excellent tool ProcessExplorer. You can also check if the t_listener thread is terminating correctly (standard Task Manager or ProcessExplorer can help you).

Set the listener object to NULL so the resource is released which should also free the connection.

i have same problem, and the problem is in UDPClient.Receive(), she keep the socket in state of used even you call Close/shutdown/... `
try{ // receive loop}
catch{}
finally {
UDP_Listner.Close();
UDP_Listner = null;
}
EDIT :
t_listener = new Thread(UDPListener);//replace by :
t_listener = new Thread(new ThreadStart(UDPListener));
`
to safely close socket & thread ( http://msdn.microsoft.com/en-us/library/system.threading.threadstart(v=vs.110).aspx )

I have the same problem, I am the safest programmer, I always close everything nicely. yet I found that the .net class does not close the socket fast enough. because if I go slow it doesn't happen, but if I open and close(cleanup fully) and open it fast, I get the same error. especially if the user wants to run the same code again and open the port again.

Might be an old answer, but in your attempt to find a usable port, but which failed, i would dispose the listener instance you tested before the next iteration.
try
{
currPort = Int32.Parse(XSensAvailablePorts[currAttempt]);
listener = new UdpClient(currPort);
successfullAttempt = true;
}
catch (Exception e)
{
currAttempt++;
if(listener != null)
{
listener.Close();
}
}

I think Bind or reuse can solve this (even if socket is not closed yet it can be reused and no error is thrown)
Example code:
udpClient = new UdpClient();
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, p));

Related

Am I closing the TCP Client efficiently?

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

Socket on a Thread stops processing and locks the UI

I have a standalone test application developed in c# (4.5).
The application is primarily meant for sending some data to COM ports. The application accepts the data through the UI and the corresponding data is sent to respective COM ports.
For eg: Data from text box 1 goes to COM 1 on pressing a button, Data from Textbox 2 goes to COM 2 on pressing a different button etc.
Later I had to add a functionailty where a different set of data has to be accepted via Windows sockets and has to be sent to a different COM port other than above. This listening socket could receive data from multiple sources. If the listening socket receives back to back socket data, the application is expected to queue the data and process the data on a First come first serve bases.
Hence I created a synchronous socket to receive data. If the server receives data from 2 sources, it processes the data from source 1 and sends the completion status to source 1 and then takes the data from source 2,processes it and informs the status and this goes on. The socket is created on a thread so that it could receive and process data independently from the UI.
The application was meeting its objective as most of the communication was through sockets and people were not really using the UI for entering data.
Recently, as people started UI, i noticed a completely new issue. When someone tries to enters a data on to UI while the socket data is in process, it stops the socket data processing. When I press ctrl+Alt+Del on the host, it resumes the processing of the socket data.
I could not identify my mistake here. Also, I looked over to the Backgroundworkder class but I am not sure if that would allow the sockets commands to be processed in a synchronous way.
Please treat me as a newbie as I am still learning and complex suggestions might be hard to digest.
public partial class frm_bot : Form
{
public frm_bot()
{
StartServer();
}
private void frm_bot_Load(object sender, EventArgs e)
{
try
{
myThread = new System.Threading.Thread(new System.Threading.ThreadStart(OnClientConnect));
myThread.IsBackground = true;
myThread.Start();
}
catch (Exception ex)
{
showErrorMsg(ex.Message);
}//catch
}
public void StartServer()
{
InitializeComponent();
System.Net.IPAddress localIPAddress = System.Net.IPAddress.Parse(GetlocalIp());
IPEndPoint ipLocal = new IPEndPoint(localIPAddress, 8089);
_listener = new TcpListener(ipLocal);
}
private void OnClientConnect()
{
try
{
_listener.Start();
TcpClient clientSocket = default(TcpClient);
clientSocket = _listener.AcceptTcpClient();
_clientSocket = clientSocket;
ReadCallback();
}
catch (Exception se)
{
MessageBox.Show("Could not bind to Port 8089! Please close all Applications that uses Port 8089");
}
}
public void ReadCallback()
{
try
{
using (StreamReader sr = new StreamReader(_clientSocket.GetStream()))
using (StreamWriter sw = new StreamWriter(_clientSocket.GetStream()))
{
sw.AutoFlush = true;
char[] c = null;
while (sr.Peek() >= 0)
{
c = new char[25];
sr.Read(c, 0, c.Length);
Console.WriteLine(c);
}
string d = new string(c);
string[] cmddata = d.Split('\0');
string dataFromClient = cmddata[0];
if (dataFromClient.Length == 0)
{
Console.WriteLine("Client sent empty string!");
}
else
{
ProcessSocketData(dataFromClient);
sw.Write("Done");
}
sw.Close();
}
OnClientConnect();
}
catch (Exception ex)
{
OnClientConnect();
return;
}
}
public void ProcessSocketData(string sockdata)
{
try
{
// Socket data is processed here.
}
catch (Exception ex)
{
MessageBox.Show("Exception on ProcessSocketData: " + ex.Message);
return;
}
}
}

TcpClient.Connected Always True [duplicate]

I'm playing around with the TcpClient and I'm trying to figure out how to make the Connected property say false when a connection is dropped.
I tried doing
NetworkStream ns = client.GetStream();
ns.Write(new byte[1], 0, 0);
But it still will not show me if the TcpClient is disconnected. How would you go about this using a TcpClient?
I wouldn't recommend you to try write just for testing the socket. And don't relay on .NET's Connected property either.
If you want to know if the remote end point is still active, you can use TcpConnectionInformation:
TcpClient client = new TcpClient(host, port);
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] tcpConnections = ipProperties.GetActiveTcpConnections().Where(x => x.LocalEndPoint.Equals(client.Client.LocalEndPoint) && x.RemoteEndPoint.Equals(client.Client.RemoteEndPoint)).ToArray();
if (tcpConnections != null && tcpConnections.Length > 0)
{
TcpState stateOfConnection = tcpConnections.First().State;
if (stateOfConnection == TcpState.Established)
{
// Connection is OK
}
else
{
// No active tcp Connection to hostName:port
}
}
client.Close();
See Also:
TcpConnectionInformation on MSDN
IPGlobalProperties on MSDN
Description of TcpState states
Netstat on Wikipedia
And here it is as an extension method on TcpClient.
public static TcpState GetState(this TcpClient tcpClient)
{
var foo = IPGlobalProperties.GetIPGlobalProperties()
.GetActiveTcpConnections()
.SingleOrDefault(x => x.LocalEndPoint.Equals(tcpClient.Client.LocalEndPoint));
return foo != null ? foo.State : TcpState.Unknown;
}
As far as I know/remember there is no way to test if a socket is connected other than reading or writing to it.
I haven't used the TcpClient at all but the Socket class will return 0 from a call to Read if the remote end has been shutdown gracefully.
If the remote end doesn't shutdown gracefully [I think] you get a timeout exception, can't remember the type sorry.
Using code like 'if(socket.Connected) { socket.Write(...) } creates a race condition. You're better off just calling socket.Write and handling the exceptions and/or disconnections.
The solution of Peter Wone and uriel is very nice. But you also need to check on the Remote Endpoint, since you can have multiple open connections to your Local Endpoint.
public static TcpState GetState(this TcpClient tcpClient)
{
var foo = IPGlobalProperties.GetIPGlobalProperties()
.GetActiveTcpConnections()
.SingleOrDefault(x => x.LocalEndPoint.Equals(tcpClient.Client.LocalEndPoint)
&& x.RemoteEndPoint.Equals(tcpClient.Client.RemoteEndPoint)
);
return foo != null ? foo.State : TcpState.Unknown;
}
I have created this function and working for me to check if client is still connected with server.
/// <summary>
/// THIS FUNCTION WILL CHECK IF CLIENT IS STILL CONNECTED WITH SERVER.
/// </summary>
/// <returns>FALSE IF NOT CONNECTED ELSE TRUE</returns>
public bool isClientConnected()
{
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] tcpConnections = ipProperties.GetActiveTcpConnections();
foreach (TcpConnectionInformation c in tcpConnections)
{
TcpState stateOfConnection = c.State;
if (c.LocalEndPoint.Equals(ClientSocket.Client.LocalEndPoint) && c.RemoteEndPoint.Equals(ClientSocket.Client.RemoteEndPoint))
{
if (stateOfConnection == TcpState.Established)
{
return true;
}
else
{
return false;
}
}
}
return false;
}
#uriel's answer works great for me, but I needed to code it in C++/CLI, which was not entirely trivial. Here is the (roughly equivalent) C++/CLI code, with a few robustness checks added in for good measure.
using namespace System::Net::Sockets;
using namespace System::Net::NetworkInformation;
TcpState GetTcpConnectionState(TcpClient ^ tcpClient)
{
TcpState tcpState = TcpState::Unknown;
if (tcpClient != nullptr)
{
// Get all active TCP connections
IPGlobalProperties ^ ipProperties = IPGlobalProperties::GetIPGlobalProperties();
array<TcpConnectionInformation^> ^ tcpConnections = ipProperties->GetActiveTcpConnections();
if ((tcpConnections != nullptr) && (tcpConnections->Length > 0))
{
// Get the end points of the TCP connection in question
EndPoint ^ localEndPoint = tcpClient->Client->LocalEndPoint;
EndPoint ^ remoteEndPoint = tcpClient->Client->RemoteEndPoint;
// Run through all active TCP connections to locate TCP connection in question
for (int i = 0; i < tcpConnections->Length; i++)
{
if ((tcpConnections[i]->LocalEndPoint->Equals(localEndPoint)) && (tcpConnections[i]->RemoteEndPoint->Equals(remoteEndPoint)))
{
// Found active TCP connection in question
tcpState = tcpConnections[i]->State;
break;
}
}
}
}
return tcpState;
}
bool TcpConnected(TcpClient ^ tcpClient)
{
bool bTcpConnected = false;
if (tcpClient != nullptr)
{
if (GetTcpConnectionState(tcpClient) == TcpState::Established)
{
bTcpConnected = true;
}
}
return bTcpConnected;
}
Hopefully this will help somebody.
As of 2019, in a cross-platform and async environment, I use the code below to continuosly check that the TCP channel is open. This check fires e.g. if the ethernet cable is pulled on my Windows machine, or if the Wifi is disabled on my Android device.
private async Task TestConnectionLoop()
{
byte[] buffer = new byte[1];
ArraySegment<byte> arraySegment = new ArraySegment<byte>(buffer, 0, 0);
SocketFlags flags = SocketFlags.None;
while (!_cancellationSource.Token.IsCancellationRequested)
{
try
{
await _soc.SendAsync(arraySegment, flags);
await Task.Delay(500);
}
catch (Exception e)
{
_cancellationSource.Cancel();
// Others can listen to the Cancellation Token or you
// can do other actions here
}
}
}
Please note that I have found GSF.Communication wrapper for System.Net.Sockets.TcpClient to be helpful because it has a CurrentState property that indicates whether the socket is open/connected or closed/disconnected. You can find details on the NuGet package here:
https://github.com/GridProtectionAlliance/gsf
Here is how you could setup a simple TCP socket and test whether it is connected:
GSF.Communication.TcpClient tcpClient;
void TestTcpConnectivity()
{
tcpClient = new GSF.Communication.TcpClient();
string myTCPServer = "localhost";
string myTCPport = "8080";
tcpClient.MaxConnectionAttempts = 5;
tcpClient.ConnectionAttempt += s_client_ConnectionAttempt;
tcpClient.ReceiveDataComplete += s_client_ReceiveDataComplete;
tcpClient.ConnectionException += s_client_ConnectionException;
tcpClient.ConnectionEstablished += s_client_ConnectionEstablished;
tcpClient.ConnectionTerminated += s_client_ConnectionTerminated;
tcpClient.ConnectionString = "Server=" + myTCPServer + ":" + myTCPport;
tcpClient.Initialize();
tcpClient.Connect();
Thread.Sleep(250);
if (tcpClient.CurrentState == ClientState.Connected)
{
Debug.WriteLine("Socket is connected");
// Do more stuff
}
else if (tcpClient.CurrentState == ClientState.Disconnected)
{
Debug.WriteLine(#"Socket didn't connect");
// Do other stuff or try again to connect
}
}
void s_client_ConnectionAttempt(object sender, EventArgs e)
{
Debug.WriteLine("Client is connecting to server.");
}
void s_client_ConnectionException(object sender, EventArgs e)
{
Debug.WriteLine("Client exception - {0}.", e.Argument.Message);
}
void s_client_ConnectionEstablished(object sender, EventArgs e)
{
Debug.WriteLine("Client connected to server.");
}
void s_client_ConnectionTerminated(object sender, EventArgs e)
{
Debug.WriteLine("Client disconnected from server.");
}
void s_client_ReceiveDataComplete(object sender, GSF.EventArgs<byte[], int> e)
{
Debug.WriteLine(string.Format("Received data - {0}.", tcpClient.TextEncoding.GetString(e.Argument1, 0, e.Argument2)));
}
I recommend the code from the answer of the user 'Uriel' above. His code in principle works great:
TcpClient client = new TcpClient(host, port);
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] tcpConnections = ipProperties.GetActiveTcpConnections().Where(x => x.LocalEndPoint.Equals(client.Client.LocalEndPoint) && x.RemoteEndPoint.Equals(client.Client.RemoteEndPoint)).ToArray();
but it has a bug:
IPEndPoint.Equals() is used here to search the retrieved list of TCP connections for the one connection that has the same endpoints as the socket TcpClient.Client of the used TCP client.
The idea and concept are fine, but in real life may fail because of the coexistence of IPv4 and IPv6: Current operating systems like Windows 10 support IPv4 and IPv6, and sockets may be created with IPv6 addresses even if addresses like "100.111.1.251" in the IPv4 format were configured:
// Creation of TCP client:
m_tcpClient = new TcpClient ();
m_tcpClient.Connect ("100.111.1.251", 54321);
// Query of the local and remote IP endpoints in Visual Studio Immediate Window:
?m_tcpClient.Client.LocalEndPoint
{[::ffff:100.111.1.254]:55412}
Address: {::ffff:100.111.1.254}
AddressFamily: InterNetworkV6
Port: 55412
?m_tcpClient.Client.RemoteEndPoint
{[::ffff:100.111.1.251]:54321}
Address: {::ffff:100.111.1.251}
AddressFamily: InterNetworkV6
Port: 54321
// Query of the addresses of the local and remote IP endpoints in Visual Studio Immediate Window:
?((IPEndPoint)m_tcpClient.Client.LocalEndPoint).Address
{::ffff:100.111.1.254}
Address: '((IPEndPoint)m_tcpClient.Client.LocalEndPoint).Address.Address' threw an exception of type 'System.Net.Sockets.SocketException'
AddressFamily: InterNetworkV6
IsIPv4MappedToIPv6: true
IsIPv6LinkLocal: false
IsIPv6Multicast: false
IsIPv6SiteLocal: false
IsIPv6Teredo: false
ScopeId: 0
?((IPEndPoint)m_tcpClient.Client.RemoteEndPoint).Address
{::ffff:100.111.1.251}
Address: '((IPEndPoint)m_tcpClient.Client.RemoteEndPoint).Address.Address' threw an exception of type 'System.Net.Sockets.SocketException'
AddressFamily: InterNetworkV6
IsIPv4MappedToIPv6: true
IsIPv6LinkLocal: false
IsIPv6Multicast: false
IsIPv6SiteLocal: false
IsIPv6Teredo: false
ScopeId: 0
AddressFamily: InterNetworkV6 and IsIPv4MappedToIPv6: true indicate that the IP address in the local IP endpoint is an IPv6 address, although an IPv4 address was used to establish the connection. This obviously is because the socket is created in "dual-mode" or as "dual-stack":
https://en.wikipedia.org/wiki/IPv6#IPv4-mapped_IPv6_addresses
https://learn.microsoft.com/en-us/dotnet/api/system.net.ipaddress.isipv4mappedtoipv6
https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2
https://www.ibm.com/docs/en/zos/2.2.0?topic=addresses-ipv4-mapped-ipv6
IPGlobalProperties.GetActiveTcpConnections() on the other side seems to always return IPEndPoint objects with IPv4 addresses:
?IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections()[48].LocalEndPoint
{100.111.1.254:55412}
Address: {100.111.1.254}
AddressFamily: InterNetwork
Port: 55412
The consequence is that IPEndPoint.Equals() may return false even if two compared EndPoint objects refer to the same IP endpoint.
The solution for this problem is writing your own Equals() method, like:
public static class EndPointHelper
{
private static readonly AddressFamily[] addressFamilies =
{
AddressFamily.InterNetwork,
AddressFamily.InterNetworkV6
};
public static bool Equals (EndPoint? endPoint1, EndPoint? endPoint2)
{
if (endPoint1 is IPEndPoint ipEndPoint1 &&
endPoint2 is IPEndPoint ipEndPoint2)
{
if (ipEndPoint1.AddressFamily != ipEndPoint2.AddressFamily &&
addressFamilies.Contains(ipEndPoint1.AddressFamily) &&
addressFamilies.Contains(ipEndPoint2.AddressFamily))
{
var ipAddress1AsV6 = ipEndPoint1.Address.MapToIPv6();
var ipAddress2AsV6 = ipEndPoint2.Address.MapToIPv6();
return ipAddress1AsV6.Equals(ipAddress2AsV6)
&& ipEndPoint1.Port.Equals(ipEndPoint2.Port);
}
}
return object.Equals (i_endPoint1, i_endPoint2);
}
}
Furthermore, there is a bug in .NET 5, which makes the whole solution above unusable: IPGlobalProperties.GetActiveTcpConnections() has a memory leak (see https://github.com/dotnet/runtime/issues/64735), which will not be fixed in .NET 5 any more, because it has run out of support. The bug is not present in .NET 6. If you are tied to .NET 5, you will have to work around it by remembering the connection state yourself in a local variable (e.g. EnumState m_cachedState). Set this variable after each related operation, e.g. after a Connect() you would have to set it to EnumState.Connected.
This method of course will not detect when a connection was closed by the other side, so you have to cyclically check if the connection was closed, using this code:
var socket = m_tcpClient.Client;
bool state = socket.Poll (100, SelectMode.SelectRead);
int available = socket.Available;
return state && available == 0 // Condition for externally closed connection. The external close will not be recognized until all received data has been read.
? EnumState.Idle
: m_cachedState;
Try this, it works for me
private void timer1_Tick(object sender, EventArgs e)
{
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; }
}
}
if (!sConnected)
{
//--Basically what you want to do afterwards
timer1.Stop();
client.Close();
ReConnect();
}
}
i used Timer because, I wanted to check connection state at regular interval
and not in a LOOP with Listening code [I felt it was slowing the sending-recieving process]
In my case, I was sending some command to a server (running in a virtual machine on the same computer) and waiting for the response. However, if the server stopped unexpectedly while waiting, I did not get any notification. I tried the possibilities proposed by the other posters, but neither did work (it always said that the server is still connected). For me, the only thing that is working is to write 0 bytes to the stream:
var client = new TcpClient();
//... open the client
var stream = client.GetStream();
//... send something to the client
byte[] empty = { 0 };
//wait for response from server
while (client.Available == 0)
{
//throws a SocketException if the connection is closed by the server
stream.Write(empty, 0, 0);
Thread.Sleep(10);
}

Is there a way to for UDP .net socket to release a bound port when the socket is closed?

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.

Threading / Linq Class list Issue

I've written a very complex multi-server IRC bot recently, and have encountered an issue..
I have stripped down the code as much as I could which can be viewed here.
My issue is that when I call the Disconnect() the connection is voided instead of disconnecting and closing the given server. It also just freezes the calling class instead of stopping the correct instance of the Class.
Any help or experience with a similar issue would be greatly appreciated.
Please include code if you can.
First off, you need to add a break so that this:
foreach (Connection connect in connections)
{
if (searching == true)
{
if (connect.SERVERID == ServerID)
{
connect.Stop();
isFound = true;
searching = false;
connections.Remove(connect);
}
}
}
Becomes:
foreach (Connection connect in connections)
{
if (connect.SERVERID == ServerID)
{
connect.Stop();
isFound = true;
connections.Remove(connect);
break;
}
}
Because you are modifying the collection, rather than using the searching == true clause. Much more efficient.
Next, I would change your thread run to look like this:
public void Run()
{
bool WhileOn = true;
NetworkStream stream;
string inputLine;
StreamReader reader;
try
{
using(TcpClient irc = new TcpClient(SERVER, PORT))
{
...
}
}
catch (ThreadAbortException)
{
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
Thread.Sleep(5000);
}
}
So that your connection gets properly disposed. You should do similarly for your stream.
And finally, I would add an Abort() call on your thread in the Stop function after a set timeout. If a TCP socket is blocked by the OS, however, I'm not sure if an abort call will interrupt it...

Categories

Resources