Java網(wǎng)絡(luò)編程 - 05 基于UDP協(xié)議的網(wǎng)絡(luò)通信

導(dǎo)讀目錄
  • UDP協(xié)議的基礎(chǔ)
  • 使用DatagramSocket發(fā)送、接受數(shù)據(jù)
  • 使用MulticastSocket實(shí)現(xiàn)多點(diǎn)廣播
1.UDP協(xié)議的基礎(chǔ)

UDP(User Datagram Protocol, 用戶數(shù)據(jù)報(bào)協(xié)議)是一中不可靠的網(wǎng)絡(luò)協(xié)議,他在通信實(shí)例的兩端各建立一個(gè)Socket,但這兩個(gè)Socket之間并沒有虛擬鏈路,它們只是發(fā)送和接受數(shù)據(jù)包的對(duì)象。

UDP是面向非連接的協(xié)議,即在正式通信之前是不需要與對(duì)方先建立連接(即對(duì)對(duì)方的狀態(tài)不關(guān)心)。
UDP和TCP均位于IP協(xié)議之上。

UDP協(xié)議的主要作用是完成網(wǎng)絡(luò)數(shù)據(jù)流和數(shù)據(jù)報(bào)之間的轉(zhuǎn)換。發(fā)送時(shí):將網(wǎng)絡(luò)數(shù)據(jù)流封裝成數(shù)據(jù)報(bào),然后將數(shù)據(jù)報(bào)發(fā)送出去。接受端:將數(shù)據(jù)報(bào)轉(zhuǎn)換為實(shí)際內(nèi)容

使用DatagramSocket代表基于UDP協(xié)議的Socket
使用DatagramPacket代表要發(fā)送或接受的數(shù)據(jù)報(bào)

UDP和TCP相比:
(1)TCP協(xié)議:可靠,傳輸大小無限制,但是需要時(shí)間建立連接,差錯(cuò)控制開銷大
(2)UDP協(xié)議:不可靠,差錯(cuò)控制開銷小,傳輸大小限制在64KB以下,不需要建立連接

2.使用DatagramSocket發(fā)送、接受數(shù)據(jù)
(1)DatagramSocket

DatagramSocket不維護(hù)狀態(tài),不能產(chǎn)生IO流(前面講的Socket可以產(chǎn)生IO流),它的唯一所用就是接受和發(fā)送數(shù)據(jù)報(bào)(即DatagramPacket對(duì)象)

DatagramSocket的構(gòu)造器
DatagramSocket();//創(chuàng)建的DatagramSocket實(shí)例綁定到默認(rèn)的IP地址和系統(tǒng)隨機(jī)分配的端口
DatagramSocket(int port);//使用默認(rèn)的IP和指定的端口
DatagramSocket(int port, InetAddress laddr);//使用指定的IP和端口

DatagramSocket的收發(fā)數(shù)據(jù)報(bào)的方法
void receive(DatagramPacket p);//從該DatagramPacket中接受數(shù)據(jù)報(bào)
void send(DatagramPacket p);//以該DatagramPacket對(duì)象向外發(fā)送數(shù)據(jù)報(bào)

注意:DatagramSocket并知道數(shù)據(jù)報(bào)要發(fā)送到哪里,而是由DatagramPacket自身決定數(shù)據(jù)報(bào)的目的地。

(2)DatagramPacket

//創(chuàng)建接受數(shù)據(jù)一方的DatagramPacket對(duì)象
DatagramPacket(byte[] buf, int length);
DatagramPacket(byte[] buf, int offset, int length);

//創(chuàng)建發(fā)送數(shù)據(jù)一方的DatagramPacket對(duì)象,因?yàn)橐獍l(fā),因此是需要傳入IP地址和端口號(hào)的
DatagramPacket(byte[] buf, int length, InetAddress address, int port);
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)

由于服務(wù)器端(客戶端一樣)接收到一個(gè)DatagramPacket對(duì)象后,它是不知道誰發(fā)送過來的,因此可以調(diào)用DatagramPacket的如下方法:
(1)InetAddress getAddress();//如果程序準(zhǔn)備發(fā)送此數(shù)據(jù)報(bào)時(shí),該方法將返回此數(shù)據(jù)報(bào)的目標(biāo)IP地址;當(dāng)程序接受到一個(gè)數(shù)據(jù)報(bào)時(shí),該方法返回該數(shù)據(jù)報(bào)的來源主機(jī)的IP地址
(2)int getPort(); //同上,只是返回的是端口,
(3)SocketAddress getSocketAddress();//同上,只是返回的是SocketAddress, 該對(duì)象封裝了一個(gè)InetAddress對(duì)象和代表port的整數(shù)

