Check for internet connectivity from Unity - c#

I have a Unity project which I build for Android and iOS platforms. I want to check for internet connectivity on Desktop, Android, and iOS devices. I've read about three different solutions:
Ping something (for example Google) - I totally dislike such decision, and I've read about mistakes on Android.
Application.internetReachability - According to Unity's documentation, this function will only determine that I have a POSSIBILITY of connecting to the Internet (it doesn't guarantee a real connection).
Network.TestConnection() - If I have no Internet connection, my application fails. So this isn't correct either.
How can I determine whether I have internet connectivity from within Unity?

I don't actually believe that Network.TestConnection() is the right tool for this job. According to the documentation, it looks to me like it's meant for testing if NAT is working and your client is publicly reachable by IP, but what you want to check for is whether you have general internet connectivity.
Here is a solution that I found on Unity Answers by user pixel_fiend, which simply tests a website to see if the user has connectivity. One benefit of this code is that it uses IEnumerator for asynchronous operation, so the connectivity test won't hold up the rest of your application:
IEnumerator checkInternetConnection(Action<bool> action){
WWW www = new WWW("http://google.com");
yield return www;
if (www.error != null) {
action (false);
} else {
action (true);
}
}
void Start(){
StartCoroutine(checkInternetConnection((isConnected)=>{
// handle connection status here
}));
}
You can change the website to whatever you want, or even modify the code to return success if any one of a number of sites are reachable. AFAIK there is no way to check for true internet connectivity without trying to connect to a specific site on the internet, so "pinging" one or more websites like this is likely to be your best bet at determining connectivity.

public static IEnumerator CheckInternetConnection(Action<bool> syncResult)
{
const string echoServer = "http://google.com";
bool result;
using (var request = UnityWebRequest.Head(echoServer))
{
request.timeout = 5;
yield return request.SendWebRequest();
result = !request.isNetworkError && !request.isHttpError && request.responseCode == 200;
}
syncResult(result);
}

void Start()
{
StartCoroutine(CheckInternetConnection(isConnected =>
{
if (isConnected)
{
Debug.Log("Internet Available!");
}
else
{
Debug.Log("Internet Not Available");
}
}));
}
IEnumerator CheckInternetConnection(Action<bool> action)
{
UnityWebRequest request = new UnityWebRequest("http://google.com");
yield return request.SendWebRequest();
if (request.error != null) {
Debug.Log ("Error");
action (false);
} else{
Debug.Log ("Success");
action (true);
}
}
Since WWW has deprecated, UnityWebRequest can be used instead.

i know this is old, but maybe can help you.
public bool CheckInternetConnection(){
return !(Application.internetReachability == NetworkReachability.NotReachable)
}

Ping 8.8.8.8 instead of sending a GET
unity already provides the tool for that:
Ping
The ping operation is asynchronous and a ping object can be polled for
status using Ping.isDone. When a response is received it is in
Ping.time.
Windows Store Apps: A stream socket is used to mimic ping
functionality, it will try to open a connection to specified IP
address using port 80. For this to work correctly, InternetClient
capability must be enabled in Package.appxmanifest.
Android: ICMP sockets are used for ping operation if they're
available, otherwise Unity spawns a child process /system/bin/ping for
ping operations. To check if ICMP sockets are available, you need to
read the contents for /proc/sys/net/ipv4/ping_group_range. If ICMP
sockets are available, this file should contain an entry for 0
2147483647.
using UnityEngine;
using System.Collections.Generic;
public class PingExample : MonoBehaviour
{
bool isConnected = false;
private IEnumerator Start()
{
while(true)
{
var ping = new Ping("8.8.8.8");
yield return new WaitForSeconds(1f);
while (!ping.isDone)
{
isConnected = false;
yield return null;
}
isConnected = true;
Debug.Log(ping.time);
}
}
}

I've created an Android's library that can be used as Unity's plugin for this purpose. If anyone's interested it's available under https://github.com/rixment/awu-plugin
As for the iOS version unfortunately I don't have enough of knowledge in this area. It would be nice if someone could extend the repo to include the iOS version too.

