Websocket server on Azure - c#

I'm trying to host a websockets server on Azure. I'm a bit confused and was hoping you could help me.
I've followed many articles but my code is close to the one from this article : https://azure.microsoft.com/en-us/blog/introduction-to-websockets-on-windows-azure-web-sites/
public void ProcessRequest(HttpContext context)
{
if (context.IsWebSocketRequest)
{
context.AcceptWebSocketRequest(ProcessWS);
}
}
public bool IsReusable { get { return false; } }
private async Task ProcessWS(AspNetWebSocketContext context)
{
try
{
WebSocket socket = context.WebSocket;
while (true)
{
var url = context.RequestUri;
ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[1024]);
WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
if (socket.State == WebSocketState.Open)
{
string userMessage = Encoding.UTF8.GetString(buffer.Array, 0, result.Count)
.Trim(new char[] { ' ' }); // We remove the spaces before and after
// DO SOMETHING
}
else
{
break;
}
}
}
catch (Exception e)
{
Log.Info("Exception" + e.Message + " >>>" + e.StackTrace);
}
}
This works fine, I'm able to get the messages from my devices and answer to them.
But in some cases I need to send a message to another device, example :
DEVICE A sends "Tell Device B to blink"
Since it's a websockets server and Device B has already talked with the server I should have somewhere a connection opened with Device B. And when Device A asks me for it I can send a message to Device B.
But how can I achieve that with my code ? How can I find the connection to device B ? If not possible how should I do it ?
I hope my problem is described enough to be understood.
Thank you,

But how can I achieve that with my code ? How can I find the connection to device B ? If not possible how should I do it ?
According to your scenario, I followed this tutorial about webapi-and-websockets and implement my Web API project that could establish connection between clients. Here is the screenshoot for test, you could refer to it:
Additionally, you could leverage SignalR and map your client (user) to signalR connections. For more details, you could refer to Mapping SignalR Users to Connections. Also, you could refer to the git sample Microsoft.AspNet.SignalR.Samples.
UPDATE:
How would you use signalR in that case ?
For a simple way, we could retain connection and user info stored in memory, For more details, you could refer to In-memory storage. Based on this scenario, I wrote a sample project AspDotNet-SignalR-Chat, you could refer to it, and here is the screenshot for test:

Related

Can Raspberry Pi running Win10 IoT uses both Wifi and Bluetooth communication at the same time?