(4)byte[] getData();//返回傳入Datagrampacket中的數(shù)組
(5)void setData(byte[] buf);//往byte[]數(shù)組中裝入數(shù)據(jù)
(6)void setData(byte[] buf, int offset, int length)
(7)int getLength();//返回讀入數(shù)組中的實(shí)際數(shù)據(jù)的長(zhǎng)度

事例
接收端

//創(chuàng)建一個(gè)DatagramSocket用于收發(fā)DatagramPacket數(shù)據(jù)報(bào)
DatagramSocket dmSocket = new DatagramSocket(3006);
//創(chuàng)建一個(gè)用于裝載數(shù)據(jù)的DatagramPacket
byte[] inBuff = new byte[1024];//為了防止放過來的數(shù)據(jù)比較長(zhǎng),因此將這個(gè)字節(jié)數(shù)組設(shè)置的盡量大些
DatagramPacket inPacket = new DatagramPacket(inBuff, inBuff.length);
//準(zhǔn)備接受收據(jù)報(bào)
while(true) {
    dmSocket.receive(inPacket);
    //程序執(zhí)行到這里時(shí)就可以通過inPacket來獲取一些關(guān)于發(fā)送端主機(jī)的信息,如IP地址、發(fā)送端口號(hào)等
    System.out.println(new String(inBuff, 0, inPacket.getLength()));
}

發(fā)送端

//創(chuàng)建一個(gè)DatagramSocket用于收發(fā)DatagramPacket數(shù)據(jù)報(bào)
DatagramSocket dgSocket = new DatagramSocket();
//創(chuàng)建一個(gè)用于裝載數(shù)據(jù)的DatagramPacket
byte[] outBuff = "string".getBytes();//將數(shù)據(jù)裝入DatagramPacket中
DatagramPacket outPacket = new DatagramPacket(outBuff, outBuff.length, InetAddress.getLocalHost(), 3006);
//發(fā)送數(shù)據(jù)
dgSocket.send(outPacket);
dgSocket.close();

注意:DatagramSocket只允許數(shù)據(jù)報(bào)發(fā)送給指定的目標(biāo)地址,而MulticastSocket可以將數(shù)據(jù)報(bào)以廣播的形式發(fā)送到多個(gè)客戶端

3.使用MulticastSocket實(shí)現(xiàn)多點(diǎn)廣播

參考博文:http://www.cnblogs.com/mengfanrong/p/3758308.html

(1)MulticastSocket的簡(jiǎn)潔

DatagramSocket僅僅同意數(shù)據(jù)報(bào)發(fā)送給指定的目標(biāo)地址,而MulticastSocket能夠?qū)?shù)據(jù)報(bào)以廣播的方式發(fā)送到多個(gè)client。 若要使用多點(diǎn)廣播,則須要讓一個(gè)數(shù)據(jù)報(bào)標(biāo)有一組目標(biāo)主機(jī)地址,當(dāng)數(shù)據(jù)報(bào)發(fā)出后,整個(gè)組的全部全部主機(jī)都能收到該數(shù)據(jù)報(bào)。IP多點(diǎn)廣播(或多點(diǎn)發(fā)送)實(shí)現(xiàn)了將單一信息發(fā)送到多個(gè)接受者的廣播,其思想是設(shè)置一組特殊網(wǎng)絡(luò)地址作為多點(diǎn)廣播地址,每個(gè)多點(diǎn)廣播地址都被看做一個(gè)組,當(dāng)client須要發(fā)送、接收廣播信息時(shí),增加到該組就可以。

應(yīng)用程序僅僅將數(shù)據(jù)報(bào)包發(fā)送給組播地址,路由器將確保包被發(fā)送到該組播組中的全部主機(jī)。

組播地址:稱為組播組的一組主機(jī)所共享的地址。組播地址的范圍在224.0.0.0--- 239.255.255.255之間(都為D類地址 1110開頭)。
備注:假設(shè)如今有三臺(tái)機(jī)器A、B、C,三臺(tái)機(jī)器IP地址都不一樣,A\B為server監(jiān)聽廣播消息,C為client發(fā)送廣播消息,個(gè)人理解是將A、B兩臺(tái)機(jī)器的MulticastSocket對(duì)象綁定在組播地址中的當(dāng)中一個(gè),然后C client發(fā)送消息的組播地址一致,則A、B就行接收C發(fā)送的消息。
假設(shè)MulticastSocket用于發(fā)送信息則使用默認(rèn)地址和隨機(jī)port就可以,可是假設(shè)用來接收信息,則必需要指定port,否則發(fā)送方無法確定發(fā)送數(shù)據(jù)報(bào)的目標(biāo)port。

