Using sockets to communicate between Javascript and C# with NodeJS
Previously, we looked at how to create a simple chat application between two web clients using NodeJS and sockets. Those that know me however, know that web development is not my preferred role anymore (not since the days of DW4N, MP101 and my pet project Lobo Malo anyway), so the work in Javascript and NodeJS on web clients was a means to an end. Today I’m going to show how you can use NodeJS and sockets to pass data to a C# program, and later we’ll go the other way round, passing data between C# applications and Javascript.
What do we need?
For this project, we’re going to need NodeJS installed (download here) with Socket.IO installed (see here and here for reminders how to do this). We’ll also need a C# compiler/editor, such as Visual Studio.
Finally, I’d recommend storing all the files for this project in their own folder (if you use Visual Studio, you can store the additional Javascript files in there as well) just to keep everything tidy, but it’s not essential on this project.
Step 1 – Create your server
Firstly we need to create our server which will be used to send information to the C# application. Create a new Javascript file (mine will be called “server.js”) and populate it with the following code.
var net = require('net'); var server = net.createServer(function(socket) { //Create the server and pass it the function which will write our data socket.write("Hello\n"); socket.write("World!\n"); socket.end("End of communications."); }); server.listen(3000); //This is the port number we're listening to
Step 2 – Create the C# application
If you want to skip the step by steps, you can get the full code here.
Now that we have our server, we can create our C# listening station. To keep things simple, we’ll be doing this to a terminal window, rather than go into the whole UI development steps. You can do that yourselves if you wish.
Usings
When you have an empty C# file, we can populate it with our namespaces which we intend to make use of. On top of the normal suspects that come with a new C# file, we will also be using the System.Net namespace and System.Net.Sockets namespace. In total, our ‘usings’ should look like this:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Net; //For our IPAddress using System.Net.Sockets; //For our TcpClient
Main
Our main method is going to perform these operations:
- Open up a client to listen to the server
- Read in any data available
- Display the data in the terminal window
- Close the connection to the server
TcpClient – listening to the server
To listen to the server we need to open up a network stream and connect to the same location the server will be broadcasting on.
TcpClient client = new TcpClient(); client.Connect(IPAddress.Loopback, 3000); //Connect to the server on our local host IP address, listening to port 3000 NetworkStream clientStream = client.GetStream();
Reading the data
To read in the data we’re going to use a byte array to read the data available in the network stream.
while(clientStream.DataAvailable) //While the network stream say's there is data to be read { byte [] inMessage = new byte[4096]; int bytesRead = 0; try { bytesRead = clientStream.Read(inMessage, 0, 4096); } catch { /*Catch exceptions and handle them here*/ } }
Displaying the data in the terminal
Now that we have the data saved in our byte array, we can encode it using ASCII encoding and display it on the terminal. This would go inside the while loop as that’s where the scope of the inMessage variable is. If you wanted to display the text after you’ve read all the data in, you would just need to move the variable and these lines out of the while loop.
ASCIIEncoding encoder = new ASCIIEncoding(); Console.WriteLine(encoder.GetString(inMessage, 0, bytesRead);
Closing the connection
Now that we’ve read the data and displayed it on the terminal window, we need to close our connection to the server.
client.Close();
Terminal window closing too fast?
Once you’ve put all these pieces of the code together, you might occasionally find that the terminal window is not open long enough for you to see the output before the C# application ends. In this case, I recommend putting the thread to sleep for 10 seconds at the end of the program so that the terminal window is open long enough for you to see the output.
System.Threading.Thread.Sleep(10000); //Sleep for 10 seconds
No data being displayed or server disconnecting errors?
I did find that sometimes the program ran too fast to obtain the data from the server. In this case, you can put the thread to sleep very briefly before starting the while loop and it should be ok. Somewhere between 50ms and 1000ms should be fine to resolve this.
Running the program
To run the program you need to first start the server in the command line. Navigate to the directory where you saved your server.js (or whatever you named it) file, and type into the command line (replacing server.js with your filename):
node server.js
This will start your server and then you’re ready to start your C# application, which should open a terminal window and display the output from the socket, wait ten seconds and then close. To disconnect the NodeJS server, press control-C in the command line window to stop the server.
If everything has worked, you should get something looking like the image below.
Full code
For those who just want to copy and paste code and get playing, here is the C# code in full. Remember to complete step one mind!
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Net; //For our IPAddress using System.Net.Sockets; //For our TcpClient namespace mySocketTest { class Program { static void Main(string[] args) { TcpClient client = new TcpClient(); client.Connect(IPAddress.Loopback, 3000); //Connect to the server on our local host IP address, listening to port 3000 NetworkStream clientStream = client.GetStream(); System.Threading.Thread.Sleep(1000); //Sleep before we get the data for 1 second while(clientStream.DataAvailable) { byte [] inMessage = new byte[4096]; int bytesRead = 0; try { bytesRead = clientStream.Read(inMessage, 0, 4096); } catch { /*Catch exceptions and handle them here*/ } ASCIIEncoding encoder = new ASCIIEncoding(); Console.WriteLine(encoder.GetString(inMessage, 0, bytesRead)); } client.Close(); System.Threading.Thread.Sleep(10000); //Sleep for 10 seconds } } }