With the latest version of Unity, WWW has become obsolete, hence you need to use WebRequest.
This is the bit of codes I'm using to check if the user is online:
private string HtmlLookUpResult_Content;
private char[] HtmlLookUpResult_Chars;
private StreamReader HtmlLookUpResult_Reader;
private bool HtmlLookUpResult_isSuccess;
private HttpWebRequest HtmlLookUpResult_Request;
private HttpWebResponse HtmlLookUpResult_Response;
public bool CheckIfOnline()
{
HtmlLookUpResult_Content = UniversalEnum.String_Empty;
HtmlLookUpResult_Request = (HttpWebRequest)WebRequest.Create(UniversalEnum.WebHtml_isOnline);
HtmlLookUpResult_Request.Timeout = 5000;
try
{
using (HtmlLookUpResult_Response = (HttpWebResponse)HtmlLookUpResult_Request.GetResponse())
{
HtmlLookUpResult_isSuccess = (int)HtmlLookUpResult_Response.StatusCode < 299 && (int)HtmlLookUpResult_Response.StatusCode >= 200;
if (HtmlLookUpResult_isSuccess)
{
using (HtmlLookUpResult_Reader = new StreamReader(HtmlLookUpResult_Response.GetResponseStream()))
{
HtmlLookUpResult_Chars = new char[1];
HtmlLookUpResult_Reader.Read(HtmlLookUpResult_Chars, 0, 1);
HtmlLookUpResult_Content += HtmlLookUpResult_Chars[0];
}
}
}
}
catch
{
HtmlLookUpResult_Content = UniversalEnum.String_Empty;
}
if (HtmlLookUpResult_Content != UniversalEnum.String_Empty)
{
return true;
}
else
{
return false;
}
}
If you would like to know if the user is just online, you can get the result just from the boolean HtmlLookUpResult_isSuccess in the code. But, in reality, you most likely want to confirm the user has also access to your server or whatever remote system you use in your project, right? Which is what the remaining of the code does.
In case you wonder what UniversalEnum is, in my code, it's a separate non-Monobehavior script that contains all persistent variables (like strings and hashes) I'm planning on reusing in my project. For short:
UniversalEnum.String_Empty = "";
UniversalEnum.WebHtml_isOnline = "http://www.ENTER_YOUR_WEBSITE_HERE.com/games-latestnews/isOnline.html"
That isOnline.html file is, as you can see, a file in the folder "games-latestnews" in the HTML_content of my hosted website and it contains only [1] as it content. It has no header, no actual content and is pretty much like a .txt file set online. I'm using this method also because I can add new news to my game by just adding new HTML page in that folder. I'm also surrounding the content check with a Try{} so that if ANYTHING fails, it returns the Catch{} value and then by comparing if the content (a string) is an empty string or contain anything, we know if the user is both online and if he/she has access to your website.
On good example of why you would want to check that the user has both access to the net AND to your website is if the user is using a limited network such as what you might find at a school. If a school decided to ban your website due to whatever reason, just looking up if the connection is possible will return a false positive since it wouldn't access the actual webpage anyway.

You can check network connection using this code
if(Application.internetReachability == NetworkReachability.NotReachable){
Debug.Log("Error. Check internet connection!");
}

Related

How to read or control a pin from different thread in C# and Raspberry Pi

