本文介紹如何利用 通過Windows Sockets (Winsock)以及多線程編程進行桌面電腦與Pocket PC(掌上電腦
簡稱
PPC)間的雙向通信
並且通過當今流行平台編程語言Visaul Basic
Net
編寫PC端和PPC端程序實現兩者的信息交換
一
概述
如今移動計算設備越來越普及
而PPC與桌面電腦的數據交換更是其必不可少的功能
筆者根據實際的無線PPC開發認為
PPC程序與桌面程序進行通信
除了可以通過SQL Server CE提供的RDA(遠程數據存取)和Replication(復制)來完成與桌面SQL Server的數據存取外
另外一種比較方便快捷的方法則是通過Socket與桌面電腦完成信息的交換
采用Visaul Basic
Net
進行PPC和桌面電腦的程序編寫
已經完全不同於過去的VB
它的諸多新特性以及依托
Net平台強大的面向對象體系使VB
Net煥然一新
不僅編寫桌面程序更加輕松快捷而且更可快速的
可視化的開發以Pocket PC為平台的智能設備程序
Net框架是一種新的計算平台
可以簡單理解為組件庫或者類庫
類似於MFC和VCL
但是卻比它們更加強大和易用
NET框架具有兩個主要組件
公共語言運行庫和
NET 框架類庫
公共語言運行庫是
NET 框架的基礎
可以將運行庫看作一個在執行時管理代碼的代理
它提供核心服務(如內存管理
線程管理和遠程處理等)
以運行庫為目標的代碼稱為托管代碼
而不以運行庫為目標的代碼稱為非托管代碼
NET 框架類庫是一個與公共語言運行庫緊密集成的可重用的類型集合
該類庫是面向對象的
NET 框架類庫能夠完成一系列常見編程任務
包括諸如字符串管理
數據收集
數據庫連接以及文件訪問等任務
Net框架精簡版是完整
Net框架的子集
它是對完整的
Net框架進行精簡後得到的版本
雖然其規模大大減小
但多數功能仍然保持完整
使用
NET框架精簡版可以針對Pocket PC和其他Windows CE
NET設備進行開發和部署
提高開發人員的工作效率 VB
Net編譯的桌面程序在目標機器上需要
Net框架的支持才能運行
而編譯過的PPC程序需要在目標PPC上裝載
Net框架精簡版後方可運行
二
設計思路
在
Net框架中System
Net
Sockets命名空間為需要嚴密控制網絡訪問的開發提供了 Windows Sockets (Winsock) 接口的托管實現
該命名空間中包含了與Socket相關的類
接口和枚舉
主要包括實現 Berkeley 套接字接口的Socket類
用於 TCP 網絡客戶端偵聽連接的TcpListener類
為 TCP 網絡服務提供客戶端連接的TcpClient類以及提供無連接的發送和接收用戶數據文報 (UDP) 的網絡服務等
該命名空間下的大部分類都受
Net框架精簡版的支持
也就是說實現這些對象的代碼完全可以在裝載有
Net框架精簡版的PPC上運行
可以把PPC當作局域網中的一個終端來與桌面電腦連接
它們之間有多種物理連接方式
通常可以使用USB線纜配合ActiveSync直接與桌面電腦連接
當然
若PPC和桌面電腦同時具備其它的連接方式
比如無線WiFi(無線
x)
藍牙等都可以組成相應的無線局域網絡
在PPC上編寫客戶端程序並實現TcpClient類
用於連接
發送和接收流數據
在桌面電腦上我們設計Socket服務端程序並實現TcpListener類和Socket類
用於偵聽和接受傳入連接的請求
Socket類為網絡通信提供了一套非常豐富的方法和屬性
服務程序可以使用 TcpListener
Listen 方法偵聽連接
Accept 方法處理任何傳入的連接請求
並返回可用於與遠程主機進行數據通信的Socket
如果當前使用的是無連接協議(如UDP)
則根本不需要偵聽連接
實際上TcpClient類和TcpListener類為 Socket通信提供了比Socket類更簡單
對用戶更友好的接口
如果編寫較簡單的應用程序
而且只需同步數據傳輸
則可以考慮使用 TcpClient
TcpListener 和 UdpClient
……
Listener = New TcpListener(System
Net
IPAddress
Parse(
)
)
Listener
Start()
Label
Text =
正在
:
處偵聽
……
三
程序的具體實現
創建PPC客戶端程序
啟動Visual Studio
Net
新建Visaul Basic項目
並選擇
智能設備應用程序
選擇
Pocket PC
平台的
Windows 應用程序
並創建項目
Pocket PC平台是Windows CE 平台的子集
Windows CE系統的應用則更加廣泛
項目創建完後
Visaul Studio
Net會創建一個默認的主窗體Form
在窗體上分別放置兩個Panel控件
四個Label控件
三個TextBox控件和兩個Button控件
PPC客戶端程序界面
設計PPC程序的Form窗體與桌面程序沒有太多差別
只是少了一些PPC上所不支持的屬性
但是屬性的名稱並沒有變化
在PPC上沒有窗口最小化的實際意義
所以主窗體的MinimizeBox屬性必須設置成False
否則
當需要退出程序點擊標題欄最右側的關閉按鈕時
程序並沒有真正退出而是隱藏在後台
程序需要重新激活才能回到前台
或者可以向一個Button添加關閉主窗體的代碼
Private Sub Button
_Click(ByVal sender As System
Object
ByVal e As System
EventArgs) Handles Button
Click
Me
Close()
End Sub
Me 為VB
Net中的關鍵字
可以引用當前在其中執行代碼的類或結構的特定實例
Me 的行為與引用當前實例的對象變量或結構變量類似
此例Me代表主窗體的實例Form
使用TcpClient向TcpListener或Socket 偵聽器連接並交換數據
可以使用下面兩種方法之一連接到偵聽器
(
)創建一個 TcpClient
並調用三個可用的 Connect 方法之一
(
)使用遠程主機的主機名和端口號創建 TcpClient
此構造函數將自動嘗試一個連接
TcpClient的Connect 方法使用指定的主機名和端口號將客戶端連接到 TCP 主機
重載函數原型為
使用指定的遠程網絡終結點將客戶端連接到遠程 TCP 主機
Overloads Public Sub Connect(IPEndPoint)
使用指定的 IP 地址和端口號將客戶端連接到 TCP 主機
Overloads Public Sub Connect(IPAddress
Integer)
將客戶端連接到指定主機上的指定端口
Overloads Public Sub Connect(String
Integer)
我們使用指定的本地主機IP地址和端口號將客戶端連接到TCP主機
在堆棧中創建TcpClient對象的實例
當執行退出當前過程或函數時
堆棧中的資源會自動清除
保證內存空間被正確釋放
連接成功後要發送和接收數據
使用 GetStream 方法來獲取一個NetworkStream
NetworkStream為基礎數據流
調用 NetworkStream 的 Write 和 Read 方法與遠程主機之間發送和接收數據
當發送操作結束後使用 TcpClient的Close 方法斷開連接
關閉對象並釋放與 TcpClient 關聯的所有資源
雙擊
連接
按鈕
編寫連接代碼
代碼片段如下
創建TcpClient對象的實例
Client = New TcpClient
通過計算機名稱和端口號連接到指定的計算機
ClientConnect()
SendData =由PPC傳遞過來的數據 – AuthorRisen
按一定的編碼規則對要傳遞的數據進行編碼 Buffer = EncodingUTFGetBytes(SendData)
向已連接的服務程序發送數據
ClientGetStream()Write(Buffer BufferLength)
DataAvailable 指示NetworkStream 上是否有可用的數據如果可以在流上讀取數據則為 true
否則為 false只要有數據存在就等待傳輸完畢
While Not ClientGetStreamDataAvailable()
ApplicationDoEvents()
End While
接收由服務程序傳遞回客戶端的數據並顯示在對話框上
If ClientGetStreamDataAvailable() Then
ClientGetStream()Read(InBuff InBuffLength)
rtndata = 服務程序已經成功收到指令在 & SystemTextEncodingDefaultGetString(InBuff InBuffLength)
MsgBox(rtndata)
End If
斷開連接關閉對象並釋放與 TcpClient 關聯的所有資源
Client
Close()
正確編譯上述代碼還需要在源文件的頭部加入使用命名空間的引用
才能正確使用命名空間中的所有枚舉
結構
類或模塊等
Imports
Sockets
<
添加需要導入的命名空間
Imports System
Text
<
添加需要導入的命名空間
Public Class Form
……
跟蹤調試PPC程序需要在適當的模擬器下進行
譬如系統默認的PocketPC
模擬器
程序調試無誤後可以連接到實際的PocketPC設備運行
實際部署到PPC設備需要在連接的桌面電腦上安裝Microsoft ActiveSync將程序傳輸到用戶目錄中
創建桌面服務端程序
啟動Visual Studio
Net
新建Visaul Basic項目
並選擇
Windows應用程序
創建項目
項目創建完後Visaul Studio
Net會創建一個默認的主窗體Form
在窗體上分別放置三個Label控件
兩個TextBox控件
一個列表框控件和一個Button控件
創建全局的TcpListener對象的實例來偵聽特定的端口
代碼片段如下
創建在本機IP地址和端口偵聽的TcpListener對象的實例
Listener = New TcpListener(
)
開始偵聽
Listener
Start()
偵聽狀態標志
Listening = True
Label
Text =
正在
處偵聽
……
通過計時器定時檢測偵聽器有無連接請求並啟用多線程來處理接收到的數據
代碼片段如下
聲明創建線程時
使用 ThreadStart 委托作為其唯一參數的構造函數創建 Thread 類的新實例
Dim CurThreadStart As ThreadStart
Dim CurThread As Thread
檢測偵聽器是否有掛起的連接請求
沒有則退出計時器事件
If Not Listener
Pending() Then
Exit Sub
End If
有連接的請求則將計時器暫停
准備進行處理
tmProcessRequest
Enabled = False
創建線程委托
傳遞需要操作的過程的地址
CurThreadStart = New ThreadStart(AddressOf ProcessRequest)
CurThread = New Thread(CurThreadStart)
開始一個線程
CurThread
Start()
重新啟動計時器
tmProcessRequest
Enabled = True
將計時器觸發事件的頻率Interval(以毫秒為單位)適當調節可以改變服務程序響應連接請求的快慢
計時器不斷循環一旦發現有連接的請求就會創建一個線程專門來處理這個連接創建線程時需要傳遞處理連接的過程或函數的地址以被線程調用
服務程序通過已連接的Socket獲取數據
接收到的數據按相應的編碼規則進行解碼並將信息添加到列表框中
……
CurThread = System
Threading
Thread
CurrentThread()
接受掛起的連接請求並返回可用來發送和接收數據的Socket
CurSocket = Listener
AcceptSocket
While Listening
If CurSocket
Available >
Then
接收來自綁定的Socket的數據
Bytes = CurSocket
Receive(Buffer
Buffer
Length
)
將接收到的數據轉化成相應編碼的字符串
ReceivedData= Encoding
UTF
GetString(Buffer)
SyncLock CurThread
lbReceived
Items
Add(ReceivedData)
End SyncLock
……
TCPListener
AcceptSocket接受掛起的連接請求
並且返回用於發送和接收數據的 Socket
此 Socket 繼續用於和新連接上的客戶端通信
SyncLock 語句確保多個線程不會同時執行向列表框添加數據的操作
當線程到達 SyncLock 塊時
將計算表達式並保持此互斥性
直到在表達式返回的對象上有鎖為止
這防止了表達式在多個線程運行期間更改值
從而避免代碼產生意外的結果
向客戶端返回服務端處理後的消息
代碼片段如下
格式化返回消息
這是服務器端處理後的結果並返回到客戶端
BacktoClientData = System
DateTime
Now
向客戶端傳遞服務端程序處理時的時間
Buffer = Encoding
UTF
GetBytes(BacktoClientData
ToCharArray)
通過打開的套接字將結果發送回客戶端應用程序
然後關閉該套接字
CurSocket
Send(Buffer
Buffer
Length
)
CurSocket
Close()
編譯桌面服務端程序運行效果如下圖所示
當服務程序處理完一個連接後就向相應的PPC客戶端返回一條成功信息
如下圖所示
至此
PPC客戶端程序和桌面服務端程序編寫完畢
該系統在安裝WindowsXP SP
的桌面電腦和Dell X
i 的PPC上測試通過
四
結論
本程序簡單介紹了PC與PPC之間Socket通信方法
在實際應用中還有很多細節要做
並且還有可以拓展的地方
該模型為實現PC與PPC間復雜的信息交互
創建復雜的無線信息系統提供了一定技術基礎
From:http://tw.wingwit.com/Article/program/net/201311/11532.html