mario lasok

mario lasok

  • 2k
  • 38
  • 176

Problem when connecting C sharp with Nodejs and namedpipes

Jan 11 2022 6:16 AM

Hi everybody, I have a rather peculiar problem. I have been struggling with it for last couple days. 

Here it is: 

I am working on an automation project which requires me to hook up C sharp with nodejs ideally via namedpipes. The problem I have encountered is that the code I have found is 'working' to some respect -> I have achived one way communication with no much effort (Client -> Server) However when it comes to replys from the server I'm stacked.

The issue seems to be the encoding method nodejs sends the response to the client (string format). The client operates on byte arrays. I have tried researching how to make them compatiable but unfortunately with no joy whatsoever. 

I woule be really grateful if you could help. I thought of using streams but not that familiar with nodejs in fact I am quite new when it comes to IPC (hardware background not software).

Anyway below is the listing of both server and client for reference.

using System;
using System.Text;
using System.Windows.Forms;
using wyDay.Controls;

namespace Pipes
{
    public partial class Form1 : Form
    {
        private PipeClient pipeClient;

        public Form1()
        {
            InitializeComponent();
            CreateNewPipeClient();
        }

        void CreateNewPipeClient()
        {
            if(pipeClient != null)
            {
                pipeClient.MessageReceived -= pipeClient_MessageReceived;
                pipeClient.ServerDisconnected -= pipeClient_ServerDisconnected; 
            }

            pipeClient = new PipeClient();
            pipeClient.MessageReceived += pipeClient_MessageReceived;
            pipeClient.ServerDisconnected += pipeClient_ServerDisconnected;
        }

        void pipeClient_ServerDisconnected()
        {
            Invoke(new PipeClient.ServerDisconnectedHandler(EnableStartButton));
        }

        void EnableStartButton()
        {
            btnStart.Enabled = true;
        }

        void pipeClient_MessageReceived(byte[] message)
        {
            Invoke(new PipeClient.MessageReceivedHandler(DisplayReceivedMessage),
                new object[] { message });
        }

        void DisplayReceivedMessage(byte[] message)
        {
            ASCIIEncoding encoder = new ASCIIEncoding();
            string str = encoder.GetString(message, 0, message.Length);

            if(str == "close")
            {
                pipeClient.Disconnect();

                CreateNewPipeClient();
                pipeClient.Connect(tbPipeName.Text);
            }

            tbReceived.Text += str + "\r\n";
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            pipeClient.Connect(tbPipeName.Text);

            if (pipeClient.Connected)
                btnStart.Enabled = false;
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            ASCIIEncoding encoder = new ASCIIEncoding();

            pipeClient.SendMessage(encoder.GetBytes(tbSend.Text));
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            tbReceived.Clear();
        }

        private void btnDisconnect_Click(object sender, EventArgs e)
        {
            pipeClient.Disconnect();
            EnableStartButton();
        }
    }
}

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.Win32.SafeHandles;

namespace wyDay.Controls
{
    /// <summary>
    /// Allow pipe communication between a server and a client
    /// </summary>
    public class PipeClient
    {
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern SafeFileHandle CreateFile(
           String pipeName,
           uint dwDesiredAccess,
           uint dwShareMode,
           IntPtr lpSecurityAttributes,
           uint dwCreationDisposition,
           uint dwFlagsAndAttributes,
           IntPtr hTemplate);

        /// <summary>
        /// Handles messages received from a server pipe
        /// </summary>
        /// <param name="message">The byte message received</param>
        public delegate void MessageReceivedHandler(byte[] message);

        /// <summary>
        /// Event is called whenever a message is received from the server pipe
        /// </summary>
        public event MessageReceivedHandler MessageReceived;


        /// <summary>
        /// Handles server disconnected messages
        /// </summary>
        public delegate void ServerDisconnectedHandler();

        /// <summary>
        /// Event is called when the server pipe is severed.
        /// </summary>
        public event ServerDisconnectedHandler ServerDisconnected;

        const int BUFFER_SIZE = 4096;

        FileStream stream;
        SafeFileHandle handle;
        Thread readThread;

