Node.js– A chat server written in Node and a client app written in C#
项目
A new twist to a boring Chat application
Most demos on Node.js illustrate how to create a chat server, but rarely provide the client side of the chat service.
That is what this post is about – creating both the server and client side of the equation.
Server
Node.js
Javascript
Client
.NET
C#
Node.js – Chat Application – Server Side
This is your traditional Node.js chat application. I’ve commented it pretty heavily. Note the following:
Create a TCP socket listener
var s = net.Server(function(socket)....
Saving the socket connection so we can send message back to the client
sockets.push(socket)....
An event that represents a client sending a text msg to server. 'data' represents the event and msg_sent is the data sent by chat client application.
socket.on('data', function(msg_sent) {....
Don't echo back the message to the sender
if(sockets[i] == socket) continue;
Write message back to listeners (except original sender)
sockets[i].write(msg_sent);
An event when a client disconnects. We need to remove dead sockets from our array.
socket.on('end', function() {
Listening on https://localhost:8000
s.listen(8000);
Filename = lamechat.js
net = require('net')// Supports multiple client chat application// Keep a pool of sockets ready for everyone// Avoid dead sockets by responding to the 'end' eventvar sockets = [];// Create a TCP socket listenervar s = net.Server(function (socket) { // Add the new client socket connection to the array of // sockets sockets.push(socket); // 'data' is an event that means that a message was just sent by the // client application socket.on('data', function (msg_sent) { // Loop through all of our sockets and send the data for (var i = 0; i < sockets.length; i++) { // Don't send the data back to the original sender if (sockets[i] == socket) // don't send the message to yourself continue; // Write the msg sent by chat client sockets[i].write(msg_sent); } }); // Use splice to get rid of the socket that is ending. // The 'end' event means tcp client has disconnected. socket.on('end', function () { var i = sockets.indexOf(socket); sockets.splice(i, 1); });});s.listen(8000);console.log('System waiting at https://localhost:8000');
Creating Chat Applications in .NET and C#
This next section will demonstrate the building of a chat client for the Node.js server.
Create a new Visual Studio Project
Project type = Windows Presentation Foundation Application
Editing MainWindow.xaml
Right mouse click on MainWindow.xaml
Where to add the various controls
We are adding textboxes, command buttons.
The graphical interface – MainWindow.xaml
MainWindow.xaml is where we define our user interface. We have 3 text boxes and 2 buttons.
txtChatName
Allows you to login with an id
txtConversation
Where the conversation between chat clients can be seen
txtOutMsg
The text message a given chat client wants to send to others
cmdConnect
Allows you to login and connect using txtChatName
cmdSendMessage
Sends your text message that was typed into txtOutMsg
The code behind – C# – chat client application logic
The next section is about writing the client code that connects, sends, and receives text/chat messages.
Proper Using Statements
“using” statements are needed to minimize typing in large amounts of code.
using System.Net.Sockets;using System.Threading.Tasks;using System.Threading;using System.Windows.Threading;
The final code in MainWindow.xaml.cs
This represents all the code needed to complete the C#-based client application.
Adding the code behind.
MainWindow.xaml.cs
Here is the entire code-behind module. No extra references are needed.
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Windows;using System.Windows.Controls;using System.Windows.Data;using System.Windows.Documents;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Imaging;using System.Windows.Navigation;using System.Windows.Shapes;using System.Net.Sockets;using System.Threading.Tasks;using System.Threading;using System.Windows.Threading;namespace NodeJsChatClient{ public partial class MainWindow : Window { // Declare member objects // Client for tcp, network stream to read bytes in socket TcpClient tcpClient = new TcpClient(); NetworkStream serverStream = default(NetworkStream); string readData = string.Empty; string msg = "Conected to Chat Server ..."; public MainWindow() { InitializeComponent(); } // Purpose: Connect to node.js application (lamechat.js) // End Result: node.js app now has a socket open that can send // messages back to this tcp client application private void cmdConnect_Click(object sender, RoutedEventArgs e) { AddPrompt(); tcpClient.Connect("127.0.0.1", 8000); serverStream = tcpClient.GetStream(); byte[] outStream = Encoding.ASCII.GetBytes(txtChatName.Text.Trim() + " is joining"); serverStream.Write(outStream, 0, outStream.Length); serverStream.Flush(); // upload as javascript blob Task taskOpenEndpoint = Task.Factory.StartNew(() => { while (true) { // Read bytes serverStream = tcpClient.GetStream(); byte[] message = new byte[4096]; int bytesRead; bytesRead = 0; try { // Read up to 4096 bytes bytesRead = serverStream.Read(message, 0, 4096); } catch { /*a socket error has occured*/ } //We have rad the message. ASCIIEncoding encoder = new ASCIIEncoding(); // Update main window AddMessage(encoder.GetString(message, 0, bytesRead)); Thread.Sleep(500); } }); } // Purpose: Updates the window with the newest message received // End Result: Will display the message received to this tcp based client private void AddMessage(string msg) { Dispatcher.BeginInvoke(DispatcherPriority.Input, (ThreadStart)( () => { this.txtConversation.Text += string.Format( Environment.NewLine + Environment.NewLine + " >> {0}", msg); })); } // Purpose: Adds the " >> " prompt in the text box // End Result: Shows prompt to user private void AddPrompt() { txtConversation.Text = txtConversation.Text + Environment.NewLine + " >> " + msg; } // Purpose: Send the text in typed by the user (stored in // txtOutMsg) // End Result: Sends text message to node.js (lamechat.js) private void cmdSendMessage_Click(object sender, RoutedEventArgs e) { byte[] outStream = Encoding.ASCII.GetBytes(txtOutMsg.Text); serverStream.Write(outStream, 0, outStream.Length); serverStream.Flush(); } }}
Let’s build the project
Right mouse click to see the “rebuild” command.
Should be a clean “recompile”
“0” errors.
Testing NodeJsChat
It is time to test the applications.
Start by running lamechat.js
Done at a command prompt.
Run the executables
Start by opening the project folder and navigating to the “bin\debug” folder.
We need at least two client chat applications to test
You will simply run NodeJsChatClient.exe twice.
The final test
Login to both and then start sending messages.
This represents the final step
Now just improve what I did and send it back to me
Download for Azure SDK
Comments
Anonymous
May 19, 2014
Hi Bruno,
your tutorial is amazing :)
I have one question about the client side: what is the purpose of that Thread.Sleep(500) at the end of taskOpenEndpoint?
Thank you in advance.
Anonymous
June 15, 2014
The comment has been removed
Anonymous
July 02, 2014
Hello BrunoTerkaly,
your tutorial is helpful, I really like it.
I am a newbie in node.js.
your tutorial can chat between 2 .net app but I try make a application to chat between web and .net app, but I don't know how to do website part.
could you please help me
Anonymous
July 02, 2014
Hello BrunoTerkaly,
I mean that I want to make Chat Applications in Html and javascript instead of in .NET and still using node.js server
Anonymous
May 05, 2015
dude you are amazing!
thanks
lehelmatyus.com
Anonymous
November 08, 2015
Thank you for this post,
In fact I have a question regarding this implementation, in the client side you are using a pooling architecture thanks to the while(true) loop asking the node server for new data. My question is the following is there a way to have a persistent connection between a C# client and a node js server with a websocket protocol?
I was looking at a SocketIO4Net project in git Hub that does not work with the last version of socket.io. I could not find a solutation for it.
Is there any solution proposed? or in progress for future?
Thank you for your answer
Achiou