成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

Java 網(wǎng)絡(luò)編程(2):UDP 的使用

learn_shifeng / 2679人閱讀

摘要:現(xiàn)在在本機(jī)同一局域網(wǎng)的一臺(tái)機(jī)器和阿里云主機(jī)上都運(yùn)行然后啟動(dòng)發(fā)送端接收端接收結(jié)果可以看到每個(gè)接收端都正確的接收了發(fā)送端發(fā)送的消息。

今天的主角是 UDP(User Datagram Protocol,用戶(hù)數(shù)據(jù)報(bào)協(xié)議)。
我們都知道 TCP 是一種可靠的協(xié)議 —— 首先客戶(hù)端和服務(wù)端需要建立連接(三次“握手”),數(shù)據(jù)發(fā)送完畢需要斷開(kāi)連接(四次“揮手”);如果發(fā)送數(shù)據(jù)時(shí)數(shù)據(jù)損壞或者丟失,那么 TCP 會(huì)重新發(fā)送。保證可靠的代價(jià)就是效率的降低(建立連接和斷開(kāi)連接就需要時(shí)間,保證數(shù)據(jù)的可靠性也需要額外的消耗)。與 TCP 相對(duì)應(yīng),UDP 是面向無(wú)連接的協(xié)議,并且它不保證數(shù)據(jù)是否會(huì)到達(dá),也不保證到達(dá)的數(shù)據(jù)是否準(zhǔn)確和數(shù)據(jù)順序是否正確 —— 所以相比于 TCP, UDP 的速度很快。在 需要不建立連接即可發(fā)送數(shù)據(jù) 的系統(tǒng),或者 保證最快的傳輸速度比每一位數(shù)據(jù)都正確更重要 的系統(tǒng)(如視頻會(huì)議,丟失某個(gè)數(shù)據(jù)包只是一個(gè)畫(huà)面或者聲音的小干擾)中,UDP 才是正確的選擇。實(shí)際上,在同一個(gè)網(wǎng)段,或者在信號(hào)很好的局域網(wǎng),UDP 是非??煽康?。

在 Java 中使用 UDP 時(shí)關(guān)鍵的兩個(gè)類(lèi)分別是:DatagramSocketDatagramPacket。
DatagramPacket 表示數(shù)據(jù)包,而 DatagrameSocket 用來(lái)發(fā)送和接收數(shù)據(jù)包。

發(fā)送數(shù)據(jù)包時(shí):

因?yàn)?UDP 協(xié)議并不需要建立連接,所以我們將數(shù)據(jù)(byte數(shù)組)放入 DatagramPacket 之后,還需要將目的地(IP地址和端口)放入到 DatagramPacket 中 —— DatagramSocket 的 send(DatagramPacket packet) 方法根據(jù) packet 中指定目的地,將其包含的數(shù)據(jù)往這個(gè)目的地發(fā)送。至于數(shù)據(jù)是否能(準(zhǔn)確)到達(dá)目的地,DatagramSocket 并不關(guān)心。

接收數(shù)據(jù)包時(shí):

DatagramSocket 在接收數(shù)據(jù)包時(shí),我們需要為其指定一個(gè)監(jiān)聽(tīng)的端口。當(dāng)有包含了接收端機(jī)器 IP 地址和 DatagramSocket 所監(jiān)聽(tīng)端口的數(shù)據(jù)包到達(dá)時(shí),DatagramSocket 的 receive(DatagramPacket packet) 方法便會(huì)對(duì)數(shù)據(jù)包進(jìn)行接收,并將接收到的數(shù)據(jù)包填入到 packet 中。

