codefans

          導(dǎo)航

          <2025年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          統(tǒng)計

          常用鏈接

          留言簿(2)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          程序設(shè)計鏈接

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          一個基于UDP數(shù)據(jù)廣播的局域網(wǎng)絡(luò)會議程序

          內(nèi)容:
          介紹
          程序設(shè)計
          程序測試
          結(jié)論
          關(guān)于作者

          蔣清野 (qjiang@ieee.org)
          美國導(dǎo)航與控制公司

          本文介紹了網(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等一系列不同平臺上。

          介紹
          隨著網(wǎng)絡(luò)技術(shù)的普及,網(wǎng)絡(luò)會議在公司、企業(yè)和單位中的應(yīng)用也越來越廣。一個網(wǎng)絡(luò)會議系統(tǒng)通常包括一個服務(wù)器程序和一個客戶端程序。其中服務(wù)器端負(fù)責(zé)進(jìn)行用戶管理、信息交互以及表決統(tǒng)計;客戶端則實現(xiàn)收聽發(fā)言,公開發(fā)言,私下討論、投票表決等功能。在一個網(wǎng)絡(luò)會議系統(tǒng)的設(shè)計和實現(xiàn)中,通常涉及到圖形用戶界面設(shè)計,TCP/IP連接,UDP 數(shù)據(jù)廣播,多線程等一系列技術(shù)。本文通過一個簡單示例程序,展示了在Java語言中進(jìn)行UDP 數(shù)據(jù)發(fā)送和接收的一般步驟以及UDP 數(shù)據(jù) 廣播在局域網(wǎng)絡(luò)會議系統(tǒng)中的作用。

          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等資料。

          這個簡單的程序包括如下三個模塊:

          1. 數(shù)據(jù)廣播與接收模塊-- Broadcast.java
          2. 數(shù)據(jù)接收線程 -- Receiver.java
          3. 圖形用戶界面 -- Chat.java


          程序設(shè)計
          數(shù)據(jù)廣播與接收模塊Broadcast.java是本示例程序的核心部分。該類包括一個構(gòu)造方法,一個數(shù)據(jù)發(fā)送方法和一個數(shù)據(jù)接收方法。為了使這個類能夠被更加廣泛的應(yīng)用到其它應(yīng)用程序中,作者又添加了一個端口配置方法。

          在構(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ù)廣播組(波段)。

          public Broadcast()
              {
                  GetBroadcastPorts();
                  try
                  {
                          // 構(gòu)造數(shù)據(jù)廣播組標(biāo)示符 (波段)
                      BroadcastGroup = InetAddress.getByName("230.0.0.1");
                          // 構(gòu)造數(shù)據(jù)發(fā)送端口
                      Sender         = new DatagramSocket(ServerPort);
                          // 構(gòu)造數(shù)據(jù)接收端口 (頻率)
                      Receiver       = new MulticastSocket(ClientPort);
                          // 指定數(shù)據(jù)接收端口的數(shù)據(jù)廣播組 (波段)
                      Receiver.joinGroup(BroadcastGroup);
                  } catch (Exception e) {}
              }
          


          在數(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ù)發(fā)送方法
              public void SendData(String Msg)
              {
                  byte[] b = new byte[1024];
                  DatagramPacket packet;
                  try
                  {
                      // 字節(jié)序列b 包括需要發(fā)送的數(shù)據(jù)
                      b = Msg.getBytes();
                      // 構(gòu)造一個數(shù)據(jù)包,BroadcastGroup是數(shù)據(jù)廣播組標(biāo)示符(波段),
                      // ClientPort是數(shù)據(jù)廣播目標(biāo)端口(頻率)。
                      packet = new DatagramPacket(b, b.length, BroadcastGroup, ClientPort);
                      // 發(fā)送數(shù)據(jù)包
                      Sender.send(packet);
                  } catch (Exception e) {}
              }
              
              // 數(shù)據(jù)接收方法
              public String ReceiveData()
              {
                  byte[] b = new byte[1024];
                  // 構(gòu)造一個空的數(shù)據(jù)包
                  DatagramPacket packet = new DatagramPacket(b, 1024);
                  String InMsg;           
                  try
                  {
                          // 接收數(shù)據(jù)
                      Receiver.receive(packet);
              } catch (IOException e) {}
              // 叢數(shù)據(jù)包中獲得接收到的數(shù)據(jù)
                  b = packet.getData();
                  InMsg = new String(b);
              return InMsg;   
              }
          


          數(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)容顯示到圖形用戶界面上。

          public class Receiver extends Thread
          {
              Broadcast Listener;
              TextArea  Display;
              String    InMsg;
              
                  // 構(gòu)造方法
              public Receiver(Broadcast listener, TextArea display )
              {
                          // Listener 是一個數(shù)據(jù)發(fā)送與接收對象,用來接收數(shù)據(jù)。
                  Listener = listener;
                          / Display是一個TextArea對象,用來顯示會議內(nèi)容。
                  Display  = display;
              }
              
                  // 運行方法
              public void run()
              {
                  while(true)
                  {
                                  // 接收廣播數(shù)據(jù)
                      InMsg = Listener.ReceiveData();
                                  // 更新圖形用戶界面
                      Display.append(InMsg);
                      Display.append("\n");
                  }
              }
          }
          


          圖形用戶界面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ò)會議中的用戶名。

             // 構(gòu)造方法
              public Chat()
              {
                  // 創(chuàng)建圖形界面
                      add(CreateGui());
                          // ....
                  // 其它操作
                  // ....
                      // 構(gòu)造一個數(shù)據(jù)發(fā)送與接收對象
                      Device = new Broadcast();
                  // 構(gòu)造一個數(shù)據(jù)接收線程
                      Receiver Recv = new Receiver(Device, InMsg);
                      Recv.start();
              }
          


          程序測試
          利用JDK 1.3編譯以上所有源代碼:
          javac *.java

          啟動網(wǎng)絡(luò)會議程序:
          java Chat

          本示例程序在一個包括Windows 98,Windows 2000,Red Hat Linux 6.1/7.0,Mac OS,Sun Solaris等多種操作系統(tǒng)的局域網(wǎng)絡(luò)中通過測試。

          結(jié)論
          本文介紹了網(wǎng)絡(luò)通訊中通用的傳輸控制協(xié)議(TCP)和用戶數(shù)據(jù)包協(xié)議(UDP),并且利用Java語言設(shè)計了一個簡單的基于UDP 數(shù)據(jù)廣播的局域網(wǎng)絡(luò)會議程序,展示了在Java語言中進(jìn)行UDP 數(shù)據(jù)發(fā)送和接收的一般步驟。本示例程序說明利用UDP 數(shù)據(jù)廣播能夠輕易實現(xiàn)局域網(wǎng)絡(luò)會議的一般功能。由于Java語言卓越的跨平臺特性,一個基于Java的局域網(wǎng)絡(luò)會議系統(tǒng)夠不加修改的運行在一系列不同平臺上。

          關(guān)于作者
          蔣清野,軟件工程專家。1999年7月獲得清華大學(xué)學(xué)士學(xué)位,2001年1月獲得伊里諾大學(xué)(Univ. of Illinois at Urbana-Champaign)碩士學(xué)位,目前是美國導(dǎo)航與控制公司(American GNC Corporation)工程專家。主要研究領(lǐng)域包括遙感圖像信息處理,GPS應(yīng)用,慣性導(dǎo)航,無線通訊和高速網(wǎng)絡(luò)技術(shù)。電子郵件:
          qjiang@ieee.org

          posted on 2005-08-20 02:52 春雷的博客 閱讀(167) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 明星| 龙里县| 泰兴市| 惠水县| 青海省| 白朗县| 新丰县| 潜山县| 文山县| 长海县| 大余县| 固原市| 长治市| 巫山县| 皮山县| 吉隆县| 通渭县| 江孜县| 玉溪市| 荣昌县| 道真| 金塔县| 敦煌市| 德江县| 三门峡市| 扶绥县| 内乡县| 龙海市| 冀州市| 六盘水市| 沐川县| 顺昌县| 德格县| 涟源市| 南投市| 安福县| 佛山市| 米易县| 武威市| 汤原县| 黄石市|