MulticastSocket既能夠?qū)?shù)據(jù)報(bào)發(fā)送到多點(diǎn)廣播地址,也能夠接收其它主機(jī)的廣播信息

構(gòu)造器
MulticastSocket();//使用默認(rèn)的地址、隨機(jī)端口來創(chuàng)建MulticastSocket對(duì)象,適用于只發(fā)不收的情況下
MulticastSocket(int port);//;//使用默認(rèn)的地址、指定的端口來創(chuàng)建MulticastSocket對(duì)象,可發(fā)可收
MulticastSocket(SocketAddress bindaddr);//使用指定的地址和端口來創(chuàng)建MulticastSocket對(duì)象

方法
(1)joinGroup(InetAddress mcastaddr);//將該MulticastSocket加入指定的多點(diǎn)廣播地址
(2)joinGroup(SocketAddress mcastaddr, NetworkInterface netIf);//將該MulticastSocket加入指定的多點(diǎn)廣播地址,并指定網(wǎng)絡(luò)接口
(3)leaveGroup(InetAddress mcastaddr);//讓該MulticastSocket離開指定的多點(diǎn)廣播地址
(4)leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf);//讓該MulticastSocket離開指定的多點(diǎn)廣播地址,并指定網(wǎng)絡(luò)接口
(5)get/setInterface(InetAddress inf);
(6)get/setNetworkInterface(NetworkInterface netIf);//設(shè)置/獲取該MulticastSocket的網(wǎng)絡(luò)接口

注:
NetworkInterface 網(wǎng)絡(luò)接口類
什么是網(wǎng)絡(luò)接口:網(wǎng)絡(luò)接口名并非計(jì)算機(jī)名,而是用于標(biāo)識(shí)物理或邏輯網(wǎng)絡(luò)接口的名字,通常是由操作系統(tǒng)設(shè)置的。網(wǎng)絡(luò)接口名在大多數(shù)操作系統(tǒng)上(包含Windows、Linux和Unix)是以eth開頭,后面是網(wǎng)絡(luò)接口的索引號(hào),從0開始。如本機(jī)安了三塊網(wǎng)卡,那么網(wǎng)絡(luò)接口名就依次是eth0、eth1和eth2。每一個(gè)網(wǎng)絡(luò)接口都能夠綁定一個(gè)ip地址,也能夠據(jù)此得到設(shè)備的MAC地址。
方法:1. Enumeration<InetAddress> getInetAddresses():一個(gè) Enumeration 對(duì)象,具有綁定到此網(wǎng)絡(luò)接口的所有或部分 InetAddress

Java中InetAddress和InetSocketAddress的區(qū)別:
在Java中InetAddress和InetSocketAddress看起來很相似,用來描述IP地址和主機(jī)名稱。當(dāng)然,它們也支持使用常規(guī)方法來檢查地址:回環(huán)地址、本地地址、組播地址;基本的返回方法:獲得IP,獲得主機(jī)名稱等。

重要的是InetSocketAddress包含InetAddress。這意味著,如果我們想對(duì)InetSocketAddress中的InetAddress做任何操作,只需要通過getInetAddress()方法獲得即可。

對(duì)照表
屬性 InetAddress InetSocketAddress
描述對(duì)象 IP地址 Socket地址(IP地址+端口)
描述 IP和主機(jī)對(duì)象名稱 IP和主機(jī)的對(duì)象名稱,并包括端口號(hào)
解決問題 IP到主機(jī)名稱,主機(jī)名稱到IP IP到主機(jī)名稱,主機(jī)名稱到IP,可以包含端口
獲取對(duì)象 InetAddress.getLocalhost(); InetSocketAddress.createUnresolved(String, port);
InetAddress.getByName(String);
InetAddress.getByAddress(String);

參考自:http://blog.csdn.net/wo541075754/article/details/66971888

(2)實(shí)現(xiàn)多點(diǎn)廣播

