Socket通信在Windows 中是排隊(duì)的形式由操作系統(tǒng)處理,而且接收方和發(fā)送方相互協(xié)同工作,否則就會(huì)造成數(shù)據(jù)丟失。因此,不能用類似于for 語句的循環(huán)來實(shí)現(xiàn)對(duì)多組數(shù)據(jù)的發(fā)送,更不能用循環(huán)語句來接收數(shù)據(jù)。比如,你可以用for 語句來實(shí)型若干文件的復(fù)制,這很普遍也很正常,但在 Socket編程以及大多數(shù)網(wǎng)絡(luò)應(yīng)用編程中都是行不通的,因?yàn)榫W(wǎng)絡(luò)通信的基本方式是請(qǐng)求和應(yīng)答。另外,和所有的通信編程一樣,Socket編程也遵循數(shù)據(jù)分包傳送這一基本規(guī)則。也就是說,在 Socket編程中,每次發(fā)送和接收一個(gè)包,以保證數(shù)據(jù)傳輸?shù)陌踩院头(wěn)定性,同時(shí)也不至于過多地占用系統(tǒng)資源。
對(duì)于ClientSocket組件,從字面上就可以看出,它用于請(qǐng)求方。也就是說,它的動(dòng)作是主動(dòng)地建立連接。顯然,ServerSocket組件用于響應(yīng)方,它的動(dòng)作是偵聽以及被動(dòng)接受連接。
組件ClientSocket的屬性是相對(duì)靜態(tài)的,它和ServerSocket之間只是連接和斷開的關(guān)系。并且僅當(dāng)ServerSocket對(duì)其接受才表示建立連接。
組件ServerSocket的屬性是動(dòng)態(tài)的。伴隨著一個(gè)新的ClientSocket與之建立連接的同時(shí),就會(huì)產(chǎn)生一個(gè)新的Socket與該ClientSocket對(duì)應(yīng),保持單獨(dú)的連接,進(jìn)行單獨(dú)的通信。因此,在同一個(gè) ServerSocket中,可以與多個(gè)ClientSocket保持同時(shí)連接和各自獨(dú)立的通信。ServerSocket的屬性 Socket.ActiveConnections用于表示客戶端連接的數(shù)量;屬性Socket.Connections[Index] 則用于訪問單個(gè)與ClientSocket連接的Socket。
正是這樣的結(jié)構(gòu),才使得WinSocket 技術(shù)能夠穩(wěn)定實(shí)現(xiàn)一個(gè)服務(wù)程序向多個(gè)客戶端提供服務(wù)。
在獨(dú)立的ClientSocket中,屬性Socket.Data 是一個(gè)指針,缺省值是nil ;在ServerSocket的每個(gè)獨(dú)立的Socket.Connections[Index]中, 屬性Data也是一個(gè)指針,缺省值是nil 。因此,可以通過該指針建立并保存各自獨(dú)立的相關(guān)信息,用于實(shí)現(xiàn)各自獨(dú)立的通信。而在ClientSocket的事件 OnRead中,調(diào)用方法傳遞的Socket值就是響應(yīng)該事件的對(duì)象屬性ClientSocket.Socket 。同樣,在 ServerSocket的事件OnClientRead中,調(diào)用方法傳遞的參數(shù)Socket就是對(duì)應(yīng)于當(dāng)前發(fā)送數(shù)據(jù)客戶端的唯一的Socket連接,即ServerSocket.Socket.Connections[Index]。這樣,就能夠?qū)Σ煌倪B接分得清清楚楚明明白白。
首先介紹實(shí)例程序的設(shè)計(jì)思想。上傳文件的過程是這樣的(這里的C和S分別代表客戶端和服務(wù)器端):
C:請(qǐng)求上傳文件; S:準(zhǔn)備就緒,可以接收; C:需要上傳的文件信息; S:收到文件信息: C:第一個(gè)包; S:收到第一個(gè)包;創(chuàng)建文件,開始寫數(shù)據(jù); C:中間的包; S:收到中間的包;繼續(xù)寫數(shù)據(jù); C:發(fā)送最后一個(gè)包,關(guān)閉文件; S:收到最后一個(gè)包;寫數(shù)據(jù),關(guān)閉文件。 下載文件的過程是這樣的:
C:請(qǐng)求下載文件; S:準(zhǔn)備就緒,可以下載; C:需要下載的文件信息(文件名); S:反饋文件信息(文件大小); C:準(zhǔn)備就緒,可以接收數(shù)據(jù); S:第一個(gè)包; C:收到第一個(gè)包;創(chuàng)建文件,開始寫數(shù)據(jù); S:中間的包; C:收到中間的包;繼續(xù)寫數(shù)據(jù); S:發(fā)送最后一個(gè)包,關(guān)閉文件; C:收到最后一個(gè)包;寫數(shù)據(jù),關(guān)閉文件;下載成功; S:下載成功。 其中,發(fā)送中間的包和收到中間的包根據(jù)包的數(shù)量可以重復(fù)。不難看出,上面的兩個(gè)過程是典型的“你一句我一句”的應(yīng)答方式。
下面是客戶端應(yīng)用程序和服務(wù)器端應(yīng)用程序的結(jié)構(gòu)。客戶端應(yīng)用程序包括:
Client.DPR uClient.PAS(.DFM)(一個(gè)ClientSocket組件、一個(gè)按鈕、一個(gè)標(biāo)簽、一個(gè)進(jìn)度條) uClientMain.PAS(.DFM)(用于選擇文件的一組控件和一個(gè)Edit控件、三個(gè)按鈕) uSocketCommon.PAS 服務(wù)器端應(yīng)用程序包括:
Server.DPR uServer.PAS(.DFM)(一個(gè)ServerSocket組件、一個(gè)Memo控件、兩個(gè)按鈕) uSocketCommon.PAS 其中,單元uSocketCommon 中包括了Socket編程的主要代碼,是客戶端應(yīng)用程序和服務(wù)器端應(yīng)用程序都需要的。
結(jié)合本例,可以對(duì)Delphi中的WinSocket編程作如下總結(jié):
數(shù)據(jù)收發(fā)是通過會(huì)話建立和撤消的; 客戶端是主動(dòng)連接,服務(wù)程序是被動(dòng)連接; 每次收發(fā)的數(shù)據(jù)包,其容量是有限的,應(yīng)當(dāng)在設(shè)計(jì)時(shí)充分考慮; 一個(gè)ClientSocket只能建立一個(gè)與ServerSocket的連接; 一個(gè)ServerSocket可以建立多個(gè)與ClientSocket的連接; 每一對(duì)連接都有唯一用于該連接的一對(duì)(兩個(gè))Socket,可以通過Data屬性進(jìn)行標(biāo)記區(qū)分; 不要對(duì)無效的數(shù)據(jù)包進(jìn)行響應(yīng),否則可能會(huì)導(dǎo)致服務(wù)程序死鎖; 可以在傳送的包中包含身份驗(yàn)證信息以確認(rèn)是有效的數(shù)據(jù)。
|
溫馨提示:喜歡本站的話,請(qǐng)收藏一下本站!