Monotouch: сбой подключения через WebRequest после отключения режима полета на iPhone - PullRequest
3 голосов
/ 04 января 2011

Мое приложение monotouch периодически выполняет фоновую синхронизацию с веб-сервисом. Он отлично работает и правильно определяет режим полета. Когда я отключаю Wi-Fi, он автоматически запускается через соединение WWAN (GPRS, 3G). Пока что я очень доволен, но ... После отключения режима «В самолете» мое приложение не сможет восстановить соединение, когда WiFi недоступен.

Он правильно определяет с помощью объекта NetworkReachability, что WWAN доступен и требуется соединение. Но время первой попытки истекло (через 90 секунд я отменяю запущенный запрос, используя таймер). При повторной попытке я получаю WebException «Ошибка: ConnectionFailure (нет маршрута к хосту)», как только я вызываю EndGetRequestStream. Единственный способ подключиться снова - запустить другое приложение, такое как Mail, которое устанавливает соединение. После этого мое приложение снова без проблем подключается. Или подождать несколько минут, пока iPhone не заснет. После пробуждения соединение снова устанавливается нормально.

Что я делаю не так?

Приведенный ниже код запускается с использованием ThreadPool.QueueUserWorkItem (CreateRequest);

    /// <summary>
    /// Sync step 1: Create the request and start asynchronously sending the data.
    /// </summary>
    private void CreateRequest(object state)
    {
        try
        {
            Console.WriteLine("Phase 1 started...");
            if (!IsNetworkAvailable())
            {
                Ready(SyncState.NoConnection);
                return;
            }
            UIApplication.SharedApplication.NetworkActivityIndicatorVisible = true;
            _request = (HttpWebRequest)WebRequest.Create(SyncUrl);
            _request.Method = HttpMethodPost;
            _request.ContentType = HttpContentTypeJson;
            Console.WriteLine("Phase 2 is starting...");
            _request.BeginGetRequestStream(new AsyncCallback(StartRequest), null);
        }
        catch (WebException e)
        {
            Console.WriteLine("WebException: " + e.Message + "\r\nStatus: " + e.Status);
            Ready(SyncState.ConnectionError);
        }
    }

    /// <summary>
    /// Sync step 2: Read syncdata from database and send to server.
    /// Start getting the response asynchronously.
    /// </summary>
    private void StartRequest(IAsyncResult asyncResult)
    {
        Console.WriteLine("Phase 2 started...");
        try
        {
            using (var stream = _request.EndGetRequestStream(asyncResult))
            {
                using (var textStream = new StreamWriter(stream))
                {
                    Database.Instance.CreateSyncData().Save(textStream);
                }
            }
            Console.WriteLine("Phase 3 is starting...");
            _request.BeginGetResponse(new AsyncCallback(ProcessResponse), null);
        }
        catch (WebException e)
        {
            Console.WriteLine("WebException: " + e.Message + "\r\nStatus: " + e.Status);
            Ready(SyncState.ConnectionError);
        }
    }

    /// <summary>
    /// Sync step 3: Get the response and process.
    /// </summary>
    private void ProcessResponse(IAsyncResult asyncResult)
    {
        Console.WriteLine("Phase 3 started...");
        try
        {
            using (HttpWebResponse response = (HttpWebResponse)_request.EndGetResponse(asyncResult))
            {
                using (var textStream = new StreamReader(response.GetResponseStream()))
                {
                    var data = (JsonObject)JsonObject.Load(textStream);
                    Database.Instance.ProcessSyncReply(data);
                    Console.WriteLine("Success: " + data.ToString());
                    LastSyncTime = DateTime.Now;
                    Ready(SyncState.Synchronized);
                }
            }
        }
        catch (WebException e)
        {
            Console.WriteLine("WebException: " + e.Message + "\r\nStatus: " + e.Status);
            Ready(SyncState.ConnectionError);
        }
    }

    private bool IsNetworkAvailable(out bool connectionRequired, out bool onlyWWAN)
    {
        bool flagsAvailable;
        NetworkReachabilityFlags networkReachabilityFlags = (NetworkReachabilityFlags)0;
        using (var networkReachability = new NetworkReachability(HostName))
        {
            flagsAvailable = networkReachability.TryGetFlags(out networkReachabilityFlags);
        }
        connectionRequired = 0 != (networkReachabilityFlags & NetworkReachabilityFlags.ConnectionRequired);
        onlyWWAN = 0 != (networkReachabilityFlags & NetworkReachabilityFlags.IsWWAN);
        return flagsAvailable && 0 != (networkReachabilityFlags & NetworkReachabilityFlags.Reachable);
    }

    private bool IsNetworkAvailable()
    {
        bool connectionRequired;
        bool onlyWWAN;
        bool available = IsNetworkAvailable(out connectionRequired, out onlyWWAN);
        string status = "Network status: ";
        if (!available)
            status += "Not available";
        else
        {
            status += "Available; ";
            if (onlyWWAN)
                status += "Mobile; ";
            if (connectionRequired)
                status += "Connection required";
        }
        Console.WriteLine(status);
        return available;
    }

1 Ответ

2 голосов
/ 04 января 2011

Объекты высокого уровня MonoTouch (ftp, smtp, http), которые обрабатывают сетевые транзакции, используют сокеты BSD.У Apple есть механизм, при котором даже если соединение 3G / EDGE «живое», его фактически переводят в спящий режим.Единственный способ пробудить это - использовать ресурсы CFStream или NSStream. Не существует публично представленного API для пробуждения соединения GPRS для сокета BSD.К счастью, вы можете обойти эту проблему.MonoTouch предоставил API:

MonoTouch.ObjCRuntime.Runtime.StartWWAN (Uri uri);

Этот API-интерфейс принимает только HTTP / HTTP-адреса URI и устанавливает быстрое соединение с указанным API для повторного пробуждения WWAN для всех соединений, после чего WWAN останетсяживы, пока не сядут в самолет или снова не истечут.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...