通訊機制示意圖 |
本單元要建立的是一個最簡單的網路通訊程式,如上圖,MSN就是我們要做的程式。 它以 IP+Port(通訊埠)為一個通訊的端點(IPEndPoint),只要兩者不完全相同就可以完成網路通訊。也就是: 一、可以在同一個 IP,也就是同一部電腦之內,以兩個不同的 Port 通訊(如上圖的Port Y與Z) 二、也可以在不同 IP (電腦)之間以相同(或不同)的 Port (如上圖的Port X)通訊。 狀況一可以讓我們寫程式時不需要兩台電腦就可以測試執行(Debug),狀況二則是程式完成後正常的執行模式。 以此程式來說,通訊機制很像大家都拿著一隻無線電對講機,通話雙方調到同一個『頻道』(也就是Port)就可以通話了! 表單介面 請建立專案設計主表單如上圖。 說明:網路通訊的基本元素包括電腦的 IP 與 Port(埠),IP代表電腦,Port代表程式,一個電腦中可以有多個網路程式同時執行,正如一個住址之內可以住好幾個人,各自都可以獨立收發訊息。所以寫網路通訊程式時一定要指定通訊的目標 IP 與 Port。 當然通訊必須是雙向的,你自己的IP當然不是在此程式裡面定義的,必須到系統程式去設定,但是要使用的Port則須在本程式內定義,且不能與其他網路程式衝突。Port可以定的範圍是0~65536,設為0時作業系統會隨意指派,其他1~1024通常視為系統保留區(譬如Port 80通常是網頁瀏覽器專用),因此我們最好用大於1024的號碼。本範例我們將先用本機電腦的Port 2011 與 2012作通訊實驗。至於"127.0.0.1"這個特殊的IP是指本機電腦的意思,不論你的電腦目前實際的IP是多少,這個IP都會指向你自己的電腦。 匯入命名空間(函式庫) 網路程式不是一般程式專案預設的功能,必須匯入(Import)以上的命名空間,前面兩個與網路的通訊端點設定及物件有關,System.Text 與文字編碼有關,網路通訊只能傳送位元組陣列,收發資訊之前都必須作編碼的轉換。最後的 System.Threading 稱為執行緒,執行緒(Thread)事實上是程式內可以獨立執行的程式(或稱程序Process)。因為網路程式常常需要一邊監聽網路可能傳來的訊息,一邊同時作輸入與傳送資訊的動作,等於要在主程式內同時執行兩個程式,所以必須使用多執行緒的方式,讓程式不會因為要持續監聽網路訊息而卡住,無法進行其他的工作(譬如打字輸入要發出的訊息。執行緒也是一般專案不會用到的特殊功能,所以必須另行匯入。 啟動監聽網路訊息的程式 前兩行宣告UDP監聽用物件及執行緒,因為以正常程式關閉表單時額外的執行緒常常是不會自動關閉的,所以我們必須將他們宣告為公用物件,以便另寫程式關掉他們,否則程式關閉後你之前建立的執行緒(等於另一個程式)卻繼續運作只是浪費電腦資源,還容易與之後執行的程式衝突。 接著是啟動監聽的按鍵程式: Control.CheckForIllegalCrossThreadCalls = False 是宣告忽略跨執行緒的錯誤檢查,在此例中當程式在監聽的執行緒收到網路訊號時,理論上不能顯示於表單(主執行緒的)物件,因為表單和它是不同的執行緒,也就類似一個程式通常不能直接修改另一個程式的內容!我們用此程式碼讓它們可以破例。 接著是建立執行緒的程式,基本上就是執行一個稱為:Listen 的副程式。(AddressOf 意義是『位置在...』) Th = New Thread(AddressOf Listen) '建立新執行緒 Th.Start() '啟動監聽執行緒 接下來讓 Button1失效(Enabled = False),目的是避免使用者重複宣告監聽執行緒(兩個執行緒使用同一個Port會當掉)。 Listen 副程式的內容如下: 先是設立一個以指定的 Port 監聽網路UDP訊息的物件,監聽端點為EP,必須包括本機的IP與Port,此處預設的IP"127.0.0.1"是指本機的意思,如果你要跨電腦測試時應該改成真實的IP值。後面會教到如何取得你的實際 IP。 接著: Do While True Loop 是一個無限等待的迴圈,此迴圈內部的程式有反應,就是收到網路訊息時,就立即處理,處理完繼續等待新訊息! 這段程式執行後等於網路收音機就打開了,同時間,因為是另外開的獨立執行緒,所以不會影響你在主表單上寫訊息與發訊息給別人的動作!簡單說,有了多執行緒你才能『邊聽邊做』,自己操作時也能隨時知道網路上對方的動作。正如你上課時偷玩遊戲,也必須有『多執行緒』隨時監看老師有沒有注意到你,否則被點名了都不知道就很白目了! 發訊息的程式 發訊息的程式就是先取得發訊的目標 IP 與 Port(程式執行中可修改)。 傳出訊息之前必須將文字轉成位元組(Byte)陣列,再用UDP通訊物件U傳出! 此地的U物件就是監聽用的同一個通訊器,它不只可以聽(收訊),也可以發訊,只要指定對象(IP & Port)即可。 當然你要在此臨時宣告建置另一個UDP通訊物件用過即丟也是可以的。 程式寫到這邊可以試著執行程式,並按下啟動監聽,要知道指定的監聽Port是不是已經啟動,可以如前一單元所教的方式,到命令提示字元視窗執行 netstat/a指令(/a是顯示全部的意思),應該可以看到一個UDP...2012的項目,如果沒有!就是程式有錯並未成功的開啟UDP的監聽。 關閉執行緒的程式 一般來說關閉表單就可以將程式內所有工作結束,但是本程式中的監聽執行緒則無法隨之關閉,所以必須在表單關閉之前的Form_Closing事件中寫程式關閉執行緒(Th)及監聽物件(U)。在此兩者次序是有關係的!必須先關閉執行緒Th,否則先關掉U而Th的程式卻還要使用到U,就會發生錯誤! 因為也有可能使用者並未啟動監聽,此時U與Th都不存在,嘗試關閉它們時會引發錯誤,上面使用Try的寫法就是如果發生錯誤(未啟動監聽)時就繼續進行,不要讓程式中斷(當掉)的意思。,不要讓程式中斷(當掉)的意思。 測試程式的方式 這個程式必須雙方通訊,因此我們需要兩個程式實體來測試,當然你可以找另一位同學跨機測試,或者拷貝專案,開兩個專案互相測試,比較簡單的方式是到專案的 bin\debug 目錄下找到*.exe的執行檔,如老師的目錄顯示是這樣的: 拷貝那個exe檔案到桌面執行就會有兩個程式了!做好適當的 Port 設定程式執行畫面大概是這樣的: 如果本機測試成功之後你就可以和其他同學跨機通訊了!當然必須知道自己與他人的IP,請到電腦的:程式集→附屬應用程式的『命令提示字元』項目點一下,打入『ipconfig』指令就可以看到目前電腦的IP了,老師的電腦畫面如下: 紅色位置就會顯示你的IP。 |