Detecting a web socket connection drop - c#

In my Windows 8 JS application, I have a web socket object defined like this:
var webSocket = new Windows.Networking.Sockets.MessageWebSocket();
webSocket.control.messageType = Windows.Networking.Sockets.SocketMessageType.utf8;
webSocket.onmessagereceived = that._onMessageReceived;
webSocket.onclosed = that._onClosed;
I connect using webSocket.connectAsync(uri).done(/* ... */) and that part works fine.
If I stop my web server on the other end, my application doesn't get notified and thinks the connection is still alive. The 'closed' event never fires, and there doesn't seem to be any 'Error' event.
Is there a way to monitor the connection status?

Figured it out. The messagereceived event actually fires when the connection fails. Inside the handler, you can use a try catch block around the data reader operation.
try {
var dataReader = args.getDataReader();
var msg = dataReader.readString(dataReader.unconsumedBufferLength);
} catch (ex) {
var error = Windows.Networking.Sockets.SocketError.getStatus(ex.number);
// do something
}

Is this a specific Windows 8 question? I've tested the following to work on Windows 7, OSX and Ubuntu (using reasonably new versions of Firefox, Safari and Chrome):
var s = new WebSocket("ws://"+window.location.hostname+":9876");
s.onopen = function(e) {
console.log("opened socket for unidrive log");
}
s.onclose = function(e) {
console.log("closed");
}
s.onmessage = function(e) {
console.log("got message: " + e.data);
}
The onclose event fires immediately if the web-server isn't running to start with, or fires on killing the server.

Thank you for this Information - really weird why the socket don't raise the closed-event, but it works great.
One more info for C# developers: to determine the correct exception-errorstatus you have to do call the WebSocketError.GetStatus(hresult) instead of the SocketError.GetStatus(hresult) method.
try
{
using (DataReader reader = e.GetDataReader())
{
reader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
string rawMessage = reader.ReadString(reader.UnconsumedBufferLength);
// Do something with the message...
}
}
catch (Exception ex)
{
var errorStatus = Windows.Networking.Sockets.WebSocketError.GetStatus(ex.HResult);
if (errorStatus == WebErrorStatus.ConnectionAborted)
{
// Handle the connection-abort...
}
}

Related

C# Windows 10 Bluetooth LE can't connect to server

