在Windows Mobile中管理网络状态的最佳方法

时间:2009-04-03 19:24:17

标签: c# windows-mobile compact-framework

我有一个.NET Compact Framework 3.5程序,用作“偶尔连接”的业务线(LOB)应用程序。如果它可以看到在线Web服务,它将使用它进行数据访问,但如果网络连接丢失,它将使用本地缓存。

处理所有连接选项和状态更改的最佳方法是什么?

  • OpenNetCF的ConnectionManager类?
  • Microsoft.WindowsBile.State.SystemState?
  • API调用?

如何理解WiFi,Cradle和GPRS之间的区别并使用最佳方法?

有人对此有任何指导吗?

4 个答案:

答案 0 :(得分:2)

我只是创建一个简单的共享类,我可以这样调用:

If MyConnectionClass.IsConnected then
     'Do connected stuff
Else
     'Do local save
End If

然后我的所有实际业务类/函数都可以使用它来隐藏UI代码中的这种肮脏。

MyConnectionClass的IsConnected属性将具有以下内容:

Public ReadOnly Property IsConnected As Boolean
   Get
    Try

        Dim HostName As String = Dns.GetHostName()
        Dim thisHost As IPHostEntry = Dns.GetHostByName(HostName)
        Dim thisIpAddr As String = thisHost.AddressList(0).ToString

        return (thisIpAddr <> Net.IPAddress.Parse("127.0.0.1").ToString())

    Catch ex As Exception
        Return False
    End Try
   End Get
End Property

还建议您使用后台线程轮询连接状态,然后在状态更改时将事件激活回主应用程序线程。这是详细的文章:

Testing for and responding to network connections in the .NET Compact Framework

修改

现在,对于 GPRS 支持:

如果您使用Web请求或Web服务,框架将为您处理连接。如果你深入研究TCPClient或UDPClient,你需要自己使用Connection manager API来处理它:

public class GPRSConnection
{
    const int S_OK = 0;
    const uint CONNMGR_PARAM_GUIDDESTNET = 0x1;
    const uint CONNMGR_FLAG_PROXY_HTTP = 0x1;
    const uint CONNMGR_PRIORITY_USERINTERACTIVE = 0x08000;
    const uint INFINITE = 0xffffffff;
    const uint CONNMGR_STATUS_CONNECTED = 0x10;
    static Hashtable ht = new Hashtable();

    static GPRSConnection()
    {
        ManualResetEvent mre = new ManualResetEvent(false);
        mre.Handle = ConnMgrApiReadyEvent();
        mre.WaitOne();
        CloseHandle(mre.Handle);
    }

    ~GPRSConnection()
    {
        ReleaseAll();
    }

    public static bool Setup(Uri url)
    {
        return Setup(url.ToString());
    }

    public static bool Setup(string urlStr)
    {
        ConnectionInfo ci = new ConnectionInfo();
        IntPtr phConnection = IntPtr.Zero;
        uint status = 0;

        if (ht[urlStr] != null)
            return true;

        if (ConnMgrMapURL(urlStr, ref ci.guidDestNet, IntPtr.Zero) != S_OK)
            return false;

        ci.cbSize = (uint) Marshal.SizeOf(ci);
        ci.dwParams = CONNMGR_PARAM_GUIDDESTNET;
        ci.dwFlags = CONNMGR_FLAG_PROXY_HTTP;
        ci.dwPriority = CONNMGR_PRIORITY_USERINTERACTIVE;
        ci.bExclusive = 0;
        ci.bDisabled = 0;
        ci.hWnd = IntPtr.Zero;
        ci.uMsg = 0;
        ci.lParam = 0;

        if (ConnMgrEstablishConnectionSync(ref ci, ref phConnection, INFINITE, ref status) != S_OK &&
            status != CONNMGR_STATUS_CONNECTED)
            return false;

        ht[urlStr] = phConnection;
        return true;
    }

    public static bool Release(Uri url)
    {
        return Release(url.ToString());
    }

