Here is the scenario: I have 5 apps which all share a common DLL which contains P2P networking functionality that I wrote. One of these apps works perfectly every single time, but the others experience the following problem:
On a multicast broadcast our x86 based tablet can send and receive packets fine, but my x64 computer and ARM tablet can only send packets. The only difference is that they use different ports. I thought that must be it, and tried switching the other apps to use the same ports as the working app as a test, but that was a no-go. Here is the relevant portion of code that handles setting up the broadcasting system.
public async Task<bool> Startup() {
if (P2PNetwork.LocalUser == null || this._listenSocket != null)
return false;
ConnectionProfile connection = null;
//See note 1 below
bool gotConnection = TryGetValidNetworkConnection(out connection);
if(!gotConnection)
return false;
this._heartbeatTimer = ThreadPoolTimer.CreatePeriodicTimer(DoHeartbeat, TimeSpan.FromSeconds(10));
var socket = new DatagramSocket();
var stream = await socket.GetOutputStreamAsync(LANBroadcasting.MULTICAST_GROUP_ADDRESS, P2PNetwork.NetworkGroup.SendPort);
this._outStreamWriter = new DataWriter(stream);
this._listenSocket = new DatagramSocket();
this._listenSocket.MessageReceived += OnMessageReceived;
await this._listenSocket.BindServiceNameAsync(P2PNetwork.NetworkGroup.ReceivePort, connection.NetworkAdapter);
this._listenSocket.JoinMulticastGroup(LANBroadcasting.MULTICAST_GROUP_ADDRESS);
DoHeartbeat(HeartbeatFlags.Ping);
return true;
}
NOTE 1: These symptoms were happening before for all 5 applications. At that time I was using the BindServiceNameAsync without any arguments. After extensive research I found a page that suggested that that approach was not good, and that the Windows 8.1 method that takes a connection profile worked more reliably. I checked the profile multiple times and I get the wireless LAN profile, which is correct for both.
In this case (non-working) the tablet's send port is 50011 and its receive port is 50010. The multicast address is ff02::fb (I've tried IPv4 as well, no change) The PC in this case is the reverse of that. I confirmed that the packets are sending via Wireshark.
I also see this line of output via netstat -a on the PC (which is failing to receive)
UDP [::]:50011 *.*
Despite all this looking correct, my PC simply does not get the OnMessageReceived method called (except for the one app which mysteriously works). What should I be looking for that can cause this odd behavior? I tried changing the ports on the working application to see if it would fail but it didn't. I also tried running the app on a different tablet to see if it was just this PC, but I got the same results on the other tablet. Could the app be failing to join the multicast group? How would I know since the method returns void?
After a few days of banging my head against the wall, I finally got the answer. If you experience this problem, go to your Windows Firewall Settings and check what kind of network you are connected to. In my case, the Wi-Fi was a Guest / Public network. Apparently this means that it is considered "Internet" by the Windows Runtime and not "Private Network". In Package.appxmanifest I had the "Private Network (Client and Server)" options selected, but only "Internet (Client)" (which provides outbound access only) and not "Internet (Client and Server)" on all but the one application that was working for some reason.
On a side note: this doesn't explain why the one x86 tablet was still able to receive for all apps. I can only assume this is some kind of driver flaw.
This should really trigger some kind of warning message because this simple setting is way too easy to overlook.
Related
A. Description
I am using ZeroMQ monitor and I find that it works when logic disconnection but does not work when network broken down (unplug my cable).
For example:
I launch client app on an android pad, then launch a server app on my windows laptop. They are connected through a router with cables.
Everything will be OK with monitor if I close or open either client app or server app manually. Namely, the monitor on both sides can receive a 'Connect' or an 'Accept' and a 'Disconnect' event.
But If I unplug cable on the server side, while the client and server are connected and running, the monitors on both sides can not detect the 'Disconnect' event.
Is the monitor designed like this?
If so, are there any solutions to detect network broken down ( a cable unplug event ) except heartbeats?
If not, how to use the ZeroMQ's original monitor mechanism to solve this problem? Can a setTCPKeepAlive() interface be useful?
B. System environment
My scenario is as below.
Client
OS: Android, running on a pad, IDE: Android studio 2.3, lib:jeromq-0.4.3
// Java Code
String monitorAddr = "inproc://client.req";
ZContext ctx = new ZContext();
ZMQ.Socket clientSocket = ctx.createSocket(ZMQ.REQ);
clientSocket.monitor(monitorAddr,ZMQ.EVENT_ALL);
// Then start a montitor thread which is implemented by my own.
Server
OS: Windows 7 ( 64 bit ), running on my laptop, IDE: VS2013, lib: Clrzmq4
// C# Code
const string MonitorEndpoint = "inproc://server.rep";
var ctx = new ZContext();
var serverSocket = new ZSocket(ctx,ZSocketType.REP);
ZError error;
// Create serverSocket pair socket
if (!serverSocket.Monitor(MonitorEndpoint, ZMonitorEvents.AllEvents, out error))
{
if (error == ZError.ETERM)
return ; // Interrupted
throw new ZException(error);
}
// Create a monitor
ZMonitor _monitor = ZMonitor.Create(ctx, MonitorEndpoint);
_monitor.AllEvents += _monitor_AllEvents;
_monitor.Start();
AFAIK there is no built in heartbeat within ZeroMQ. I know there was some discussion on the topic within the ZMQ community some years ago, and that discussion may still be going on.
It is comparatively simple to incorporate your own heartbeat messaging in your application's use of ZeroMQ, especially if you use something like Google Protocol Buffers to encode different message types; the heartbeat is just another message.
Doing heartbeats in your application (rather than relying on some inbuilt mechanism) is ultimately more flexible; you can choose the heartbeat rate, you can choose what to do if the heartbeat fails, you can decide when heartbeating is important and not important, etc.
Consider heartbeats within a PUB/SUB pattern; it's a bit difficult for the ZMQ authors to decide on your behalf what connection / disconnection / connection-break events matter to you. And if they do build in a mechanism, but an application developer didn't want it, then it is a waste of bandwidth.
It's far easier for the ZMQ authors to leave that kind of application architectural issue to the application author (that's you!) to deal with.
With your specific example, an unplugged network cable simply looks (so far as any software can determine) like no traffic is flowing; it's the same as the application not sending anything. ZMQ doesn't send anything if the application hasn't sent anything.
If you look at the events that the socket monitor can report on, they're all the consequence of something flowing over the network connection, or something done to the socket by the application.
Trying to go lower than ZMQ protocol itself and access the TCP connection that specific ZeroMQ sockets use (while others do not) doesn't sound like a good idea; it would required to break encapsulation in multiple classes.
The answer #bazza gave in 2017 was entirely correct at the time.
However, newer versions of ZMQ (specifically ZMTP) include an heartbeat functionality.
Check ZMQ documentation for
socketOpt
Java functions
name
purpose
ZMQ_HEARTBEAT_IVL
get/setHeartbeatLvl()
heartbeat interval
milliseconds between ZMPT PINGs
ZMQ_HEARTBEAT_TIMEOUT
get/setHeartbeatTimeout()
local heartbeat timeout
how long the local socket waits between received packets until it considers the connection timed out
ZMQ_HEARTBEAT_TTL
get/setHeartbeatTtl()
remote heartbeat timeout
if and when remote side shall consider the connection timed out
ZMQ_HEARTBEAT_CONTEXT is still in draft state as of 2022. It is supposed to send an byte[] context with every ping.
Now, by design of ZMQ, quoting from chapter 2 of its documentation,
The network connection itself happens in the background, and ZeroMQ
will automatically reconnect if the network connection is broken
(e.g., if the peer disappears and then comes back).
Thus, answering your main question, I'd expect the monitor to give you ZMQ_EVENT_CONNECT_RETRIED / ZMQ_EVENT_CONNECTED events after the underlying connection was detected as disrupted.
I have been searching for solution to test or check the connectivity between my device and the server that contains my database.
Note: I want to implement the solution on my PCL project.
You can use James Montemagno's Connectivity Plugin for this.
You can either check if the device you are using is connected by calling;
bool isConnected = CrossConnectivity.Current.IsConnected;
Or, you can 'ping' a server to see if it can be reached. You can do that like this:
var isReachable = await CrossConnectivity.Current.IsReachable("google.com", 5000);
You can also provide an IP address. The second parameter is the timeout which defaults to 5 seconds. There is also the specific IsRemoteReachable method which also let's you specify a port number.
This library can be used in a PCL.
Note; for Android you will need the ACCESS_NETWORK_STATE and ACCESS_WIFI_STATE permissions, it should be added automatically when you install the NuGet package.
In the most cases it is completed with ICMP pings. You can ping the server every 1-5 secs depending on your appliation. But I suggest to use multicast address and ping that from the server because of performance and securtiy reasons (the last one needs firewall be configurated on server side too). You can determine connectivity lost if some of the replys (at least 3) doesn't reach the target host.
My intention is to receive UDP messages over the internet on a windows phone 8.
-> First question: am I wrong assuming that this is possible?
Test setup:
WIFI switched off, cellular data on
Running NetworkInformation.GetHostNames() I get one host with IANA network code 344, IP Address was "10.146.8.159".
Opening icanhazip.com at the same time in the browser I get an IP Address of "192.230.159.176".
-> Second question: why are these two IP addresses different?
My code is:
public async void Start()
{
m_rxSocket = new DatagramSocket();
m_rxSocket.MessageReceived += MessageReceived;
await m_rxSocket.BindServiceNameAsync("57000");
}
private async void MessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs socketEventData)
{
// This is never called
}
The problem is that the method MessageReceived is never called despite:
Sending a UDP message to 10.146.8.159 as well as 192.230.159.176 over the internet
Registering the ID_CAP_NETWORKING
-> Third question: why is no message received by the setup above?
(-> Fourth question: anyone else thinking that wp development with silverlight was superior to this new apis that are smelling C++ all over...?)
Hi i have found what was wrong:
Lack of UDP hole punching was the reason for the behaviour and adding UDP hole punching the solution to make it work.
resolved I've resolved the issue turning off Windows firewall
I run the same code on two different computers.
s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
ipep = new IPEndPoint(IPAddress.Any, int.Parse(mcastPort));
s.Bind(ipep);
// setting options
// ................
// s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddSourceMembership, option);
if (s.Poll(1, SelectMode.SelectRead))
{
Console.WriteLine("Poll returned true");
} else
{
Console.WriteLine("Poll returned false");
}
On one computer code works fine, so at least SOMETIMES it works.
However on another computer it doesn't work. In one case Poll returns true and in another case Poll returns false; I've used Wireshark to check that on both computers I can see datagrams on the specified connection (mcastGroup, mcastPort, sourceIp). I was thinking that probably on second computer wrong interface is used, so I replaced new IPEndPoint(IPAddress.Any... with new IPEndPoint(IPAddress.Parse("10.11.12.13")... but this doesn't help.
The only difference I can see. On the computer where program works I can see datagrams only when program is launched. On computer where program doesn't work I always see datagrams, even if application is shutdown.
The question is - how can I troubleshot the problem?
i'm sure that there are datagrams in network because I see them in wireshark
i'm sure that my application and wireshark use the same multicastGroup, multicastPort, sourceIp
i'm sure that I'm using the same interface because I provide it explicitly
But Socket.Poll still returns false. What else should I do?
upd Also I noticed in sniffer that computer that doesn't work uses IGMP v2, while computer that does work uses IGMP V3. Probably feature AddSourceMembership is new to IGMP v3 and that's why my program doesn't work? How to force computer to use IGMP v3?
upd I've created another question https://stackoverflow.com/questions/9775405/the-same-udp-multicast-addsourcemembership-code-results-in-completely-different because I think this is not c# or .net problem
I'm following a tutorial # http://www.geekpedia.com/tutorial239_Csharp-Chat-Part-1---Building-the-Chat-Client.html to try and gather the basics of networking. For those not wanting to hit the jump, it's a quick tut demonstrating how to program a simple client-server-model chat application.
When I try and run the code in the tut, it works fine as long as both the client and the server are on the same network, but the second I try and do it externally (getting a mate to run the client app, and running the server app my side), it all goes to pot. The fact that the code works when in the same network leads me to believe that it's not a coding issue, but an issue with the way my network is set up.
I'm trying to run the server on my IP address at port 21719, which I have opened, but still other people can't connect to my server, not able to get any form of response at all.
The code (from the tut) that is being used for the server to listen to connections is:
public void StartListening()
{
IPAddress ipaLocal = ipAddress; //ipAddress is parsed from txtIP
tlsClient = new TcpListener(ipaLocal, 21719);
tlsClient.Start();
ServRunning = true; //for the running loop
// Start the new tread that hosts the listener
thrListener = new Thread(KeepListening);
thrListener.Start();
}
Now, the tutorial does actually point out that
IPAddress ipaLocal = ipAddress;
Will cause issues on some configurations, and I'm beginning to fear that my configuration may be included in that.
So, does anyone have any solution for me?
Thanks,
Sam
What is the local IP address that you're using? (ipAddress) If it's 127.0.0.1, that's not correct (I don't know how it would work internally either, but Windows seems to use magic from time to time). Also, if you have multiple NICs in your local machine, maybe the port forwarding is only set up to forward to one of them, and you're using the IP of the other?
If that's not the problem, here are a few generic suggestions:
Grab a copy of netcat. It's a small network testing util whose only job is to form a simple TCP connection. That will allow you to eliminate your code as a variable in all this. If netcat can form a connection, then you know the problem is your code. If not, you've confirmed that it's your router.
You can use WireShark (or TShark) to look for ICMP packets. Capture ICMP packets on the remote machine. If you get "Destination Unreachable" from the router, you've again proved that it's your router.
As Spencer said you need to make sure Port Forwarding is setup on your router, to forward all packets that come in on port 21719 to your internal machine. As for exactly how to do that, it's hard to say without knowing what type of router.
Are you having people use your external (internet) IP address? (See yours here.)
Have you pinholed your router to forward all communications from port 21719 to your server?
Some tips:
What kind of operating system are you using? Please check the Scope and/or Profiles (under Advanced tab) of your firewall rule.
While your friend is trying to telnet to the port (connect to the im server) monitor the traffic using Wireshark or Network Monitor (Wireshark have problems with Vista and Win 7). If you don't see anything hitting your machine the problem is probably on the router side. Double check the settings - you said you set the forward rule (NAT) but did it also set the rule on firewall of your router?