I'm developing a c# desktop api with forms where I want to receive ACC data from a BLE server und display them in a chart.
So I'm running in a connection problem and I can't find any solution.
I can find my LE server Device with the watcher.
DevicePairingResult dpr = await device.DeviceInformation.Pairing.PairAsync(DevicePairingProtectionLevel.Encryption);
returns me "AlreadyPaired"
But when I do
device = await BluetoothLEDevice.FromBluetoothAddressAsync(bluetoothAddress: eventArgs.BluetoothAddress);
mGattService = device.GetGattService(MotionService_GUID);
mCharacteristic = mGattService.GetCharacteristics(ACC_Characteristic_GUID)[0];
and then
var con = device.ConnectionStatus;
I receive "Disconnected" in con.
I am bound with de device on windows( I searched for it in Windows and entered the Code) but I am not connected(based on the Status in the windows info center).
I've read in another Thread in the windows c# developer page that it should not be necessary anymore to pair the device manually.
I'm pretty shure that the rest of my code works because sometimes I can get a connection( pretty confusing for me) and see the right Data in my chart.
Right now I just want to reach a stable connection before changing other part of my code.
Anyone any idea how to solve this?
Thx medTech
Edit:
Here is part of the Code:
Scanning for BLE
private void button1_Click(object sender, EventArgs e)
{
// Create Bluetooth Listener
var watcher = new BluetoothLEAdvertisementWatcher();
watcher.ScanningMode = BluetoothLEScanningMode.Active;
// Register callback for when we see an advertisements
watcher.Received += OnAdvertisementReceivedAsync;
// Wait 5 seconds to make sure the device is really out of range
watcher.SignalStrengthFilter.OutOfRangeTimeout = TimeSpan.FromMilliseconds(5000);
watcher.SignalStrengthFilter.SamplingInterval = TimeSpan.FromMilliseconds(2000);
// Starting watching for advertisements
watcher.Start();
}
Connect to Server:
private async void OnAdvertisementReceivedAsync(BluetoothLEAdvertisementWatcher watcher, BluetoothLEAdvertisementReceivedEventArgs eventArgs)
{
// Filter for specific Device
if (eventArgs.Advertisement.LocalName == "MYDEVICE")
{
watcher.Stop();
var MotionService_GUID = new Guid("00002000-0000-1000-8000-00805F9B34FB");
var ACC_Characteristic_GUID = new Guid("00002001-0000-1000-8000-00805F9B34FB");
device = await BluetoothLEDevice.FromBluetoothAddressAsync(bluetoothAddress: eventArgs.BluetoothAddress);
DevicePairingResult dpr = await device.DeviceInformation.Pairing.PairAsync(DevicePairingProtectionLevel.Encryption);
mGattService = device.GetGattService(MotionService_GUID);
mCharacteristic = mGattService.GetCharacteristics(ACC_Characteristic_GUID)[0];
GattDeviceServicesResult result = await device.GetGattServicesAsync();
GattCommunicationStatus status1 = await ReadFromCharacteristicAsync(mCharacteristic);
var con = device.ConnectionStatus;
while (status1 == GattCommunicationStatus.Success)
{
try
{
status1 = await ReadFromCharacteristicAsync(mCharacteristic);
}
catch
{
Console.WriteLine("ERROR");
status1 = GattCommunicationStatus.Unreachable;
}
}
}
}
Read from Characteristic:
async Task ReadFromCharacteristicAsync(GattCharacteristic mCharacteristic)
{
GattReadResult readResult = await mCharacteristic.ReadValueAsync(BluetoothCacheMode.Uncached);
if (readResult.Status == GattCommunicationStatus.Success)
{
byte[] data = new byte[readResult.Value.Length];
DataReader.FromBuffer(readResult.Value).ReadBytes(data);
if (chart1.IsHandleCreated)
{
this.Invoke((MethodInvoker)delegate { updateChart(data); });
}
return readResult.Status;
}
return readResult.Status;
}
Terminate Connection
private async Task<bool> ClearBluetoothLEDeviceAsync()
{
mCharacteristic.Service.Dispose();
mGattService.Dispose();
await device.DeviceInformation.Pairing.UnpairAsync();
device?.Dispose();
device = null;
GC.Collect();
return true;
}
SO now when I connect the first time to the Server, I only receive zeros which shows me that the there might be a authentication Error.
After that I always receive this Error:
"System.ArgumentException" in mscorlib.dll with a notification that there is noch executable Code left because all Threads are doing some asynchronous stuff.
This Error gets thrown when I try to read from the Characteristic.
I never coded in c# before so I am not shure if there is an error in my asynchronous part oder the communication part.
Thanks you
Pairing is not the same as connecting!
I really advise using the BLE-advertisementWatcher to select and connect to your device.
The reason is that many BLE-devices don't save their pairing status.
In windows device-watcher once paired, the device stays paired even if it is switched off or out of reach.
Also many times the connection status is kept, unless the device is unpaired and disposed in code or removed in windows settings.
All BLE-devices that I know of start advertising as soon as there is no connection for some time.
This time depends on the device, but most of the time within seconds.
So don't pair but just connect if the device is advertising.

UWP AppServiceConnection not getting value

I'm trying to communicate between my host app and service via AppServiceConnection. I'm using the following code in my host app:
using (var connection = new AppServiceConnection())
{
connection.AppServiceName = extension.AppServiceName;
connection.PackageFamilyName = extension.PackageFamilyName;
var connectionStatus = await connection.OpenAsync();
if (connectionStatus == AppServiceConnectionStatus.Success)
{
var response = await connection.SendMessageAsync(requestMessage);
if (response.Status == AppServiceResponseStatus.Success)
returnValue = response.Message as ValueSet;
}
}
And my service code:
private async void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
var messageDeferral = args.GetDeferral();
var message = args.Request.Message;
var returnData = new ValueSet();
var command = message["Command"] as string;
switch (command)
{
case "ACTION":
var value = await AsyncAction();
returnData = new ValueSet { { "Value", JsonConvert.SerializeObject(value) } };
break;
default:
break;
}
await args.Request.SendResponseAsync(returnData);
messageDeferral.Complete();
}
This works some of the time, but other times the ValueSet (returnValue) is randomly empty when the host receives it. It has Value in it when returned in the service, but when I get the response in the host, nothing.
I've verified that the service is indeed setting the value, adding it to the ValueSet and returning it correctly.
Note that my service is receiving the request, the host is receiving the response and the response status is Success; a failed connection isn't the issue.
Sometimes this happens only once before requests start working again, other times it will happen ten times in a row.
The first working response after a failure always takes significantly longer than normal.
Also, I have no issues in the request from host to service. It's always service to host where the problem shows up.
Has anyone else run into this issue and figured it out?
In the process of creating a sample app I realized what the problem was. I was performing an asynchronous action (albeit a very short one) before my line var messageDeferral = args.GetDeferral();. It appears that this was allowing the background task to be closed before it had responded to the host. Simply moving that line to the beginning of the OnRequestReceived function fixed the problem for me.
So for anyone who runs into a similar issue, get your deferral before you do anything else! Spare yourself the pain I went through.