I have a C# WebAPI application running on Raspberry Pi that controls a water valve. I want to be able to open the valve for 60 minutes on one thread and check the state on a separate thread. I have separate threads for opening the valve and checking the state which work correctly on their own. The problem I'm having is the thread for checking the state doesn't read the correct value until the original open thread is finished.
How can I read or control a pin from a different thread?
Also, I'm using the System.Device.Gpio library.
This is the code I have.
...
using System.Device.Gpio;
...
[ApiController]
[Route("[controller]")]
public class WaterValveSensorController : ControllerBase
{
private GpioController controller = new GpioController();
[HttpGet("{gpioPin}")]
public WaterValveReading Get(int gpioPin)
{
//This method is intended for adhoc requests to get the status of the watervalve whether the valve is open or closed.
var valveOpen = IsPinOpen(gpioPin);
var waterValveReading = new WaterValveReading(microComputer.HostName, microComputer.IP, gpioPin, valveOpen, DateTimeOffset.Now);
return waterValveReading;
}
[Route("[action]/{gpioPin}/{wateringSeconds}")]
[HttpGet]
public async Task StartWatering(int gpioPin, int wateringSeconds)
{
var maxWateringSeconds = int.Parse(configuration["WaterValveSettings:MaxWateringSeconds"]);
if (OpenValve(gpioPin))
{
await Task.Delay(TimeSpan.FromSeconds((wateringSeconds > maxWateringSeconds) ? maxWateringSeconds : wateringSeconds));
}
}
private bool OpenValve(int gpioPin)
{
if (!IsPinOpen(gpioPin))
{
controller.OpenPin(gpioPin, PinMode.Output);
controller.Write(gpioPin, PinValue.High);
}
return true;
}
private bool IsPinOpen(int gpioPin)
{
return controller.IsPinOpen(gpioPin);
}
}
I think your Get function mixes up a few things. IsPinOpen asks whether the pin has been opened for reading/writing. It does not indicate whether the valve is open or not. Therefore using it to construct the WaterValveReading structure is quite pointless. Additionally, you need to be aware that the GpioController class is not currently thread safe, so opening/closing pins from different threads is dangerous (reading/writing the pin value should be safe, though).
[HttpGet("{gpioPin}")]
public WaterValveReading Get(int gpioPin)
{
//This method is intended for adhoc requests to get the status of the watervalve whether the valve is open or closed.
bool valvePinOpen = IsPinOpen(gpioPin);
WaterValveReading waterValveReading;
if (valvePinOpen)
{
var isValveOpen = controller.Read(gpioPin);
waterValveReading = new WaterValveReading(microComputer.HostName, microComputer.IP, gpioPin, isValveOpen, DateTimeOffset.Now);
}
else
{
waterValveReading = new WaterValveReading(....); // Some error return (pin not open)
}
return waterValveReading;
}
Additionally, I would reconsider whether you want the pin number to be in the web request. Typically, that will be fixed by hardware (the valve is attached to a very specific pin), so that having it in the API would allow the caller to open and write any pin, with possibly undesired side effects. If you know the pin number beforehand, you can open the corresponding pin already in the constructor.

TNonblockingServerTransport not implemented with Thrift C# library

