Cyh的博客

          Email:kissyan4916@163.com
          posts - 26, comments - 19, trackbacks - 0, articles - 220

          網絡編程>>UDP編程

          Posted on 2009-12-17 22:59 啥都寫點 閱讀(862) 評論(0)  編輯  收藏 所屬分類: J2SE
            上面的例子都用Socket建立連接,屬于TCP(Transmission Control Protocol)連接,本節實例實現UDP(User Data Protocol)編程,包括發送和接收UDP報文。 首先來看看UDP與TCP的區別:

            TCP是基于連接的協議,也就是說,在正式收發數據前,必須和對方建立可靠的連接,這與打電話的機制相似。在前面幾節的編程中,客戶端都與服務器請求建立Socket連接,當服務器端的ServerSocket的accept方法接受連接時,客戶端與服務器的連接便確立了,由于要事先建立好連接,所以用TCP傳輸數據速度相對比較慢,但是比較穩定。
            UDP是面向非連接的協議,也就是說,在正式通信前不必與對方先建立連接,不管對方狀態就直接發送,這與用手機發短信的機制非常相似。由于不用建立連接,所以傳輸速度比較快,但是傳輸的可靠性較差。

          在Java中實現UDP編程的關鍵技術如下:

            java.net.DatagramSocket和java.net.DatagramPacket類可以實現UDP編程,前者實現與目標機的連接(這種連接不需要目標主機的認可),后者用于封裝UDP包。
            發送UDP包時,先將數據包裝成DatagramPacket對象,然后建立一個DatagramSocket,調用它的send方法,將DatagramPacket發送給目標主機
            收取UDP包時,建立一個偵聽本地端口的DatagramSocket,創建一個空的DatagramPacket對象,以存放收到的報文,調用DatagramSocket的receive方法將收到的UDP包寫入到DatagramPacket對象中。
            DatagramPacket 的getAddress方法能獲得UDP消息發送者的網絡地址信息。

          /** */

          import java.net.DatagramPacket;
          import java.net.DatagramSocket;

          /**
           * 該程序接收來自指定端口得UDP報文。
           *
          */

          public class UDPReceive {
              
          // 幫助信息
              public static final String usage = "Usage: java book.net.udp.UDPReceive <port>";

              
          public static void main(String args[]) {
                  
          try {
                      
          if (args.length != 1){
                          
          throw new IllegalArgumentException("Wrong number of args");
                      }

                      
          // 從命令行中獲取端口號參數
                      int port = Integer.parseInt(args[0]);

                      
          // 創建一個socket,偵聽這個端口。
                      DatagramSocket dsocket = new DatagramSocket(port);

                      
          // 保存接收到的UDP報文的字節數組
                      byte[] buffer = new byte[2048];

                      
          // 創建一個DatagramPacket,將收到的報文寫入buffer中。
                      
          // 注意,這里指定了報文的長度,如果收到的UDP報文比2048大,多余的信息被舍棄
                      DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

                      
          // 不斷循環,接收數據
                      for ( ; ;) {
                          
          // 等待收到一個數據包
                          dsocket.receive(packet);

                          
          // 將收到的報文的字節數組封裝成字符串。
                          String msg = new String(buffer, 0, packet.getLength());
                          
          // 從數據包中取得消息來源的地址
                          System.out.println("Receive: " + packet.getAddress().getHostAddress() + ""
                                  
          + msg);

                          
          // 如果收到QUIT指令,則退出循環。
                          if (msg.equals("QUIT")){
                              System.out.println(
          "Exit the UDPReceive!");
                              
          break;
                          }

                          
                          
          // 重設數據包的長度
                          packet.setLength(buffer.length);
                      }

                      
          // 關閉socket
                      dsocket.close();
                  }
           catch (Exception e) {
                      System.err.println(e);
                      System.err.println(usage);
                  }

              }

          }




          /**--------------------------------------------UDPSend.java---------------------------------------------------*/


          import java.io.File;
          import java.io.FileInputStream;
          import java.net.DatagramPacket;
          import java.net.DatagramSocket;
          import java.net.InetAddress;

          /**
           * 該實例實現一個發送UDP報文的類。
           * UDP與TCP不同在于,UDP在發送報文前無需建立連接,直接發送;而TCP需要建立連接。
           * 即TCP比UDP更可靠。另外,UDP報文會出現舍棄的情況,因為發送端和接收端的報文大小可能不一致。
           * 體現在編程時,UDP編程無需ServerSocket和Socket,只需要DatagramSocket類即可。
           *
          */

          public class UDPSend {
              
          public static final String usage = 
              
          "Usage: java book.net.udp.UDPSend <hostname> <port> <msg>\n" +
              
          "   or: java book.net.udp.UDPSend <hostname> <port> -f <file>";

              
          public static void main(String args[]) {
                  
          try 
                      
          // 檢查參數個數
                      if (args.length < 3)
                          
          throw new IllegalArgumentException("Wrong number of args");
                      }

                      
                      
          // 域名和端口
                      String host = args[0];
                      
          int port = Integer.parseInt(args[1]);
                  
                      
          // 下面構造待發送報文的字節數組  
                      byte[] message;
                      
          if (args[2].equals("-f")) {
                          
          // 如果第三個參數為 -f,則表示將文件的內容以UDP方式發送
                          
          // 獲得待發送的文件對象以及文件的長度
                          File f = new File(args[3]);
                          
          int len = (int)f.length(); 
                          
          // 創建一個足夠容納文件內容的字節數組
                          message = new byte[len]; 
                          FileInputStream in 
          = new FileInputStream(f);
                          
          // 將文件內容以字節的方式讀到字節數組中
                          int bytes_read = 0, n;
                          
          do {
                              n 
          = in.read(message, bytes_read, len-bytes_read);
                              bytes_read 
          += n;
                          }
           while((bytes_read < len)&& (n != -1));
                      }

                      
          else 
                          
          // 如果第三個參數不是 -f,則將后面的參數當作消息發送
                          String msg = args[2];  
                          
          for (int i = 3; i < args.length; i++){
                              msg 
          += " " + args[i];
                          }

                          message 
          = msg.getBytes();
                      }

                      
                      
          // 根據域名獲取IP地址
                      InetAddress address = InetAddress.getByName(host);
                  
                      
          // 初始化一個UDP包。
                      
          // DatagramPacket的構造方法中必須使用InetAddress,而不能是IP地址或者域名
                      DatagramPacket packet = new DatagramPacket(message, message.length,
                                         address, port);
                  
                      
          // 創建一個DatagramSocket,以發送UDP包
                      DatagramSocket dsocket = new DatagramSocket();
                      dsocket.send(packet);
                      System.out.println(
          "send: " + new String(message));
                      dsocket.close();
                      
                      
          // 注意:如果在構造DatagramPacket時,不提供IP地址和端口號,
                      
          // 則需要調用DatagramSocket的connect方法,否則無法發送UDP包
                      packet = new DatagramPacket(message, message.length);
                      dsocket 
          = new DatagramSocket();
                      dsocket.connect(address, port);
                      dsocket.send(packet);
                      System.out.println(
          "Send: " + new String(message));
                      dsocket.close();
                      
                  }
           catch (Exception e) {
                      System.err.println(e);
                      System.err.println(usage);
                  }

              }

          }



          首先在命令行中輸入“java book.net.udp.UDPReceive 8888”,以啟動UDPReceive進程,接收來自8888端口的UDP報文,然后另開一個命令行,輸入"java book.net.udp.UDPSend 127.0.0.1 8888 This is the UDP message!" ,將發送一條消息給本地的8888端口。接著再發送一條“QUIT”消息,停止UDPReceive 進程。  





                                                                                                                 --    學海無涯
                  

          主站蜘蛛池模板: 如皋市| 尤溪县| 南宫市| 黄龙县| 吕梁市| 白河县| 黄陵县| 双桥区| 大同县| 临桂县| 阳谷县| 高要市| 扎兰屯市| 博罗县| 白朗县| 从江县| 永济市| 桑日县| 沽源县| 沾化县| 木兰县| 朝阳市| 广平县| 花莲市| 军事| 镇康县| 高州市| 石屏县| 黄冈市| 乌兰察布市| 阿拉善左旗| 翼城县| 旬阳县| 嫩江县| 略阳县| 孝昌县| 贵德县| 诸暨市| 萍乡市| 渭源县| 盱眙县|