天天看點

讓智能手機和居家電腦互聯互通(WM6 GPRS)

GPRS資費受3G的影響逐漸降低,目前5元包月即可以獲得30M的流量,而cmwap日漸式微大有被cmnet取代之勢(北京GPRS套餐其流量已不區分cmwap和cmnet),而後者可無障礙地和網際網路互聯互通,這種變化更促進了GPRS的進一步應用。

原以為一旦GPRS連接配接建立,手機與接入網際網路的PC通信和PC之間的通信一樣簡單,通過簡單配置後就可以用socket進行互聯,後來深入研究才發現暗礁重重,要想完美實作手機和PC的互聯互通還真得費一番功夫。

試驗平台如下:

1、  智能手機Windows Mobile 6.0;

2、  一台通過ADSL上網的PC(動态公網IP,每次撥接上網後的IP都很随機);

3、  一個個人網站空間;

實作思路如下:

1、  開發一個運作在PC上的網絡服務程式(服務端),功能包括:擷取PC撥号後的動态公網IP,把該IP和端口資訊上傳到有固定域名的個人網站空間(當然這個功能也可以用花生殼之類的工具完成域名到動态IP的綁定);提供特定的功能的網絡服務(如讓家中的電腦執行如下載下傳指定的檔案,打開攝像頭等任務,甚而如果PC連接配接了家庭控制系統,可以遙控家裡的空調、熱水器等家電進行工作)。

2、  開發運作在Windows Mobile 5.0/6.0上的用戶端控制程式,功能包括:可從指定URL獲得PC服務程式上傳的IP和端口資訊;通過獲得的IP、端口和PC上的服務程式進行連接配接并通信,進而得以遠端控制居家的PC。

網絡拓撲圖:

  說明:① PC上傳公網IP和端口号到Web伺服器;

② 手機從Web伺服器擷取PC的IP和端口号;

③ 手機和PC直接通信互聯;

實際效果圖:

說明:① 選擇GPRS接入點(要選擇Internet設定),并接入;

② 探測居家PC的IP和端口(從Web Server擷取);

③ 連接配接居家PC,并進行通信測試;

說明:PC服務程式

相關代碼部分:

1、  GPRS連接配接

本打算讓程式也可以通過cmwap進行連接配接,調試時程式也可以和代理伺服器10.0.0.127:80進行連接配接,但是相關的Http請求總是傳回出錯,檢視了相關文章,估計移動對10.0.0.127代理還是做了一定的限制的,幸好cmnet目前已可取代cmwap,是以我們姑且先用cmnet方式吧,不過如果在cmwap上網友有更好的解決方案,也希望能share一下。

2、  GPRS檔案下載下傳(下載下傳IP和端口資訊)

奇怪的是下列代碼當手機通過Microsoft ActiveSync連接配接時,可以正确擷取,但是建立GPRS連接配接後則代碼執行失敗。

public static string DownLoadFile(string fileURL)

        {

            StreamReader rdr = null;

            FileStream wrtr = null;

            string localFileName = string.Empty;

            try

            {

                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(fileURL);

                req.Method = "GET";

                HttpWebResponse resp = (HttpWebResponse)req.GetResponse();

                long len = resp.ContentLength;

                Stream respStream = resp.GetResponseStream();

                localFileName = @"/Program Files/" + fileURL.Substring(fileURL.LastIndexOf("/") + 1);

                wrtr = new FileStream(localFileName, FileMode.Create);

                byte[] inData = new byte[4096];

                int bytesRead = respStream.Read(inData, 0, inData.Length);

                while (bytesRead > 0)

                {

                    wrtr.Write(inData, 0, bytesRead);

                    bytesRead = respStream.Read(inData, 0, inData.Length);

                }

                //判斷下在是否成功

                System.IO.FileInfo fi = new FileInfo(localFileName);

                if (fi.Length != len) localFileName = string.Empty;

                fi = null;

            }

            catch {}

           finally

                if (rdr != null) rdr.Close();

                if (wrtr != null) wrtr.Close();

            return localFileName;

  }

最後沒有辦法,我隻好自己實作了一個基于HTTP協定下載下傳的程式,相關代碼如下:

public string HttpDownload(string url)

                url = url.ToLower().Replace("http://", "");

                int offset = url.IndexOf("/");

                string Host=url.Substring(0,offset);

                string file = url.Substring(offset);

                IPHostEntry IpHost = Dns.GetHostEntry(Host);

                Socket Sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                IPEndPoint point = new IPEndPoint(IpHost.AddressList[0], 80);

                Sock.Connect(point);

                if (Sock.Connected)

                    string strGet = "GET " + file + " HTTP/1.0/r/n" +

                            "Host:" + Host + "/r/n" +

                            "Accept:*/*/r/n" +

                            "User-Agent:GeneralDownloadApplication/r/n" +

                            "Connection:Keep-Alive/r/n/r/n";

                    Byte[] cmd = Encoding.Default.GetBytes(strGet.ToCharArray());

                    Sock.Send(cmd, cmd.Length, SocketFlags.None);

                    string strInfo = "";

                    for (int i = 0; i < 1000; i++)  //10s

                    {

                        if (Sock.Available > 0)

                        {

                            Byte[] bytes = new Byte[1024];

                            int intSize = Sock.Receive(bytes, 1024, 0);

                            strInfo += Encoding.Default.GetString(bytes, 0, intSize);

                            if (strInfo.IndexOf("HTTP/1.1 200 OK") == 0)

                            {

                                intSize = strInfo.IndexOf("/r/n/r/n");

                                if (intSize > 0)

                                {

                                    return strInfo.Substring(intSize + 4);

                                }

                            }

                        }

                        Thread.Sleep(10);

                    }

            catch { }

            return "";

        }

3、  GPRS通信程式,該部分和正常的Socket通信一般無二,是以相關代碼略。

4、  服務端資訊上傳代碼。

該部分代碼實作比較簡單,直接用WebClient類的UploadString可以上傳到指定FTP伺服器,代碼如下:

public static bool HttpUpLoad(string HostName,string ip,int port)

            WebClient client = new WebClient();

            {  client.UploadString("ftp://yefan:[email protected]/yefanqiu/" + HostName + ".txt", ip + "|" + port.ToString() + "|" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"));

                return true;

            catch(Exception ex)

                YFBase.ShowInfo(ex.Message.ToString(), "HttpUpLoad", YFBase.InfoTypes.LVS_error);

            return false;

      }

5、  服務端通信代碼,和用戶端一樣,普通的Socket通信,代碼略。

以上僅僅是一個簡單的demo和粗略的想法,希望能起到抛磚引玉的作用,讓更多的網友參與其中,做出更炫更實用的GPRS程式。(作者:葉帆 2009年9月6日)