problems with TCP clients and sockets - c#

Background : my application has the option to check automatically whether a device on the network is connected to the network.
If a device is not connected, it is represented as a blue square, and a green square for connected. I've tested the program rather thoroughly and have a few different sets of data to look at;
If a device starts off disconnected, i can connect, and then disconnect, which goes from blue, to green, to blue, but stops functioning after this.
If a device starts of connected, i can disconnect, but then not connect again, so this goes from green, to blue, but then stops functioning.
Here are some snippets of code to show how i'm connecting to these (this is not asynchronous as some devices to not have callbacks(?));
TcpClient _tc = new TcpClient();
if (!_tc.Client.Connected)
{
try
{
_tc.Client.Connect(device.deviceIPAddress, device.devicePort);
_tc.Client.ReceiveTimeout = 10;
}
catch
{
if (deviceDownNotified == false)
{
//do stuff to notify me
}
}
}
if (_tc.Client.Connected)
{
tcpSet = true;
try
{
result = this.SendCommandResult(bData, 72);
if (result[0] == 0xF0 && result[1] == 0xF0 && result[2] == 0x00 && result[3] == 0x02 && result[68] == 0xF0 && result[69] == 0xF0)
{
CheckChanges(result, device, exit);
deviceDownNotified = false;
}
}
catch
{
}
}
edit: also i was just thinking, theres not really any need for me to disconnect manually sometimes. if a client isn't connected, then connect, if it is, then do stuff. i'm a bit baffled as to which it switches between states once and stops working though.
I think my issue may be due to the way i am disconnecting the socket / client if the device is disconnected. Anyone have any ideas? if you need more information, just ask.
edit 2: i wired up a reconnect button that i clicked manually when it should reconnect and i get the following error exception:
"Once the socket has been disconnected, you can only reconnect again asynchronously, and only to a different EndPoint. BeginConnect must be called on a thread that won't exit until the operation has been completed."

