Java編寫網(wǎng)絡(luò)聊天程序?qū)嶒?yàn)
本文實(shí)例為大家分享了Java編寫網(wǎng)絡(luò)聊天程序的具體代碼,供大家參考,具體內(nèi)容如下
課程名稱 高級(jí)Java程序設(shè)計(jì)
實(shí)驗(yàn)項(xiàng)目 Java網(wǎng)絡(luò)編程
實(shí)驗(yàn)?zāi)康模?/strong>
使用客戶機(jī)/服務(wù)器模式、基于TCP協(xié)議編寫一對(duì)多“群聊”程序。其中客戶機(jī)端單擊“連接服務(wù)器”或“斷開連接”按鈕,均能即時(shí)更新服務(wù)器和所有客戶機(jī)的在線人數(shù)和客戶名。
實(shí)驗(yàn)要求:
設(shè)計(jì)一對(duì)多的網(wǎng)絡(luò)聊天程序,要求:
1、基于TCP/IP設(shè)計(jì)聊天程序
2、采用圖形界面設(shè)計(jì)
3、能夠進(jìn)行一對(duì)多聊天
項(xiàng)目截圖
服務(wù)器端代碼:
import javax.swing.*; import javax.swing.border.TitledBorder; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.Vector; ? ? public class Server extends JFrame { ? ? // TODO 該圖形界面擁有三塊區(qū)域,分別位于上、中、下 (up、middle、down)。 ? ? private JPanel panUp = new JPanel(); ? ? private JPanel panMid = new JPanel(); ? ? private JPanel panDown = new JPanel(); ? ? ? // panUp 區(qū)域的子節(jié)點(diǎn)定義,標(biāo)簽、輸入框、按鈕 ? ? private JLabel lblLocalPort = new JLabel("本機(jī)服務(wù)器監(jiān)聽端口:"); ? ? protected JButton butStart = new JButton("啟動(dòng)服務(wù)器"); ? ? protected JTextField tfLocalPort = new JTextField(25); ? ? ? // panMid 區(qū)域的子節(jié)點(diǎn)定義,顯示框 以及 滾動(dòng)條 ? ? protected JTextArea taMsg = new JTextArea(25, 25); ? ? JScrollPane scroll = new JScrollPane(taMsg); ? ? ? // panDown 區(qū)域的子節(jié)點(diǎn)定義,lstUsers在線用戶界面 ? ? JList lstUsers = new JList(); ? ? ? // TODO 以下是存放數(shù)據(jù)的變量 ? ? public static int localPort = 8000; ? ? // 默認(rèn)端口 8000 ? ? static int SerialNum = 0; ? ? ? // 用戶連接數(shù)量 ? ? ServerSocket serverSocket; ? ? ?// 服務(wù)器端 Socket ? ? ArrayList<AcceptRunnable.Client> clients = new ArrayList<>(); ? ? ? ?// 用戶連接對(duì)象數(shù)組 ? ? Vector<String> clientNames = new Vector<>(); ? ? ? // lstUsers 中存放的數(shù)據(jù) ? ? ? // TODO 構(gòu)造方法 ? ? public Server() { ? ? ? ? init(); ? ? } ? ? ? // TODO 初始化方法:初始化圖形界面布局 ? ? private void init() { ? ? ? ? // panUp 區(qū)域初始化:流式區(qū)域 ? ? ? ? panUp.setLayout(new FlowLayout()); ? ? ? ? panUp.add(lblLocalPort); ? ? ? ? panUp.add(tfLocalPort); ? ? ? ? panUp.add(butStart); ? ? ? ? tfLocalPort.setText(String.valueOf(localPort)); ? ? ? ? butStart.addActionListener(new startServerHandler()); ? // 注冊(cè) "啟動(dòng)服務(wù)器" 按鈕點(diǎn)擊事件 ? ? ? ? ? // panMid 區(qū)域初始化 ? ? ? ? panMid.setBorder(new TitledBorder("監(jiān)聽消息")); ? ? ? ? taMsg.setEditable(false); ? ? ? ? panMid.add(scroll); ? ? ? ? ? // panDown 區(qū)域初始化 ? ? ? ? panDown.setBorder(new TitledBorder("在線用戶")); ? ? ? ? panDown.add(lstUsers); ? ? ? ? lstUsers.setVisibleRowCount(10); ? ? ? ? ? // 圖形界面的總體初始化 + 啟動(dòng)圖形界面 ? ? ? ? this.setTitle("服務(wù)器端"); ? ? ? ? this.add(panUp, BorderLayout.NORTH); ? ? ? ? this.add(panMid, BorderLayout.CENTER); ? ? ? ? this.add(panDown, BorderLayout.SOUTH); ? ? ? ? this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); ? ? ? ? this.setPreferredSize(new Dimension(600, 400)); ? ? ? ? this.pack(); ? ? ? ? this.setVisible(true); ? ? } ? ? ? // TODO “啟動(dòng)服務(wù)器”按鈕的動(dòng)作事件監(jiān)聽處理類 ? ? private class startServerHandler implements ActionListener { ? ? ? ? @Override ? ? ? ? public void actionPerformed(ActionEvent e) { ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? // 當(dāng)點(diǎn)擊按鈕時(shí),獲取端口設(shè)置并啟動(dòng)新進(jìn)程、監(jiān)聽端口 ? ? ? ? ? ? ? ? localPort = Integer.parseInt(tfLocalPort.getText()); ? ? ? ? ? ? ? ? serverSocket = new ServerSocket(localPort); ? ? ? ? ? ? ? ? Thread acptThrd = new Thread(new AcceptRunnable()); ? ? ? ? ? ? ? ? acptThrd.start(); ? ? ? ? ? ? ? ? taMsg.append("**** 服務(wù)器(端口" + localPort + ")已啟動(dòng) ****\n"); ? ? ? ? ? ? } catch (Exception ex) { ? ? ? ? ? ? ? ? System.out.println(ex); ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? ? // TODO 接受用戶連接請(qǐng)求的線程關(guān)聯(lián)類 ? ? private class AcceptRunnable implements Runnable { ? ? ? ? public void run() { ? ? ? ? ? ? // 持續(xù)監(jiān)聽端口,當(dāng)有新用戶連接時(shí) 再開啟新進(jìn)程 ? ? ? ? ? ? while (true) { ? ? ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? ? ? Socket socket = serverSocket.accept(); ? ? ? ? ? ? ? ? ? ? // 新的用戶已連接,創(chuàng)建 Client 對(duì)象 ? ? ? ? ? ? ? ? ? ? Client client = new Client(socket); ? ? ? ? ? ? ? ? ? ? taMsg.append("——客戶【" + client.nickname + "】加入\n"); ? ? ? ? ? ? ? ? ? ? Thread clientThread = new Thread(client); ? ? ? ? ? ? ? ? ? ? clientThread.start(); ? ? ? ? ? ? ? ? ? ? clients.add(client); ? ? ? ? ? ? ? ? } catch (Exception ex) { ? ? ? ? ? ? ? ? ? ? System.out.println(ex); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? ? // TODO 服務(wù)器存放用戶對(duì)象的客戶類(主要編程)。每當(dāng)有新的用戶連接時(shí),該類都會(huì)被調(diào)用 ? ? ? ? // TODO 該類繼承自 Runnable,內(nèi)部含有 run()方法 ? ? ? ? private class Client implements Runnable { ? ? ? ? ? ? private Socket socket; ? ? ?// 用來保存用戶的連接對(duì)象 ? ? ? ? ? ? private BufferedReader in; ? // IO 流 ? ? ? ? ? ? private PrintStream out; ? ? ? ? ? ? private String nickname; ? ? ? ?// 保存用戶昵稱 ? ? ? ? ? ? ? // Client類的構(gòu)建方法。當(dāng)有 新用戶 連接時(shí)會(huì)被調(diào)用 ? ? ? ? ? ? public Client(Socket socket) throws Exception { ? ? ? ? ? ? ? ? this.socket = socket; ? ? ? ? ? ? ? ? InputStream is = socket.getInputStream(); ? ? ? ? ? ? ? ? in = new BufferedReader(new InputStreamReader(is)); ? ? ? ? ? ? ? ? OutputStream os = socket.getOutputStream(); ? ? ? ? ? ? ? ? out = new PrintStream(os); ? ? ? ? ? ? ? ? nickname = in.readLine(); ? ? // 獲取用戶昵稱 ? ? ? ? ? ? ? ? for (Client c : clients) { ? // 將新用戶的登錄消息發(fā)給所有用戶 ? ? ? ? ? ? ? ? ? ? c.out.println("——客戶【" + nickname + "】加入\n"); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? ? ? ? //客戶類線程運(yùn)行方法 ?? ? ? ? ? ? ? public void run() { ? ? ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? ? ? while (true) { ? ? ? ? ? ? ? ? ? ? ? ? String usermsg ? = in.readLine(); ? //讀用戶發(fā)來消息 ? ? ? ? ? ? ? ? ? ? ? ? String secondMsg = usermsg.substring(usermsg.lastIndexOf(":") + 1); ? // 字符串輔助對(duì)象 ? ? ? ? ? ? ? ? ? ? ? ? ? // 如果用戶發(fā)過來的消息不為空 ? ? ? ? ? ? ? ? ? ? ? ? if (usermsg != null && usermsg.length() > 0) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 如果消息是 bye,則斷開與此用戶的連接 并 告知所有用戶當(dāng)前信息,跳出循環(huán)終止當(dāng)前進(jìn)程 ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (secondMsg.equals("bye")) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? clients.remove(this); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? for (Client c : clients) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? c.out.println(usermsg); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? taMsg.append("——客戶離開:" + nickname + "\n"); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 更新在線用戶數(shù)量 lstUsers的界面信息 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? updateUsers(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? break;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /** ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?* 每當(dāng)有新用戶連接時(shí),服務(wù)器就會(huì)接收到 USERS 請(qǐng)求 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?* 當(dāng)服務(wù)器接收到此請(qǐng)求時(shí),就會(huì)要求現(xiàn)在所有用戶更新 在線用戶數(shù)量 的列表 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?* */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (usermsg.equals("USERS")) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? updateUsers(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? continue; ? ? ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 當(dāng)用戶發(fā)出的消息都不是以上兩者時(shí),消息才會(huì)被正常發(fā)送 ? ? ? ? ? ? ? ? ? ? ? ? ? ? for (Client c : clients) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? c.out.println(usermsg); ? ? ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? socket.close(); ? ? ? ? ? ? ? ? } catch (Exception ex) { ? ? ? ? ? ? ? ? ? ? System.out.println(ex); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? ? ? ? // TODO 更新在線用戶數(shù)量 lstUsers 信息,并要求所有的用戶端同步更新 ? ? ? ? ? ? public void updateUsers() { ? ? ? ? ? ? ? ? // clientNames 是 Vector<String>對(duì)象,用來存放所有用戶的名字 ? ? ? ? ? ? ? ? clientNames.removeAllElements(); ? ? ? ? ? ? ? ? StringBuffer allname = new StringBuffer(); ? ? ? ? ? ? ? ? for (AcceptRunnable.Client client : clients) { ? ? ? ? ? ? ? ? ? ? clientNames.add(0, client.nickname); ? ? ? ? ? ? ? ? ? ? allname.insert(0, "|" + client.nickname); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? panDown.setBorder(new TitledBorder("在線用戶(" +clientNames.size() + "個(gè))")); ? ? ? ? ? ? ? ? // 要求所有的用戶端同步更新 ? ? ? ? ? ? ? ? for (Client c : clients) { ? ? ? ? ? ? ? ? ? ? c.out.println(clientNames); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? lstUsers.setListData(clientNames); ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? ? // TODO 主方法 ? ? public static void main(String[] args) { ? ? ? ? new Server(); ? ? } }
客戶端代碼:
import javax.swing.*; import javax.swing.border.TitledBorder; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket; import java.util.Vector; ? ? public class Client extends JFrame { ? ? ?//客戶機(jī)窗體類 ? ? // TODO 該圖形界面擁有四塊區(qū)域,分別位于上、左、中、下 (up、Left、middle、down)。 ? ? private JPanel panUp = new JPanel(); ? ? private JPanel panLeft = new JPanel(); ? ? private JPanel panMid = new JPanel(); ? ? private JPanel panDown = new JPanel(); ? ? ? // panUp 區(qū)域的子節(jié)點(diǎn)定義,3個(gè)標(biāo)簽、3個(gè)輸入框、2個(gè)按鈕 ? ? private JLabel lblLocalPort1 = new JLabel("服務(wù)器IP: "); ? ? private JLabel lblLocalPort2 = new JLabel("端口: "); ? ? private JLabel lblLocalPort3 = new JLabel("本人昵稱: "); ? ? protected JTextField tfLocalPort1 = new JTextField(15); ? ? protected JTextField tfLocalPort2 = new JTextField(5); ? ? protected JTextField tfLocalPort3 = new JTextField(5); ? ? protected JButton butStart = new JButton("連接服務(wù)器"); ? ? protected JButton butStop = new JButton("斷開服務(wù)器"); ? ? // TODO ? ? ? // panLeft 區(qū)域的子節(jié)點(diǎn)定義,顯示框、滾動(dòng)條 ? ? protected JTextArea taMsg = new JTextArea(25, 25); ? ? JScrollPane scroll = new JScrollPane(taMsg); ? ? ? // panMid 區(qū)域的子節(jié)點(diǎn)定義,lstUsers在線用戶界面 ? ? JList lstUsers = new JList(); ? ? ? // panDown 區(qū)域的子節(jié)點(diǎn)定義,標(biāo)簽,輸入框 ? ? private JLabel lblLocalPort4 = new JLabel("消息(按回車發(fā)送): "); ? ? protected JTextField tfLocalPort4 = new JTextField(20); ? ? /** ? ? ?* ===== 變量分割 ===== ? ? ?* 上面是圖形界面變量,下面是存放數(shù)據(jù)的變量 ? ? ?*/ ? ? BufferedReader in; ? ? PrintStream out; ? ? public static int localPort = 8000; ? ? // 默認(rèn)端口 ? ? public static String localIP = "127.0.0.1"; ? ? // 默認(rèn)服務(wù)器IP地址 ? ? public static String nickname = "Cat"; ? ? ?// 默認(rèn)用戶名 ? ? public Socket socket; ? ? public static String msg; ? ? ? // 存放本次發(fā)送的消息 ? ? Vector<String> clientNames = new Vector<>(); ? ? ? // TODO 構(gòu)造方法 ? ? public Client() { ? ? ? ? init(); ? ? } ? ? ? // TODO 初始化方法:初始化圖形界面 ? ? private void init() { ? ? ? ? // panUp 區(qū)域初始化:流式面板,3個(gè)標(biāo)簽、3個(gè)輸入框,2個(gè)按鈕 ? ? ? ? panUp.setLayout(new FlowLayout()); ? ? ? ? panUp.add(lblLocalPort1); ? ? ? ? panUp.add(tfLocalPort1); ? ? ? ? panUp.add(lblLocalPort2); ? ? ? ? panUp.add(tfLocalPort2); ? ? ? ? panUp.add(lblLocalPort3); ? ? ? ? panUp.add(tfLocalPort3); ? ? ? ? tfLocalPort1.setText(localIP); ? ? ? ? tfLocalPort2.setText(String.valueOf(localPort)); ? ? ? ? tfLocalPort3.setText(nickname); ? ? ? ? panUp.add(butStart); ? ? ? ? panUp.add(butStop); ? ? ? ? butStart.addActionListener(new linkServerHandlerStart()); ? ? ? ? butStop.addActionListener(new linkServerHandlerStop()); ? ? ? ? butStop.setEnabled(false); ? ? ?// 斷開服務(wù)器按鈕的初始狀態(tài)應(yīng)該為 不可點(diǎn)擊,只有連接服務(wù)器之后才能點(diǎn)擊 ? ? ? ? ? // 添加 Left ? ? ? ? taMsg.setEditable(false); ? ? ? ? panLeft.add(scroll); ? ? ? ? panLeft.setBorder(new TitledBorder("聊天——消息區(qū)")); ? ? ? ? scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); ? ? ? ? scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); ? ? ? ? ? // 添加 Middle ? ? ? ? panMid.setBorder(new TitledBorder("在線用戶")); ? ? ? ? panMid.add(lstUsers); ? ? ? ? lstUsers.setVisibleRowCount(20); ? ? ? ? ? // 添加 Down ? ? ? ? // TODO 此處注意:JTextField輸入框 的回車事件默認(rèn)存在,無需添加 ? ? ? ? panDown.setLayout(new FlowLayout()); ? ? ? ? panDown.add(lblLocalPort4); ? ? ? ? panDown.add(tfLocalPort4); ? ? ? ? tfLocalPort4.addActionListener(new Client.SendHandler()); ? ? ? ? ? // 圖形界面的總體初始化 + 啟動(dòng)圖形界面 ? ? ? ? this.setTitle("客戶端"); ? ? ? ? this.add(panUp, BorderLayout.NORTH); ? ? ? ? this.add(panLeft, BorderLayout.WEST); ? ? ? ? this.add(panMid, BorderLayout.CENTER); ? ? ? ? this.add(panDown, BorderLayout.SOUTH); ? ? ? ? this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); ? ? ? ? this.addWindowListener(new WindowHandler()); ? ? ? ? this.setPreferredSize(new Dimension(800, 600)); ? ? ? ? this.pack(); ? ? ? ? this.setVisible(true); ? ? } ? ? ? // TODO “連接服務(wù)器”按鈕的動(dòng)作事件監(jiān)聽處理類: ? ? private class linkServerHandlerStart implements ActionListener { ? ? ? ? @Override ? ? ? ? public void actionPerformed(ActionEvent e) { ? ? ? ? ? ? // 當(dāng)點(diǎn)擊"連接服務(wù)器"按鈕之后,該按鈕被禁用(不可重復(fù)點(diǎn)擊)。同時(shí)"斷開服務(wù)器按鈕"被恢復(fù)使用 ? ? ? ? ? ? butStart.setEnabled(false); ? ? ? ? ? ? butStop.setEnabled(true); ? ? ? ? ? ? localIP = tfLocalPort1.getText(); ? ? ? ? ? ? localPort = Integer.parseInt(tfLocalPort2.getText()); ? ? ? ? ? ? nickname = tfLocalPort3.getText(); ? ? ? ? ? ? linkServer(); ? // 連接服務(wù)器 ? ? ? ? ? ? Thread acceptThread = new Thread(new Client.ReceiveRunnable()); ? ? ? ? ? ? acceptThread.start(); ? ? ? ? } ? ? } ? ? ? // TODO “斷開服務(wù)器”按鈕的動(dòng)作事件監(jiān)聽處理類 ? ? private class linkServerHandlerStop implements ActionListener { ? ? ? ? /** ? ? ? ? ?* 當(dāng)點(diǎn)擊該按鈕之后,斷開服務(wù)器連接、清空?qǐng)D形界面所有數(shù)據(jù) ? ? ? ? ?*/ ? ? ? ? @Override ? ? ? ? public void actionPerformed(ActionEvent e) { ? ? ? ? ? ? taMsg.setText(""); ? ? ? ? ? ? clientNames = new Vector<>(); ? ? ? ? ? ? updateUsers(); ? ? ? ? ? ? out.println("——客戶【" + nickname + "】離開:bye\n"); ? ? ? ? ? ? butStart.setEnabled(true); ? ? ? ? ? ? butStop.setEnabled(false); ? ? ? ? } ? ? } ? ? ? // TODO 連接服務(wù)器的方法 ? ? public void linkServer() { ? ? ? ? try { ? ? ? ? ? ? socket = new Socket(localIP, localPort); ? ? ? ? } catch (Exception ex) { ? ? ? ? ? ? taMsg.append("==== 連接服務(wù)器失敗~ ===="); ? ? ? ? } ? ? } ? ? ? // TODO 接收服務(wù)器消息的線程關(guān)聯(lián)類 ? ? private class ReceiveRunnable implements Runnable { ? ? ? ? public void run() { ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? in = new BufferedReader(new InputStreamReader(socket.getInputStream())); ? ? ? ? ? ? ? ? out = new PrintStream(socket.getOutputStream()); ? ? ? ? ? ? ? ? out.println(nickname); ? ? ?// 當(dāng)用戶首次連接服務(wù)器時(shí),應(yīng)該向服務(wù)器發(fā)送自己的用戶名、方便服務(wù)器區(qū)分 ? ? ? ? ? ? ? ? taMsg.append("——本人【" + nickname + "】成功連接到服務(wù)器......\n"); ? ? ? ? ? ? ? ? out.println("USERS"); ? ? ? // 向服務(wù)器發(fā)送"神秘代碼",請(qǐng)求 當(dāng)前在線用戶 列表 ? ? ? ? ? ? ? ? while (true) { ? ? ? ? ? ? ? ? ? ? msg = in.readLine(); ? ? ? // 讀取服務(wù)器端的發(fā)送的數(shù)據(jù) ? ? ? ? ? ? ? ? ? ? // 此 if 語句的作用是:過濾服務(wù)器發(fā)送過來的 更新當(dāng)前在線用戶列表 請(qǐng)求 ? ? ? ? ? ? ? ? ? ? if (msg.matches(".*\\[.*\\].*")) { ? ? ? ? ? ? ? ? ? ? ? ? clientNames.removeAllElements(); ? ? ? ? ? ? ? ? ? ? ? ? String[] split = msg.split(","); ? ? ? ? ? ? ? ? ? ? ? ? for (String single : split) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? clientNames.add(single); ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? updateUsers(); ? ? ? ? ? ? ? ? ? ? ? ? continue; ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? // 更新 "聊天——消息區(qū)" 信息 ? ? ? ? ? ? ? ? ? ? taMsg.append(msg + "\n"); ? ? ? ? ? ? ? ? ? ? ? // 此 if 語句作用:與服務(wù)器進(jìn)行握手確認(rèn)消息。 ? ? ? ? ? ? ? ? ? ? // 當(dāng)接收到服務(wù)器端發(fā)送的確認(rèn)離開請(qǐng)求bye 的時(shí)候,用戶真正離線 ? ? ? ? ? ? ? ? ? ? msg = msg.substring(msg.lastIndexOf(":") + 1); ? ? ? ? ? ? ? ? ? ? if (msg.equals(nickname)) { ? ? ? ? ? ? ? ? ? ? ? ? socket.close(); ? ? ? ? ? ? ? ? ? ? ? ? clientNames.remove(nickname); ? ? ? ? ? ? ? ? ? ? ? ? updateUsers(); ? ? ? ? ? ? ? ? ? ? ? ? break; ? ? ? // 終止線程 ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } catch (Exception e) { ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? ? // TODO "發(fā)送消息文本框" 的動(dòng)作事件監(jiān)聽處理類 ? ? private class SendHandler implements ActionListener { ? ? ? ? @Override ? ? ? ? public void actionPerformed(ActionEvent e) { ? ? ? ? ? ? out.println("【" + nickname + "】:" + tfLocalPort4.getText()); ? ? ? ? ? ? tfLocalPort4.setText(""); ? ? ? // 當(dāng)按下回車發(fā)送消息之后,輸入框應(yīng)該被清空 ? ? ? ? } ? ? } ? ? ? // TODO 窗口關(guān)閉的動(dòng)作事件監(jiān)聽處理類 ? ? // 當(dāng)用戶點(diǎn)擊 "x" 離開窗口時(shí),也會(huì)向服務(wù)器發(fā)送 bye 請(qǐng)求,目的是為了同步更新數(shù)據(jù)。 ? ? private class WindowHandler extends WindowAdapter { ? ? ? ? @Override ? ? ? ? public void windowClosing(WindowEvent e) { ? ? ? ? ? ? cutServer(); ? ? ? ? } ? ? } ? ? ? private void cutServer() { ? ? ? ? out.println("——客戶【" + nickname + "】離開:bye"); ? ? } ? ? ? // TODO 更新 "在線用戶列表" 的方法 ? ? public void updateUsers() { ? ? ? ? panMid.setBorder(new TitledBorder("在線用戶(" + clientNames.size() + "個(gè))")); ? ? ? ? lstUsers.setListData(clientNames); ? ? } ? ? ? // TODO 主方法 ? ? public static void main(String[] args) { ? ? ? ? new Client(); ? ? } }
如何同時(shí)開啟兩個(gè)客戶端進(jìn)行聊天?
將上述的 Client 類復(fù)制一份,改名為 Client2 ,然后同時(shí)啟動(dòng) Client 和 Client2 程序。
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- java中UDP簡單聊天程序?qū)嵗a
- 詳解基于java的Socket聊天程序——客戶端(附demo)
- java網(wǎng)絡(luò)編程學(xué)習(xí)java聊天程序代碼分享
- java基于TCP協(xié)議實(shí)現(xiàn)聊天程序
- java基于C/S模式實(shí)現(xiàn)聊天程序(客戶端)
- 詳解基于java的Socket聊天程序——服務(wù)端(附demo)
- java實(shí)現(xiàn)基于Tcp的socket聊天程序
- 詳解基于java的Socket聊天程序——初始設(shè)計(jì)(附demo)
- java實(shí)現(xiàn)簡單TCP聊天程序
- 基于Java的Socket多客戶端Client-Server聊天程序的實(shí)現(xiàn)
相關(guān)文章
mybatis?mapper.xml?注釋帶參數(shù)的坑及解決
這篇文章主要介紹了mybatis?mapper.xml?注釋帶參數(shù)的坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01SpringBoot 文件或圖片上傳與下載功能的實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot 文件或圖片上傳與下載功能的實(shí)現(xiàn),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02Java運(yùn)算符的知識(shí)點(diǎn)與代碼匯總
這篇文章主要給大家總結(jié)介紹了關(guān)于Java運(yùn)算符知識(shí)點(diǎn)與代碼的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04