首頁
中文書目錄
原文書目錄
 站內快速搜尋
資源中心
Book Series
Special Interest













■好消息,歐萊禮書籍已重新鋪貨至各大書局及網路書店,歡迎讀者選購       ■歡迎各院校採用歐萊禮書籍,學校團購請洽校園服務團隊

[FAQ]

Java 網路程式設計問題

------ Original Message -----
From: cic
To: bookquestion@oreilly.com.tw
Sent: Thursday, August 22, 2002 3:59 PM
Subject: MulticastSocket請教


辛苦的技術服務人員你們好 :
我現在正在閱讀Java網路程式設計第一版
同時配合著原文的Java Network Programming 2nd Edition對照著看..
我以原文書為主來發問問題..(中文版也有同樣的內容)

在p468頁的MulticastSniffer的程式中
我沒有辦法run出書中的結果...
沒有半點的資料送回我的console..
我想應該是sap.mcast.net 9875的問題吧!那我該如何修正呢 ?
是否可以選出在p455頁中表14-1任一個Domain Name來替換sap.mcast.net
那表14-1為何都沒有提供port呢?我想要監聽來自domain name的data不是需要指明監聽哪一個port嗎?
如果我只想在自己架設的區域網路中做到Multicast 的效果 ...
我是應該要加入表14-1的某個group嗎?還是......

書中p462頁中提到MulticastSocket的兩個constructor,書上說沒有指定port的 constructor主要是用來當client的..
但我還是不了解.到底那時後要用那一個constructor,又怎樣才算是client呢 ?

底下是書中的範例程式的一部份 :p467 : MulticastSniffer
我有幾個問題想要請教 :

  1. 據我所知,try {} ,catch{} , while(){} ,只要由{}包住的區域,在裡面的變數都是 區域變數,為何byte[] buffer=new byte[8192];是宣告在while(){}這個區域的外面而不是 while loop裡面呢?
    這個程式會在receive();的那一行block住,直到有資料過來,從buffer[0]開始存放, 一直存到buffer[8192]或者是存放到沒有資料送過來為止才會往下跑到下一行,這樣對嗎 ?
    那假使已經是第二輪的迴圈了,也就是說buffer中有上一輪的資料了,buffer中第一 輪的資料會被第二輪所取代嗎 ?
    假如會的話?
    那假設第一輪的資料比第二輪多的話,那我們在第二輪用println將他印出來的時候不 是也會印出第一輪的東西來嗎 ?
  2. 如果我們將 byte[] buffer = new byte[8192];移到while loop中的話是否可以 使得每依次迴圈的開始, buffer中的東西都是空的
    因為在while loop中每經過一輪,buffer就重新宣告.
  3. 這個程式在怎樣的情況下會執行到ms.leaveGroup(group);這一行呢?看起來好像流程永遠不會到那一行..

Soucrc code:
MulticastSocket ms = null;
  try {
   ms = new MulticastSocket(port);
   ms.joinGroup(group);

   byte[] buffer = new byte[8192];
   while (true) {
    DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
    ms.receive(dp);
    String s = new String(dp.getData());
    System.out.println(s);
   }
  }
  catch (IOException e) {
   System.err.println(e);
  }
  finally {
   if (ms != null) {
    try {
     ms.leaveGroup(group);
     ms.close();
    }
     catch (IOException e) {}
    }
   }

謝謝你們的回答....

cic