When using Apache Thrift [https://github.com/apache/thrift] to create a non blocking server in C#, the following Classes/Types cannot be recognized:
TNonblockingServerTransport
TNonblockingServer
I want to send command from my win10 laptop to control a time-consuming calculation performed on a high performance server (ubuntu). That's why I came to Apache Thrift. I have found the official C# version tutorial [https://github.com/apache/thrift/tree/master/tutorial/csharp] and it works well. This tutorial uses the so-called Blocking Mode (TSimpleServer). But in my situation, the time-consuming calculation procedure should be interrupt-able. Consequently, I must use a non-blocking server.
The logic is simple. For the server, I used a private flag forceStop. If the Client call Stop(), forceStop will set to true and the calculation loop will break.
// #Server#
// Server Set-Up
private void SetUp()
{
try
{
CalculatorHandler handler = new CalculatorHandler();
Calculator.Processor processor = new
Calculator.Processor(handler);
var serverTransport = new TServerSocket(9090);
TServer server = new TSimpleServer(processor, serverTransport);
// Use this for a multithreaded server
// server = new TThreadPoolServer(processor, serverTransport);
Console.WriteLine("Starting the server...");
server.Serve();
}
catch (Exception x)
{
Console.WriteLine(x.StackTrace);
}
}
private bool forceStop;
public int TimeConsumingOperation(int n1, int n2)
{
Console.WriteLine("add({0},{1})", n1, n2);
for (int i = 0; i < 10; i++)
{
//calculating
Thread.Sleep(500);
if (forceStop)
{
Quit();
}
}
return n1 + n2;
}
public void Stop()
{
forceStop = true;
}
// Client
// Button#1 Click callback
private void Button_Start_Click()
{
client.TimeConsumingOperation(0,0);
}
// Button#2 Click callback
private void Button_Stop_Click()
{
client.Stop();
}
//
I've found some useful examples in java [https://chamibuddhika.wordpress.com/2011/10/02/apache-thrift-quickstart-tutorial/]. I've try my best to convert the java code of non-block server to the corresponding C# code but I found that there seems to be no TNonblockingServerTransport in C#. Anyone could help me with this probelm?
// Java Code
public class NonblockingServer {
private void start() {
try {
TNonblockingServerTransport serverTransport = new TNonblockingServerSocket(7911);
ArithmeticService.Processor processor = new ArithmeticService.Processor(new ArithmeticServiceImpl());
TServer server = new TNonblockingServer(new TNonblockingServer.Args(serverTransport).
processor(processor));
System.out.println("Starting server on port 7911 ...");
server.serve();
} catch (TTransportException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
NonblockingServer srv = new NonblockingServer();
srv.start();
}
}
There's actually two answers to that question.
Possible implementation
Your setup is flawed, to begin with.
// #Server#
// Server Set-Up
private bool forceStop;
public void Stop()
{
forceStop = true;
}
Let's assume, we have two clients, both starting a new calculation. Now one client wants to abort. What happens?
The solution would be to structure it in a way where the calculation is a separate business logic object that is instantiated at TimeConsumingOperation() and made available to the client by some means, typically by returning some sort of ID.
When the client now wants to abort, it calls Stop(calcualtionID). The server side logic now routes that call to the implementation and triggers whatever the abort mechanism might be, with C# is is probably a CancellationToken.
A third call would be needed to query the final results from the server end once the calculation has finished. Note that we still work with a TSimpleServer and the reason it works is because we avoid blocking calls by means of the API design.
Nonblocking server
Yes, there is no implementation yet for C#. Since Thrift is Open Source, that probably simply means that there were nobody running into that use case so far and wanted to spend time on an implementation. That is not to say that such a use case may not exist.
What exists are
Threaded and Threadpool servers
Task.Run(() => { your code })
which may help to solve your use case. Also, when used with ASP.NET there is no need for a nonblocking server since the runtime offers enough support already for multiple connections.
Bottom line
There are certain ways to work around that limitation you experierenced. One additional alternative could be to become a contributor by porting one of the existing (e.g. Java) nonblocking implementation to NetStd (preferred, since C# and NetCore will mature into "deprecated" state with the next release and both be replaced by NetStd eventually)

DNS resolve failing for specific domains. Domains work with nslookup

What I want to happen: Pass the method a domain as a string and have it return true if the domain resolves. False if it does not. The underlying goal is to see if a domain exists.
What happens: Most valid domain strings return true. Some, however, return false despite resolving with nslookup.
I don't understand why certain domains are failing to resolve when they look fine when using command prompt nslookup and nslookup sites. (I've used https://centralops.net/ , http://www.kloth.net/services/nslookup.php , and http://network-tools.com/nslook/)
Method (C#):
//no blank domains
public bool CheckDomain(string sDomain)
{
if (string.IsNullOrWhiteSpace(sDomain)) return false;
for (int i = 1; i <= mQueryRetry; i++)
{
try
{
System.Net.IPAddress dnsCli = System.Net.IPAddress.Parse("8.8.8.8")
DnsClient myClient = new DnsClient(dnsCli);
DnsMessage dnsMessage = myClient.Resolve(ARSoft.Tools.Net.DomainName.Parse(sDomain), RecordType.A);
if ((dnsMessage == null) || ((dnsMessage.ReturnCode != ReturnCode.NoError) && (dnsMessage.ReturnCode != ReturnCode.NxDomain)))
{
throw new Exception("DNS request failed");
}
else
{
foreach (DnsRecordBase dnsRecord in dnsMessage.AnswerRecords)
{
ARecord aRecord = dnsRecord as ARecord;
if (aRecord != null)
{
return true;
}
}
}
}
catch (Exception ex)
{
// Back off and try again after 1 seconds
if (i != mQueryRetry)
{
System.Threading.Thread.Sleep(1000);
}
else
{
System.Diagnostics.Trace.WriteLine(string.Format("Domain: {0} error: {1}", sDomain, ex.Message));
}
}
}
System.Diagnostics.Trace.Flush();
return false;
}
If you plan to test it, I suggest replacing the dnsCli IPAddress with one of these. I've left the IP for the google DNS server in there as an example but I am using my company's DNS server in my production code. I've found that changing the DNS server in no way impacts the method's behavior.
I am using the latest version of Arsoft.Tools.Net (2.2.8) for the DnsClient, DnsMessage, DomainName, DnsRecordBase, and ARecord, classes/objects. We had the same problem with an older version (1.8.1).
Some of the domains that are failing to resolve are:
appraisallinks-amc.com
resurgenstech.com
orpheusvr.com
trovvit.com
Additional info: I've tried some ludicrously long query timeout limits, upwards of 5 minutes, and they made no difference. Therefore, I am certain that this is not a timeout issue.
"you can try and use a different library, the DnsClient (nuget) instead, see dnsclient.michaco.net. The domain names in question seem to work just fine " -
#MichaC
The problem was in fact the Arsoft.Tools.Net library I was using. Switching to DnsClient.Net fixed the problem.

Broadcast receiver listening for connectivity change firing at random intervals

I have a Xamarin.Android application that is supposed to sync my data when the device it is running on connects to a WiFi network. To save data and battery I only let this happen whenever it detects a connections.
The only thing is, the application would randomly run the sync service multiple time throughout the day, despite the WiFi connection remaining constant. Now, I can only imagine that the Android system is sending out the broadcast multiple times to remind applications of the connection state or something like that.
I've used a bit of a quick fix, the static bool FirstTime there, but I'm hoping to find a bit more of an elegant solution. Any suggestions?
This is the code I'm using to do it:
[BroadcastReceiver]
[IntentFilter(new string[] { "android.net.conn.CONNECTIVITY_CHANGE" })]
class ConnectivityReceiver : BroadcastReceiver
{
public static bool FirstTime = true;
public override void OnReceive(Context context, Intent intent)
{
if ( intent.Action != null && intent.Action == "android.net.conn.CONNECTIVITY_CHANGE")
{
ConnectivityManager cm = (ConnectivityManager)context.GetSystemService(Context.ConnectivityService);
NetworkInfo info = cm.ActiveNetworkInfo;
if (FirstTime && info != null)
{
FirstTime = false;
Intent background = new Intent(context, typeof(BackgroundDataSyncService));
context.StartService(background);
}else
{
FirstTime = true;
Intent background = new Intent(context, typeof(BackgroundDataSyncService));
context.StopService(background);
}
}
}
}
You have a plugin called Connectivity that can pulled from nuget.
This plugin is compatible with almost every mobile platform and it can be used only in android it you want.
The plugin does all that code for you and you only have to subscribe to connectivity events like:
CrossConnectivity.Current.ConnectivityChanged += (sender, args) =>
{
page.DisplayAlert("Connectivity Changed", "IsConnected: " + args.IsConnected.ToString(), "OK");
};
The plugin has another nice features please take a look at the documentation.
Check the information in your Intent Bundle. I had the same issue.
Whenever the system changes from WiFi to Cellular, or anything else weird happens in the system, the BroadCastReceiver will send out a message.
At first I thought this was a random event.
I also thought I had to use the ConnectivityManager to get the network information.
If you read the Intent Bundle that comes with the OnReceive(Context context, Intent intent), you'll get all kinds of information.
In my tests, I was working with Visual Studio's emulator. I used the built in tools to switch from WiFi to Cell then kill off the signal, as well as change the signal strength.
I found that the BroadcastReceiver reports at least twice; once for the disconnect, and once for the reconnect.
Here is how I read the Bundle.
Bundle extras = intent.Extras;
if (extras != null)
{
foreach (String key in extras.KeySet())
{
Object value = extras.Get(key);
Log.Info("myApp", "intent.extras " + key + " " + value.ToString());
}
}
You'll also find that one part of the Bundle contains the NetworkInfo too.
object netObj = extras.Get("networkInfo");
NetworkInfo netInf = null;
if (netObj != null)
{
netInf = (NetworkInfo)netObj;
}
With this, you can check the status of different network functions.
Log.Info("myApp", "netInf.IsAvailable: " + netInf.IsAvailable.ToString());
Log.Info("myApp", "netInf.IsConnected: " + netInf.IsConnected.ToString());
I truly hope this helps someone.
I've been chasing this for days.
Use Xamarin.Essentials.Connectivity.ConnectivityChanged event. Subscribe to this event.

Server Sent Events not sent ASP.Net 4

My server-sent events are not sending anymore. This use to work perfectly and now something has changed and it might be that I am running this as an ASP.Net 4 application. I'm using a pretty standard iHTTPRequest Handler with a loop, a little threading timeout, and around I go, writing messages like this:
A Message - Note: the reason for parsing the message the way I do below, is I wasn't sure if there was a max message length, so in order to elminate this as a potential problem I broke it out. Well forget this bit anyways, because I'm testing now with the most basic message "alive" so it never hits this.
public static void WriteClientMessage(this HttpResponse Response, string Message)
{
if (Message.Length > 50)
{
int start = 0;
int length = 50;
while (length > 0)
{
Response.Write("data: {0}\n", Message.Substring(start, length));
start = start + length;
length = Message.Substring(start, (Message.Substring(start).Length >= length) ? length : Message.Substring(start).Length).Length;
}
}
else
{
Response.Write("data: " + Message);
Response.Write("\n");
}
Response.Write("\n");
Response.Flush();
}
An Event
public static void WriteClientEvent(this HttpResponse Response, string EventName)
{
Response.Write("event: {0}\n", EventName.TrimNewLine());
Response.Write("data: \n\n");
Response.Flush();
}
Something else to note and I think this is really important is that eventually the message do come, but they come all at once, as if they are buffered. So I've played with this, both enable and disable buffering. I've even investigated to make sure that my dynamic content isn't being compressed, although I'm not confident I have this right, but pretty sure that it isn't. I will investigate this further if someone says that for sure it is and this is my problem
So what is it? Is this a .Net 4ism?
**UPDATE - Insert Minimal Sample here - **
I've added a sample of the script here: http://live.meetscoresonline.com/test-sse.aspx
This app loops 10 times and then breaks out of the loop. This is the actual SSE service, so you should get the result directly to your browser, at least in chrome, FF tries to download the file, and haven't tested the other browsers. What I expect to see is data: alive to apear in the browser as it happens, instead nothing appears until the script terminates and then all data: alive events appear. I've tested SSE this way before so I know this works (or use to work). Here is this test code. Am I missing something?
UPDATE: I commented out the break to demonstrate a new behavior. If you wait about 20 or 30 loops, the real-time streaming begins and continues as expected. So what is this initial pause?
public class TestSSE : IHttpHandler
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/event-stream";
var itt = 0; ;
while (true)
{
if (!context.Response.IsClientConnected)
break;
/* **** UPDATE: REMOVED THE BREAK. STREAMING BEGINS AFTER ABOUT THE 20TH OR 30TH LOOP ****/
// if (itt++ > 10)
// break;
context.Response.Write("data: alive {0}\n\n", DateTime.Now.ToLongTimeString());
context.Response.Flush();
System.Threading.Thread.Sleep(2000);
}
}
}
Looking at the Network tab in Google Chrome developer tools reveals quite a lot from your http://live.meetscoresonline.com/test-sse.aspx
There are no SSE being generated at all - to see this click on the Others button under Network, this is where you would normally be able to track the SSE data stream
I use the following code in my SSE's with a simple HTTPListener and it works well without the delays you mentioned, and always shows up correctly across browsers when using this polyfill
res.AddHeader("Content-Type", "text/event-stream")
res.AddHeader("Cache-Control", "no-cache")
res.AddHeader("Access-Control-Allow-Origin", "*")
res.KeepAlive = True

Categories

Resources