2020久久超碰欧美精品最新亚洲欧美日韩久久精品,国产福利电影一区二区三区,亚洲欧美日韩一区在线观看,亚洲国产欧美日韩欧美特级,亚洲欧美日韩成人一区久久,欧美日韩精品一区二区三区不卡,国产欧美日韩va另类影音先锋,亚洲欧美日韩久久精品,亚洲欧美日韩国产成人精品影院,亚洲国产欧美日韩精品一区二区三区,欧美日韩国产成人高清视频,日韩久久精品国产免费观看频道,久久人人爽人人爽从片av高清,国产精品综合一区二区

首頁技術文章正文

Java培訓:UDP實現群聊聊天室

更新時間:2022-09-16 來源:黑馬程序員 瀏覽量:

  大家好,今天為大家帶來了一個非常有意思的小程序——UDP實現的群聊聊天室。這個程序使用的UDP協議,并使用DatagramSocket的子類MulticastSocket實現組播,可以部署在一個局域網內的多臺電腦上,并可以實現文字群聊。

   本文將會按照以下幾個小節講解:

   1). 組播的概念:**這個小節我們將講解什么是:單播、廣播、組播。

   2). MulticastSocket類的使用:**這個小節我們將講解MulticastSocket類的基本使用,并實現控制臺的信息收發。

   3). 基于Swing和MulticastSocket實現的UDP群聊聊天室:**這個小節我們將制作一個界面,并結合MulticastSocket類實現一個完整的UDP群聊聊天室。

   4). 結束語:

  一、組播的概念

   網絡數據傳播按照接收者的數量,可分為以下3種方式:

  1.1 單播:

   單播是指實現“點對點”的通信,發送者發送數據要發送給網絡上的唯一的一臺電腦,指定一個接收者。像TCP協議和UDP協議都能實現點對點通信。

  1.2 廣播:

   發送者發送的數據可以被某個接收范圍內所有的接收者接收。它類似于廣播電臺,向某個范圍內的所有用戶發送廣播信號,接收人打開廣播就可以聽到,關閉廣播設備就停止收聽。由于廣播會大大增加網絡數據流量,所以通常情況下一些網絡路由器會禁止廣播數據,尤其是一些占用網絡資源比較大的視頻數據等。

  1.3 組播:

   組播是指發送的數據可以被指定的一組用戶接收。組播的范圍沒有廣播那么廣,任何的一臺電腦都可以隨時加入某一個組接收組播數據。若要使用組播,則需要讓一個數據報標有一組目標主機地址,當數據報發出后,整個組的所有主機都能收到該數據報。IP協議為組播提供了這批特殊的IP地址,這些IP地址的范圍是224.0.0.0至239.255.255.255。在Java類庫中,DatagramSocket有一個子類:MulticastSocket,它具有組播的功能,它可以與DatagramPackage結合使用,用于發送和接收組播包。

  二. MulticastSocket類的使用

   Java類庫中MulticastSocket類可以實現組播功能,它是DatagramSocket的子類:

1663291462281_1.jpg

  2.1 構造方法說明

   通過API文檔我們可以看到它有三個構造方法:

1. MulticastSocket() 創建一個多播套接字。(使用隨機端口,如果只發送,可以使用這個構造方法)
2. MulticastSocket(int port) 創建一個多播套接字并將其綁定到一個特定的端口。(如果需要發送和接收,需要使用這個構造方法)
3. MulticastSocket(SocketAddress bindaddr) 創建一個多播套接字綁定到指定的套接字地址。

  2.2 成員方法說明

   以下是幾個比較重要的成員方法:

