PB中的套接字是通過Winsock.pbl庫來提供的,它封裝了套接字編程中用到的數據結構和過程,在功能上類似於VB中的Winsock控件。
Winsock.pbl中定義了兩種類型的Socket:流式Socket和數據報式Socket。流式Socket需要連接到另一個處於監聽狀態的流式Socket後才能進行通信,是基於連接的,其可靠性高;數據報式Socket無需建立連接,源主機發出的報文在網絡中經過存儲轉發後到達目的主機,效率高但可靠性低。編程時,根據應用環境和需求選擇其中一種,若通信子網相當可靠,可考慮採用數據報式Socket。
圖1
用PB編寫WinSock TCP/IP應用程序的第一步是將Winsock.pbl加到應用程序中,然後聲明如下全局變量:
Winsock ws
Boolean b—tcp—active
//用於檢驗ws是否初始化成功
PowerObject gpo—null//全局空對象
在應用程序的Open事件加入下列代碼:
ws=Create Winsock
//初始化Winsock的一個實例
SetNull(gpo—null)//ws的函數中用到空對象gpo—null
在應用程序的Close事件加入下列代碼:
圖2
Destroy ws//銷燬ws對象
完成以上工作後,就可以着手編程了,下面介紹如何利用Socket進行通信。
1.用數據報式Socket向本機的7號端口發送數據
TCP和UDP協議規定了傳輸層端口的長度爲16比特,因此TCP和UDP軟件可以使用216個不同的端口進行通信。儘管如此,編程時最好不要使用前1024個端口,因爲這個範圍內很多是專用端口,如21爲FTP端口。本例中用到的7號端口很特殊,它回顯接收到的任何數據,常用於端口檢測。下面就向本機的7號端口發送數據報:
DGSock=Create Socketdgram
//創建數據報式Socket對象
ulAddr=ws.inet—addr(″127.0.0.1″)
//將本機IP地址轉換爲32位的ulong類型
buf=Blob(″These data is send through datagram~r ~n″)//要發送的數據
DGSock.sendto(buf,Len(buf),0,ulAddr,7)
//向ulAddr主機的7號端發送數據報
buf=Blob(Space(Len(buf)))
//清空buf緩衝區
DGSock.recv(buf,Len(buf),0)
//接收數據報
MessageBox(′Data Received′,String(buf))
//顯示接收到的數據
DGSock.closesocket()//關閉Socket
Destroy DGSock
從上面的演示可以看出,發送到本機7號端口的數據報立即被反彈回來。
2.用流式Socket 開發網絡聊天程序
網絡聊天程序通常包含兩個部分:服務程序和客戶程序。服務程序一直處於監聽狀態,當聽到客戶程序的呼叫時,就創建一個Socket對它進行響應。下面用流式Socket開發一個兩節點聊天程序:
(1)編寫服務程序
服務程序界面如圖1所示。在主窗口的Open事件中創建流式Socket的一個實例:
sSock=Create SockStream//sSock爲實例變量
在“監聽”按鈕的Clicked事件中加入下列代碼:
ulAddr=ws.inet—addr(″202.140.1.20″)
//將服務器地址轉爲ulong類型
sSock.bind(ulAddr,2000)//將流式Socket綁定到ulAddr地址的2000號端口上
sSock.listen(5)//監聽上述地址和端口,參數爲請求隊列長度,最大值爲5
uiSockType=sSock.accept(ulClientAddr,iClientPort)
//接受客戶請求,參數填入了客戶Socket的地址和端口,返回值爲客戶Socket類型
sAccept=Create Socket
//創建一個Socket響應客戶請求
ulParam=1
sAccept.initsocket(uiSockType)
//與客戶Socket類型相同
sAccept.ioctlsocket(ws.FIONBIO,ulParam)
//異步模式
Timer(0.5)
//啓動定時器,以0.5秒的間隔接收數據
在Timer事件中加入下列代碼來處理到達的數據:
buf=Blob(Space(256))//定義緩衝區大小
sAccept.recv(buf,Len(buf),0)
//接收到達的數據
mle—1.Text=mle—1.Text+Trim(String(buf))
//顯示消息
在“發送”按鈕的Clicked事件中加入下列代碼:
buf=Blob(mle—2.Text+″~r~n″)
//將mle—2中的內容放入發送緩衝區
sAccept.send(buf,Len(buf),0)
//將buf中的內容發給對方
mle—2.Text=″ ″
//清除已發送的內容
在“退出”按鈕的Clicked事件中加入下列代碼:
sAccept closesocket()//關閉Socket
Destroy sAccept
sSock.closesocket()
Destroy sSock//清除Socket
(2)編寫客戶程序
設計如圖2所示的窗口,其Open事件的代碼爲:
sClient=Create SocketStream
//創建流式Socket
ulParam=1
//1表示異步模式(即非阻塞模式)
Timer(0.5)//啓動定時器,以0.5秒的間隔檢查是否有數據到達
sClient.ioctlsocket(ws.FIONBIO, ulParam)
//將sClient設置爲異步模式
在“連接” 按鈕的Clicked事件中加入下列代碼:
ulAddr=ws.inet—addr(″202.140.1.20″)
//服務器地址
If sClient.wsconnect(ulAddr,2000)=-1 Then//連接到服務器的2000號端口
MessageBox(′Socket′,″連接服務器失敗″)
End If
Timer事件和“發送”按鈕的Clicked事件的代碼與服務程序相同,只需將套接字對象sAccept改爲sClient即可。
聲明:缺省情況下創建的流式Socket對象使用同步模式,可根據需要將其轉換成異步模式。在同步模式下,一些Winsock函數調用在完成處理之前不會把控制權還給程序,導致程序無響應。例如,在數據到達之前,recv()調用將一直處於等待狀態。在上面的服務程序中,用於監聽客戶連接的Socket使用了同步模式,響應客戶請求的Socket使用了異步模式,客戶程序中的Socket也使用了異步模式。
運行服務程序,點擊“監聽”進入等待狀態;運行客戶程序,點擊“連接”進行呼叫。建立連接後,就可以聊天了。在mle—2中輸入消息,點擊“發送”就可傳給對方,對方發過來的消息顯示在mle—1中 |