使用Winsock控制項,實現網路點對點通訊

來源:互聯網
上載者:User
控制項|網路 網路的階梯第二話:
使用Winsock控制項,實現網路點對點通訊
  blog出現在CSDN,也就blog將不blog也。你會問為什麼吧?無論你心裡有沒有這個問號,但在我心裡這是個句號!你又會問為什麼嗎?好,不管你問不問。我決定,現在作答。但那種長篇大論的前因後果,請恕我無法一一羅列。我只能直接而又間接地說明,blog出現在CSDN,也就blog將不blog也。
  使用VB,寫過網路程式,沒試過Winsock這個控制項實在是遺憾(API高手除外)。我想沒有朋友有這種遺憾的...呵呵!因為,通過Winsock控制項,你可以把網路通訊簡化簡化再簡化。那是什麼程度?可能就是10行代碼以內就行了那種(IDE產生的隨外)!因為那隻是網路通訊,而通訊,僅僅就發送一條資訊,對方收到了,顯示出來。可以算了吧?來看看:

  首先,視窗載入過程,我們寫上:
            '設定了第一個Winsock控制項進入等待
            Winsock1.LocalPort = 5052
            Winsock1.Listen
            '再來把第二個Winsock控制項連向第一個
            Winsock2.Connect "127.0.0.1", 5052

  好了,這時Winsock1控制項的ConnectionRequest事件觸發。我們寫上:
            If Winsock1.State <> sckClosed Then Winsock1.Close
            Winsock1.Accept requestID '接受串連

  就這樣就連上啦!簡單得很。再來:
            Winsock1.SendData Text1.Text '把Text1中的文本傳給對方

  當然了,你傳了資料給Winsock2,那它的DataArrival事件也觸發了。
            Dim strDat As String
            Winsock2.GetData strDat '取得資料
            Text2.Text = strDat '在Text2中顯示出來

  至此,一個使用Winsock控制項,實現網路通訊程式就完成了!哈哈哈,是不是覺得上當受騙了?這種點子,MSDN裡早有出賣了!蓋茲可真不是蓋的,竟然早早想到用MSDN斷我財路!唉.難怪他比我富!

  我完成任務了?沒有,我要作的是《使用Winsock控制項,實現網路點對點通訊》。通訊實現了,也是一個點對另一個點。可是,在普遍認識裡,點對點並不是這麼解釋的。怎麼解?就是雙向通訊吧!呵呵,但蓋茲始終比我富。這點子在MSDN裡又已經出賣了!

  不耐煩了吧?但要寫程式,就不能怕煩。如果你決定走這條路,那還有更煩更煩的等著你。喂,煩人,你能看得下去嗎?哈哈~!既然好點子全給蓋茲拿去賣了,那還有什麼好說的?就如,比爾賣你一個空的資料表,可是不填上資料。它還是一個空的資料表,而不是資料表!但比爾是不能幫你填上適合你的資料的,所以,你要照著你現有的資料表,向空的資料表填上資料,再把來源資料表刪了,那它就成了一個獨一無二的資料表了!

  我看你真的不耐煩了...你餓嗎?把滑鼠蒸熟吃了頂一會吧!
  好,現在就讓我說一說,點對點通訊應用裡的一個重要程式...但這次,不會再像上面那樣,列出一行一行的代碼,然後告訴你添加到那裡,然後怎樣...現在我要就“授人以漁”的政策,堅持“編程重思想”的方針;向“由淺入深”的路線,從“理解到認識”的哲學角度出發。解釋一下,通過Winsock控制項,在網路上傳送檔案的VB程式是怎麼寫的!

  正如前面的例子一樣,用Winsock控制項通訊,得分開用戶端與伺服器,即:Client、Server(C\S)。但大家都知道,這僅是使用TCP協議必需要上演的一幕。而在UDP裡,並沒有明確的把C\S分開!但這樣概念要變模糊了。這在以後的話題裡,我會再作解釋。今天我們的主角是TCP。
  上例中,那個循序漸進的步驟,大家體會到嗎?沒關係,現在來回顧一下。