您好,
  關於收到群播封包的條件( router, ttl... ),作者已經說得很清楚了,
  那些源頭在美國的群播群組,台灣大概都收不到,
  所以只能測試那些區域網路上可能存在的群播封包,像是 DHCP, NTP, WINS ... 等等。
  由後者製造一些假信號給前者接收。( 參考中文第一版的p.382 )。
  大概只有需要跨越 router 的群播應用,才會指定 port (例如 sap.mcast.net9875 )。
  從 MulticastSocket 的 constructors 可以看出,用 port 或 SocketAddress 都可以建立 MulticastSocket :

  MulticastSocket(int port)
       Create a multicast socket and bind it to a specific port.

  MulticastSocket(SocketAddress bindaddr)
       Create a MulticastSocket bound to the specified socket address.

  會留在區域網路上,而且有正式定義的群播應用( DHCP, NTP ... ),都已經配發了固定位址,
  所以不必使用 port。你可以用 MulticastSocket(SocketAddress bindaddr) 來收/發這類群播的封包。

  server 通常有固定的位址或固定的 port,這樣 client 才知道要如何與 server 連線。
  當 client 向 server 發出 request 時,則是隨機挑選一個尚未使用的 port ( 通常在 1024 ~ 65535 之間),
  如果 package 是宣告成 com.oreilly.javaxml2 ,則 SAXTreeViewer   讓 server 知道 response 要回到 client 的哪一個 port。所以作者才會說 MulticastSocket()
  通常是給 client 使用,因為它會隨機挑選一個 port ( 用 getLocalPort() 可以得知實際配置的 port )。
  不管是 unicast 或 multicast,這觀念都是一樣的。以下是從我們的 web server 取得的畫面,
  如你所見,client ( 此例中的 218.163.52.123 )每次給的 port 都不固定,但是 server ( 211.23.29.123)
  則是固定的 port 80。

  [root@www ~]# netstat -nat
  Active Internet connections (servers and established)
  Proto   Recv-Q   Send-Q   Local Address       Foreign Address           State
   tcp      0        0       211.23.29.123:80    218.163.52.123:1464    TIME_WAIT
   tcp      0        0       211.23.29.123:80    218.163.52.123:1463   TIME_WAIT
   tcp      0        0       211.23.29.123:80    218.163.52.123:1462    TIME_WAIT
   tcp      0        0       211.23.29.123:80    218.163.52.123:1461    TIME_WAIT
   tcp      0        0       211.23.29.123:80    218.163.52.123:1460   TIME_WAIT
   tcp      0        0       211.23.29.123:80    218.163.52.123:1459   TIME_WAIT
   tcp      0        0       211.23.29.123:80    218.163.52.123:1458    TIME_WAIT
   tcp      0        0       211.23.29.123:80    218.163.52.123:1457    TIME_WAIT
   tcp      0        0       211.23.29.123:80    218.163.52.123:1456    TIME_WAIT
   tcp      0        0       211.23.29.123:80    218.163.52.123:1455   TIME_WAIT
   tcp      0        0       211.23.29.123:80    218.163.52.123:1454    TIME_WAIT
   tcp      0        0       211.23.29.123:80    218.163.52.123:1453    TIME_WAIT
   tcp      0        0       211.23.29.123:80    218.163.52.123:1452   TIME_WAIT
   tcp      0        0       211.23.29.123:80    218.163.52.123:1451    TIME_WAIT
   tcp      0        0       211.23.29.123:80    218.163.52.123:1450    TIME_WAIT
   tcp      0        0       211.23.29.123:80    218.163.52.123:1449    TIME_WAIT
   tcp      0        0       211.23.29.123:80    218.163.52.123:1448    TIME_WAIT
   tcp      0        0       211.23.29.123:80    218.163.52.123:1447   TIME_WAIT
   tcp      0        0       211.23.29.123:80    218.163.52.123:1446    TIME_WAIT
   tcp      0        0       211.23.29.123:80    218.163.52.123:1445    TIME_WAIT
   tcp      0        0       211.23.29.123:80    218.163.52.123:1444    TIME_WAIT

關於 p467 MulticastSniffer程式碼的問題 :

  1. 如果將 byte[] buffer = new byte[8192]; 放在 while 迴圈內,你的記憶體很快就不夠用了。
    所謂的區域變數是 "出了該區域才沒效的變數",在該區域內以及其子區域內都是有效的。
    receive() 的返回條件是 '收到一個完整封包' ,不管緩衝區有沒有滿。如果封包大於所給的緩衝區,多出來的資料就不見了。
    在第二輪時,由於給的是同樣的緩衝區,所以前一輪的資料會被蓋掉。填入緩衝區的是 DatagramPacket,這物件包含了封包長度的資訊,所以不會有你說的問題。
  2. 再次強調, " byte[] buffer = new byte[8192]; " 不是 '宣告',而是向 JVM 要求配置一塊 8 K 記憶體。
  3. 不管是離開 try{} 或是離開 catch{} ,都一定會執行 finally{}。在此例中,進入 try{} 之後,要等使用者按下 ctrl-c 才會中斷。如果在接收資料的過程中發生 I/O 異常,則會進入 catch{}。


林長毅 Technical Editor

| 首頁 | 聯絡我們 |
© 2009, O'Reilly Media, Inc. Taiwan Branch