用PB編寫WinSock TCP/IP應(yīng)用程序
2024-07-21 02:10:22
供稿:網(wǎng)友
pb中的套接字是通過winsock.pbl庫來提供的,它封裝了套接字編程中用到的數(shù)據(jù)結(jié)構(gòu)和過程,在功能上類似于vb中的winsock控件。
winsock.pbl中定義了兩種類型的socket:流式socket和數(shù)據(jù)報(bào)式socket。流式socket需要連接到另一個(gè)處于監(jiān)聽狀態(tài)的流式socket后才能進(jìn)行通信,是基于連接的,其可靠性高;數(shù)據(jù)報(bào)式socket無需建立連接,源主機(jī)發(fā)出的報(bào)文在網(wǎng)絡(luò)中經(jīng)過存儲(chǔ)轉(zhuǎn)發(fā)后到達(dá)目的主機(jī),效率高但可靠性低。編程時(shí),根據(jù)應(yīng)用環(huán)境和需求選擇其中一種,若通信子網(wǎng)相當(dāng)可靠,可考慮采用數(shù)據(jù)報(bào)式socket。
圖1
用pb編寫winsock tcp/ip應(yīng)用程序的第一步是將winsock.pbl加到應(yīng)用程序中,然后聲明如下全局變量:
winsock ws
boolean b—tcp—active
//用于檢驗(yàn)ws是否初始化成功
powerobject gpo—null//全局空對(duì)象
在應(yīng)用程序的open事件加入下列代碼:
ws=create winsock
//初始化winsock的一個(gè)實(shí)例
setnull(gpo—null)//ws的函數(shù)中用到空對(duì)象gpo—null
在應(yīng)用程序的close事件加入下列代碼:
圖2
destroy ws//銷毀ws對(duì)象
完成以上工作后,就可以著手編程了,下面介紹如何利用socket進(jìn)行通信。
1.用數(shù)據(jù)報(bào)式socket向本機(jī)的7號(hào)端口發(fā)送數(shù)據(jù)
tcp和udp協(xié)議規(guī)定了傳輸層端口的長(zhǎng)度為16比特,因此tcp和udp軟件可以使用216個(gè)不同的端口進(jìn)行通信。盡管如此,編程時(shí)最好不要使用前1024個(gè)端口,因?yàn)檫@個(gè)范圍內(nèi)很多是專用端口,如21為ftp端口。本例中用到的7號(hào)端口很特殊,它回顯接收到的任何數(shù)據(jù),常用于端口檢測(cè)。下面就向本機(jī)的7號(hào)端口發(fā)送數(shù)據(jù)報(bào):
dgsock=create socketdgram
//創(chuàng)建數(shù)據(jù)報(bào)式socket對(duì)象
uladdr=ws.inet—addr(″127.0.0.1″)
//將本機(jī)ip地址轉(zhuǎn)換為32位的ulong類型
buf=blob(″these data is send through datagram~r ~n″)//要發(fā)送的數(shù)據(jù)
dgsock.sendto(buf,len(buf),0,uladdr,7)
//向uladdr主機(jī)的7號(hào)端發(fā)送數(shù)據(jù)報(bào)
buf=blob(space(len(buf)))
//清空buf緩沖區(qū)
dgsock.recv(buf,len(buf),0)
//接收數(shù)據(jù)報(bào)
messagebox(′data received′,string(buf))
//顯示接收到的數(shù)據(jù)
dgsock.closesocket()//關(guān)閉socket
destroy dgsock
從上面的演示可以看出,發(fā)送到本機(jī)7號(hào)端口的數(shù)據(jù)報(bào)立即被反彈回來。
2.用流式socket 開發(fā)網(wǎng)絡(luò)聊天程序
網(wǎng)絡(luò)聊天程序通常包含兩個(gè)部分:服務(wù)程序和客戶程序。服務(wù)程序一直處于監(jiān)聽狀態(tài),當(dāng)聽到客戶程序的呼叫時(shí),就創(chuàng)建一個(gè)socket對(duì)它進(jìn)行響應(yīng)。下面用流式socket開發(fā)一個(gè)兩節(jié)點(diǎn)聊天程序:
(1)編寫服務(wù)程序
服務(wù)程序界面如圖1所示。在主窗口的open事件中創(chuàng)建流式socket的一個(gè)實(shí)例:
ssock=create sockstream//ssock為實(shí)例變量
在“監(jiān)聽”按鈕的clicked事件中加入下列代碼:
uladdr=ws.inet—addr(″202.140.1.20″)
//將服務(wù)器地址轉(zhuǎn)為ulong類型
ssock.bind(uladdr,2000)//將流式socket綁定到uladdr地址的2000號(hào)端口上
ssock.listen(5)//監(jiān)聽上述地址和端口,參數(shù)為請(qǐng)求隊(duì)列長(zhǎng)度,最大值為5
uisocktype=ssock.accept(ulclientaddr,iclientport)
//接受客戶請(qǐng)求,參數(shù)填入了客戶socket的地址和端口,返回值為客戶socket類型
saccept=create socket
//創(chuàng)建一個(gè)socket響應(yīng)客戶請(qǐng)求
ulparam=1
saccept.initsocket(uisocktype)
//與客戶socket類型相同
saccept.ioctlsocket(ws.fionbio,ulparam)
//異步模式
timer(0.5)
//啟動(dòng)定時(shí)器,以0.5秒的間隔接收數(shù)據(jù)
在timer事件中加入下列代碼來處理到達(dá)的數(shù)據(jù):
buf=blob(space(256))//定義緩沖區(qū)大小
saccept.recv(buf,len(buf),0)
//接收到達(dá)的數(shù)據(jù)
mle—1.text=mle—1.text+trim(string(buf))
//顯示消息
在“發(fā)送”按鈕的clicked事件中加入下列代碼:
buf=blob(mle—2.text+″~r~n″)
//將mle—2中的內(nèi)容放入發(fā)送緩沖區(qū)
saccept.send(buf,len(buf),0)
//將buf中的內(nèi)容發(fā)給對(duì)方
mle—2.text=″ ″
//清除已發(fā)送的內(nèi)容
在“退出”按鈕的clicked事件中加入下列代碼:
saccept closesocket()//關(guān)閉socket
destroy saccept
ssock.closesocket()
destroy ssock//清除socket
(2)編寫客戶程序
設(shè)計(jì)如圖2所示的窗口,其open事件的代碼為:
sclient=create socketstream
//創(chuàng)建流式socket
ulparam=1
//1表示異步模式(即非阻塞模式)
timer(0.5)//啟動(dòng)定時(shí)器,以0.5秒的間隔檢查是否有數(shù)據(jù)到達(dá)
sclient.ioctlsocket(ws.fionbio, ulparam)
//將sclient設(shè)置為異步模式
在“連接” 按鈕的clicked事件中加入下列代碼:
uladdr=ws.inet—addr(″202.140.1.20″)
//服務(wù)器地址
if sclient.wsconnect(uladdr,2000)=-1 then//連接到服務(wù)器的2000號(hào)端口
messagebox(′socket′,″連接服務(wù)器失敗″)
end if
timer事件和“發(fā)送”按鈕的clicked事件的代碼與服務(wù)程序相同,只需將套接字對(duì)象saccept改為sclient即可。
聲明:缺省情況下創(chuàng)建的流式socket對(duì)象使用同步模式,可根據(jù)需要將其轉(zhuǎn)換成異步模式。在同步模式下,一些winsock函數(shù)調(diào)用在完成處理之前不會(huì)把控制權(quán)還給程序,導(dǎo)致程序無響應(yīng)。例如,在數(shù)據(jù)到達(dá)之前,recv()調(diào)用將一直處于等待狀態(tài)。在上面的服務(wù)程序中,用于監(jiān)聽客戶連接的socket使用了同步模式,響應(yīng)客戶請(qǐng)求的socket使用了異步模式,客戶程序中的socket也使用了異步模式。
運(yùn)行服務(wù)程序,點(diǎn)擊“監(jiān)聽”進(jìn)入等待狀態(tài);運(yùn)行客戶程序,點(diǎn)擊“連接”進(jìn)行呼叫。建立連接后,就可以聊天了。在mle—2中輸入消息,點(diǎn)擊“發(fā)送”就可傳給對(duì)方,對(duì)方發(fā)過來的消息顯示在mle—1中