現(xiàn)在讓我們來(lái)實(shí)踐 DatagramSocket 和 DatagramPacket:
因?yàn)?UDP 沒(méi)有服務(wù)端和客戶(hù)端之分,所以我們把兩端分別定義為 發(fā)送端 和 接收端。
發(fā)送端代碼:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class UDPSender {

    private static final int RECVER_LISTENING_PORT = 9999;

    public static void main(String[] args) throws Exception {
        List messages = new ArrayList<>(12);
        for (int i = 0; i < 4; i++) {
            String msgBody = (i == 3 ? "" : "Hello UDP-" + i);

            DatagramPacket msg0 = parseMsg(
                    msgBody, "127.0.0.1", RECVER_LISTENING_PORT); // 發(fā)送給本機(jī)
            DatagramPacket msg1 = parseMsg(
                    msgBody, "192.168.3.3", RECVER_LISTENING_PORT); // 發(fā)送給同一局域網(wǎng)的一臺(tái)機(jī)器
            DatagramPacket msg2 = parseMsg(
                    msgBody, "120.77.**.***", RECVER_LISTENING_PORT); // 120.77.**.*** 是我阿里云主機(jī)的公網(wǎng) IP 地址

            // JDK1.5 時(shí) Collections 添加的 addAll 方法,可以一次往某個(gè)集合中添加多個(gè)元素
            Collections.addAll(messages, msg0, msg2, msg1);
        }

        startSending(messages);
    }

    private static void startSending(List messages)
            throws IOException, InterruptedException {

        // 無(wú)參構(gòu)造的 DatagramSocket 會(huì)隨機(jī)選擇一個(gè)端口進(jìn)行監(jiān)聽(tīng)
        // 因?yàn)榇藭r(shí) DatagramSocket 的作用是發(fā)送,所以無(wú)需顯式指定固定端口
        try (DatagramSocket socket = new DatagramSocket()) {
            System.out.println("隨機(jī)給發(fā)送端分配的端口為:" + socket.getLocalPort() + "
");
            
            for (DatagramPacket msg : messages) {
                socket.send(msg); // 發(fā)送數(shù)據(jù)包

                int recverPort = msg.getPort();
                InetAddress recverAddr = msg.getAddress();
                System.out.printf("消息已經(jīng)發(fā)送 -> (%s:%d)
",
                        recverAddr.getHostAddress(), recverPort);

                Thread.sleep(500); // 設(shè)定 每隔 0.5 秒發(fā)送一個(gè)消息
            }
        }
    }

    private static DatagramPacket parseMsg(String msgBody, String addr, int port)
            throws UnknownHostException {

        byte[] msgData = msgBody.getBytes();
        DatagramPacket msg = new DatagramPacket(
                msgData, 0, msgData.length, // 數(shù)據(jù)從位置 0 開(kāi)始,長(zhǎng)度為 msgData.length
                InetAddress.getByName(addr), port); // 目的地 地址為 addr,監(jiān)聽(tīng)端口為 port

        return msg;
    }

}

接收端代碼:

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

public class UDPReceiver {

    private static final int LISTENING_PORT = 9999;
    private static final int BUFFER_SIZE = 512;

    public static void main(String[] args) throws Exception {
        byte[] buffer = new byte[BUFFER_SIZE];
        DatagramPacket msg = new DatagramPacket(buffer, buffer.length);

        try (DatagramSocket socket = new DatagramSocket(LISTENING_PORT)) {
            System.out.println("接收端已經(jīng)啟動(dòng)...
");
            while (true) {
                socket.receive(msg); // 接收數(shù)據(jù)包

                String msgBody = new String(
                        msg.getData(), msg.getOffset(), msg.getLength());
                if (msgBody.isEmpty()) { // 發(fā)現(xiàn)接收的消息是空字符串("")便跳出循環(huán)
                    break;
                }

                int senderPort = msg.getPort();
                InetAddress senderAddr = msg.getAddress();

                System.out.printf("發(fā)送端 地址和端口 -> (%s:%d)
",
                        senderAddr.getHostAddress(), senderPort);

                System.out.println("發(fā)送端 發(fā)送的消息 -> " + msgBody + "
");
            }
        }

        System.out.println("接收端已經(jīng)關(guān)閉。");
    }
}

現(xiàn)在 在本機(jī)、同一局域網(wǎng)的一臺(tái)機(jī)器和阿里云主機(jī)上都運(yùn)行 UDPReceiver:

然后啟動(dòng)發(fā)送端 UDPSender:

接收端接收結(jié)果:

可以看到每個(gè)接收端都正確的接收了發(fā)送端發(fā)送的消息。

(本機(jī) 和 局域網(wǎng)機(jī)器 顯示的發(fā)送端的端口(49756)是一致的,但是遠(yuǎn)程機(jī)器即阿里云主機(jī)顯示的(4802)卻與他們不一致——這個(gè)問(wèn)題留給有興趣的讀者自己思考)

雖然 UDP 是不可靠的協(xié)議,但是因?yàn)樗恍枰⑦B接,效率更快,所以在 需要不建立連接即可發(fā)送數(shù)據(jù) 的系統(tǒng)(比如本文的例子),或者 保證最快的傳輸速度比每一位數(shù)據(jù)都正確更重要 的系統(tǒng)中,我們應(yīng)該使用 UDP。當(dāng)然,基于 UDP 我們同樣可以開(kāi)發(fā)出可靠的協(xié)議——數(shù)據(jù)包的正確與否可以交給應(yīng)用程序來(lái)判斷,如果有問(wèn)題接收端便提示發(fā)送端重新發(fā)送。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/69833.html

相關(guān)文章

  • Java015-網(wǎng)絡(luò)編程

    摘要:具備發(fā)送和接受功能,在進(jìn)行傳輸時(shí),需要明確一個(gè)是發(fā)送端,一個(gè)是接收端。指定發(fā)送端口,不指定系統(tǒng)會(huì)隨機(jī)分配。傳輸兩個(gè)端點(diǎn)的建立連接后會(huì)有一個(gè)傳輸數(shù)據(jù)的通道,這通道稱(chēng)為流,而且是建立在網(wǎng)絡(luò)基礎(chǔ)上的流,稱(chēng)之為流。 端口:物理端口:邏輯端口: 用于標(biāo)識(shí)進(jìn)程的邏輯地址,不同進(jìn)程的標(biāo)識(shí);有效端口:0~65535,其中0~1024系統(tǒng)使用或保留端口。 java 中ip對(duì)象:InetAddress....

    Blackjun 評(píng)論0 收藏0
  • JAVA網(wǎng)絡(luò)程序設(shè)計(jì)基礎(chǔ)(筆記)

    摘要:三端口與套接字端口指一臺(tái)計(jì)算機(jī)只有單一的連接到網(wǎng)絡(luò)的物理連接,所以的數(shù)據(jù)都通過(guò)此連接對(duì)內(nèi)對(duì)外送達(dá)特定的計(jì)算機(jī),這就是端口。三程序設(shè)計(jì)由上面可知基于的信息傳遞速度更快。接收數(shù)據(jù)包使用創(chuàng)建數(shù)據(jù)包套接字,綁定指定端口。 服務(wù)器 網(wǎng)絡(luò) 客戶(hù)機(jī) 第一部分 一.局域網(wǎng)與因特網(wǎng) 服務(wù)器是指提供信息的計(jì)算機(jī)或程序,...

    PAMPANG 評(píng)論0 收藏0
  • Java網(wǎng)絡(luò)編程(3):使用 UDP 探測(cè)局域網(wǎng)內(nèi)特定類(lèi)型機(jī)器

    摘要:那沒(méi)有建立連接的情況下,發(fā)現(xiàn)房間這個(gè)功能是怎么實(shí)現(xiàn)的呢首先,既然手機(jī)處于局域網(wǎng)中,那么根據(jù)手機(jī)當(dāng)前在局域網(wǎng)的地址和子網(wǎng)掩碼,就可以獲得這個(gè)局域網(wǎng)內(nèi)所有機(jī)器的地址的范圍。 記得以前我們使用類(lèi)似快牙這些文件分享工具的時(shí)候,一開(kāi)始就是先在 手機(jī)A 上創(chuàng)建一個(gè)房間,然后連接上 手機(jī)A WiFi 熱點(diǎn)的其他手機(jī)(即這些手機(jī)處于一個(gè)局域網(wǎng)內(nèi))就可以發(fā)現(xiàn)到這個(gè)房間并加入到這個(gè)房間里面,然后就可以互相...

    focusj 評(píng)論0 收藏0
  • Java Socket編程UDP編程

    摘要:更多資料請(qǐng)看編程之編程協(xié)議用戶(hù)數(shù)據(jù)報(bào)協(xié)議是無(wú)連接的不可靠的無(wú)序的速度快進(jìn)行數(shù)據(jù)傳輸時(shí),首先將要傳輸?shù)臄?shù)據(jù)定義成數(shù)據(jù)報(bào),大小限制在,在數(shù)據(jù)報(bào)中指明數(shù)據(jù)索要達(dá)到的主機(jī)地址和端口號(hào),然后再將數(shù)據(jù)報(bào)發(fā)送出去類(lèi)表示數(shù)據(jù)報(bào)包類(lèi)進(jìn)行端到端通信的類(lèi)服務(wù)器端 更多資料請(qǐng)看:https://www.yuque.com/shizhiy... Java Socket編程之UDP編程 UDP協(xié)議(用戶(hù)數(shù)據(jù)報(bào)協(xié)...

    ityouknow 評(píng)論0 收藏0
  • 1、網(wǎng)絡(luò)三要素及傳輸協(xié)議 2、實(shí)現(xiàn)UDP協(xié)議發(fā)送端和接收端 3、實(shí)現(xiàn)TCP協(xié)議客戶(hù)端和服務(wù)器 4

    摘要:應(yīng)用層主要負(fù)責(zé)應(yīng)用程序的協(xié)議,例如協(xié)議協(xié)議等。在計(jì)算機(jī)中,不同的應(yīng)用程序是通過(guò)端口號(hào)區(qū)分的。區(qū)別在于,中只有發(fā)送端和接收端,不區(qū)分客戶(hù)端與服務(wù)器端,計(jì)算機(jī)之間可以任意地發(fā)送數(shù)據(jù)。 01網(wǎng)絡(luò)模型 *A:網(wǎng)絡(luò)模型 TCP/IP協(xié)議中的四層分別是應(yīng)用層、傳輸層、網(wǎng)絡(luò)層和鏈路層,每層分別負(fù)責(zé)不同的通信功能,接下來(lái)針對(duì)這四層進(jìn)行詳細(xì)地講解。 鏈路層:鏈路層是用于定義物理傳輸通道,通常是對(duì)...

    CastlePeaK 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<