    public static bool Release(string urlStr)
    {
        return Release(urlStr, true);
    }

    private static bool Release(string urlStr, bool removeNode)
    {
        bool res = true;
        IntPtr ph = IntPtr.Zero;
        if (ht[urlStr] == null)
            return true;
        ph = (IntPtr)ht[urlStr];
        if (ConnMgrReleaseConnection(ph, 1) != S_OK)
            res = false;
        CloseHandle(ph);
        if (removeNode)
            ht.Remove(urlStr);
        return res;
    }

    public static void ReleaseAll()
    {
       foreach(DictionaryEntry de in ht)
       {
           Release((string)de.Key, false);
       }
       ht.Clear();
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct ConnectionInfo
    {
        public uint cbSize;
        public uint dwParams;
        public uint dwFlags;
        public uint dwPriority;
        public int bExclusive;
        public int bDisabled;
        public Guid guidDestNet;
        public IntPtr hWnd;
        public uint uMsg;
        public uint lParam;
        public uint ulMaxCost;
        public uint ulMinRcvBw;
        public uint ulMaxConnLatency;
    }

    [DllImport("cellcore.dll")]
    private static extern int ConnMgrMapURL(string pwszURL, ref Guid pguid, IntPtr pdwIndex);

    [DllImport("cellcore.dll")]
    private static extern int ConnMgrEstablishConnectionSync(ref ConnectionInfo ci, ref IntPtr phConnection, uint dwTimeout, ref uint pdwStatus);

    [DllImport("cellcore.dll")]
    private static extern IntPtr ConnMgrApiReadyEvent();

    [DllImport("cellcore.dll")]
    private static extern int ConnMgrReleaseConnection(IntPtr hConnection, int bCache);

    [DllImport("coredll.dll")]
    private static extern int CloseHandle(IntPtr hObject);
}

要使用它,请执行以下操作:

public void DoTcpConnection()
    {
        string url = "www.msn.com";
        bool res = GPRSConnection.Setup("http://" + url + "/");
        if (res)
        {
            TcpClient tc = new TcpClient(url, 80);
            NetworkStream ns = tc.GetStream();
            byte[] buf = new byte[100];
            ns.Write(buf, 0, 100);
            tc.Client.Shutdown(SocketShutdown.Both);
            ns.Close();
            tc.Close();
            MessageBox.Show("Wrote 100 bytes");
        }
        else
        {
            MessageBox.Show("Connection establishment failed");
        }
    }

这是来自Anthony Wong的博客:

Anthony Wong

请记住,您只需要更低级别的TCP或UDP内容。 HTTPRequests不需要这个。

答案 1 :(得分:1)

在Microsoft.WindowsMo​​bile.Status命名空间中使用SystemState类怎么样?当状态发生变化时,您可以监视系统的当前状态并获取通知。有关一些代码,请参阅此post

SystemState仅与连接状态有关。您可以通过ConnectionManager使用特定连接。我建议你阅读article。如果您使用的是.NET Compact Framework 3.5,则会包含托管API。您也可以使用OpenNetCF ConnectionManager。

答案 2 :(得分:1)

我尝试编写移动应用程序,因此他们甚至不知道有涉及的网络。我在本地保留了足够好的验证数据,然后将事务写入本地队列,该队列在连接时清除;队列读取器包括一个未连接时重试的计时器。队列消息是双向的,因此也可以提供本地刷新。基本消息队列模式。

这允许我以最简单的方式处理网络连接,使用高度可移植的基本套接字打开/关闭/读/写/ ioctl逻辑;并且您的连接不需要持续任何重要的时间。 (我不想想在过去几年中与所有MS架构变化保持同步所需要的东西 - 这仍然没有解决恕我直言。)

答案 3 :(得分:1)

我发现Microsoft.WindowsMo​​bile.State.SystemState报告的网络连接不可靠。这是6.0及更早。我没有进行详尽的测试,但是当它出现时没有连接就被放弃了。