1.創(chuàng)建MulticastSocket對(duì)象
2.將該MulticastSocket增加到指定的多點(diǎn)廣播地址:
joinGroup(InetAddress multicastAddr):將該MulticastSocket增加指定的多點(diǎn)廣播地址。
leaveGroup(InetAddress multicastAddr):讓該MulticastSocket離開指定的多點(diǎn)廣播地址。
3.創(chuàng)建相關(guān)的DatagramPacket,用于接受或發(fā)送數(shù)據(jù)
4.接受或發(fā)送數(shù)據(jù)

import java.net.MulticastSocket;
import java.net.InetAddress;
import java.net.DatagramPacket;
import java.io.*;
import java.util.*;
public class MulticastSocketTest implements Runnable {
    
    MulticastSocket mSocket = null;//創(chuàng)建MulticastSocket對(duì)象
    byte[] inBuff = new byte[1024];
    DatagramPacket inPacket = null;//創(chuàng)建相關(guān)的DatagramPacket,用于接受數(shù)據(jù)
    public void init() throws IOException { 
        //1.創(chuàng)建MulticastSocket對(duì)象
        mSocket = new MulticastSocket(3006);//指定端口號(hào),就可以收發(fā)數(shù)據(jù)
        //2.將該MulticastSocket加入到組播地址中
        InetAddress boradcastAddrss = InetAddress.getByName("230.0.0.1");
        mSocket.joinGroup(boradcastAddrss);
        //設(shè)置本MulticastSocket發(fā)送的數(shù)據(jù)報(bào)會(huì)被回送到自身
        mSocket.setLoopbackMode(false);//true表示不會(huì)回送
        //3.創(chuàng)建相關(guān)的DatagramPacket,用于接受數(shù)據(jù)
        inPacket = new DatagramPacket(inBuff, inBuff.length);
    
        //3.創(chuàng)建用于發(fā)送數(shù)據(jù)的DatagramPacket(這個(gè)可以在其他類中實(shí)現(xiàn),只是本類設(shè)計(jì)成了可以進(jìn)行收發(fā)的)
        DatagramPacket outPacket = new DatagramPacket(inBuff, inBuff.length, boradcastAddrss, 3006);
        
        new Thread(this).start();//開啟單獨(dú)的線程用于接受數(shù)據(jù)
        //下面是為了實(shí)現(xiàn)發(fā)送數(shù)據(jù)的邏輯
        Scanner sc = new Scanner(System.in);
        while(sc.hasNextLine()) {
            //將數(shù)據(jù)轉(zhuǎn)換為byte[]
            byte[] outBuff = sc.nextLine().getBytes();
            //設(shè)置發(fā)送用的DatagramSocket的數(shù)據(jù)
            outPacket.setData(outBuff);
            //4.發(fā)送數(shù)據(jù)
            mSocket.send(outPacket);
        }
    }

    public void run() { 
        try{
            while(true) {
                //4.等待接收數(shù)據(jù)
                mSocket.receive(inPacket);
                System.out.println(new String(inBuff, 0, inPacket.getLength()));
            }
        }catch(IOException ie) {
            ie.printStackTrace();
        }
    }
    //主方法
    public static void main(String[] args) throws IOException{
        new MulticastSocketTest().init();
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 個(gè)人認(rèn)為,Goodboy1881先生的TCP /IP 協(xié)議詳解學(xué)習(xí)博客系列博客是一部非常精彩的學(xué)習(xí)筆記,這雖然只是...
    貳零壹柒_fc10閱讀 5,210評(píng)論 0 8
  • 1 網(wǎng)絡(luò)編程----UDPNo25 【Scanner scanner =new Scanner(System....
    征程_Journey閱讀 510評(píng)論 0 0
  • 1.這篇文章不是本人原創(chuàng)的,只是個(gè)人為了對(duì)這部分知識(shí)做一個(gè)整理和系統(tǒng)的輸出而編輯成的,在此鄭重地向本文所引用文章的...
    SOMCENT閱讀 13,384評(píng)論 6 174
  • 簡(jiǎn)介 用簡(jiǎn)單的話來定義tcpdump,就是:dump the traffic on a network,根據(jù)使用者...
    保川閱讀 6,088評(píng)論 1 13
  • 1. 網(wǎng)絡(luò)編程概述 1.1 計(jì)算機(jī)網(wǎng)絡(luò) 是指將地理位置不同的具有獨(dú)立功能的多臺(tái)計(jì)算機(jī)及其外部設(shè)備,通過通信線路連接...
    JackChen1024閱讀 1,137評(píng)論 0 3

友情鏈接更多精彩內(nèi)容