blocking listen prevents disconnect

Overview of Problem:
I need to connect to an IRC Server. Once connected, the program will send a message to the channel, and a response will occur over multiple lines back. I need to read these lines and store in a variable for later use. A special character at the end of the message (]) will define the end of the message over multiple lines. Once we have received this character, the IRC session should disconnect and processing should continue.
Situation:
I am using the Smartirc4net library. Calling irc.Disconnect() takes about 40 seconds to disconnect the session. Once we've received the ] character, the session should be disconnected, Listen() should not be blocking, and the rest of the program should continue to run.
Research:
I have found this: smartirc4net listens forever, can't exit thread, and I think it might be the same issue, however, I am unsure of what I need to do to resolve the problem.
Code:
public class IrcCommunicator
{
public IrcClient irc = new IrcClient();
string data;
public string Data { get { return data; } }
// this method we will use to analyse queries (also known as private messages)
public void OnQueryMessage(object sender, IrcEventArgs e)
{
data += e.Data.Message;
if (e.Data.Message.Contains("]"))
{
irc.Disconnect(); //THIS TAKES 40 SECONDS!!!
}
}
public void RunCommand()
{
irc.OnQueryMessage += new IrcEventHandler(OnQueryMessage);
string[] serverlist;
serverlist = new string[] { "127.0.0.1" };
int port = 6667;
string channel = "#test";
try
{
irc.Connect(serverlist, port);
}
catch (ConnectionException e)
{
// something went wrong, the reason will be shown
System.Console.WriteLine("couldn't connect! Reason: " + e.Message);
}
try
{
// here we logon and register our nickname and so on
irc.Login("test", "test");
// join the channel
irc.RfcJoin(channel);
irc.SendMessage(SendType.Message, "test", "!query");
// here we tell the IRC API to go into a receive mode, all events
// will be triggered by _this_ thread (main thread in this case)
// Listen() blocks by default, you can also use ListenOnce() if you
// need that does one IRC operation and then returns, so you need then
// an own loop
irc.Listen();
// when Listen() returns our IRC session is over, to be sure we call
// disconnect manually
irc.Disconnect();
}
catch (Exception e)
{
// this should not happen by just in case we handle it nicely
System.Console.WriteLine("Error occurred! Message: " + e.Message);
System.Console.WriteLine("Exception: " + e.StackTrace);
}
}
}
IrcBot bot = new IrcBot();
bot.RunCommand();
ViewBag.IRC = bot.Data;
As you can see, once this
Thank you for your time to look at this code and read my problem description. If you have any thoughts, or other suggestions, please let me know.
Mike
I was able to successfully disconnect straight away by calling RfcQuit() within OnQueryMessage(), before irc.Disconnect();

IPC Cannot Find the File Specified

