Nodejs Express + Socket.io + client on C# - c#

i just don't understand why simple socket.io part don't work.
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
http.listen(3000, function(){
console.log('listening on *:3000');
});
app.use(function(req, res, next) {
console.log("INIT");
console.log(req.headers['user-agent']);
console.log(req.ip);
next();
});
app.use('/', routes);
io.on('connection', function(socket){
console.log('a user connected');
socket.on('disconnect', function(){
console.log('user disconnected');
});
});
This is my cliend side code at C#. So when my nodejs server is online i don't get any errors from C#, so it's connecting, but i don't see it at node console.
And this must work, i get this example here - https://www.youtube.com/watch?v=nwV3MS6pryY
using System;
using System.Net.Sockets;
namespace TCPSocketConsole
{
class Program
{
static TcpClient mySocket = new TcpClient();
static void Main(string[] args)
{
mySocket.Connect("127.0.0.1", 3000);
Console.ReadLine();
}
}
}
So when i connect to http://localhost:3000 i don't get "a user connected" at my console.

You are listening for a socket.io connection on your server, but your client is just make a plain TCP connection. The two protocols on each end must be the same. socket.io is not a plain TCP connection.
You can either listen for a plain TCP connection on your node.js server (and thus invent your own protocol) or you can get a class for a socket.io connection in your C# client so your C# client can actually speak to a socket.io server properly.
socket.io is based on webSocket and webSocket has a whole protocol for establishing the initial connection (it starts with an HTTP connection that is then upgraded to a webSocket connection) and then both webSocket and socket.io have their own framing for how data is sent. Both ends of the connection must speak the same protocol.

In the socket.io docs you have an example of the client and server side. It seems your are not connecting from client side.

Related

EngineIoClientDotNet change path

I'm using Node.js with socket.io server and EngineIoClientDotNet and MAUI on client side. This is how I'm connecting to the server on client side using Quobject.EngineIoClientDotNet.Client.Socket:
socket = new Socket("https://api.example.com");
And here's how it is on server side:
const io: Server = new Server(server, { cors: { origin: "*" } });
And instead of making requests to https://api.example.com/socket.io, like socket.io-client for javascript, EngineIoClientDotNet makes requests to https://api.example.com/engine.io, which resultst in 404 response.
How do I change path from /engine.io to /socket.io?
Use SocketIOClient
EngineIoClientDotNet is deprecated, and SocketIOClient is still maintained.
If you need to change path from /socket.io (which is default in SocketIOClient) use SocketIOOptions:
using SocketIOClient;
socket = new SocketIO("https://example.com", new SocketIOOptions() { Path = "/custom-path" });
NuGet SocketIOClient
Github SocketIOClient

Possible to have C# SSH client communicate with a NodeJS SSH Server?

I have a C# application that needs to run certain commands on a piece of hardware over SSH. The application is using SSH.Net to make the connection, send the command, and the read the result. I have this working if I connect to my local machine using OpenSSH. Finally, I wanted to go a step further and setup my own SSH server so I could simulate multiple hardware devices at one time (need to simulate having 50+ devices to SSH into).
For this I have setup a simple SSH server using nodejs and the ssh2 package. So far I have the client connected, authenticated (all connections are accepted for now), and I can see a session object being created. Although where I'm hitting a wall is with the execution of commands sent by the client. I noticed that ssh2 has an event for exec on the session object but this never seems to trigger (regardless of what i put in SSH.Net's ShellStream).
The C# client code that initiates the connection is the following (command is already defined that the command string to be executed):
using(SshClient client = new SshClient(hostname, port, username, password))
{
try
{
client.ErrorOccurred += Client_ErrorOccurred;
client.Connect();
ShellStream shellStream = client.CreateShellStream("xterm", Columns, Rows, Width, Height, BufferSize, terminalModes);
var initialPrompt = await ReadDataAsync(shellStream);
// The command I write to the stream will get executed on OpenSSH
// but not on the nodejs SSH server
shellStream.WriteLine(command);
var output = await ReadDataAsync(shellStream);
var results = $"Command: {command} \nResult: {output}";
client.Disconnect();
Console.WriteLine($"Prompt: {initialPrompt} \n{results}\n");
}
catch (Exception ex)
{
Console.WriteLine($"Exception during SSH connection: {ex.ToString()}");
}
}
The nodejs server code that set ups the ssh2 server is following:
new ssh2.Server({
hostKeys: [fs.readFileSync('host.key')]
}, function(client) {
console.log('Client connected!');
client.on('authentication', function(ctx) {
ctx.accept();
}).on('ready', function() {
console.log('Client authenticated!');
client.on('session', function(accept, reject) {
var session = accept();
// Code gets here but never triggers the exec
session.once('exec', function(accept, reject, info) {
console.log('Client wants to execute: ' + inspect(info.command));
var stream = accept();
stream.write('returned result\n');
stream.exit(0);
stream.end();
});
});
}).on('end', function() {
console.log('Client disconnected');
});
}).listen(port, '127.0.0.1', function() {
console.log('Listening on port ' + this.address().port);
});
I have seen various ssh2 client examples invoking a client.exec function but I was assuming that it did not matter that my client was not using the ssh2 node package. Is there something that I'm missing here?
The "exec" Node.js server session event is for "non-interactive (exec) command execution". By which they most likely mean SSH "exec" channel (which is intended for "non-interactive command execution").
To execute a command using "exec" SSH channel in SSH.NET, use SshClient.RunCommand.
On the contrary SshClient.CreateShellStream uses SSH "shell" channel, which is intended for implementing an interactive shell session.
For that, you need to handle "shell" Node.js server session event.

