Monotouch:在iPhone上关闭飞行模式后,WebRequest连接失败

时间:2011-01-04 09:31:44

标签: iphone xamarin.ios webrequest

我的monotouch应用程序正在与Web服务进行定期后台同步。它运行完美,可以正确检测飞行模式。当我关闭WiFi时,它会自动开始使用WWAN(GPRS,3G)连接。到目前为止,我非常满意,但是...关闭Airplan模式后,当没有WiFi可用时,我的应用程序无法重新连接。

使用WWAN可用的NetworkReachability对象正确检测并且需要连接。但是第一次尝试超时(90秒后我使用计时器中止运行请求)。当我再次尝试时,一旦调用EndGetRequestStream,我就会收到WebException“错误:ConnectionFailure(无主机路由)”。再次连接的唯一方法是启动另一个应用程序,如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 个答案:

答案 0 :(得分:2)

处理网络事务的MonoTouch高级对象(ftp,smtp,http)使用BSD套接字。 Apple有一种机制,即使3G / EDGE连接“活着”,它实际上也会进入睡眠状态。唤醒这一点的唯一方法是使用CFStream或NSStream资源,没有公开暴露的API来唤醒BSD套接字的GPRS连接。谢天谢地,你可以解决这个问题。 MonoTouch提供了一个API:

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

此api仅接受HTTP / HTTPs uri,并将快速连接到指定的API,以便为所有连接重新唤醒WWAN,此时WWAN将保持活动状态,直到空中计划或超时为止。