fixed my own problem. finally. Here's some information for anyone out there reading this that may be looking for a solution.
from what i gather, when a TCP connection is interrupted, you must create a new one as it's not possible to reconnect or reuse in this way. what i did was this:
(modified from code in my question)
if (!_tc.Connected)
{
try
{
connect2(deviceIPAddress, devicePort);
}
catch
{
if (deviceDownNotified == false)
{
((ListBox)mainUI.Controls["lbLog"]).InvokeEx(f => ((ListBox)mainUI.Controls["lbLog"]).Items.Add("device " + device.deviceDescription + " down at " + System.DateTime.Now));
(mainUI.Controls["btn" + device.deviceButtonNumber]).BackgroundImage = null;
(mainUI.Controls["btn" + device.deviceButtonNumber]).BackColor = Color.Blue;
deviceDownNotified = true;
try
{
_tc = new TcpClient();
initialPoll = false;
MessageBox.Show("here");
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
}
}
Here i simply created a new tcplistener with the same name (my original one was a variable of an instance of a class (what a tongue twister). creating this new TCP instance and then setting my inialPoll variable allowed everything to get back into track.

Related

HoloLens unable to send or receive data via BT and TCP

I am working on HoloLens (Unity-UWP) and trying to make a connection with PC (UWP) or Android phone work (Xamarin). So far I tried client and host with both Bluetooth and TCP (even two versions with different libraries) on Android and UWP. I kept the code entirely separated from user interface, so that it is easier to use, to understand and modular. An Action<string> is used to output results (error logs and sent messages).
Everything that is not on the HoloLens works fine (even though it's exactly the same code). It worked from PC (UWP) to Android with client and host switched. But it doesn't even work between HoloLens and PC (UWP). The behavior ranged from crashes (mostly for Bluetooth) to instant disconnection. The last tests resulted in disconnection once bytes are about to be received. It could even read the first 4 bytes (uint for the length of the following UTF-8 message), but then it was disconnected. The other devices seemed to work fine.
What I know: Capabilities are set, the code works, the issue is likely something that is common for everything that has to do with networking and HoloLens.
So the question is, is Unity or HoloLens incompatible with something I am using? What I used which is worth mentioning: StreamSocket, BinaryWriter, BinaryReader, Task (async, await). Or is HoloLens actively blocking communication with applications on other devices? I know it can connect to devices with Bluetooth and that it can connect via TCP, and it looks like people succeed to get it to work. Are there known issues? Or is there something with Unity that causes this - a bad setting maybe? Do I have to use async methods or only sync? Are there incompatibility issues with Tasks/Threads and Unity? Is this possibly the issue (inability to consent to permissions)?
Another thing to note is that I cannot ping HoloLens via its IP by using the cmd, even though the IP is correct.
I'd appreciate any advice, answer or guess. I can provide more information if requested (see also the comments below). I would suggest to focus on the TCP connection as it seemed to be working better and appears to be more "basic." Here is the code:
using System;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Windows.Networking;
using Windows.Networking.Sockets;
#region Common
public abstract class TcpCore
{
protected StreamSocket Socket;
protected BinaryWriter BWriter;
protected BinaryReader BReader;
protected Task ReadingTask;
public bool DetailedInfos { get; set; } = false;
public bool Listening { get; protected set; }
public ActionSingle<string> MessageOutput { get; protected set; } = new ActionSingle<string> (); // Used for message and debug output. They wrap an Action and allow safer use.
public ActionSingle<string> LogOutput { get; protected set; } = new ActionSingle<string> ();
protected const string USED_PORT = "1337";
protected readonly Encoding USED_ENCODING = Encoding.UTF8;
public abstract void Disconnect ();
protected void StartCommunication ()
{
Stream streamOut = Socket.OutputStream.AsStreamForWrite ();
Stream streamIn = Socket.InputStream.AsStreamForRead ();
BWriter = new BinaryWriter (streamOut); //{ AutoFlush = true };
BReader = new BinaryReader (streamIn);
LogOutput.Trigger ("Connection established.");
ReadingTask = new Task (() => StartReading ());
ReadingTask.Start ();
}
public void SendMessage (string message)
{
// There's no need to send a zero length message.
if (string.IsNullOrEmpty (message)) return;
// Make sure that the connection is still up and there is a message to send.
if (Socket == null || BWriter == null) { LogOutput.Trigger ("Cannot send message: No clients connected."); return; }
uint length = (uint) message.Length;
byte[] countBuffer = BitConverter.GetBytes (length);
byte[] buffer = USED_ENCODING.GetBytes (message);
if (DetailedInfos) LogOutput.Trigger ("Sending: " + message);
BWriter.Write (countBuffer);
BWriter.Write (buffer);
BWriter.Flush ();
}
protected void StartReading ()
{
if (DetailedInfos) LogOutput.Trigger ("Starting to listen for input.");
Listening = true;
while (Listening)
{
try
{
if (DetailedInfos) LogOutput.Trigger ("Starting a listen iteration.");
// Based on the protocol we've defined, the first uint is the size of the message. [UInt (4)] + [Message (1*n)] - The UInt describes the length of the message (=n).
uint length = BReader.ReadUInt32 ();
if (DetailedInfos) LogOutput.Trigger ("ReadLength: " + length.ToString ());
MessageOutput.Trigger ("A");
byte[] messageBuffer = BReader.ReadBytes ((int) length);
MessageOutput.Trigger ("B");
string message = USED_ENCODING.GetString (messageBuffer);
MessageOutput.Trigger ("Received Message: " + message);
}
catch (Exception e)
{
// If this is an unknown status it means that the error is fatal and retry will likely fail.
if (SocketError.GetStatus (e.HResult) == SocketErrorStatus.Unknown)
{
// Seems to occur on disconnects. Let's not throw().
Listening = false;
Disconnect ();
LogOutput.Trigger ("Unknown error occurred: " + e.Message);
break;
}
else
{
Listening = false;
Disconnect ();
break;
}
}
}
LogOutput.Trigger ("Stopped to listen for input.");
}
}
#endregion
#region Client
public class GTcpClient : TcpCore
{
public async void Connect (string target, string port = USED_PORT) // Target is IP address.
{
try
{
Socket = new StreamSocket ();
HostName serverHost = new HostName (target);
await Socket.ConnectAsync (serverHost, port);
LogOutput.Trigger ("Connection successful to: " + target + ":" + port);
StartCommunication ();
}
catch (Exception e)
{
LogOutput.Trigger ("Connection error: " + e.Message);
}
}
public override void Disconnect ()
{
Listening = false;
if (BWriter != null) { BWriter.Dispose (); BWriter.Dispose (); BWriter = null; }
if (BReader != null) { BReader.Dispose (); BReader.Dispose (); BReader = null; }
if (Socket != null) { Socket.Dispose (); Socket = null; }
if (ReadingTask != null) { ReadingTask = null; }
}
}
#endregion
#region Server
public class GTcpServer : TcpCore
{
private StreamSocketListener socketListener;
public bool AutoResponse { get; set; } = false;
public async void StartServer ()
{
try
{
//Create a StreamSocketListener to start listening for TCP connections.
socketListener = new StreamSocketListener ();
//Hook up an event handler to call when connections are received.
socketListener.ConnectionReceived += ConnectionReceived;
//Start listening for incoming TCP connections on the specified port. You can specify any port that's not currently in use.
await socketListener.BindServiceNameAsync (USED_PORT);
}
catch (Exception e)
{
LogOutput.Trigger ("Connection error: " + e.Message);
}
}
private void ConnectionReceived (StreamSocketListener listener, StreamSocketListenerConnectionReceivedEventArgs args)
{
try
{
listener.Dispose ();
Socket = args.Socket;
if (DetailedInfos) LogOutput.Trigger ("Connection received from: " + Socket.Information.RemoteAddress + ":" + Socket.Information.RemotePort);
StartCommunication ();
}
catch (Exception e)
{
LogOutput.Trigger ("Connection Received error: " + e.Message);
}
}
public override void Disconnect ()
{
Listening = false;
if (socketListener != null) { socketListener.Dispose (); socketListener = null; }
if (BWriter != null) { BWriter.Dispose (); BWriter.Dispose (); BWriter = null; }
if (BReader != null) { BReader.Dispose (); BReader.Dispose (); BReader = null; }
if (Socket != null) { Socket.Dispose (); Socket = null; }
if (ReadingTask != null) { ReadingTask = null; }
}
}
#endregion
Coincidentially, I just implemented a BT connection between HoloLens and an UWP app. I followed the sample at https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/BluetoothRfcommChat.
As capabilities, I set "Bluetooth" (of course), "Internet (Client & Server)" and "Private Networks (Client & Server)". The steps on the server side then are:
Create an RfcommServiceProvider for your own or an existing (eg OBEX object push) service ID.
Create a StreamSocketListener and wire its ConnectionReceived Event.
Bind the service Name on the listener: listener.BindServiceNameAsync(provider.ServiceId.AsString(), SocketProtectionLevel.BluetoothEncryptionAllowNullAuthentication);
If you have a custom service ID, set its name along with other attributes you may want to configure. See the sample linked above for this. I think, this is mostly optional.
Start advertising the BT service: provider.StartAdvertising(listener, true);
Once a client connects, there is a StreamSocket in the StreamSocketListenerConnectionReceivedEventArgs that you can use to create a DataReader and DataWriter on like on any other stream. If you only want to allow one client, you can also stop advertising now.
On the client side, you would:
Show the DevicePicker and let the user select the peer device. Do not forget setting a filter like picker.Filter.SupportedDeviceSelectors.Add(BluetoothDevice.GetDeviceSelectorFromPairingState(true)); You can also allow unpaired devices, but you need to call PairAsync before you can continue in step 2. Also, I think there is no way to circumvent the user consent dialogue in this case, so I would recommend pairing before. To be honest, I did not check whether the unpaired stuff works on HoloLens.
You get a DeviceInformation instance from the picker, which you can use to obtain a BT device like await BluetoothDevice.FromIdAsync(info.Id);
Get the services from the device like device.GetRfcommServicesAsync(BluetoothCacheMode.Uncached); and select the one you are interested in. Note that I found that the built-in filtering did not behave as expected, so I just enumerated the result and compared the UUIDs manually. I believe that the UWP implementation performs a case-sensitive string comparison at some point, which might lead to the requested service not showing up although it is there.
Once you found your service, which I will call s from now on, create a StreamSocket and connect using socket.ConnectAsync(s.ConnectionHostName, s.ConnectionServiceName, SocketProtectionLevel.PlainSocket);
Again, you can not create the stream readers and writers like on the server side.
The answer is Threading.
For whoever may have similar issues, I found the solution. It was due to Unity itself, not HoloLens specifically. My issue was that I wrote my code separately in an own class instead of commingle it with UI code, which would have made it 1. unreadable and 2. not modular to use. So I tried a better coding approach (in my opinion). Everybody could download it and easily integrate it and have basic code for text messaging. While this was no issue for Xamarin and UWP, it was an issue for Unity itself (and there the Unity-UWP solution as well).
The receiving end of Bluetooth and TCP seemed to create an own thread (maybe even something else, but I didn't do it actively), which was unable to write on the main thread in Unity, which solely handles GameObjects (like the output log). Thus I got weird log outputs when I tested it on HoloLens.
I created a new TCP code which works for Unity but not the Unity-UWP solution, using TcpClient/TcpListener, in order to try another version with TCP connection. Luckily when I ran that in the editor it finally pointed on the issue itself: The main thread could not be accessed, which would have written into the UI - the text box for the log output. In order to solve that, I just had to use Unity's Update() method in order to set the text to the output. The variables themselves still could be accessed, but not the GameObjects.

C# socket thinks it's connected [duplicate]

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.

(Apparently) Gracefully Closed UDPClient leaves the socket blocked

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

USB Serial Port Unplugged but still in the list of Ports

So I have a code which detect the devices plugged with the method
SerialPort.GetPortNames();
Anyway, everything works well except when I open an existing port (By selecting it from the list)
port = new SerialPort(portname, 9600);
port.Open();
Then if the device is unplugged, it's not removed from the list.. I think it's because the port is not closed..
But I can't figure out why it's still on the list if I don't close it manually, even though the device is unplugged..
port.Close();
Because if I open a port which is not in the list, it doesn't appear in the list then..
Can anyone explain me this behavior ?
It is entirely up to the USB device driver that emulates the serial port. Unplugging a port while it is opened is in general a very bad idea. There are plenty of drivers that make the port disappear, even if your SerialPort object has a handle opened on the port. This tends to crash a worker thread that generates the DataReceived, PinChanged and ErrorReceived events. The exception is not catchable because it occurs on a worker thread, terminating your program. Some drivers even reject an attempt to close the port, making it impossible to end your program cleanly.
Sounds like you have a decent driver that keeps the emulated port alive as long as you don't call Close(). That's a Good Thing, not a problem. Don't count on this working on your user's machine, you cannot predict what kind of driver they'll get with their device. A buying recommendation is a good idea.
Long story short, serial ports are very primitive devices that date from the stone age of computing. There is no plug and play support for them so what happens is completely unpredictable. Only sane thing to do is never to unplug the cable while the device is in use. This is not hard to do :) More about the kind of trouble it causes in this answer.
This topic might be interesting: COM port disappears when unplugging USB. Have you tried to Dispose the SerialPort object?
It could be stale data effect, because SerialPort is still using that com-port (it is not disposed, registry is not updated, etc):
The port names are obtained from the system registry (for example, HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM). If the registry contains stale or otherwise incorrect data then the GetPortNames method will return incorrect data.
When you are using USB-to-serial adapter, once it is unplugged you will start getting "Access denied" or something like this exception if you try to write something into opened before com-port. You could try then to Close it and then GetPortNames should return proper list.
Sinatr answered correctly, it is stale data in the registry that remains stale until the opened port is closed and the resources released.
SerialPort.Close() does signal to release the resources, but you probably have to force a garbage collection. (I had to for my app.)
So something like:
//EDIT: this actually isn't consistent, and I wouldn't recommend.
// I recommend the notes following the EDIT below.
try
{
if (port != null)
port.Close(); //this will throw an exception if the port was unplugged
}
catch (Exception ex) //of type 'System.IO.IOException'
{
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
}
port = null;
EDIT:
So, it turns out this was terribly inconsistent, even on the same machine. The Nuget library SerialPortStream is an independent implementation of Microsoft's SerialPort, and gracefully catches all the bugs I had except detecting when the USB device was unplugged.
My solution is now checking when the USB device is plugged back in, evident when there are duplicate entries in SerialPortStream.GetPortNames(). Closing the port fully closes it, so calling the garbage collector isn't necessary anymore.
I use the following function to routinely check the connected serial ports:
private List<string> m_portList;
public event EventHandler<string[]> PortListChanged;
public void CheckForAddedDevices()
{
string[] portNames = SerialPortStream.GetPortNames();
if (portNames == null || portNames.Length == 0)
{
if (m_portList.Count > 0)
{
m_portList.Clear();
PortListChanged?.Invoke(this, null);
}
}
else
{
if (m_portList.Count != portNames.Length)
{
m_portList.Clear();
m_portList.AddRange(portNames);
//check for duplicate serial ports (when usb is plugged in again)
for (int i = 0; i < m_portList.Count - 1; i++)
{
for (int j = i + 1; j < m_portList.Count; j++)
{
if (String.Compare(m_portList[i], m_portList[j]) == 0)
{
m_portList.Clear();
Close();
}
}
}
PortListChanged?.Invoke(this, m_portList.ToArray());
}
else
{
bool anyChange = true;
foreach (var item in portNames)
{
anyChange = true;
for (int i = 0; i < m_portList.Count; i++)
{
if (String.Compare(m_portList[i], item) == 0)
{
anyChange = false;
break;
}
}
if (anyChange)
break;
}
if (anyChange)
{
m_portList.Clear();
m_portList.AddRange(portNames);
//check for duplicate serial ports (when usb is plugged in again)
for (int i = 0; i < m_portList.Count - 1; i++)
{
for (int j = i + 1; j < m_portList.Count; j++)
{
if (String.Compare(m_portList[i], m_portList[j]) == 0)
{
m_portList.Clear();
Close();
}
}
}
PortListChanged?.Invoke(this, m_portList.ToArray());
}
}
}
}

C# program causes bluescreen?

This is only the important stuff that the bluescreen shows. I'm on Windows 7 x64.
"A problem has been detected and Windows has been shut down to prevent damage
to your computer.
PROCESS_HAS_LOCKED_PAGES
* STOP: 0x00000076 (0x0000000000000000, 0xfffffa8009dcd060, 0x0000000000000011,
0x0000000000000000)"
I can't work on it now because every time I close it I get a bluescreen!
The program doesn't do anything yet except run the background worker below. It pings all addresses that could be part of the user's home network and attempts to connect to a certain port that another program will be listening on.
private void NetworkScanner_DoWork(object sender, DoWorkEventArgs e)
{
bool ExceptionEncountered = false;
int IPsProcessed = 0;
NetworkSearcherOutput = "Starting network scanner...";
NetworkSearcher.ReportProgress(0);
Thread.Sleep(1000);
foreach (IPAddress IP in Dns.GetHostAddresses(Dns.GetHostName()))
{
if (IP.AddressFamily == AddressFamily.InterNetwork)
{
string[] Octets = IP.ToString().Split('.');
Octets[3] = "0";
IPAddress CurrentAddressIteration = StringArrayToIP(Octets);
while (GetLastOctet(CurrentAddressIteration) != 255)
{
PingReply Reply = new Ping().Send(CurrentAddressIteration, 5);
if (Reply.Status == IPStatus.Success)
{
NetworkSearcherOutput = CurrentAddressIteration.ToString() + " sent response.";
NetworkSearcher.ReportProgress(0);
Thread.Sleep(500);
InClient Client = new InClient(CurrentAddressIteration);
try
{
Client.Connect();
SnapshotBox.Image = Client.Receive(typeof(Image));
NetworkSearcherOutput = CurrentAddressIteration.ToString() + " is running program.";
NetworkSearcher.ReportProgress(0);
Thread.Sleep(1000);
}
catch (Exception E)
{
// A socket exception is expected when the client is not running the program.
if (E is SocketException)
{
Client.Close();
NetworkSearcherOutput = CurrentAddressIteration.ToString() + " is not running program.";
NetworkSearcher.ReportProgress(0);
Thread.Sleep(1000);
}
//Unhandled exception. Show messagebox and close.
else
{
MessageBox.Show("Network scanner encountered an unhandled exception.\n\n" + E.GetType().ToString() + ": " + E.Message, "Unhandled Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
ExceptionEncountered = true;
break;
}
}
}
else
{
NetworkSearcherOutput = CurrentAddressIteration.ToString() + " did not respond.";
NetworkSearcher.ReportProgress(0);
}
IPsProcessed++;
if (IPsProcessed == 5)
{
NetworkSearcher.ReportProgress(2);
IPsProcessed = 0;
}
Octets = CurrentAddressIteration.ToString().Split('.');
Octets[3] = (Int32.Parse(Octets[3]) + 1).ToString();
CurrentAddressIteration = StringArrayToIP(Octets);
}
}
}
if (!ExceptionEncountered)
{
NetworkSearcherOutput = "Network scanning complete.";
NetworkSearcher.ReportProgress(0);
NetworkSearcher.ReportProgress(100);
}
else
{
NetworkSearcherOutput = "Network scanning encountered an error.";
NetworkSearcher.ReportProgress(-1);
}
I thought C# programs were supposed to never cause bluescreens?
I discovered this issue a few weeks back. It only happens when using .NET 4.
Reported at MS Connect.
Edit:
(Will*) Add this link to MS Connect bug report.
*login.live.com is going into an infinite loop again...
Just to be clear, there is no way for "user" mode code to forcibly create a blue screen in windows, unless it uses undocumented APIs and or forces bad data into a driver. Your C# code is likely not be at fault here, as if you use the user mode classes (Socket) then the socket is responsible for not crashing your computer.
As #Joe has commented Microsoft Support KB Article 256010 clearly describes this stop message, but better yet has clear instructions on capturing the driver name responsible for this error.
Note that any software firewall that you have installed also is involved at kernel mode level so could also be responsible for this error. I recommend you follow the KB articles advice and try to find out what is at fault. But you could also ensure that you have updated your network drivers and firewall/VPN software to the latest stable versions.

Categories

Resources