【问题标题】:Best way to manage network state in Windows Mobile在 Windows Mobile 中管理网络状态的最佳方式
【发布时间】:2010-10-17 10:48:50
【问题描述】:

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

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

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

您如何了解 WiFi、Cradle 和 GPRS 之间的区别并使用可用的最佳方法?

有人对此有任何指导吗?

【问题讨论】:

    标签: c# windows-mobile compact-framework


    【解决方案1】:

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

    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,则需要自己使用连接管理器 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 不需要这个。

    【讨论】:

    • 我如何告诉它尝试连接(即,如果 GPRS 可用,则启动 GPRS)?发布的方法(和链接)似乎只解决了连接打开或关闭的 WiFi 问题。
    【解决方案2】:

    如何在 Microsoft.WindowsMo​​bile.Status 命名空间中使用 SystemState 类?您可以监控系统的当前状态并在状态更改时获取通知。有关一些代码,请参阅此post

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

    【讨论】:

    • 我如何使用 SystemState 告诉它尝试连接(即如果 GPRS 可用,则启动它)?
    【解决方案3】:

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

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

    【讨论】:

    • 我非常同意您写的内容,我有一个移动应用程序,当没有 WiFi 时,它会切换到使用 SMS 作为协议。这很容易做到,因为我在 CLSA for CE 中内置了一个基于“消息队列”的 xfer 系统。我希望我仍然可以使用它,但该项目放弃了电话选项 =(
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多