蔣清野 (qjiang@ieee.org) 美國導航與控制公司
本文介紹了網絡通訊中通用的傳輸控制協議(TCP)和用戶數據包協議(UDP),并且利用Java語言設計了一個簡單的基于UDP 數據廣播的局域網絡會議程序,展示了 在Java語言中進行UDP 數據發送和接收的一般步驟。由于Java語言卓越的跨平臺特性,本系統能夠不加修改的運行在Windows, Linux, Mac OS等一系列不同平臺上。
介紹 隨著網絡技術的普及,網絡會議在公司、企業和單位中的應用也越來越廣。一個網絡會議系統通常包括一個服務器程序和一個客戶端程序。其中服務器端負責進行用戶管理、信息交互以及表決統計;客戶端則實現收聽發言,公開發言,私下討論、投票表決等功能。在一個網絡會議系統的設計和實現中,通常涉及到圖形用戶界面設計,TCP/IP連接,UDP 數據廣播,多線程等一系列技術。本文通過一個簡單示例程序,展示了在Java語言中進行UDP 數據發送和接收的一般步驟以及UDP 數據 廣播在局域網絡會議系統中的作用。
TCP (Transmission Control Protocol,傳輸控制協議) 是一種基于連接的通訊協議。當兩臺計算機之間需要進行可靠的數據傳輸時,它們通過網絡建立起一個穩定的連接,這種連接通常也被稱為數據鏈。與電話網絡相類似,這種數據鏈是點對點的,通訊的雙方則通過這條數據鏈來回傳輸數據。在這條穩定的數據鏈的基礎上,TCP 協議通過信息校驗能夠保證接收方所接收到的數據和發送方所發送的數據在內容和順序上是完全一致的,從而實現了數據的可靠傳輸。
UDP (User Datagram Protocol,用戶數據包協議)與TCP 協議之間的不同在于 UDP 不是一種基于穩定連接的通訊協議。UDP 協議將獨立的數據包從一臺計算機傳輸到另外一臺計算機,但是并不保證接受方能夠接收到該數據包,也不保證接收方所接收到的數據和發送方所發送的數據在內容和順序上是完全一致的。因此,UDP 協議更類似于普通郵政服務,寄信人不能夠保證所寄出去的信能夠被收信人及時收到,后發出的信也許會比先發出的信更早到達。
對于很多應用程序來說,在互相通訊的兩臺計算機之間保證一個可靠與穩定的數據鏈是至關重要的。在這種情況下,就應該首先考慮使用TCP 協議在涼臺計算機 之間建立起TCP/IP連接。在HTTP (Hyper-Text Transfer Protocol,超級文本傳輸 協議)、FTP (File Transfer Protocol,文件傳輸協議)以及TELNET 應用程序中,均要求在通訊的雙方之間建立起穩定可靠的數據鏈,因此它們都使用了TCP 協議來 進行數據傳輸。
在TCP 協議中,發送方和接收方必須交換額外的信息以保證接收方已經接收到所發送的數據包并且所接收到的數據和發送方所發送的數據在內容和順序上是完全一致的。這些額外的信息交換提高了數據傳輸的可靠度,但是也給網絡帶來了額外的負擔,導致數據交換的延遲,從而降低了整個網絡的數據交換能力。對于某些對實時性要求較高的應用程序來說,這樣的延遲有可能是不可接受的。例如一個毫秒級的時鐘服務器按照一定的頻率向客戶機提供當時的時間數據,如果這些時間數據在傳輸過程中受到了較大的延遲,這些過時的時間數據是完全沒有意義的,即使客戶機準確無誤的接收到了這些數據。相反,如果客戶機所接收到的每一個數據包都是實時的,那么即使客戶機錯過了一兩個數據包也是可以接受的,因為他總是可以根據后面所接收到的數據包來對自己進行校正。因此,對于對實時性要求比較高但是對傳輸可靠度要求比較低的應用程序來說,UDP 協議顯然是一個合適的選擇。
在通用的以太網(Ehternet)構架下,計算機于計算機之間的數據交換都是通過交換機來完成的。如果一份數據需要被傳送給多個接收者,在使用TCP/IP連接的情況下,數據發送者需要向交換機發送N 個同樣的拷貝,而交換機則負責將這N 個拷 貝分發給所有的接收者;在使用UDP 數據廣播的情況下,數據發送者只需要向交換機發送一個拷貝,交換機負責將這個信息制作N 個拷貝發送給所有的機器。在這種情況下,使用TCP/IP連接會大大的增加網絡的負擔。在一個普通局域網絡中,可以認為由于網絡狀況較差而造成數據丟失的可能性比較小,而利用UDP 數據廣播進行 數據交換能夠大幅度減輕網絡的負擔,因此設計一個基于UDP 數據廣播的局域網絡 會議系統式完全可行的。
通常來說,一臺計算機只有一個物理界面與網絡相連接,所有的應用程序均通過該物理界面從網絡接收數據或者將數據發送到網絡。由于一個網絡上同時存在多臺計算機,并且一臺計算機上有可能同時存在多個應用程序需要與網絡進行數據交換,我們通常使用IP和端口號來識別需要進行數據交換的計算機和應用程序。每臺計算機由一個32位的IP地址來識別,在一個網絡中,每臺計算機的IP地址都是唯一的,因此應用程序能夠根據IP地址來將數據發送到正確的計算機。每個需要與網絡進行數據交換的應用程序均被系統分配一個16位的端口號,系統根據這個端口號將從網絡接收到的數據轉發給相對應的應用程序。端口號的范圍是從0 到65535 ,其 中從0 到1023被系統所保留,主要是用來提供HTTP, FTP 以及TELNET等系統服務,因此用戶自己的應用程序不應該試圖去使用小于1023的端口。
Java語言的一個顯著優點就是它從語言的高度上提供了對網絡的支持,使得程序員能夠很容易的構建基于網絡的應用程序。在Java 1.3版的標準類庫java.net中 提供了5 個接口以及21個Java類,在這些接口和類的基礎上,程序員能夠輕易的實現幾乎是所有的常見網絡應用。例如,ServerSocket能夠用來構建基于TCP/IP的服務器程序,Socket能夠用來構建基于TCP/IP的客戶端程序,而DatagramPacket以及 DatagramSocket能夠用來構建基于UDP 的數據廣播程序。在java.net中的其他Java 庫能夠被用來實現域名解析、身份認證、安全許可等一系列功能。由于這些Java庫的功能和具體用法等內容已經超出了本文的討論范圍,感興趣的讀者可以進一步參考Java的文檔以及Sun 公司的Java Tutorial等資料。
這個簡單的程序包括如下三個模塊:
- 數據廣播與接收模塊-- Broadcast.java
- 數據接收線程 -- Receiver.java
- 圖形用戶界面 -- Chat.java
程序設計 數據廣播與接收模塊Broadcast.java是本示例程序的核心部分。該類包括一個構造方法,一個數據發送方法和一個數據接收方法。為了使這個類能夠被更加廣泛的應用到其它應用程序中,作者又添加了一個端口配置方法。
在構造方法中,我們首先利用InetAddress 定義一個數據廣播組,同時構造一個用于發送數據的DatagramSocket與一個用于接收數據的MulticastSocket。在這 里我們使用230.0.0.1 來作為數據廣播組的標示符,雖然這個標示符與IP地址的格式相同,但是它并不表示Internet上的一臺機器。此外,我們在端口配置方法中分別指定1235端口和1236端口位數據發送和數據接收端口。如果把一個UDP 數據廣播系統比喻成無線電廣播系統的話,數據廣播標示符可以被認為是波段,而數據接收端口可以被認為是頻率。收音機用戶必須把收音機調整到相應的波段和頻率才能夠接收到電臺信號,我們的UDP 數據接收程序也必須加入相對應的數據廣播組并且使用正確的數據接收端口才能夠正確的接收到UDP 廣播數據。在構造方法中,我們利 用MulticastSocket 的構造函數指定數據接收端口(頻率),并利用其joinGroup 方法指定數據廣播組(波段)。
public Broadcast()
{
GetBroadcastPorts();
try
{
// 構造數據廣播組標示符 (波段)
BroadcastGroup = InetAddress.getByName("230.0.0.1");
// 構造數據發送端口
Sender = new DatagramSocket(ServerPort);
// 構造數據接收端口 (頻率)
Receiver = new MulticastSocket(ClientPort);
// 指定數據接收端口的數據廣播組 (波段)
Receiver.joinGroup(BroadcastGroup);
} catch (Exception e) {}
}
|
在數據發送方法中,我們基于用戶所提供的數據以及數據廣播目標端口(頻率) 構造一個DatagramPacket數據包,然后利用發送數據的DatagramSocket的send方法將該數據包發送到局域網。與此相反,在數據接收方法中,我們首先構造一個空的 DatagramPacket數據包,然后利用接收數據的MulticastSocket的receive方法填充該數據包中的內容。為了避免由于數據包大小不同所造成的數據丟失等麻煩,我們特地將兩個數據包的大小設置成一樣的。
// 數據發送方法
public void SendData(String Msg)
{
byte[] b = new byte[1024];
DatagramPacket packet;
try
{
// 字節序列b 包括需要發送的數據
b = Msg.getBytes();
// 構造一個數據包,BroadcastGroup是數據廣播組標示符(波段),
// ClientPort是數據廣播目標端口(頻率)。
packet = new DatagramPacket(b, b.length, BroadcastGroup, ClientPort);
// 發送數據包
Sender.send(packet);
} catch (Exception e) {}
}
// 數據接收方法
public String ReceiveData()
{
byte[] b = new byte[1024];
// 構造一個空的數據包
DatagramPacket packet = new DatagramPacket(b, 1024);
String InMsg;
try
{
// 接收數據
Receiver.receive(packet);
} catch (IOException e) {}
// 叢數據包中獲得接收到的數據
b = packet.getData();
InMsg = new String(b);
return InMsg;
}
|
數據接收線程Receiver.java的任務是接收廣播數據并更新圖形用戶界面。該類的構造函數包括兩個參數,參數listener指定用來接收數據的Broadcast對象,參數 display則指定用來顯示會議內容的TextArea對象。在其運行方法run 中,循環調用 Broadcast對象的數據接收方法ReceiveData 接收廣播數據,并且利用TextArea對象的append方法將新接收到的內容顯示到圖形用戶界面上。
public class Receiver extends Thread
{
Broadcast Listener;
TextArea Display;
String InMsg;
// 構造方法
public Receiver(Broadcast listener, TextArea display )
{
// Listener 是一個數據發送與接收對象,用來接收數據。
Listener = listener;
/ Display是一個TextArea對象,用來顯示會議內容。
Display = display;
}
// 運行方法
public void run()
{
while(true)
{
// 接收廣播數據
InMsg = Listener.ReceiveData();
// 更新圖形用戶界面
Display.append(InMsg);
Display.append("\n");
}
}
}
|
圖形用戶界面chat.java是基于Java抽象窗口工具包AWT構建的。該界面包括一個用來顯示會議內容TextArea,一個用來接收用戶輸入的TextField ,以及一個數據發送命令按鈕。在Chat的構造方法中,我們首先創建圖形界面,構造一個數據發送與接收對象和一個數據接收線程,然后啟動該線程開始接收會議信息。在這個方法中,我們還利用InetAddress.getLocalHost()方法來獲得用戶的機器名,這個標示符被用來作為用戶在網絡會議中的用戶名。
// 構造方法
public Chat()
{
// 創建圖形界面
add(CreateGui());
// ....
// 其它操作
// ....
// 構造一個數據發送與接收對象
Device = new Broadcast();
// 構造一個數據接收線程
Receiver Recv = new Receiver(Device, InMsg);
Recv.start();
}
|
程序測試 利用JDK 1.3編譯以上所有源代碼:
javac *.java
啟動網絡會議程序:
java Chat
本示例程序在一個包括Windows 98,Windows 2000,Red Hat Linux 6.1/7.0,Mac OS,Sun Solaris等多種操作系統的局域網絡中通過測試。
結論 本文介紹了網絡通訊中通用的傳輸控制協議(TCP)和用戶數據包協議(UDP),并且利用Java語言設計了一個簡單的基于UDP 數據廣播的局域網絡會議程序,展示了在Java語言中進行UDP 數據發送和接收的一般步驟。本示例程序說明利用UDP 數據廣播能夠輕易實現局域網絡會議的一般功能。由于Java語言卓越的跨平臺特性,一個基于Java的局域網絡會議系統夠不加修改的運行在一系列不同平臺上。
關于作者 蔣清野,軟件工程專家。1999年7月獲得清華大學學士學位,2001年1月獲得伊里諾大學(Univ. of Illinois at Urbana-Champaign)碩士學位,目前是美國導航與控制公司(American GNC Corporation)工程專家。主要研究領域包括遙感圖像信息處理,GPS應用,慣性導航,無線通訊和高速網絡技術。電子郵件:qjiang@ieee.org。 | |