1.public void joinGroup(InetAddress mcastaddr):將該MulticastSocket加入指定的多點廣播地址。
2.public void leaveGroup(InetAddress mcastaddr讓該MulticastSocket離開指定的多點廣播地址。
3.public void setInterface(InetAddress inf):如果當前系統有多個網絡接口,可以使用次方法指定一個網絡接口。
4.public InetAddress getInterface():獲取當前的網絡接口。
5.public void setTimeToLive(int ttl):該參數設置數據報最多可以跨過多少個網絡,當ttl為0時,指定數據報應停留在本地主機;當ttl的值為1時,指定數據報發送到本地局域網;當ttl的值為32時,意味著只能發送到本站點的網絡上;當ttl為64時,意味著數據報應保留在本地區;當ttl的值為128時,意味著數據報應保留在本大洲;當ttl為255時,意味著數據報可發送到所有地方;默認情況下,該ttl的值為1。

  2.3 一個簡單的示例

   接下來我們寫一個小例子來看一下MulticastSocket的使用方式。這個程序將包含兩個線程:1. 接收線程,主要用于接收信息;2. 主線程,主要用于發送信息。將這個程序部署到局域網上的幾臺電腦上,全部啟動,就可以實現多臺電腦的組播了,而且每臺主機都可以發出信息,其它主機則會收到這條信息。

package com.heima.se.chat;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.util.Date;
import java.util.Scanner;

public class MulticastSocketDemo {
    public static void main(String[] args) throws IOException {
        //創建MuticastSocket對象,并監聽端口55555
        MulticastSocket socket = new MulticastSocket(55555);
        //加入組:235.235.235.235
        socket.joinGroup(InetAddress.getByName("235.235.235.235"));

        //啟動線程-此線程用于接收數據報
        new Thread(()->{
            byte[] bytes = new byte[1024];
            DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
            while (true) {
                try {
                    socket.receive(packet);
                    System.out.println(new String(packet.getData(), 0, packet.getLength()));

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        //獲取本機IP
        String localIp = InetAddress.getLocalHost().getHostAddress();

        //創建一個Scanner對象,用于接收控制臺數據
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("【請輸入信息】");
            String msg = sc.next();
            // 獲取當前時間格式化字符串,把IP、時間,以及要發送的文本連接在一起
            String time = String.format(" <====> %tF %<tT", new Date());
            msg = localIp + time + "\n" + msg + "\n\n";
            //發送數據報
            socket.send(new DatagramPacket(msg.getBytes(),
                                            msg.getBytes().length,
                                            InetAddress.getByName("235.235.235.235"),
                                            55555));
        }
    }
}

  通過上面的程序,我們發現,MulticastSocket類的使用和DatagramSocket類基本相同,只是多了一步加入組:joinGroup(),所有加入這個組的主機都將會收到信息。

  三. 基于Swing和MulticastSocket實現的UDP群聊聊天室

   接下來我們使用Swing為這個程序制作一個界面,讓用戶操作起來更加方便。

   這個程序我們制作了兩個類:

   1). ChatFrame:這個類繼承自JFrame,實現了界面的顯示、布局等相關功能。

   2). SocketChat:這個類繼承自ChatFrame,加入了MulticastSocket的連接、信息發送和接收。

  3.1 界面ChatFrame類

package com.heima.se.chat;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.net.InetAddress;

public abstract class ChatFrame extends JFrame {
    private JTextArea receiveArea = new JTextArea();//接收文本框,用來顯示服務器發送過來的文本
    private JTextArea sendArea = new JTextArea();//發送文本框,用來顯示當前用戶要發送的文本

    private JButton sendBtn = new JButton("SEND");//發送按鍵

    public ChatFrame() {
        this.initFrame();//初始化窗口
        this.initComponent();//初始化組件
        this.initListener();//初始化監聽器
        this.receive();//開啟監聽服務器線程,把接收到的文本顯示在receiveArea中
    }

    // 初始化監聽器
    private void initListener() {
        // 給發送按鍵添加監聽器,當被點擊時調用send()方法
        sendBtn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                send();
            }
        });

        // 給發送文本框添加鍵盤監聽器,當按下Ctrl+ENTER時調用send()方法
        sendArea.addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent e) {
                if(e.isControlDown()) {
                    if(e.getKeyCode() == KeyEvent.VK_ENTER) {
                        send();
                    }
                }
            }
        });
    }

    // 子類需要重寫本方法
    // 在本方法中使用socket實現消息發送
    public abstract void sendText(String text);

    // 子類需要重寫本方法
    // 在本方法中啟動監聽服務器線程,調用本類receiveText(String)把接收到的文本顯示出來
    public abstract void receive();

    // 本方法用來發送文本
    public void send() {
        // 如果發送文本框中沒有文本,彈出警告對話框
        if(sendArea.getText().equals("")) {
            javax.swing.JOptionPane.showMessageDialog(this, "空文本不能發送!");
            sendArea.requestFocus();// 把光標歸還給發送文本框
            return;
        }

        // 調用子類的方法完成文本發送
        sendText(sendArea.getText());
        // 把發送文本框內容清空
        sendArea.setText(null);
    }

    // 本方法完成接收服務器消息的后續工作-在文本框中顯示服務器消息,子類的receive()方法在接收服務器消息后可以調用本方法
    public void receiveText(String text) {
        receiveArea.append(text);//把接收到的消息添加到文本框中
        // 設置光標位置到最后,如果不設置滾動條不動
        receiveArea.setCaretPosition(receiveArea.getText().length());
    }

    // 初始化組件
    private void initComponent() {
        // 使用接收文本框創建滾動窗口(把文本框添加到了滾動窗口中),總是顯示縱向滾動條,永不顯示橫向滾動條
        JScrollPane sp1 = new JScrollPane(receiveArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        // 設置滾動窗口大小、位置、無邊框;并把滾動窗口添加到主窗口中
        sp1.setSize(606, 350);
        sp1.setLocation(14, 20);
        sp1.setBorder(null);
        this.add(sp1);

        // 設置接收文本框背景色、不可編輯、自動換行
        receiveArea.setBackground(new Color(238, 238, 238));
        receiveArea.setEditable(false);
        receiveArea.setLineWrap(true);

        // 創建發送文本框的滾動窗口,設置自動換行、大小、位置,然后添加到主窗口中
        JScrollPane sp2 = new JScrollPane(sendArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        sendArea.setLineWrap(true);
        sp2.setSize(606, 145);
        sp2.setLocation(14, 400);
        this.add(sp2);

        // 設置發送按鍵的大小、位置,并添加到主窗口中
        sendBtn.setSize(68, 21);
        sendBtn.setLocation(553, 560);
        this.add(sendBtn);

        // 設置主窗口的標題為當前IP地址
        try {
            this.setTitle(InetAddress.getLocalHost().getHostAddress());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    // 初始化主窗口
    private void initFrame() {
        // 設置主窗口的大小、布局管理器為空、背景色、位置、大小不可改變
        this.setSize(640, 620);
        this.setLayout(null);
        this.setBackground(new Color(246, 246, 247));
        this.setLocation(350, 50);
        this.setResizable(false);

        // 設置主窗口的“X”按鈕點擊后結束程序
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    // 顯示主窗口方法
    public void setVisible(boolean b) {
        super.setVisible(b);//調用父類的顯示方法
        sendArea.requestFocus();//讓發送文本框得到焦點
    }
}

  這個類中定義了很多抽象方法,這些抽象方法由子類實現。

  3.2 組播聊天SocketChat類

package com.heima.se.chat;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.util.Date;

/**
 * 本類繼承了ChatFrame,ChatFrame實現了GUI顯示
 * 本類負責使用MulticastSocket完成群聊的發送消息與接收消息
 */
public class SocketChat extends ChatFrame {
    private MulticastSocket socket;//群組Socket

    public SocketChat() throws IOException {
        socket = new MulticastSocket(54321);//創建群組Socket,綁定54321端口
        //加入虛擬IP:235.235.235.235指定的群組中。虛擬IP范圍是:224.0.0.1 和 239.255.255.255
        //加入群組后,就可以接收群組的消息,也可以向群組發送消息了
        socket.joinGroup(InetAddress.getByName("235.235.235.235"));
    }

    // 發送消息方法
    public void sendText(String text) {
        try {
            // 獲取IP地址
            String ip = InetAddress.getLocalHost().getHostAddress();
            // 獲取當前時間格式化字符串
            String time = String.format(" <====> %tF %<tT", new Date());
            // 把IP、時間,以及要發送的文本連接在一起
            text = ip + time + "\n" + text + "\n\n";
            // 把文本轉換成字節數組
            byte[] buff = text.getBytes();
            // 使用socket向群組發送,socket的send()方法需要兩個參數:DatagramPacket、端口號
            // DatagramPacket表示數據包,創建它需要三個參數:數據包的內容、數據包的字節數、要發送的IP地址
            socket.send(new DatagramPacket(buff, buff.length, InetAddress.getByName("235.235.235.235"), 54321));
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    // 本方法用來接收群組發送過來的消息
    public void receive() {
        // 創建監聽群組消息的線程,并啟動它
        new Thread() {
            public void run() {
                // 循環監聽
                while(true) {
                    try {
                        // 創建數據包的字節數組,大小為1KB
                        byte[] buff = new byte[1024];
                        // 創建數據包
                        DatagramPacket dp = new DatagramPacket(buff, buff.length);
                        // 接收群組發送過來的消息到數據包中
                        // 本方法會阻塞當前線程,直到接收到消息為止
                        socket.receive(dp);
                        // 把接收到的消息轉換成字符串
                        String text = new String(dp.getData(), 0, dp.getLength());
                        // 調用父類的方法完成顯示
                        receiveText(text);
                    } catch(Exception e) {}
                }
            }
        }.start();
    }

    public static void main(String[] args) throws IOException {
        SocketChat sc = new SocketChat();
        sc.setVisible(true);
    }
}

  這個類使用MulticastSocket,使用端口:54321,組播地址:235.235.235.235。當用戶在界面按下send按鈕時,會觸發sendText()方法發送數據;receive()方法用于使用線程接收數據,它是在父類的構造方法中被觸發啟動,啟動后,使用無限循環進行信息的接收。

  四.結束語

   這篇文章我們使用MulticastSocket類實現了組播功能,并使用Swing和MulticastSocket制作了一個基于UDP的群聊聊天室,希望大家能夠通過本篇文章了解MulticastSocket類的使用,有興趣的朋友可以基于這個程序,為它添加更多的功能,例如:文件的發送、接收;表情圖片的發送、接收等等。后面我還會為大家帶來更多更實用的程序,期待大家來圍觀哦!謝謝大家!!

分享到:
在線咨詢 我要報名
和我們在線交談!