Java使用MulticastSocket實(shí)現(xiàn)群聊應(yīng)用程序
本文實(shí)例為大家分享了Java使用MulticastSocket實(shí)現(xiàn)群聊應(yīng)用程序的具體代碼,供大家參考,具體內(nèi)容如下
在這篇文章中,討論了一個(gè)使用 MulticastSocket (Java Platform SE 7) 類的群聊應(yīng)用程序。MulticastSocket 是一個(gè) (UDP) DatagramSocket,具有加入 Internet 上其他多播主機(jī)“組”的附加功能。
import java.net.*; import java.io.*; import java.util.*; ? public class GroupChat { ?? ?private static final String TERMINATE = "Exit"; ?? ?static String name; ?? ?static volatile boolean finished = false; ? ?? ?public static void main(String[] args) { ?? ??? ?if (args.length != 2) ?? ??? ??? ?System.out.println("Two arguments required: <multicast-host> <port-number>"); ?? ??? ?else { ?? ??? ??? ?try { ?? ??? ??? ??? ?InetAddress group = InetAddress.getByName(args[0]); ?? ??? ??? ??? ?int port = Integer.parseInt(args[1]); ?? ??? ??? ??? ?Scanner sc = new Scanner(System.in); ?? ??? ??? ??? ?System.out.print("Enter your name: "); ?? ??? ??? ??? ?name = sc.nextLine(); ?? ??? ??? ??? ?MulticastSocket socket = new MulticastSocket(port); ? ?? ??? ??? ??? ?// Since we are deploying ?? ??? ??? ??? ?socket.setTimeToLive(0); ?? ??? ??? ??? ?// this on localhost only (For a subnet set it as 1) ? ?? ??? ??? ??? ?socket.joinGroup(group); ?? ??? ??? ??? ?Thread t = new Thread(new ReadThread(socket, group, port)); ? ?? ??? ??? ??? ?// Spawn a thread for reading messages ?? ??? ??? ??? ?t.start(); ? ?? ??? ??? ??? ?// sent to the current group ?? ??? ??? ??? ?System.out.println("Start typing messages...\n"); ?? ??? ??? ??? ?while (true) { ?? ??? ??? ??? ??? ?String message; ?? ??? ??? ??? ??? ?message = sc.nextLine(); ?? ??? ??? ??? ??? ?if (message.equalsIgnoreCase(GroupChat.TERMINATE)) { ?? ??? ??? ??? ??? ??? ?finished = true; ?? ??? ??? ??? ??? ??? ?socket.leaveGroup(group); ?? ??? ??? ??? ??? ??? ?socket.close(); ?? ??? ??? ??? ??? ??? ?break; ?? ??? ??? ??? ??? ?} ?? ??? ??? ??? ??? ?message = name + ": " + message; ?? ??? ??? ??? ??? ?byte[] buffer = message.getBytes(); ?? ??? ??? ??? ??? ?DatagramPacket datagram = new DatagramPacket(buffer, buffer.length, group, port); ?? ??? ??? ??? ??? ?socket.send(datagram); ?? ??? ??? ??? ?} ?? ??? ??? ?} catch (SocketException se) { ?? ??? ??? ??? ?System.out.println("Error creating socket"); ?? ??? ??? ??? ?se.printStackTrace(); ?? ??? ??? ?} catch (IOException ie) { ?? ??? ??? ??? ?System.out.println("Error reading/writing from/to socket"); ?? ??? ??? ??? ?ie.printStackTrace(); ?? ??? ??? ?} ?? ??? ?} ?? ?} } ? class ReadThread implements Runnable { ?? ?private MulticastSocket socket; ?? ?private InetAddress group; ?? ?private int port; ?? ?private static final int MAX_LEN = 1000; ? ?? ?ReadThread(MulticastSocket socket, InetAddress group, int port) { ?? ??? ?this.socket = socket; ?? ??? ?this.group = group; ?? ??? ?this.port = port; ?? ?} ? ?? ?@Override ?? ?public void run() { ?? ??? ?while (!GroupChat.finished) { ?? ??? ??? ?byte[] buffer = new byte[ReadThread.MAX_LEN]; ?? ??? ??? ?DatagramPacket datagram = new DatagramPacket(buffer, buffer.length, group, port); ?? ??? ??? ?String message; ?? ??? ??? ?try { ?? ??? ??? ??? ?socket.receive(datagram); ?? ??? ??? ??? ?message = new String(buffer, 0, datagram.getLength(), "UTF-8"); ?? ??? ??? ??? ?if (!message.startsWith(GroupChat.name)) ?? ??? ??? ??? ??? ?System.out.println(message); ?? ??? ??? ?} catch (IOException e) { ?? ??? ??? ??? ?System.out.println("Socket closed!"); ?? ??? ??? ?} ?? ??? ?} ?? ?} }
將文件另存為 GroupChat.java 并使用 javac 編譯它,然后使用指定的兩個(gè)命令行參數(shù)運(yùn)行程序。多播主機(jī)由 D 類 IP 地址和標(biāo)準(zhǔn) UDP 端口號(hào)指定。D 類 IP 地址的范圍為 224.0.0.0 到 239.255.255.255(含)。地址 224.0.0.0 是保留地址,不應(yīng)使用。
以下是上述程序的示例輸出:
我們使用多播主機(jī) IP 地址為 239.0.0.0,端口號(hào)為 1234(因?yàn)槎丝谔?hào) 0 到 1023 被保留)。該組有 3 名成員:Ironman、CaptainAmerica 和 Groot。在發(fā)送消息之前首先啟動(dòng)所有三個(gè)終端,否則在啟動(dòng)終端之前發(fā)送的消息將丟失(因?yàn)闆](méi)有合并緩沖區(qū)來(lái)存儲(chǔ)消息。)我們?cè)谶@個(gè)應(yīng)用程序中需要兩個(gè)線程。一個(gè)用于接受用戶輸入(使用 java.util.Scanner 類),另一個(gè)用于讀取從其他客戶端發(fā)送的消息。因此,我將執(zhí)行讀取工作的線程分離到 ReadThreadclass 中。要離開(kāi)組,任何用戶都可以鍵入退出以終止會(huì)話。
上述程序在單機(jī)上執(zhí)行。套接字編程適用于分布式編程。相同的代碼片段出現(xiàn)在安裝了 Java 的不同機(jī)器上時(shí)可以滿足該要求。這只是最基本的服務(wù)邏輯。如果前端開(kāi)發(fā)出來(lái),這個(gè)項(xiàng)目會(huì)更加吸引人。您可以使用 Java 的 AWT(抽象窗口工具包)或其高級(jí)對(duì)應(yīng)物 Java Swing 來(lái)開(kāi)發(fā)前端。由于這不是 Socket 編程的一部分,因此我將在不深入了解細(xì)節(jié)的情況下保持不變。
附加點(diǎn):
您可以通過(guò)在通過(guò)網(wǎng)絡(luò)發(fā)送消息之前執(zhí)行加密來(lái)合并網(wǎng)絡(luò)安全功能。
凱撒密碼等原始技術(shù)或 RSA 等高級(jí)方法可用于執(zhí)行加解密。您可以嘗試使用 Java 的 RMI(遠(yuǎn)程方法調(diào)用)來(lái)執(zhí)行相同的任務(wù)。
在這里,您可以最大限度地利用 Java 提供的抽象。但是,如果您的主要目標(biāo)是效率,那么 Socket 編程是最佳選擇。由于它不需要任何運(yùn)行時(shí)支持,因此與 RMI 相比要快一些。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
詳解Java中NullPointerException的處理方法
這篇文章將帶大家來(lái)單獨(dú)看一個(gè)很常見(jiàn)的異常--空指針異常,這個(gè)可以說(shuō)是每個(gè)Java程序員都必知的異常,所以我們不得不單獨(dú)學(xué)習(xí)一下,文中有詳細(xì)的代碼示例,需要的朋友可以參考下2023-08-08一篇文章帶你了解jdk1.8新特性--為什么使用lambda表達(dá)式
Lambda是一個(gè)匿名函數(shù),我們可以把Lambda表達(dá)式理解為是一段可以傳遞的代碼,本篇文章就帶你了解,希望能給你帶來(lái)幫助2021-08-08java實(shí)現(xiàn)簡(jiǎn)單計(jì)算器
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)單計(jì)算器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12Java后臺(tái)Controller實(shí)現(xiàn)文件下載操作
這篇文章主要介紹了Java后臺(tái)Controller實(shí)現(xiàn)文件下載操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-10-10java實(shí)現(xiàn)遺傳算法實(shí)例分享(打印城市信息)
本文介紹java實(shí)現(xiàn)遺傳算法的實(shí)例,代碼中使用城市名做為數(shù)據(jù),可以打印當(dāng)前代數(shù)的所有城市序列,以及其相關(guān)的參數(shù),大家參考使用吧2014-01-01Spring Bean創(chuàng)建和循環(huán)依賴
這篇文章主要介紹了Spring Bean創(chuàng)建和循環(huán)依賴,講述了Spring容器中?Bean?的創(chuàng)建過(guò)程已經(jīng)主要的方法,另外也著重分析了循環(huán)依賴的問(wèn)題,需要的小伙伴可以參考一下2022-05-05