一個基于UDP數(shù)據(jù)廣播的局域網(wǎng)絡(luò)會議程序
![]() |
蔣清野 (qjiang@ieee.org) 本文介紹了網(wǎng)絡(luò)通訊中通用的傳輸控制協(xié)議(TCP)和用戶數(shù)據(jù)包協(xié)議(UDP),并且利用Java語言設(shè)計了一個簡單的基于UDP 數(shù)據(jù)廣播的局域網(wǎng)絡(luò)會議程序,展示了 在Java語言中進(jìn)行UDP 數(shù)據(jù)發(fā)送和接收的一般步驟。由于Java語言卓越的跨平臺特性,本系統(tǒng)能夠不加修改的運行在Windows, Linux, Mac OS等一系列不同平臺上。 介紹 TCP (Transmission Control Protocol,傳輸控制協(xié)議) 是一種基于連接的通訊協(xié)議。當(dāng)兩臺計算機(jī)之間需要進(jìn)行可靠的數(shù)據(jù)傳輸時,它們通過網(wǎng)絡(luò)建立起一個穩(wěn)定的連接,這種連接通常也被稱為數(shù)據(jù)鏈。與電話網(wǎng)絡(luò)相類似,這種數(shù)據(jù)鏈?zhǔn)屈c對點的,通訊的雙方則通過這條數(shù)據(jù)鏈來回傳輸數(shù)據(jù)。在這條穩(wěn)定的數(shù)據(jù)鏈的基礎(chǔ)上,TCP 協(xié)議通過信息校驗?zāi)軌虮WC接收方所接收到的數(shù)據(jù)和發(fā)送方所發(fā)送的數(shù)據(jù)在內(nèi)容和順序上是完全一致的,從而實現(xiàn)了數(shù)據(jù)的可靠傳輸。 UDP (User Datagram Protocol,用戶數(shù)據(jù)包協(xié)議)與TCP 協(xié)議之間的不同在于 UDP 不是一種基于穩(wěn)定連接的通訊協(xié)議。UDP 協(xié)議將獨立的數(shù)據(jù)包從一臺計算機(jī)傳輸?shù)搅硗庖慌_計算機(jī),但是并不保證接受方能夠接收到該數(shù)據(jù)包,也不保證接收方所接收到的數(shù)據(jù)和發(fā)送方所發(fā)送的數(shù)據(jù)在內(nèi)容和順序上是完全一致的。因此,UDP 協(xié)議更類似于普通郵政服務(wù),寄信人不能夠保證所寄出去的信能夠被收信人及時收到,后發(fā)出的信也許會比先發(fā)出的信更早到達(dá)。 對于很多應(yīng)用程序來說,在互相通訊的兩臺計算機(jī)之間保證一個可靠與穩(wěn)定的數(shù)據(jù)鏈?zhǔn)侵陵P(guān)重要的。在這種情況下,就應(yīng)該首先考慮使用TCP 協(xié)議在涼臺計算機(jī) 之間建立起TCP/IP連接。在HTTP (Hyper-Text Transfer Protocol,超級文本傳輸 協(xié)議)、FTP (File Transfer Protocol,文件傳輸協(xié)議)以及TELNET 應(yīng)用程序中,均要求在通訊的雙方之間建立起穩(wěn)定可靠的數(shù)據(jù)鏈,因此它們都使用了TCP 協(xié)議來 進(jìn)行數(shù)據(jù)傳輸。 在TCP 協(xié)議中,發(fā)送方和接收方必須交換額外的信息以保證接收方已經(jīng)接收到所發(fā)送的數(shù)據(jù)包并且所接收到的數(shù)據(jù)和發(fā)送方所發(fā)送的數(shù)據(jù)在內(nèi)容和順序上是完全一致的。這些額外的信息交換提高了數(shù)據(jù)傳輸?shù)目煽慷龋且步o網(wǎng)絡(luò)帶來了額外的負(fù)擔(dān),導(dǎo)致數(shù)據(jù)交換的延遲,從而降低了整個網(wǎng)絡(luò)的數(shù)據(jù)交換能力。對于某些對實時性要求較高的應(yīng)用程序來說,這樣的延遲有可能是不可接受的。例如一個毫秒級的時鐘服務(wù)器按照一定的頻率向客戶機(jī)提供當(dāng)時的時間數(shù)據(jù),如果這些時間數(shù)據(jù)在傳輸過程中受到了較大的延遲,這些過時的時間數(shù)據(jù)是完全沒有意義的,即使客戶機(jī)準(zhǔn)確無誤的接收到了這些數(shù)據(jù)。相反,如果客戶機(jī)所接收到的每一個數(shù)據(jù)包都是實時的,那么即使客戶機(jī)錯過了一兩個數(shù)據(jù)包也是可以接受的,因為他總是可以根據(jù)后面所接收到的數(shù)據(jù)包來對自己進(jìn)行校正。因此,對于對實時性要求比較高但是對傳輸可靠度要求比較低的應(yīng)用程序來說,UDP 協(xié)議顯然是一個合適的選擇。 在通用的以太網(wǎng)(Ehternet)構(gòu)架下,計算機(jī)于計算機(jī)之間的數(shù)據(jù)交換都是通過交換機(jī)來完成的。如果一份數(shù)據(jù)需要被傳送給多個接收者,在使用TCP/IP連接的情況下,數(shù)據(jù)發(fā)送者需要向交換機(jī)發(fā)送N 個同樣的拷貝,而交換機(jī)則負(fù)責(zé)將這N 個拷 貝分發(fā)給所有的接收者;在使用UDP 數(shù)據(jù)廣播的情況下,數(shù)據(jù)發(fā)送者只需要向交換機(jī)發(fā)送一個拷貝,交換機(jī)負(fù)責(zé)將這個信息制作N 個拷貝發(fā)送給所有的機(jī)器。在這種情況下,使用TCP/IP連接會大大的增加網(wǎng)絡(luò)的負(fù)擔(dān)。在一個普通局域網(wǎng)絡(luò)中,可以認(rèn)為由于網(wǎng)絡(luò)狀況較差而造成數(shù)據(jù)丟失的可能性比較小,而利用UDP 數(shù)據(jù)廣播進(jìn)行 數(shù)據(jù)交換能夠大幅度減輕網(wǎng)絡(luò)的負(fù)擔(dān),因此設(shè)計一個基于UDP 數(shù)據(jù)廣播的局域網(wǎng)絡(luò) 會議系統(tǒng)式完全可行的。 通常來說,一臺計算機(jī)只有一個物理界面與網(wǎng)絡(luò)相連接,所有的應(yīng)用程序均通過該物理界面從網(wǎng)絡(luò)接收數(shù)據(jù)或者將數(shù)據(jù)發(fā)送到網(wǎng)絡(luò)。由于一個網(wǎng)絡(luò)上同時存在多臺計算機(jī),并且一臺計算機(jī)上有可能同時存在多個應(yīng)用程序需要與網(wǎng)絡(luò)進(jìn)行數(shù)據(jù)交換,我們通常使用IP和端口號來識別需要進(jìn)行數(shù)據(jù)交換的計算機(jī)和應(yīng)用程序。每臺計算機(jī)由一個32位的IP地址來識別,在一個網(wǎng)絡(luò)中,每臺計算機(jī)的IP地址都是唯一的,因此應(yīng)用程序能夠根據(jù)IP地址來將數(shù)據(jù)發(fā)送到正確的計算機(jī)。每個需要與網(wǎng)絡(luò)進(jìn)行數(shù)據(jù)交換的應(yīng)用程序均被系統(tǒng)分配一個16位的端口號,系統(tǒng)根據(jù)這個端口號將從網(wǎng)絡(luò)接收到的數(shù)據(jù)轉(zhuǎn)發(fā)給相對應(yīng)的應(yīng)用程序。端口號的范圍是從0 到65535 ,其 中從0 到1023被系統(tǒng)所保留,主要是用來提供HTTP, FTP 以及TELNET等系統(tǒng)服務(wù),因此用戶自己的應(yīng)用程序不應(yīng)該試圖去使用小于1023的端口。 Java語言的一個顯著優(yōu)點就是它從語言的高度上提供了對網(wǎng)絡(luò)的支持,使得程序員能夠很容易的構(gòu)建基于網(wǎng)絡(luò)的應(yīng)用程序。在Java 1.3版的標(biāo)準(zhǔn)類庫java.net中 提供了5 個接口以及21個Java類,在這些接口和類的基礎(chǔ)上,程序員能夠輕易的實現(xiàn)幾乎是所有的常見網(wǎng)絡(luò)應(yīng)用。例如,ServerSocket能夠用來構(gòu)建基于TCP/IP的服務(wù)器程序,Socket能夠用來構(gòu)建基于TCP/IP的客戶端程序,而DatagramPacket以及 DatagramSocket能夠用來構(gòu)建基于UDP 的數(shù)據(jù)廣播程序。在java.net中的其他Java 庫能夠被用來實現(xiàn)域名解析、身份認(rèn)證、安全許可等一系列功能。由于這些Java庫的功能和具體用法等內(nèi)容已經(jīng)超出了本文的討論范圍,感興趣的讀者可以進(jìn)一步參考Java的文檔以及Sun 公司的Java Tutorial等資料。 這個簡單的程序包括如下三個模塊:
程序設(shè)計 在構(gòu)造方法中,我們首先利用InetAddress 定義一個數(shù)據(jù)廣播組,同時構(gòu)造一個用于發(fā)送數(shù)據(jù)的DatagramSocket與一個用于接收數(shù)據(jù)的MulticastSocket。在這 里我們使用230.0.0.1 來作為數(shù)據(jù)廣播組的標(biāo)示符,雖然這個標(biāo)示符與IP地址的格式相同,但是它并不表示Internet上的一臺機(jī)器。此外,我們在端口配置方法中分別指定1235端口和1236端口位數(shù)據(jù)發(fā)送和數(shù)據(jù)接收端口。如果把一個UDP 數(shù)據(jù)廣播系統(tǒng)比喻成無線電廣播系統(tǒng)的話,數(shù)據(jù)廣播標(biāo)示符可以被認(rèn)為是波段,而數(shù)據(jù)接收端口可以被認(rèn)為是頻率。收音機(jī)用戶必須把收音機(jī)調(diào)整到相應(yīng)的波段和頻率才能夠接收到電臺信號,我們的UDP 數(shù)據(jù)接收程序也必須加入相對應(yīng)的數(shù)據(jù)廣播組并且使用正確的數(shù)據(jù)接收端口才能夠正確的接收到UDP 廣播數(shù)據(jù)。在構(gòu)造方法中,我們利 用MulticastSocket 的構(gòu)造函數(shù)指定數(shù)據(jù)接收端口(頻率),并利用其joinGroup 方法指定數(shù)據(jù)廣播組(波段)。
在數(shù)據(jù)發(fā)送方法中,我們基于用戶所提供的數(shù)據(jù)以及數(shù)據(jù)廣播目標(biāo)端口(頻率) 構(gòu)造一個DatagramPacket數(shù)據(jù)包,然后利用發(fā)送數(shù)據(jù)的DatagramSocket的send方法將該數(shù)據(jù)包發(fā)送到局域網(wǎng)。與此相反,在數(shù)據(jù)接收方法中,我們首先構(gòu)造一個空的 DatagramPacket數(shù)據(jù)包,然后利用接收數(shù)據(jù)的MulticastSocket的receive方法填充該數(shù)據(jù)包中的內(nèi)容。為了避免由于數(shù)據(jù)包大小不同所造成的數(shù)據(jù)丟失等麻煩,我們特地將兩個數(shù)據(jù)包的大小設(shè)置成一樣的。
數(shù)據(jù)接收線程Receiver.java的任務(wù)是接收廣播數(shù)據(jù)并更新圖形用戶界面。該類的構(gòu)造函數(shù)包括兩個參數(shù),參數(shù)listener指定用來接收數(shù)據(jù)的Broadcast對象,參數(shù) display則指定用來顯示會議內(nèi)容的TextArea對象。在其運行方法run 中,循環(huán)調(diào)用 Broadcast對象的數(shù)據(jù)接收方法ReceiveData 接收廣播數(shù)據(jù),并且利用TextArea對象的append方法將新接收到的內(nèi)容顯示到圖形用戶界面上。
圖形用戶界面chat.java是基于Java抽象窗口工具包AWT構(gòu)建的。該界面包括一個用來顯示會議內(nèi)容TextArea,一個用來接收用戶輸入的TextField ,以及一個數(shù)據(jù)發(fā)送命令按鈕。在Chat的構(gòu)造方法中,我們首先創(chuàng)建圖形界面,構(gòu)造一個數(shù)據(jù)發(fā)送與接收對象和一個數(shù)據(jù)接收線程,然后啟動該線程開始接收會議信息。在這個方法中,我們還利用InetAddress.getLocalHost()方法來獲得用戶的機(jī)器名,這個標(biāo)示符被用來作為用戶在網(wǎng)絡(luò)會議中的用戶名。
程序測試 啟動網(wǎng)絡(luò)會議程序: 本示例程序在一個包括Windows 98,Windows 2000,Red Hat Linux 6.1/7.0,Mac OS,Sun Solaris等多種操作系統(tǒng)的局域網(wǎng)絡(luò)中通過測試。 結(jié)論
|