using IPC over local TCP to communicate from Client to a Server thread. The connection itself doesn't seem to be throwing any errors, but every time I try to make one of the associated calls, I get this message:
System.Runtime.Remoting.RemotingException: Could not connect to an IPC Port: The System cannot Find the file specified
What I am attempting to figure out is WHY. Because this WAS working correctly, until I transitioned the projects in question (yes, both) from .NET 3.5 to .NET 4.0.
Listen Code
private void ThreadListen()
{
_listenerThread = new Thread(Listen) {Name = "Listener Thread", Priority = ThreadPriority.AboveNormal};
_listenerThread.Start();
}
private void Listen()
{
_listener = new Listener(this);
LifetimeServices.LeaseTime = TimeSpan.FromDays(365);
IDictionary props = new Hashtable();
props["port"] = 63726;
props["name"] = "AGENT";
TcpChannel channel = new TcpChannel(props, null, null);
ChannelServices.RegisterChannel(channel, false);
RemotingServices.Marshal(_listener, "Agent");
Logger.WriteLog(new LogMessage(MethodBase.GetCurrentMethod().Name, "Now Listening for commands..."));
LogEvent("Now Listening for commands...");
}
Selected Client Code
private void InitializeAgent()
{
try
{
_agentController =
(IAgent)RemotingServices.Connect(typeof(IAgent), IPC_URL);
//Note: IPC_URL was originally "ipc://AGENT/AGENT"
// It has been changed to read "tcp://localhost:63726/Agent"
SetAgentPid();
}
catch (Exception ex)
{
HandleError("Unable to initialize the connected agent.", 3850244, ex);
}
}
//This is the method that throws the error
public override void LoadTimer()
{
// first check to see if we have already set the agent process id and set it if not
if (_agentPid < 0)
{
SetAgentPid();
}
try
{
TryStart();
var tries = 0;
while (tries < RUNCHECK_TRYCOUNT)
{
try
{
_agentController.ReloadSettings();//<---Error occurs here
return;
} catch (RemotingException)
{
Thread.Sleep(2000);
tries++;
if (tries == RUNCHECK_TRYCOUNT)
throw;
}
}
}
catch (Exception ex)
{
HandleError("Unable to reload the timer for the connected agent.", 3850243, ex);
}
}
If you need to see something I haven't shown, please ask, I'm pretty much flying blind here.
Edit: I think the issue is the IPC_URL String. It is currently set to "ipc://AGENT/AGENT". The thing is, I have no idea where that came from, why it worked before, or what might be stopping it from working now.
Update
I was able to get the IPC Calls working correctly by changing the IPC_URL String, but I still lack understanding of why what I did worked. Or rather, why the original code stopped working and I needed to change it in the first place.
The string I am using now is "tcp://localhost:63726/Agent"
Can anyone tell me, not why the new string works, I know that...but Why did the original string work before and why did updating the project target to .NET 4.0 break it?

Need help in "Socket Programming" using Visual C# (Dot Net Framework 4.0)?

