用PB編寫WinSock TCP/IP應用程序

 

  PB中的套接字是通過Winsock.pbl庫來提供的,它封裝了套接字編程中用到的數據結構和過程,在功能上類似於VB中的Winsock控件。

  Winsock.pbl中定義了兩種類型的Socket:流式Socket和數據報式Socket。流式Socket需要連接到另一個處於監聽狀態的流式Socket後才能進行通信,是基於連接的,其可靠性高;數據報式Socket無需建立連接,源主機發出的報文在網絡中經過存儲轉發後到達目的主機,效率高但可靠性低。編程時,根據應用環境和需求選擇其中一種,若通信子網相當可靠,可考慮採用數據報式Socket。

217844__b1201t01.jpg圖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事件加入下列代碼:

217844__b1201t02.jpg圖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中

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章