Socket can connect to server on WIFI, but not with cellular data

I have a 100 clients that connect to my server using websockets (now tcp). My code is very simple (see below). I have a client on T-Mobile 4G Data using a OnePlus 5t that is not able to connect to the server on mobile data, yet he can on wifi data. Any idea what could be the problem? I must note that I am using .netstandard 2.0 also.
What I have tried so far:
User has checked that the app has permission to use mobile data.
I have changed the protocol to use 'wss' instead of 'ws'.
I have changed the port (user checked https://www.websocket.org/echo.html and it said he was able to connect to it).
Finally, (a few weeks later) I have switched everything to a tcp client protocol and this still did not work.
None of these options have thus far worked.
public void Connect(string address, int port)
{
UriBuilder uriBuild = new UriBuilder("ws", address, port);
Uri uri = uriBuild.Uri;
_ws = new ClientWebSocket();
_tokenSource = new CancellationTokenSource();
ConnectToServerAsync(uri);
}
private async void ConnectToServerAsync(Uri uri)
{
await _ws.ConnectAsync(uri, _tokenSource.Token);
}

websocket-sharp how to work with socketio server and send "emit" request

i can connect to my socketio server, but how can i send a requst with params?
My socketio server listen event
socket.on('init', ( data ) => {
console.log('init', data);
});
on client side i tryed to do this
_socket.OnMessage += (sender, e) =>
{
Console.WriteLine("message: {0} {1}", e.IsBinary, e.Data);
_socket.Send(MakePacket("init", new Init
{
key = "1",
room = "eq",
type = "s"
}.ToJson())
);
};
private string MakePacket(string e, string data)
{
return new[] {e, data}.ToJson();
}
so i send json to server
["init", {"type":"s","key":"1","room":"eq"}]
But server wont react at this packet. Server working fine, i have problem only with call this event at C#. What i do wrong?
The problem is that socket.io is not plain websocket, but a custom protocol on top of websocket (or also on top of HTTP long polling as a fallback and on initialization). That means to speak with a socket.io server you have to encode your data and messages just like socket.io would do it. Here seems to be some documentation about how it works.
Alternatives:
Use a socket.io library on client side - but I don't know if one exists
Work with raw websockets on server side
C# has socketio library but i have some issues that i can't find answers at and there are no support at all. So i switched to websocket-sharp.
Afer some reseach of debug info from socketio server i found the answer. If i send this string all works fine
42["init", {"type":"s","key":"1","room":"eq"}]
Just add 42 before json and all will work fine. Magic.
I think this 42 number is like your current connect status or something like this. Because when you just connect to socketio server it's send string with 0 before json.

IPC between C# and C++ using named pipes

I have a C++ server application and C# client application, and I want them to communicate with each other using named pipes mechanism.
I want to use a multithreded server (each tread will service a client), I found a working code here: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365588(v=vs.85).aspx
It works great with the C++ client from here: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365592(v=vs.85).aspx
My goal is to make this C++ server to work with C# client, so I wrote this simple program for the client side:
public static void Main(string[] Args)
{
//Client
var client = new NamedPipeClientStream(".", "mynamedpipe", PipeDirection.InOut);
client.Connect();
StreamReader reader = new StreamReader(client, Encoding.Unicode);
StreamWriter writer = new StreamWriter(client, Encoding.Unicode);
int i = 0;
while (true)
{
writer.WriteLine("Message" + i.ToString() + Char.MinValue);
writer.Flush();
i++;
System.Console.WriteLine(reader.ReadLine());
Console.ReadKey();
}
}
The behavior I expect is :
Client->Server: "Message1"
Server->Client: "default answer from server"
Client->Server: "Message2"
Server->Client: "default answer from server"
Client->Server: "Message3"
Server->Client: "default answer from server"
Client->Server: "Message4"
Server->Client: "default answer from server"
And so on...
Instead, this is the output I get:
Pipe Server: Main thread awaiting client connection on \.\pipe\mynamedpipe
Client connected, creating a processing thread.
Pipe Server: Main thread awaiting client connection on \.\pipe\mynamedpipe
InstanceThread created, receiving and processing messages.
Client Request String:"?????????????????????????????????????????????????????????
????????????????????????????????????????????????????????????????????????????????
????????????????????????????????????????????????????????????????????????????????
????????????????????????????????????????????????????????????????????????????????
????????????????????????????????????????????????????????????????????????????????
????????????????????????????????????????????????????????????????????????????????
???????????????????????????????????????????????????????????"
Client Request String:"Message0"
After some debugging here are few weird things I noticed:
client.Connect(); causes 2 bytes (not null terminated) to be written to the pipe. this explains the "?????..."
"Messege0" gets written correctly from the client side and the server reads it correctly also, but:
Client side does not seem to read the reply from the server ("default answer from server") correctly - it is stuck on the blocking "reader.ReadLine()" line. I do not think it is because of a bug on the server as the same server seems to work fine with the C++ client.
After closing the server, the message gets to the client. I added
FlushFileBuffers(hPipe);
after
WriteFile()
in the server - it did not help.
Encoding seems to be correct on both sides - Unicode, Little Endien.
Both server and client running on the same Windows machine.
The issue in item number 3, is the most disturbing to me, and I cannot find an explanation.

Categories

Resources