I'm still a beginner to programming. I have met some problem of my problem, where the pi couldnt use the wifi and bluetooth at the same time. This is because initially the code without the bluetooth element, it works fine. But when i added the bluetooth code into the program, it just went weird. It couldnt retrieve any data from the Firebase through Wifi. Is it really that they couldnt work together at the same time or it is wrong with the code. Is it because of the socketstream something like this? Really thanks for the help.
Link to the code as it is too long.
I have tested with your code. The app will get an exception as "Access is denied. ", it will cause the app crash. So you need to add try catch in the function DeviceWatcher_Added to ensure the app won't dump when the Bluetooth could not connect.
private async void DeviceWatcher_Added(DeviceWatcher sender, DeviceInformation args)
{
try
{
var device = await BluetoothDevice.FromIdAsync(args.Id);
var services = await device.GetRfcommServicesAsync();
if (services.Services.Count > 0)
{
var service = services.Services[0];
stream = new StreamSocket();
await stream.ConnectAsync(service.ConnectionHostName, service.ConnectionServiceName);
rx = new DataReader(stream.InputStream);
tx = new DataWriter(stream.OutputStream);
await this.Dispatcher.RunAsync(
Windows.UI.Core.CoreDispatcherPriority.Normal,
() => { Device_9.IsEnabled = true; });
deviceWatcher.Stop();
}
}
catch(Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
BTW, you may refer to the sample mentioned in my first comment, it shows how to connect the RfcommService to communicate with Bluetooth. Please note that, in the sample the server creates the RfcommServiceProvider by guid, and the client connects the server with RfcommService from this guid as uuid.
var rfcommServices = await bluetoothDevice.GetRfcommServicesForIdAsync(
RfcommServiceId.FromUuid(Constants.RfcommChatServiceUuid), BluetoothCacheMode.Uncached);

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.

How to check connection to mongodb

I use MongoDB drivers to connect to the database. When my form loads, I want to set up connection and to check whether it is ok or not. I do it like this:
var connectionString = "mongodb://localhost";
var client = new MongoClient(connectionString);
var server = client.GetServer();
var database = server.GetDatabase("reestr");
But I do not know how to check connection. I tried to overlap this code with try-catch, but to no avail. Even if I make an incorrect connectionString, I still can not get any error message.
To ping the server with the new 3.0 driver its:
var database = client.GetDatabase("YourDbHere");
database.RunCommandAsync((Command<BsonDocument>)"{ping:1}")
.Wait();
There's a ping method for that:
var connectionString = "mongodb://localhost";
var client = new MongoClient(connectionString);
var server = client.GetServer();
server.Ping();
full example for 2.4.3 - where "client.GetServer()" isn't available.
based on "Paul Keister" answer.
client = new MongoClient("mongodb://localhost");
database = client.GetDatabase(mongoDbStr);
bool isMongoLive = database.RunCommandAsync((Command<BsonDocument>)"{ping:1}").Wait(1000);
if(isMongoLive)
{
// connected
}
else
{
// couldn't connect
}
I've had the same question as the OP, and tried every and each solution I was able to find on Internet...
Well, none of them worked to my true satisfaction, so I've opted for a research to find a reliable and responsive way of checking if connection to a MongoDB Database Server is alive. And this without to block the application's synchronous execution for too long time period...
So here are my prerequisites:
Synchronous processing of the connection check
Short to very short time slice for the connection check
Reliability of the connection check
If possible, not throwing exceptions and not triggering timeouts
I've provided a fresh MongoDB Installation (version 3.6) on the default localhost URL: mongodb://localhost:27017. I've also written down another URL, where there was no MongoDB Database Server: mongodb://localhost:27071.
I'm also using the C# Driver 2.4.4 and do not use the legacy implementation (MongoDB.Driver.Legacy assembly).
So my expectations are, when I'm checking the connection to the first URL, it should give to me the Ok for a alive connection to an existing MongoDB server, when I'm checking the connection to the second URL it should give to me the Fail for a non-existing MongoDB server...
Using the IMongoDatabase.RunCommand method, queries the server and causes the server response timeout to elapse, thus not qualifying against the prerequisites. Furthermore after the timeout, it breaks with a TimeoutException, which requires additional exception handling.
This actual SO question and also this SO question have delivered the most of the start information I needed for my solution... So guys, many thanks for this!
Now my solution:
private static bool ProbeForMongoDbConnection(string connectionString, string dbName)
{
var probeTask =
Task.Run(() =>
{
var isAlive = false;
var client = new MongoDB.Driver.MongoClient(connectionString);
for (var k = 0; k < 6; k++)
{
client.GetDatabase(dbName);
var server = client.Cluster.Description.Servers.FirstOrDefault();
isAlive = (server != null &&
server.HeartbeatException == null &&
server.State == MongoDB.Driver.Core.Servers.ServerState.Connected);
if (isAlive)
{
break;
}
System.Threading.Thread.Sleep(300);
}
return isAlive;
});
probeTask.Wait();
return probeTask.Result;
}
The idea behind this is the MongoDB Server does not react (and seems to be non-existing) until a real attempt is made to access some resource on the server (for example a database). But retrieving some resource alone is not enough, as the server still has no updates to its state in the server's Cluster Description. This update comes first, when the resource is retrieved again. From this time point, the server has valid Cluster Description and valid data inside it...
Generally it seems to me, the MongoDB Server does not proactivelly propagate its Cluster Description to all connected clients. Rather then, each client receives the description, when a request to the server has been made. If some of you fellows have more information on this, please either confirm or deny my understandings on the topic...
Now when we target an invalid MongoDB Server URL, then the Cluster Description remains invalid and we can catch and deliver an usable signal for this case...
So the following statements (for the valid URL)
// The admin database should exist on each MongoDB 3.6 Installation, if not explicitly deleted!
var isAlive = ProbeForMongoDbConnection("mongodb://localhost:27017", "admin");
Console.WriteLine("Connection to mongodb://localhost:27017 was " + (isAlive ? "successful!" : "NOT successful!"));
will print out
Connection to mongodb://localhost:27017 was successful!
and the statements (for the invalid URL)
// The admin database should exist on each MongoDB 3.6 Installation, if not explicitly deleted!
isAlive = ProbeForMongoDbConnection("mongodb://localhost:27071", "admin");
Console.WriteLine("Connection to mongodb://localhost:27071 was " + (isAlive ? "successful!" : "NOT successful!"));
will print out
Connection to mongodb://localhost:27071 was NOT successful!
Here a simple extension method to ping mongodb server
public static class MongoDbExt
{
public static bool Ping(this IMongoDatabase db, int secondToWait = 1)
{
if (secondToWait <= 0)
throw new ArgumentOutOfRangeException("secondToWait", secondToWait, "Must be at least 1 second");
return db.RunCommandAsync((Command<MongoDB.Bson.BsonDocument>)"{ping:1}").Wait(secondToWait * 1000);
}
}
You can use it like so:
var client = new MongoClient("yourConnectionString");
var database = client.GetDatabase("yourDatabase");
if (!database.Ping())
throw new Exception("Could not connect to MongoDb");
This is a solution by using the try-catch approach,
var database = client.GetDatabase("YourDbHere");
bool isMongoConnected;
try
{
await database.RunCommandAsync((Command<BsonDocument>)"{ping:1}");
isMongoConnected = true;
}
catch(Exception)
{
isMongoConnected = false;
}
so when it fails to connect to the database, it will throw an exception and we can handle our bool flag there.
If you want to handle connection issues in your program you can use the ICluster.Description event.
When the MongoClient is created, it will continue to attempt connections in the background until it succeeds.
using MongoDB.Driver;
using MongoDB.Driver.Core.Clusters;
var mongoClient = new MongoClient("localhost")
mongoClient.Cluster.DescriptionChanged += Cluster_DescriptionChanged;
public void Cluster_DescriptionChanged(object sender, ClusterDescriptionChangedEventArgs e)
{
switch (e.NewClusterDescription.State)
{
case ClusterState.Disconnected:
break;
case ClusterState.Connected:
break;
}
}

debugging sockets and DLL's

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

WebSockets - How to create different messages?

I am creating a websocket chat application and I managed to relay chat messages to other browsers connected. I have a console application listening on one port.
My question is... If one person logs on to the system I want everybody to know that, how can I do that? I'm using Linq to map the DB but if the logging is ok how do I send that message, that user X has logged in?
FINALLY I was able to create a chatroom using websockets, here is the final product, thanks for the orientation!
http://ukchatpoint.no-ip.org/Chatpoint/Pages/Uklobby.aspx
First make sure you're sending messages as JSON (JavaScript Object Notation) as this allows structured data to be sent back and forth, and client & server can differentiate between a chat message and an instruction (e.g. someone new logged in). For instance on the client:
mySocket.onmessage = function(event) {
var command = JSON.parse(event.data);
if(command.type === 'message') {
var message = command.message;
// handle chat message
}
else if (command.type === 'newUser') {
var username = command.username;
// handle new user
}
};
On the server in ASP.NET C# you'd send them as:
public class ChatHandler : WebSocketHandler
{
private JavaScriptSerializer serializer = new JavaScriptSerializer();
private static WebSocketCollection chatapp = new WebSocketCollection();
public override void OnMessage(string message)
{
var m = serializer.Deserialize<Message>(message);
switch (m.Type)
{
case MessageType.NewUser:
chatapp.Broadcast(serializer.Serialize(new
{
type = "newUser",
username = m.username
}));
break;
case MessageType.Message:
chatapp.Broadcast(serializer.Serialize(new
{
type = "message",
message = m.message
}));
break;
default:
return;
}
}
}
As Hightechrider says, you'll need to keep track of a list of connected clients, that's what WebSocketCollection class does in the code listing above.
Check out Paul Batum's WebSocket chat example on github here (https://github.com/paulbatum/BUILD-2011-WebSocket-Chat-Samples/blob/master/BasicAspNetChat/ChatHandler.cs)
Also he did a presentation at the recent MS BUILD conference here (http://channel9.msdn.com/Events/BUILD/BUILD2011/SAC-807T)
You would need to track the connections at the application level so you can send to all of them. But take a look at SignalR instead where a lot of the work involved with webSockets and long polling is being written for you. With SignalR you can use GetClients to get all the clients connected to a Hub.
When using PostgreSQL, you could use NOTIFY from within the database to notify the application layer, which could generate messages sent via WebSockets.

Categories

Resources