        /// <summary>
        /// Is this client connected to a server pipe
        /// </summary>
        public bool Connected { get; private set; }

        /// <summary>
        /// The pipe this client is connected to
        /// </summary>
        public string PipeName { get; private set; }

        /// <summary>
        /// Connects to the server with a pipename.
        /// </summary>
        /// <param name="pipename">The name of the pipe to connect to.</param>
        public void Connect(string pipename)
        {
            if (Connected)
                throw new Exception("Already connected to pipe server.");

            PipeName = pipename;

            handle =
               CreateFile(
                  PipeName,
                  0xC0000000, // GENERIC_READ | GENERIC_WRITE = 0x80000000 | 0x40000000
                  0,
                  IntPtr.Zero,
                  3, // OPEN_EXISTING
                  0x40000000, // FILE_FLAG_OVERLAPPED
                  IntPtr.Zero);

            //could not create handle - server probably not running
            if (handle.IsInvalid)
                return;

            Connected = true;

            //start listening for messages
            readThread = new Thread(Read)
                             {
                                 IsBackground = true
                             };
            readThread.Start();
        }

        /// <summary>
        /// Disconnects from the server.
        /// </summary>
        public void Disconnect()
        {
            if (!Connected)
                return;

            // we're no longer connected to the server
            Connected = false;
            PipeName = null;

            //clean up resource
            if (stream != null)
                stream.Close();
            handle.Close();

            stream = null;
            handle = null;
        }

        void Read()
        {
            stream = new FileStream(handle, FileAccess.ReadWrite, BUFFER_SIZE, true);
            byte[] readBuffer = new byte[BUFFER_SIZE];

            while (true)
            {
                int bytesRead = 0;

                using (MemoryStream ms = new MemoryStream())
                {
                    try
                    {
                        // read the total stream length
                        int totalSize = stream.Read(readBuffer, 0, 4);

                        // client has disconnected
                        if (totalSize == 0)
                            break;

                        totalSize = BitConverter.ToInt32(readBuffer, 0);

                        do
                        {
                            int numBytes = stream.Read(readBuffer, 0, Math.Min(totalSize - bytesRead, BUFFER_SIZE));

                            ms.Write(readBuffer, 0, numBytes);

                            bytesRead += numBytes;

                        } while (bytesRead < totalSize);

                    }
                    catch
                    {
                        //read error has occurred
                        break;
                    }

                    //client has disconnected
                    if (bytesRead == 0)
                        break;

                    //fire message received event
                    if (MessageReceived != null)
                        MessageReceived(ms.ToArray());
                }
            }

            // if connected, then the disconnection was
            // caused by a server terminating, otherwise it was from
            // a call to Disconnect()
            if (Connected)
            {
                //clean up resource
                stream.Close();
                handle.Close();

                stream = null;
                handle = null;

                // we're no longer connected to the server
                Connected = false;
                PipeName = null;

                if (ServerDisconnected != null)
                    ServerDisconnected();
            }
        }

        /// <summary>
        /// Sends a message to the server.
        /// </summary>
        /// <param name="message">The message to send.</param>
        /// <returns>True if the message is sent successfully - false otherwise.</returns>
        public bool SendMessage(byte[] message)
        {
            try
            {
                // write the entire stream length
                stream.Write(BitConverter.GetBytes(message.Length), 0, 4);

                stream.Write(message, 0, message.Length);
                stream.Flush();
                return true;
            }
            catch
            {
                return false;
            }
        }
    }
}

var net = require('net');
var L = console.log;

var PIPE_NAME = "myNamedPipe";
var PIPE_PATH = "\\\\.\\pipe\\" + PIPE_NAME;


var server = net.createServer(function(stream) {
    L('Server: on connection')

    stream.on('data', function(c) {
        L('Server: on data:', c.toString());
    });

    stream.on('end', function() {
        L('Server: on end')
        server.close();
    });

    stream.pipe(stream);
});

server.on('close',function(){
    L('Server: on close');
})

server.listen(PIPE_PATH,function(){
    L('Server: on listening');
})
server.on('data', function(data) {
    L('Client send :', data.toString());
    client.end('Thanks!');
});


I'm looking for two-way (bidirectional) communication any help really apriciated