В следующем примере, который я написал, показано, как
Этот рабочий пример является автономным. Он будет определять простой объект запроса, который использует объект window XMLHttpRequest
для совершения вызовов. Он будет определять простую функцию, чтобы дождаться завершения кучи обещаний.
Контекст. В этом примере запрашивается конечная точка Spotify Web API для поиска объектов playlist
для заданного набора строк запроса:
[
"search?type=playlist&q=%22doom%20metal%22",
"search?type=playlist&q=Adele"
]
Для каждого элемента новый Promise запустит блок - ExecutionBlock
, проанализирует результат, заплатит новый набор обещаний на основе массива результатов, который представляет собой список объектов Spotify user
и выполняет новый HTTP-вызов в ExecutionProfileBlock
асинхронно.
Затем вы можете увидеть вложенную структуру Promise, которая позволяет вам генерировать множественные и полностью асинхронные вложенные HTTP-вызовы и присоединять результаты к каждому подмножеству вызовов через Promise.all
.
NOTE Recent Spotify search
API-интерфейсам потребуется указать токен доступа в заголовках запроса:
-H "Authorization: Bearer {your access token}"
Итак, вы должны запустить следующий пример, вам нужно поместить маркер доступа в заголовки запроса:
var spotifyAccessToken = "YourSpotifyAccessToken";
var console = {
log: function(s) {
document.getElementById("console").innerHTML += s + "
"
}
}
// Simple XMLHttpRequest
// based on https://davidwalsh.name/xmlhttprequest
SimpleRequest = {
call: function(what, response) {
var request;
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
request = new XMLHttpRequest();
} else if (window.ActiveXObject) { // Internet Explorer
try {
request = new ActiveXObject('Msxml2.XMLHTTP');
}
catch (e) {
try {
request = new ActiveXObject('Microsoft.XMLHTTP');
} catch (e) {}
}
}
// State changes
request.onreadystatechange = function() {
if (request.readyState === 4) { // Done
if (request.status === 200) { // Complete
response(request.responseText)
}
else
response();
}
}
request.open('GET', what, true);
request.setRequestHeader("Authorization", "Bearer " + spotifyAccessToken);
request.send(null);
}
}
//PromiseAll
var promiseAll = function(items, block, done, fail) {
var self = this;
var promises = [],
index = 0;
items.forEach(function(item) {
promises.push(function(item, i) {
return new Promise(function(resolve, reject) {
if (block) {
block.apply(this, [item, index, resolve, reject]);
}
});
}(item, ++index))
});
Promise.all(promises).then(function AcceptHandler(results) {
if (done) done(results);
}, function ErrorHandler(error) {
if (fail) fail(error);
});
}; //promiseAll
// LP: deferred execution block
var ExecutionBlock = function(item, index, resolve, reject) {
var url = "https://api.spotify.com/v1/"
url += item;
console.log( url )
SimpleRequest.call(url, function(result) {
if (result) {
var profileUrls = JSON.parse(result).playlists.items.map(function(item, index) {
return item.owner.href;
})
resolve(profileUrls);
}
else {
reject(new Error("call error"));
}
})
}
arr = [
"search?type=playlist&q=%22doom%20metal%22",
"search?type=playlist&q=Adele"
]
promiseAll(arr, function(item, index, resolve, reject) {
console.log("Making request [" + index + "]")
ExecutionBlock(item, index, resolve, reject);
}, function(results) { // Aggregated results
console.log("All profiles received " + results.length);
//console.log(JSON.stringify(results[0], null, 2));
///// promiseall again
var ExecutionProfileBlock = function(item, index, resolve, reject) {
SimpleRequest.call(item, function(result) {
if (result) {
var obj = JSON.parse(result);
resolve({
name: obj.display_name,
followers: obj.followers.total,
url: obj.href
});
} //result
})
} //ExecutionProfileBlock
promiseAll(results[0], function(item, index, resolve, reject) {
//console.log("Making request [" + index + "] " + item)
ExecutionProfileBlock(item, index, resolve, reject);
}, function(results) { // aggregated results
console.log("All response received " + results.length);
console.log(JSON.stringify(results, null, 2));
}
, function(error) { // Error
console.log(error);
})
/////
},
function(error) { // Error
console.log(error);
});
Я подробно рассмотрел это решение здесь .
Что-то вроде этого должно работать.
public static bool CheckForInternetConnection()
{
try
{
using (var client = new WebClient())
using (client.OpenRead("http://clients3.google.com/generate_204"))
{
return true;
}
}
catch
{
return false;
}
}
Вот , как это реализовано в Android.
В качестве доказательства концепции я перевел этот код на C #:
var request = (HttpWebRequest)WebRequest.Create("http://g.cn/generate_204");
request.UserAgent = "Android";
request.KeepAlive = false;
request.Timeout = 1500;
using (var response = (HttpWebResponse)request.GetResponse())
{
if (response.ContentLength == 0 && response.StatusCode == HttpStatusCode.NoContent)
{
//Connection to internet available
}
else
{
//Connection to internet not available
}
}
У меня три теста для подключения к Интернету.
System.Net
и System.Net.Sockets
Тест 1
public bool IsOnlineTest1()
{
try
{
IPHostEntry dummy = Dns.GetHostEntry("https://www.google.com");
return true;
}
catch (SocketException ex)
{
return false;
}
}
Тест 2
public bool IsOnlineTest2()
{
try
{
IPHostEntry dummy = Dns.GetHostEntry("https://www.google.com");
return true;
}
catch (SocketException ex)
{
return false;
}
}
Тест 3
public bool IsOnlineTest3()
{
System.Net.WebRequest req = System.Net.WebRequest.Create("https://www.google.com");
System.Net.WebResponse resp = default(System.Net.WebResponse);
try
{
resp = req.GetResponse();
resp.Close();
req = null;
return true;
}
catch (Exception ex)
{
req = null;
return false;
}
}
Выполнение тестов
Если вы сделаете Dictionary
из String
и Boolean
с именем CheckList
, вы можете добавить результаты каждого теста к CheckList
.
Теперь, рекурсия через каждый KeyValuePair
с помощью for...each
.
Если CheckList
содержит Value
в true
, то вы знаете, что есть подключение к Интернету.
Тест для подключения к Интернету путем проверки Google:
new Ping().Send("www.google.com.mx").Status == IPStatus.Success
Вместо проверки просто выполните действие (веб-запрос, почту, ftp и т. д.) и будьте готовы к сбою запроса, что вам нужно сделать в любом случае, даже если ваш чек был успешным.
Рассмотрим следующее:
1 - check, and it is OK
2 - start to perform action
3 - network goes down
4 - action fails
5 - lot of good your check did
Если сеть не работает, ваше действие завершится так же быстро, как пинг и т. д.
1 - start to perform action
2 - if the net is down(or goes down) the action will fail
У меня проблема с этим методом на моем маршрутизаторе / модеме 3g, потому что если интернет отключен, маршрутизатор перенаправляет страницу на свою страницу ответа, так что вы все равно получаете пар, а ваш код считает, что есть интернет. Яблоки (или другие) имеют страницу с горячей точкой, которая всегда возвращает определенный ответ. Следующий образец возвращает ответ «Успех». Таким образом, вы точно убедитесь, что сможете подключиться к Интернету и получить реальный ответ!
public static bool CheckForInternetConnection()
{
try
{
using (var webClient = new WebClient())
using (var stream = webClient.OpenRead("http://captive.apple.com/hotspot-detect.html"))
{
if (stream != null)
{
//return true;
stream.ReadTimeout = 1000;
using (var reader = new StreamReader(stream, Encoding.UTF8, false))
{
string line;
while ((line = reader.ReadLine()) != null)
{
if (line == "<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>")
{
return true;
}
Console.WriteLine(line);
}
}
}
return false;
}
}
catch
{
}
return false;
}
Я видел все варианты, перечисленные выше, и единственная жизнеспособная опция проверки увядания интернета доступна или нет, это опция «Пинг». Импорт [DllImport("Wininet.dll")]
и System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()
или любой другой вариант класса NetworkInterface
не работает хорошо при обнаружении доступности сети. Эти методы проверяют только подключение сетевого кабеля. / G0]
Параметр «Ping»
if
(соединение доступно) возвращает true
if
(подключение недоступно и сетевой кабель подключен) возвращает false
if
(сетевой кабель не подключен) Throws an exception
NetworkInterface
if
(доступен Интернет) Возвращает True
if
(Интернет недоступен, а сетевой кабель подключен) Возвраты True
if
(сетевой кабель не подключен) возвращает false
[DllImport («Wininet.dll»)]
if
(доступен Интернет) Возвращает True
if
(Интернет не Доступен и подключен сетевой кабель) Возврат True
if
(сетевой кабель не подключен) возвращает false
Поэтому в случае [DllImport("Wininet.dll")]
и NetworkInterface
Нет никакого способа узнать, доступно ли подключение к Интернету ле.
Pinging google.com вводит зависимость разрешения DNS. Pinging 8.8.8.8 в порядке, но Google в нескольких прыжках от меня. Все, что мне нужно сделать, - это рассказать о ближайшей вещи, которая есть в Интернете.
Я могу использовать функцию TTL Ping для ping hop # 1, then hop # 2 и т. д., пока не получаю ответ от чего-то, что находится на маршрутизируемом адресе; если этот узел находится на маршрутизируемом адресе, то он находится в Интернете. Для большинства из нас, хоп # 1 будет нашим локальным шлюзом / маршрутизатором, а hop # 2 будет первым пунктом на другой стороне нашего оптоволоконного соединения или что-то еще.
Этот код работает для меня и быстрее реагирует на некоторые другие предложения в этом потоке, потому что он пингует все, что ближе ко мне в Интернете.
using System.Net;
using System.Net.Sockets;
using System.Net.NetworkInformation;
using System.Diagnostics;
internal static bool ConnectedToInternet()
{
const int maxHops = 30;
const string someFarAwayIpAddress = "8.8.8.8";
// Keep pinging further along the line from here to google
// until we find a response that is from a routable address
for (int ttl = 1; ttl <= maxHops; ttl++)
{
Ping pinger = new Ping();
PingOptions options = new PingOptions(ttl, true);
byte[] buffer = new byte[32];
PingReply reply = null;
try
{
reply = pinger.Send(someFarAwayIpAddress, 10000, buffer, options);
}
catch (System.Net.NetworkInformation.PingException pingex)
{
Debug.Print("Ping exception (probably due to no network connection or recent change in network conditions), hence not connected to internet. Message: " + pingex.Message);
return false;
}
System.Diagnostics.Debug.Print("Hop #" + ttl.ToString() + " is " + (reply.Address == null ? "null" : reply.Address.ToString()) + ", " + reply.Status.ToString());
if (reply.Status != IPStatus.TtlExpired && reply.Status != IPStatus.Success)
{
Debug.Print("Hop #" + ttl.ToString() + " is " + reply.Status.ToString() + ", hence we are not connected.");
return false;
}
if (IsRoutableAddress(reply.Address))
{
System.Diagnostics.Debug.Print("That's routable so you must be connected to the internet.");
return true;
}
}
return false;
}
private static bool IsRoutableAddress(IPAddress addr)
{
if (addr == null)
{
return false;
}
else if (addr.AddressFamily == AddressFamily.InterNetworkV6)
{
return !addr.IsIPv6LinkLocal && !addr.IsIPv6SiteLocal;
}
else // IPv4
{
byte[] bytes = addr.GetAddressBytes();
if (bytes[0] == 10)
{ // Class A network
return false;
}
else if (bytes[0] == 172 && bytes[1] >= 16 && bytes[1] <= 31)
{ // Class B network
return false;
}
else if (bytes[0] == 192 && bytes[1] == 168)
{ // Class C network
return false;
}
else
{ // None of the above, so must be routable
return true;
}
}
}
Вы абсолютно не можете надежно проверить, есть ли подключение к Интернету или нет (я предполагаю, что вы имеете в виду доступ в Интернет).
Вы можете, однако, запросить ресурсы, которые практически никогда не работают в автономном режиме , например, pinging google.com или что-то подобное. Я думаю, что это будет эффективно.
try {
Ping myPing = new Ping();
String host = "google.com";
byte[] buffer = new byte[32];
int timeout = 1000;
PingOptions pingOptions = new PingOptions();
PingReply reply = myPing.Send(host, timeout, buffer, pingOptions);
return (reply.Status == IPStatus.Success);
}
catch (Exception) {
return false;
}
Многопоточная версия ping:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.NetworkInformation;
using System.Threading;
namespace OnlineCheck
{
class Program
{
static bool isOnline = false;
static void Main(string[] args)
{
List<string> ipList = new List<string> {
"1.1.1.1", // Bad ip
"2.2.2.2",
"4.2.2.2",
"8.8.8.8",
"9.9.9.9",
"208.67.222.222",
"139.130.4.5"
};
int timeOut = 1000 * 5; // Seconds
List<Thread> threadList = new List<Thread>();
foreach (string ip in ipList)
{
Thread threadTest = new Thread(() => IsOnline(ip));
threadList.Add(threadTest);
threadTest.Start();
}
Stopwatch stopwatch = Stopwatch.StartNew();
while (!isOnline && stopwatch.ElapsedMilliseconds <= timeOut)
{
Thread.Sleep(10); // Cooldown the CPU
}
foreach (Thread thread in threadList)
{
thread.Abort(); // We love threads, don't we?
}
Console.WriteLine("Am I online: " + isOnline.ToYesNo());
Console.ReadKey();
}
static bool Ping(string host, int timeout = 3000, int buffer = 32)
{
bool result = false;
try
{
Ping ping = new Ping();
byte[] byteBuffer = new byte[buffer];
PingOptions options = new PingOptions();
PingReply reply = ping.Send(host, timeout, byteBuffer, options);
result = (reply.Status == IPStatus.Success);
}
catch (Exception ex)
{
}
return result;
}
static void IsOnline(string host)
{
isOnline = Ping(host) || isOnline;
}
}
public static class BooleanExtensions
{
public static string ToYesNo(this bool value)
{
return value ? "Yes" : "No";
}
}
}
Я не согласен с людьми, которые заявляют: «В чем смысл проверки подключения перед выполнением задачи, так как сразу после проверки соединение может быть потеряно». Конечно, существует определенная неопределенность во многих задачах программирования, которые мы, как разработчики, предпринимаем, но уменьшение неопределенности до уровня принятия является частью задачи.
Недавно я столкнулся с этой проблемой, создав приложение, которое включает в себя который связан с сервером онлайн-плитки. Эта функция была отключена, когда было отмечено отсутствие подключения к Интернету.
Некоторые ответы на этой странице были очень хорошими, но, тем не менее, вызывали множество проблем с производительностью, таких как зависание, главным образом в случае отсутствия связи.
Вот решение, которое я в конечном итоге использовал с помощью некоторых из этих ответов и моих коллег:
// Insert this where check is required, in my case program start
ThreadPool.QueueUserWorkItem(CheckInternetConnectivity);
}
void CheckInternetConnectivity(object state)
{
if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
{
using (WebClient webClient = new WebClient())
{
webClient.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.BypassCache);
webClient.Proxy = null;
webClient.OpenReadCompleted += webClient_OpenReadCompleted;
webClient.OpenReadAsync(new Uri("<url of choice here>"));
}
}
}
volatile bool internetAvailable = false; // boolean used elsewhere in code
void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error == null)
{
internetAvailable = true;
Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
{
// UI changes made here
}));
}
}
public static bool HasConnection()
{
try
{
System.Net.IPHostEntry i = System.Net.Dns.GetHostEntry("www.google.com");
return true;
}
catch
{
return false;
}
}
Это работает
Для моего приложения мы также проверяем загрузку миниатюрного файла.
string remoteUri = "https://www.microsoft.com/favicon.ico"
WebClient myWebClient = new WebClient();
try
{
byte[] myDataBuffer = myWebClient.DownloadData (remoteUri);
if(myDataBuffer.length > 0) // Or add more validate. eg. checksum
{
return true;
}
}
catch
{
return false;
}
Также. Некоторые интернет-провайдеры могут использовать средний сервер для кэширования файла. Добавьте случайный неиспользуемый параметр, например. https://www.microsoft.com/favicon.ico?req=random_number Может предотвратить кеширование.
Не решает проблему смены сети между проверкой и запуском вашего кода, но довольно надежна
public static bool IsAvailableNetworkActive()
{
// only recognizes changes related to Internet adapters
if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
{
// however, this will include all adapters -- filter by opstatus and activity
NetworkInterface[] interfaces = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();
return (from face in interfaces
where face.OperationalStatus == OperationalStatus.Up
where (face.NetworkInterfaceType != NetworkInterfaceType.Tunnel) && (face.NetworkInterfaceType != NetworkInterfaceType.Loopback)
select face.GetIPv4Statistics()).Any(statistics => (statistics.BytesReceived > 0) && (statistics.BytesSent > 0));
}
return false;
}