I would like to run a WebSocket server off a worker role in Azure.
This works fine locally on the emulator, but there is a windows firewall prompt the first time the socket server runs.
I'm wondering if anyone would know how to overcome the connection issues with regards to sockets on Azure.
My socket server implementation: OnStart
var server = new WebSocketServer("ws://theappname.cloudapp.net:8080/");
server.Start(socket =>
{
socket.OnOpen = () =>
{
Trace.WriteLine("Connected to " + socket.ConnectionInfo.ClientIpAddress,"Information");
_sockets.Add(socket);
};
});
.... etc
The client implementation:
var socket = new WebSocket("ws://theappname.cloudapp.net:8080");
socket.onopen = function () {
status.html("Connection Opened");
};
socket.onclose = function () {
status.html("Connection Closed");
}
The status changes to closed a few seconds after loading the page.
My endpoint for the worker role below:
WebSocket Input http 8080 <Not Set>
I have now tried to bind to the internal IP address using the following:
RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["WebSocket"].IPEndpoint.ToString();
SOLUTION
For the sake of anyone else facing this when implementing websockets on Azure;
Your firewall probably will deny your connection if not on port 80 or 8080 so create a separate deployment for it.
Endpoint must be set to TCP and not HTTP for the correct firewall rules to be created. (see image)
Just for the sake of trial, why don't you change your Input Endpoit from "http" to "tcp" protocol. And explicitly set the local port to 8080 (which in your case is ). Also you have to keep in mind that Windows Azure Load Balancer would kill any connection that is idleing for more than 60 seconds, so you might want to implement some kind of "ping" solution to keep the connection open.
You might want to take a look at this introductory video that Steve Marx (#smarx) put together on how to run node.js on Windows Azure.
Related
I'm struggling to get a gRPC client built with Xamarin.Forms to communicate with a gRPC server running on my localhost. The server can be reached without issue with BloomRPC, however I can't seem to get it to work properly from my client. The server is listening on http://localhost:5000 and https://localhost:5001.
I initially thought that perhaps it was because it's running on localhost that my client is struggling, so I also tried using a RemoteURL courtesy of Conveyor by Keyoti, which is set to http://192.168.1.64:45455 and https://192.168.1.64:45456, however I'm not quite sure how that works with my gRPC server as it is specifically listening on ports 5000 and 5001. Either way, trying to connect by either method results in an RPCException stating "failed to connect to all addresses".
I'm using the Grpc.Core library, and Grpc.Core.Xamarin (version 2.41.1) with the below code. I've also tried using version 1.20.1, but without success. The below code tries to connect to the authentication service which simply returns a GUID.
public static async Task<Msg.SessionTokenResponse> test()
{
// I've also tried, localhost:5000, localhost:5001 (with and without SSL credentials),
// 127.0.0.1:5001 (with and without SSL credentials), 0.0.0.0:5000, 0.0.0.0:5001
// (with and without SSL credentials), 192.168.1.64:45455, 192.168.1.64:45456 (with and
// without SSL credentials)
var channel = new Channel("127.0.0.1:5000", ChannelCredentials.Insecure);
var client = new AuthenticationService.AuthenticationServiceClient(channel);
var request = new Msg.SessionTokenRequest();
try
{
return await client.CreateSessionTokenAsync(request);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
throw ex;
}
finally
{
await channel.ShutdownAsync();
}
}
It's also worth noting if I try to pass http:// or https:// at the start of the address I get a "DNS resolution failed for service" error message. Upon reading up it looks like this is not meant to be provided as part of the address, but I may be misunderstanding the requirements. I have tried this with my firewall disabled, and have no proxy. I've also tried adding the following environment variables:
Environment.SetEnvironmentVariable("NO_PROXY", "127.0.0.1");
Environment.SetEnvironmentVariable("GRPC_DNS_RESOLVER", "native");
Environment.SetEnvironmentVariable("GRPC_VERBOSITY", "debug");
Environment.SetEnvironmentVariable("GRPC_TRACE", "all");
I can't see anything helpful in the logging.
Any and all help would be greatly appreciated.
After all the help from #Jason I was finally able to get this resolved.
As he alluded to, the problem was because the code is running on the simulators, not my local machine (even if the simulators are on my local machine), and thus referring to localhost will simply try to access the simulator, not my PC.
To get around this without publishing my gRPC server to some other device, I simply needed to change the applicationUrl in my gRPC server's launchSettings.json file so that it would listen specifically to my internal IP address, and not localhost. My launchSettings.json file looks like below:
{
"profiles": {
"MyGRPCServer.API": {
"commandName": "Project",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://192.168.1.64:45456;http://192.168.1.64:45455"
}
}
}
I then simply whitelisted ports 45455 and 45456 in my firewall and the simulators were able to access my gRPC server.
I also changed
var channel = new Channel("127.0.0.1:5000", ChannelCredentials.Insecure);
to
var channel = new Channel("192.168.1.64:45455", ChannelCredentials.Insecure);
Thanks again for all the help Jason, and hopefully this helps someone else.
Using the example Chat Server/Client project available as part of the Akka.NET source code I have attempted to modify it such that it would successfully work over two computers on my network.
I have two systems that are connected via a router like this
192.168.0.29 (Server) <---------------| Router |---------------> 192.168.0.52 (Client)
I then have two actor systems that are configured like this:
Server:
akka {
actor {
provider = remote #Specify remote provider
}
remote {
dot-netty.tcp {
port = 666 #Akka server port number
hostname = 0.0.0.0 #Bind to all local network interfaces
public-hostname = 192.168.0.29 #Expose public IP to enable correct routing of public messages.
}
}
}
Client:
akka {
actor {
provider = remote
}
remote {
dot-netty.tcp {
port = 0 #Tell Akka that this is a client connection/use random port.
hostname = 192.168.0.29 #Tell Akka.NET which remote instance to connect to
}
}
}
Unfortunately, while I am able to successfully connect to the chat server locally, no matter how I configure my Hocon I cannot seem to get the remote instance to bind to my server actor located on the machine 192.168.0.29.
The specific error message that I receive
[ERROR][27/11/2019 4:58:36 PM][Thread 0004][Akka.Remote.Transport.DotNetty.TcpTransport] Failed to bind to 192.168.0.29:0; shutting down DotNetty transport.
Cause: System.Net.Sockets.SocketException (10049): The requested address is not valid in its context
at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, String callerName)
This error message suggests to me that there is no available socket that Akka.NET can access.
Ironically enough, some time ago I asked a very similar question which at the time helped me resolve my connectivity issues but I never used Akka.NET till recently again.
I note that both machines have their firewalls turned off and can successfully ping each other, I have also played around with all various combinations of settings.
The original source code to the Akka.NET server/client application is located here, my current version of it is here.
Could anyone provide any insight into what I might be doing wrong and how I can improve my debugging of Akka.NET remote connections? For example is there a way that I can verify that the Actor system on server 192.168.0.29 is accessible from 192.168.0.52 externally?
Haha, and literally 5 minutes after posting my question I was finally able to determine the solution (although its not ideal).
The solution was the realisation that when you instantiate the ActorSystem on the client application you are NOT actually connecting the local actor system to the remote system BUT rather creating a local instance of an actor system which itself is listening on a random port.
The remote connection itself occurs when you create an ActorSelection() reference.
So all I needed to do was change my client hocon from
hostname = 192.168.0.29
TO
hostname = 192.168.0.52
However this creates one final (albeit rather small) problem. I now need a different hocon file for an instance running locally vs an instance running remotely. Admittedly this could probably be addressed through code....
I'd be happy to mark as the solution someone who might be able to propose something that addresses this issue.
I'm developing a really simple MQTT Android client, so I can connect to it with an MQTT Server I created in C# using the MQTTnet library.
I first tested the C# broker with a C# client and Node-RED and it worked just fine.
I also tested the Android Client with CloudMQTT following this tutorial, and it also worked perfectly fine.
But when I tried to connect my Android Client to the C# Server, the Android Client gave me the following error:
Mqtt: Failed to connect to: tcp://localhost:1883 It's not possible to connect to server (32103) - java.net.ConnectException: Connection refused
I'm using BlueStacks as an emulator (I will try to test it in a real Android device asap). I tried to restart the emulator (as said in Paho Mqtt Android connecting to broker fails with (32103)) but it didn't work either.
The code for the Android Client is exactly the same as in the tutorial I mentioned earlier (using the Paho-MQTT library), but changing the serverUri and subscription topic:
final String serverUri = "tcp://localhost:1883";
final String subscriptionTopic = "step/time";
The app only has a TextView where I set the received messages.
As for the C# server, I'm sending a timestamp every 10 seconds. This is my code:
namespace MQTTServerExample
{
class Program
{
static void Main(string[] args)
{
serverAsync();
}
private static async Task serverAsync()
{
// Starting the MQTT Server
var mqttServer = new MqttFactory().CreateMqttServer();
var options = new MqttServerOptions();
//Saving retained application messages
options.Storage = new RetainedMessageHandler();
// Publishing messages
await mqttServer.StartAsync(options);
Console.WriteLine("### SERVER CONNECTED ###");
Console.WriteLine("Press ENTER to exit.");
MqttApplicationMessage message;
#pragma warning disable CS4014
Task.Run(async () =>
{
while (true)
{
message = new MqttApplicationMessageBuilder()
.WithTopic("step/time")
.WithPayload(DateTime.Now.ToString())
.WithExactlyOnceQoS()
.WithRetainFlag(true)
.Build();
await mqttServer.PublishAsync(message);
await Task.Delay(10000); // Every 10 seconds
}
});
#pragma warning restore CS4014
//await mqttServer.PublishAsync(message);
Console.ReadKey();
await mqttServer.StopAsync();
}
}
I'm new to connection protocols and I still don't understand them clearly, so I was hoping you could help me understand this problem.
A java.net.ConnectException: Connection refused exception means that there is no service listening on the host and port you are trying to connect to, for example because the host address or port is wrong, or the service is not started.
Using "tcp://localhost:1883" as server address only works if the server runs on the same machine as the client (i.e. in your case the Android device). You should use the server's name or IP address.
I'm going to guess that your C# broker is only listening on localhost not the external IP address of the machine hosting it.
This would work when ran the C# client on the same machine, but not when you use the external IP address from the Android client.
The other possible option is that you are running a firewall on the broker machine which is stopping the Android client connecting.
Edit/Summary
After a lot of trial and error, Paul Kearney - pk helped lead me to the answer, although I still don't know why this happens, at least I know how to get it to work.
Quick Summary: Clients can connect to port 8080 on my laptop when I'm directly connected to my network at work. Clients cannot connect to port 8080 when I'm on a home network. To solve this, I created a firewall rule (on my laptop) to allow inbound traffic on 8080. I'd really like to know why this is the case. Does my laptop's Windows Firewall service actually change its settings based on the network I'm connected to?
Note: This all works when I'm on my network at work, but it doesn't work on my home network, or someone else's home network. The host computer (my laptop) is the same at both locations.
I have a web app that uses SignalR. Everything works when I run the web app on the same machine as where the SignalR host is running. When I try to connect from a different machine, I get this error:
> GET http://10.0.0.13:8080/signalr/hubs net::ERR_CONNECTION_TIMED_OUT. Cannot read property 'client' of undefined.
That error comes from my index.html page:
<script src="http://10.0.0.13:8080/signalr/hubs"></script>
From the research that I've done, I know that I shouldn't be using localhost in my SignalR URL. So I used an asterisk. This is in my self-hosted SignalR app:
class Program
{
static void Main(string[] args)
{
string url = "http://*:8080";
using (WebApp.Start(url))
{
Console.WriteLine("Server running on {0}", url);
Console.ReadLine();
}
}
}
class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
}
}
public class RaceHub : Hub
{
public void Send(string name, string message)
{
Clients.All.addMessage(name, message);
}
}
And this is my JavaScript to connect:
var signalRUrl = 'http://10.0.0.13:8080/signalr';
$.connection.hub.url = signalRUrl;
var hub = $.connection.raceHub; // proxy reference to hub
// Create a function that the hub can call to broadcast messages.
hub.client.addMessage = function (name, message) {
receiveSignalRMessage(name, message);
};
$.connection.hub.start(); // Start the connection.
Like I said, this all works locally. But it doesn't work from another machine. I do not have Windows Firewall enabled, so that's not the issue. Any ideas?
HTTPS didn't work. It works when I'm on my network at work, but not at home. The configuration is the same. Must have something to do with my home network.
Also, this is what the page looks like when it's working properly:
And this is what happens when it's not working:
(Full disclosure - #BobHorn typed up this answer based on my comments)
There are different firewall settings on your machine, depending on the type of network you are attached to.
Have you ever noticed when you connect to a new network for the very first time, it asks you to define it as "work, private, public, home, etc"?
Whatever you choose for that network is sticky, and the related firewall policy is applied when you are on that type of network.
To check this, you can either completely turn off your firewall, or make sure inbound port 8080 is open for all firewall profiles, especially "home" networks and/or the "home" firewall profile.
ahh.. so you say your windows firewall is off. Are you sure it's not OFF only for the WORK network profile, but enabled for the HOME network profile ?
To troubleshoot this, I would put wireshark on one of the client computers trying to connect to port 8080 at home, and see how/why it's being blocked or cannot connect.
You can also try to telnet to port 8080 from the client machine at home (if the Telnet Client feature is enabled). You'll know right away if the port is open and connection succeeds, or a big fat denied. Quick and easy test. type TELNET ServerIPAddress PortNumber from a command line. If Telnet command not found, you need to turn on the Telnet Client in Windows Features/Components.
Does your network use IP security? You might try using HTTPS instead to see if that alleviates anything.
It looks like your work network is blocking your IP. Try whitelisting your home IP on your work network.
I believe the issue here is that your laptop's IP address changes from one network (i.e. work) to another (i.e. home), but you may not be updating the value of the signalRUrl variable in your javascript file accordingly, thus the client side of your app is looking for a hub at an IP address that doesn't exist on your home network.
When you change networks, you need to update the value of signalRUrl in javascript to reflect the current IP address of the host machine.
I recently deployed an Azure app to the staging environment which is supposed to accept TCP packets in port 2993. When run in the Azure emulator, it does this very well, and performs exactly as it should.
However, now that it is on Azure's staging servers, whenever I try to connect to the TCP port, i get the following SocketException:
A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
My web app has two instances, one is a worker role (it has 2993 configured in its endpoints) and a web role (only for port 80). Port 80, by the way, functions perfectly. The web app was created with Visual Studio in C#. Why is this happening and how can I fix it?
All help is greatly appreciated.
I would like to explain what was the issue and why adding above code solve this problem for others benefit.
In your worker role, you configure any TCP endpoint along with any port number. When this VM starts the VM is provisioned to use this port and firewall is included an exception to provide access to this port. By the time your is ready to start your Azure VM already have TCP/IP address and configured port is enabled.
Now when your role starts and if you have any service or application required access this port you really need to l
For example If I have Tomcat/Java configured in my worker role, I must have to create a TCP listener on my configured port. This can be done when my worker role starts as below:
Get the IP address and Port number of the current role instance
Create a TCP Listener and start on this IP address and Port
Add the code to perform step 1) and 2) in my worker role OnStart() function.
The code will look like as below:
TcpListener TomcatPortListener = new TcpListener(RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["TomcatWeb80"].IPEndpoint);
TomcatPortListener.Start();
In your case you you did exactly the same you got the IP address and Port number from and then created an endpoint from a socket address using IP/Port:
RoleInstanceEndpoint externalEndPoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["TCPin"];
IPEndPoint localEndPoint = new IPEndPoint(externalEndPoint.IPEndpoint.Address, externalEndPoint.IPEndpoint.Port);
localEndPoint.Create();
It is a must setting for any web or worker role which create TCP endpoint.
It seems the problem had something to do with the program's detection of the server's IP address. By using the following server code instead, I managed to fix the problem:
RoleInstanceEndpoint externalEndPoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["TCPin"];
IPEndPoint localEndPoint = new IPEndPoint(externalEndPoint.IPEndpoint.Address, externalEndPoint.IPEndpoint.Port);
The IPEndpoint can then be used with the tcpListener socket.