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
Related
I'm attempting to connect to Amazon IoT MQTT broker using a C# net core 2.1 class library. My requirements say I must use port 443, which means per Amazon's documentation I have to use a connection that supports ALPN.
.Net Core 2.1 now has the methods to support this, so I try the following code:
(Note: I can try this same code using port 8883 instead of 443, and it connects fine and sends my MQTT data, so I know my certs and endpoint address are correct.)
this.socket = new Socket(this.remoteIpAddress.GetAddressFamily(), SocketType.Stream, ProtocolType.Tcp);
this.socket.Connect(new IPEndPoint(this.remoteIpAddress, this.remotePort));
this.netStream = new NetworkStream(this.socket);
this.sslStream = new SslStream(this.netStream, false, this.userCertificateValidationCallback, this.userCertificateSelectionCallback);
X509CertificateCollection clientCertificates = null;
clientCertificates = new X509CertificateCollection(new X509Certificate[] { this.clientCert });
SslApplicationProtocol amzProtocol = new SslApplicationProtocol("x-amzn-mqtt-ca");
System.Threading.CancellationToken token = new System.Threading.CancellationToken();
SslClientAuthenticationOptions options = new SslClientAuthenticationOptions()
{
AllowRenegotiation = false,
TargetHost = this.remoteHostName,
ClientCertificates = clientCertificates,
EnabledSslProtocols = SslProtocols.Tls12,
CertificateRevocationCheckMode = X509RevocationMode.NoCheck,
ApplicationProtocols = new List<SslApplicationProtocol>() { amzProtocol },
LocalCertificateSelectionCallback = this.userCertificateSelectionCallback,
RemoteCertificateValidationCallback = this.userCertificateValidationCallback,
EncryptionPolicy = EncryptionPolicy.RequireEncryption
};
this.sslStream.AuthenticateAsClientAsync(options, token).Wait();
Now, from what I understand, I should see (I'm using wireshark) an extension added on to the Client Hello handshake protocol similar to this:
Extension: Application Layer Protocol Negotiation
Type: Application Layer Protocol Negotiation (0x0010)
Length: ##
ALPN Extension Length: ##
ALPN Protocol
ALPN string length: 14
ALPN Next Protocol: x-amzn-mqtt-ca
But I'm not getting that extension, and the connection fails on port 443.
Am I missing something in setting up the list of protocols? I'm not getting any errors from that, but since this is a pretty new release there's not a lot of reference material out there to look for hints.
Well, It seems that even though Net CORE 2.1 has added the functions to support this, that it won't work with Windows 7. You must be using Windows 8.1 or greater. This was not documented anywhere in the code or on the examples on GitHub, but I found out from one of the dev team that for some reason they decided to have it "fail silently", rather than throw an error.
I have created a very simple console application that connects to Azure ServiceBus and sends one message. I tried the latest library from Microsoft (Microsoft.Azure.ServiceBus) but no matter what I do I just get this error:
No connection could be made because the target machine actively
refused it ErrorCode: ConnectionRefused
I have tried exactly the same connection string in Service Bus Explorer and it does work just fine. Moreover I connected without problems using the older library from Microsoft (WindowsAzure.ServiceBus).
var sender = new MessageSender("endpoint", "topicName");
sender.SendAsync(new Message(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject("test"))));
I tried with .NET Framework 4.6.2 and Core, same exception. I suspect there may be some differences in the default protocol that these libraries use, but I could not figure out that for sure.
P.S. Have tried the example from Microsoft docs but result is still the same exception
The old client supported ConnectivityMode using TCP, HTTP, HTTPS, and AutoDetect. ServiceBus Explorer is using AutoDetect, trying TCP first and then failing over to HTTPS, regardless of the TransportMode you were using (SBMP or AMQP).
With the new client this has changed. TransportMode now combines both options and offers Amqp (AMQP over TCP) or AmqpWebSockets (AMQP over WebSockets). There's no AutoDetect mode. You will have to create your clients and specify TransportType as AmqpWebSockets to bypass blocked TCP port 5671 and instead use port 443.
It seems that the documentation is lacking a lot on how to connect using HTTPS (Amqp over WebSockets) but after some help from Sean Feldman in the accepted answer I managed to connect. Here is the code that I used if someone is interested:
var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(
"RootManageSharedAccessKey", // SharedAccessKeyName
"SomeToken");
var sender = new MessageSender(
"sb://mydomain.servicebus.windows.net/",
"topicName",
tokenProvider,
TransportType.AmqpWebSockets);
Or a variant that let's you have the whole connection string in one piece
var builder = new ServiceBusConnectionStringBuilder("YouConnectionString");
var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(
builder.SasKeyName,
builder.SasKey);
var sender = new MessageSender(
builder.Endpoint,
"TopicName",
tokenProvider,
TransportType.AmqpWebSockets);
It is actually possible to use ConnectionString directly but then it has to be augmented to use the right protocol.
var sender = new MessageSender("TransportType=AmqpWebSockets;Endpoint=...", "TopicName")
Or the version that allows to embed EntityPath into the ConnectionString
var connectionBuilder = new ServiceBusConnectionStringBuilder("EntityPath=MyTopic;TransportType=AmqpWebSockets;Endpoint=...")
var sender = new MessageSender(connectionBuilder);
I was having the same issue but his worked for me
var clientOptions = new ServiceBusClientOptions();
clientOptions.TransportType = ServiceBusTransportType.AmqpWebSockets;
client = new ServiceBusClient(connectionString, clientOptions);
sender = client.CreateSender(topicName);
// create a batch
using ServiceBusMessageBatch messageBatch = await sender.CreateMessageBatchAsync();
I set up a rest service with the grapevine, plus I'm having trouble accessing remotely even with the firewall turned off.
Are you only accepting connections through localhost or 127.0.0.1, when I try to access the IP of the machine or remotely gives this error
Bad Request - Invalid Hostname
HTTP Error 400. The request hostname is invalid.
using (var server = new RestServer())
{
server.Port = "9999";
server.LogToConsole().Start();
Console.ReadLine();
server.Stop();
}
Edit: Please refer to the (updated) documentation, specifically the page On Using HttpListener
The current default value is localhost. You can change the directly using the Host property:
server.Host = "*";
Use "*" to indicate that the HttpListener accepts requests sent to the port if the requested URI does not match any other prefix. Similarly, to specify that the HttpListener accepts all requests sent to a port, replace the host element with the "+" character.
So, for Grapevine 4, you could write your code as follows:
using (var server = new RestServer{Port = "9999", Host = "*"})
{
server.LogToConsole().Start();
Console.ReadLine();
server.Stop();
}
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.
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.