Recently, I was given an assignment...
"To develop a Windows Forms application which can be installed on various windows machines at an office or enterprise. There would be a database in just one machine(ALPHA machine).. This database would be used by applications on other Beta machines to access data. The application would itself manage to check if it is an Alpha or a Beta (Has Database file with it?) and hence has to act as a server or a client."
I can do everything except the Network and Inter-Application Communication requirements. So, I started to learn Socket Programming over the Internet and I have gone through this link...
The idea I am working on is...
To have the client send the message to server.
To have the server accept this message and put this message in queue.
Read the message to get Client's IP Address and the its Request for Data.
Apply this request on database and get the result.
Convert the result in string.
Send it to the requesting client.
I can manage to perform steps 3,4 & 5. I am stuck on 1, 2 & 6.
Towards this...
I have created a function for Server as well as for client who return the Sockets when called. I create a separate function as I like my code to be clean, tidy and understandable after years.
Check my code below...
For Server...
private Socket GetServerReady()
{
IPEndPoint RemoteEP = new IPEndPoint(IPAddress.Any, 8000);
Socket newSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
newSock.Connect(RemoteEP);
newSock.Listen(10);
return (newSock);
}
You will notice there is no Accept() method anywhere, This is because I wish to call it like below for further use...
Socket CltSock = GetServerReady().Accept();
The Code for Client is...
private Socket GetClientReady()
{
IPEndPoint RemoteEP = new IPEndPoint(IPAddress.Parse(txtBxHost2.Text.Trim()), 8000);
Socket ServerSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
ServerSock.Connect(RemoteEP);
return (ServerSock);
}
Finally, The questions are....
"Where is the appropriate place to call the functions I wrote above?"
"Should I call the Server and Client Function in Form_Load() Event?"
"What must be the next step towards my main intention which is point 1,2 & 6 mentioned above?"
I don't expect the full code that I can just copy as it is. Just the correct procedure and a little detail over the concept would do.
I would be using just a single PC for testing purpose. Also, another limitation is, It would all be coded in a single application. I don't want to write two separate applications for client & server.
I hope I made it all clear for you to understand.
Thanks a Lot.
Awaiting the response.
I was struggling to get things done and somehow managed to get the solution.
Below is my solution:
Server Side code:
(I put this code in a function which loops back the execution if any exception is caught)
private void Looper()
{
int i = 0;
int AttemptCount = 1;
while (i == 0)
{
try
{
TcpListener tL = new TcpListener(Network.GetLocalIPAddress(), 56009);
tL.Start(10);
Socket tS = tL.AcceptSocket();
if (tS.Connected)
{
NetworkStream nS = new NetworkStream(tS);
StreamReader Reader = new StreamReader(nS);
Output = Reader.ReadToEnd().Trim();
Reader.Close();
nS.Close();
tS.Close();
tL.Stop();
//If Done, End Execution
i = 1;
}
else
{
MessageBox.Show("The connection to the client is broken or failed..!!\n\nPlease check connection and try again.","Error",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
}
catch (SystemException ex)
{
//If Not, Loop Execution Again
if (MessageBox.Show("Exception: " + ex.Message + "\n\nAttempt Count: " + AttemptCount + "\n\nDo you want to terminate the transmission?", "Error", MessageBoxButtons.YesNo, MessageBoxIcon.Error) == DialogResult.Yes)
{
i = 1;
ResetTimer.Stop();
}
else
{
i = 0;
AttemptCount++;
}
}
}
}
When above function is called, The server waits to accept any incoming socket. If there is any error somewhere due to port re-usage or anything, It loops back itself and resets the server. (So, we don't have to manually call the server function again & again.)
Once the server accepts any incoming socket, the execution ends up successfully. Lot's of time we don't want to keep invoking server even after a successful reception. So, I, instead of calling this function in a button "click_event", I called it in a timer Tick_Event. So, the human need is eliminated at server side.
This leads to a problem. Once the server starts waiting to accept, It is in blocking mode.
It hangs all the processes and controls in same thread. So, I moved the call to above function to BackgroundWorker's "Do_Work" Event.
Check below Code:
private void GetServerReady()
{
if (!bW.IsBusy)
{
bW.RunWorkerAsync();
txtBxHistory.Text += "\r\n" + Output;
}
}
private void bW_DoWork(object sender, DoWorkEventArgs e)
{
Looper();
}
private void ResetTimer_Tick(object sender, EventArgs e)
{
GetServerReady();
}
"bW" is "BackgroundWorker".
"Output" is a variable I defined globally.
The reason we need a variable is that,
BackgroundWorker has its own thread to execute the code placed in its "Do_Work" Event. So, a TextBox from our application's thread can't be used by BackgroundWorker to store the received output. Doing this to a variable and then setting TextBox's Text property to this variable does the trick.
Client Side code:
private void btnSend_Click(object sender, EventArgs e)
{
TcpClient socketForServer;
try
{
socketForServer = new TcpClient(txtBxDestIP.Text.Trim(), 56009);
}
catch
{
MessageBox.Show("Failed to connect to server at " + txtBxDestIP.Text.Trim() + ":999", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
NetworkStream networkStream = socketForServer.GetStream();
StreamWriter streamWriter = new System.IO.StreamWriter(networkStream);
try
{
string InputString;
InputString = Network.GetLocalIPAddress() + ": " + txtBxData.Text;
streamWriter.Write(InputString);
streamWriter.Flush();
socketForServer.Close();
txtBxHistory.Text += "\r\nMe: " + txtBxData.Text.Trim();
txtBxData.Clear();
}
catch
{
MessageBox.Show("Exception reading from Server.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
streamWriter.Close();
networkStream.Close();
socketForServer.Close();
}
"txtBxDestIP" is a TextBox having the Destination IP address as Text.
"txtBxData" is a TextBox having the text to be sent.
This code works flawless for me. With above solution I can achieve all my motives from step 1 to 6 (Mentioned in the question above.)
I hope it helps others too. Please suggest if there is a better and efficient way to perform this.
Thanks.
Regards.

Categories