伺服器監聽5052連接埠。
客端串連到伺服器的5052連接埠,就是伺服器程式監聽的連接埠了!
由於有客戶串連,伺服器程式那的Winsock控制項就觸發ConnectionRequest事件(說明見MSDN)。
伺服器接受了串連,客端程式的Winsock控制項會觸發Connect事件,以表示串連上(例省略)。
串連上後,由伺服器程式向用戶端程式發送資料。
資料到達客端,Winsock控制項觸發起客端程式的DataArrival事件提示,取得資料,顯示!
  整個流程就這樣,顯然很簡單了,不對嗎?呵呵!然後,我們得到這麼一個流程表後。就要開始填空了。開啟我們想發送的檔案讀取資料給伺服器發送。對方收到資料後,再寫回到檔案!過程就這麼個樣了!具體實現起來,還得要思考思考。好,現在我們就從一個使用者的角度出發去想吧!

  兩個Winsock怎麼連上我就不說了,反正蓋茲都已經比我富!那我們要傳檔案,先得讓使用者選擇一個檔案吧。然後就開始傳囉!好傳,慢著!客端怎麼知道伺服器要傳的是什麼類型的檔案呢?好!有了這個想法,我們在使用者點擊伺服器程式傳送檔案按扭的時候,擷取剛才使用者選擇的檔案的名字吧。要傳過去了?還是不行,如果我們這個程式是聊天+傳檔案的話,那不是很混亂了?嗯,給這個資訊一個名字吧!就叫:“Send”怎樣?好,是個很有霸氣的名字~大家用過QQ之類的聊天軟體傳檔案都知道,QQ會先詢問接收方是否接收XXXX.XXX的檔案!那我們就模仿一下吧,把傳送命令和檔案名稱設定成:"Send 檔案名稱",這樣的一個格式。然後用Winsock的SendData方法傳給對方。

  那就去了用戶端編寫代碼囉:
  好,當收到這條命令,我們從前4個字得出,對方要傳檔案過來了!也沒什麼好寫的,就彈個Msgbox出來說,對方要傳XXXX.XXX給你,你願意接收嗎?好,當使用者把儲存路徑確定下來了,然後在這樣的路徑裡,建立一個這樣的檔案,以備接收到資料時寫入。我們現在就得返回一條資訊給伺服器那,就叫:"ILiefly "吧!表示確認接收。

  又轉回來伺服器那寫代碼了:
  收到接收確認資訊,我們開始進行讀檔案操作了!把檔案開啟,聲明一個Byte數組。把開啟的檔案資料全讀入到這個數組裡。哈哈~不就成了嗎?那傳過去試試...

  用戶端開始接收到資料了:
  嘿,糟糕,怎麼會有資料類型錯誤呢?原來每當有資料到達用戶端,我們在DataArrival事件寫的代碼都執行了。還以為是命令或聊天內容呢!不行,要給它設定一個標記,用作記錄什麼時候傳過來的資料是檔案的的資料吧。用一個Static的語句(見MSDN)聲明一個靜態布爾的變數,當False的時候是我們命令或聊天內容,而True的時候就是檔案資料吧!再改一改上一次在用戶端那寫的源碼,在答應接收之後,把這個布爾變數設為True!啊?問題又出來了!這時我想到,那什麼時候才能把布爾變數設回False呢?倒,還是有問題!目光集中到伺服器那裡去...

  再回到伺服器的代碼編輯框:
  有什麼辦法讓用戶端知道什麼時候傳完呢?發送命令?不行,那裡會把命令寫入到檔案的。串連關閉?更加不行,我還要聊天...嗯,要是讓用戶端知道傳過去的檔案長度,不就可以確定什麼時候是接收完了嗎?哈哈!行動,改一改傳送檔案的命令為:"Send 檔案名稱 檔案長度"。哦?太多空格啦,那樣對方解釋起來相當麻煩嘛,用InStr?不行,要是檔案名稱裡有空格怎辦?不就又出錯了...還好,我們有Split嘛(見MSDN)。好,那得把命令用個特別的字元分開了!就vbNullChar吧(見MSDN)!把命令改成:["SEND" & vbNullChar & 檔案名稱 & vbNullChar & 檔案長度]。傳給對方。(註:FileLen函數)

  用戶端要修改代碼了:
  聲明一個動態字串數組,把Split函數的傳回值附給它,哈哈!下標0是命令,下標1是檔案名稱,下標2是檔案長度!爽了~把長度用模組域變數儲存著,以備計算什麼時候收完吧!(註:Val函數)

  繼續在用戶端那寫我們沒完的代碼:
  布爾變數為True,有資料到達。那就取得它的資料吧!可要注意接收到的資料類型哦,對面傳過來的不是字串了,我們要指定類型為"vbArray + vbByte"(見MSND關於GetData的說明),意思就是位元組數組啦。當然,我們要定義一個位元組數組才能接收嘛 Dim ByteArray() As Byte。好,那剛才儲存下來的長度就有用啦,總長度-當次收到的位元組數=剩餘位元組數。當剩餘位元組數為0的時候,不就接收完了嗎?哈哈!不急,先來組織一下思路:資料到達,取得,儲存到位元組數組。用UBound函數(見MSDN)得到位元組數組的最大下標,但由於數組下標0也存著資料,但檔案不是這麼算啊,所以要算就得+1算!總長度 = 總長度 - UBound(ByteArray) + 1 嘿,行了!

  趕快運行試試,找個50多MB的傳。呵呵,突然,鐺!“記憶體不足”暈!搞什麼鬼啊,再看一下進程列表,哇!我的程式佔用了60MB左右的記憶體!暈,什麼回事啊?是不是那裡出錯了?再重組一下思路:選擇檔案,發送命令,當收到返回確認資訊,開啟檔案,讀...讀???不會吧,我把檔案整個讀入記憶體了,難怪難怪(其實不會發生這個錯誤的,因為Windows有虛擬記憶體嘛!但的確,要把整個檔案讀入記憶體再發送出去,有點讓系統難為啊)!得最佳化最佳化了。

  回到伺服器代碼裡進行最佳化:
  不能一次讀入這麼多,那...分開來吧!一次傳送:8192個位元組如何?好!就這樣吧。但不是每個檔案的位元組數都為8192的倍數,怎辦呢?嗯,作個計算。之前,我們不是得到了要傳的檔案的長度?既然對方都可以計算什麼時候收完,那我也可以計算什麼時候傳完嘛!首先,確定一下,要傳的檔案長度是不是比8192大。如果是,那我們就把檔案長度-8192。然後定義個下標是8191的位元組數組(因為數組下標0也可以存資料嘛,所以要-1),用Get方法,讀取開啟的檔案資料來填充這個位元組數組。然後傳過去...嗯?對方好像會收了啊,未達到檔案總長度時,用戶端不會把布爾數組設回來的。但,這邊怎麼知道什麼時候可以傳下一筆資料呢?嗯~SendComplete 事件——在完成一個發送操作時出現。好,就是這個了!我們在這邊也用檔案長度為0時作為結束傳送的條件。如果不為0,那就再看看還沒傳的檔案剩下多少,因為上面的計算已經-去了上次傳送的位元組了,那現在的檔案長度變數就是剩下位元組的數量啦,再比較一下,是否比8192大。哈哈~不是就定義一個這麼大小的位元組數組,讀檔案,送出!完成~[MsgBox "傳輸完畢!", vbInformation, "⊙_⌒γ - Server"]...
  但突然發現,原來SendComplete事件,在我們把傳檔案命令發出去之後也會觸發。那沒法子了,只好再定義一個布爾變數來確定什麼時候是傳檔案吧...

  至此,一個用Winsock控制項傳送檔案的VB程式寫完了!呵呵,沒睡著吧?不過我快睡著了!好睏,上一次睡覺的時間只有3小時!現在-_-#了...但得說明一下,上面提到的8192,並不是我隨便安上去的。這個在以後再作詳細說明吧!

  嗯,要做的事還沒完!好像我沒說為什麼:“blog出現在CSDN,也就blog將不blog也”哈哈~其實這篇東東已經說得很清楚了!



相關文章

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

11.11 Big Sale for Cloud

Get Unbeatable Offers with up to 90% Off,Oct.24-Nov.13 (UTC+8)

Get It Now >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。