问题描述
我的monotouch应用程序正在与Web服务进行定期后台同步。它运行完美,可以正确检测飞行模式。当我关闭WiFi时,它会自动开始使用WWAN(GPRS,3G)连接。到目前为止,我非常满意,但是...关闭Airplan模式后,当没有WiFi可用时,我的应用程序无法重新连接。
My monotouch app is doing periodic background synchronization with a web-service. It runs perfectly and detects Airplane mode correctly. When I switch off WiFi, it automatically starts using the WWAN (GPRS, 3G) connection. So far I'm very satisfied, but... After switching off Airplan Mode there is no way my app will reconnect when there is no WiFi available.
它正确检测到使用WWAN可用的NetworkReachability对象并且需要连接。但是第一次尝试超时(90秒后我使用计时器中止运行请求)。当我再次尝试时,一旦调用EndGetRequestStream,我就会收到WebException错误:ConnectionFailure(没有到主机的路由)。再次连接的唯一方法是启动另一个应用程序,如Mail,它建立连接。之后,我的应用程序再次完美连接。或等待几分钟,直到iPhone进入睡眠状态。醒来后,连接再次设置好。
It detects correctly using a NetworkReachability object that WWAN is available and that a connection is required. But the first try times out (after 90 seconds I abort the running request using a timer). When I try again I get a WebException "Error: ConnectionFailure (No route to host)" as soon as I call EndGetRequestStream. The only way to connect again is to start another app, like Mail, which makes a connection. After that my app connects flawlessly again. Or to wait a few minutes until the iPhone goes to sleep. After a wake up, the connection is set up ok again.
我做错了什么?
下面的代码是使用ThreadPool.QueueUserWorkItem(CreateRequest)启动的;
The code below is started using 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;
}
推荐答案
MonoTouch高级对象(ftp ,smtp,http)处理网络事务利用BSD套接字。 Apple有一种机制,即使3G / EDGE连接活着,它实际上也会进入睡眠状态。唤醒这一点的唯一方法是使用CFStream或NSStream资源,没有公开的API来唤醒BSD套接字的GPRS连接。谢天谢地,你可以解决这个问题。 MonoTouch提供了一个API:
MonoTouch high level objects (ftp, smtp, http) that process network transactions utilize BSD sockets. Apple has a mechanism where even if the 3G/EDGE connection is "alive" its actually put to sleep. The only way to wake this up is to use CFStream or NSStream resources, there is no publically exposed API to wake up a GPRS connection for a BSD socket. Thankfully you can work around this issue. MonoTouch has provided an API:
MonoTouch.ObjCRuntime.Runtime.StartWWAN (Uri uri);
此api仅接受HTTP / HTTPs uri,并将快速连接到指定的API以重新连接唤醒所有连接的WWAN,此时WWAN将保持活力直到空中飞行或再次超时。
This api only accepts HTTP/HTTPs uri's and will make a quick connection to the specified API to re-awaken the WWAN for all connections, at which point the WWAN will stay alive until airplaned or timed out again.
这篇关于Monotouch:在iPhone上关闭飞行模式后,WebRequest连接失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!