Java編寫網(wǎng)絡(luò)聊天程序?qū)嶒?/h1>
更新時間:2022年08月10日 11:42:59 作者:ThinkStu
這篇文章主要為大家詳細(xì)介紹了Java編寫網(wǎng)絡(luò)聊天程序?qū)嶒?,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
本文實例為大家分享了Java編寫網(wǎng)絡(luò)聊天程序的具體代碼,供大家參考,具體內(nèi)容如下
課程名稱 高級Java程序設(shè)計
實驗項目 Java網(wǎng)絡(luò)編程
實驗?zāi)康模?/strong>
使用客戶機(jī)/服務(wù)器模式、基于TCP協(xié)議編寫一對多“群聊”程序。其中客戶機(jī)端單擊“連接服務(wù)器”或“斷開連接”按鈕,均能即時更新服務(wù)器和所有客戶機(jī)的在線人數(shù)和客戶名。
實驗要求:
設(shè)計一對多的網(wǎng)絡(luò)聊天程序,要求:
1、基于TCP/IP設(shè)計聊天程序
2、采用圖形界面設(shè)計
3、能夠進(jìn)行一對多聊天
項目截圖


服務(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é)點定義,標(biāo)簽、輸入框、按鈕
? ? private JLabel lblLocalPort = new JLabel("本機(jī)服務(wù)器監(jiān)聽端口:");
? ? protected JButton butStart = new JButton("啟動服務(wù)器");
? ? protected JTextField tfLocalPort = new JTextField(25);
?
? ? // panMid 區(qū)域的子節(jié)點定義,顯示框 以及 滾動條
? ? protected JTextArea taMsg = new JTextArea(25, 25);
? ? JScrollPane scroll = new JScrollPane(taMsg);
?
? ? // panDown 區(qū)域的子節(jié)點定義,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<>(); ? ? ? ?// 用戶連接對象數(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()); ? // 注冊 "啟動服務(wù)器" 按鈕點擊事件
?
? ? ? ? // 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);
?
? ? ? ? // 圖形界面的總體初始化 + 啟動圖形界面
? ? ? ? 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 “啟動服務(wù)器”按鈕的動作事件監(jiān)聽處理類
? ? private class startServerHandler implements ActionListener {
? ? ? ? @Override
? ? ? ? public void actionPerformed(ActionEvent e) {
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? // 當(dāng)點擊按鈕時,獲取端口設(shè)置并啟動新進(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 + ")已啟動 ****\n");
? ? ? ? ? ? } catch (Exception ex) {
? ? ? ? ? ? ? ? System.out.println(ex);
? ? ? ? ? ? }
? ? ? ? }
? ? }
?
? ? // TODO 接受用戶連接請求的線程關(guān)聯(lián)類
? ? private class AcceptRunnable implements Runnable {
? ? ? ? public void run() {
? ? ? ? ? ? // 持續(xù)監(jiān)聽端口,當(dāng)有新用戶連接時 再開啟新進(jìn)程
? ? ? ? ? ? while (true) {
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? Socket socket = serverSocket.accept();
? ? ? ? ? ? ? ? ? ? // 新的用戶已連接,創(chuàng)建 Client 對象
? ? ? ? ? ? ? ? ? ? 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ù)器存放用戶對象的客戶類(主要編程)。每當(dāng)有新的用戶連接時,該類都會被調(diào)用
? ? ? ? // TODO 該類繼承自 Runnable,內(nèi)部含有 run()方法
? ? ? ? private class Client implements Runnable {
? ? ? ? ? ? private Socket socket; ? ? ?// 用來保存用戶的連接對象
? ? ? ? ? ? private BufferedReader in; ? // IO 流
? ? ? ? ? ? private PrintStream out;
? ? ? ? ? ? private String nickname; ? ? ? ?// 保存用戶昵稱
?
? ? ? ? ? ? // Client類的構(gòu)建方法。當(dāng)有 新用戶 連接時會被調(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");
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
?
? ? ? ? ? ? //客戶類線程運行方法 ??
? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? try {
? ? ? ? ? ? ? ? ? ? while (true) {
? ? ? ? ? ? ? ? ? ? ? ? String usermsg ? = in.readLine(); ? //讀用戶發(fā)來消息
? ? ? ? ? ? ? ? ? ? ? ? String secondMsg = usermsg.substring(usermsg.lastIndexOf(":") + 1); ? // 字符串輔助對象
?
? ? ? ? ? ? ? ? ? ? ? ? // 如果用戶發(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)有新用戶連接時,服務(wù)器就會接收到 USERS 請求
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?* 當(dāng)服務(wù)器接收到此請求時,就會要求現(xiàn)在所有用戶更新 在線用戶數(shù)量 的列表
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?* */
? ? ? ? ? ? ? ? ? ? ? ? ? ? if (usermsg.equals("USERS")) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? updateUsers();
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? continue;
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
?
? ? ? ? ? ? ? ? ? ? ? ? ? ? // 當(dāng)用戶發(fā)出的消息都不是以上兩者時,消息才會被正常發(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>對象,用來存放所有用戶的名字
? ? ? ? ? ? ? ? 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() + "個)"));
? ? ? ? ? ? ? ? // 要求所有的用戶端同步更新
? ? ? ? ? ? ? ? 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é)點定義,3個標(biāo)簽、3個輸入框、2個按鈕
? ? 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é)點定義,顯示框、滾動條
? ? protected JTextArea taMsg = new JTextArea(25, 25);
? ? JScrollPane scroll = new JScrollPane(taMsg);
?
? ? // panMid 區(qū)域的子節(jié)點定義,lstUsers在線用戶界面
? ? JList lstUsers = new JList();
?
? ? // panDown 區(qū)域的子節(jié)點定義,標(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個標(biāo)簽、3個輸入框,2個按鈕
? ? ? ? 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)該為 不可點擊,只有連接服務(wù)器之后才能點擊
?
? ? ? ? // 添加 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());
?
? ? ? ? // 圖形界面的總體初始化 + 啟動圖形界面
? ? ? ? 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ù)器”按鈕的動作事件監(jiān)聽處理類:
? ? private class linkServerHandlerStart implements ActionListener {
? ? ? ? @Override
? ? ? ? public void actionPerformed(ActionEvent e) {
? ? ? ? ? ? // 當(dāng)點擊"連接服務(wù)器"按鈕之后,該按鈕被禁用(不可重復(fù)點擊)。同時"斷開服務(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ù)器”按鈕的動作事件監(jiān)聽處理類
? ? private class linkServerHandlerStop implements ActionListener {
? ? ? ? /**
? ? ? ? ?* 當(dāng)點擊該按鈕之后,斷開服務(wù)器連接、清空圖形界面所有數(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ù)器時,應(yīng)該向服務(wù)器發(fā)送自己的用戶名、方便服務(wù)器區(qū)分
? ? ? ? ? ? ? ? taMsg.append("——本人【" + nickname + "】成功連接到服務(wù)器......\n");
? ? ? ? ? ? ? ? out.println("USERS"); ? ? ? // 向服務(wù)器發(fā)送"神秘代碼",請求 當(dāng)前在線用戶 列表
? ? ? ? ? ? ? ? while (true) {
? ? ? ? ? ? ? ? ? ? msg = in.readLine(); ? ? ? // 讀取服務(wù)器端的發(fā)送的數(shù)據(jù)
? ? ? ? ? ? ? ? ? ? // 此 if 語句的作用是:過濾服務(wù)器發(fā)送過來的 更新當(dā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)離開請求bye 的時候,用戶真正離線
? ? ? ? ? ? ? ? ? ? msg = msg.substring(msg.lastIndexOf(":") + 1);
? ? ? ? ? ? ? ? ? ? if (msg.equals(nickname)) {
? ? ? ? ? ? ? ? ? ? ? ? socket.close();
? ? ? ? ? ? ? ? ? ? ? ? clientNames.remove(nickname);
? ? ? ? ? ? ? ? ? ? ? ? updateUsers();
? ? ? ? ? ? ? ? ? ? ? ? break; ? ? ? // 終止線程
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? } catch (Exception e) {
? ? ? ? ? ? }
? ? ? ? }
? ? }
?
? ? // TODO "發(fā)送消息文本框" 的動作事件監(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)閉的動作事件監(jiān)聽處理類
? ? // 當(dāng)用戶點擊 "x" 離開窗口時,也會向服務(wù)器發(fā)送 bye 請求,目的是為了同步更新數(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() + "個)"));
? ? ? ? lstUsers.setListData(clientNames);
? ? }
?
? ? // TODO 主方法
? ? public static void main(String[] args) {
? ? ? ? new Client();
? ? }
}
如何同時開啟兩個客戶端進(jìn)行聊天?
將上述的 Client 類復(fù)制一份,改名為 Client2 ,然后同時啟動 Client 和 Client2 程序。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
您可能感興趣的文章:- java中UDP簡單聊天程序?qū)嵗a
- 詳解基于java的Socket聊天程序——客戶端(附demo)
- java網(wǎng)絡(luò)編程學(xué)習(xí)java聊天程序代碼分享
- java基于TCP協(xié)議實現(xiàn)聊天程序
- java基于C/S模式實現(xiàn)聊天程序(客戶端)
- 詳解基于java的Socket聊天程序——服務(wù)端(附demo)
- java實現(xiàn)基于Tcp的socket聊天程序
- 詳解基于java的Socket聊天程序——初始設(shè)計(附demo)
- java實現(xiàn)簡單TCP聊天程序
- 基于Java的Socket多客戶端Client-Server聊天程序的實現(xiàn)
相關(guān)文章
-
mybatis?mapper.xml?注釋帶參數(shù)的坑及解決
這篇文章主要介紹了mybatis?mapper.xml?注釋帶參數(shù)的坑及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教 2022-01-01
-
SpringBoot 文件或圖片上傳與下載功能的實現(xiàn)
這篇文章主要介紹了SpringBoot 文件或圖片上傳與下載功能的實現(xiàn),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下 2021-02-02
最新評論
本文實例為大家分享了Java編寫網(wǎng)絡(luò)聊天程序的具體代碼,供大家參考,具體內(nèi)容如下
課程名稱 高級Java程序設(shè)計
實驗項目 Java網(wǎng)絡(luò)編程
實驗?zāi)康模?/strong>
使用客戶機(jī)/服務(wù)器模式、基于TCP協(xié)議編寫一對多“群聊”程序。其中客戶機(jī)端單擊“連接服務(wù)器”或“斷開連接”按鈕,均能即時更新服務(wù)器和所有客戶機(jī)的在線人數(shù)和客戶名。
實驗要求:
設(shè)計一對多的網(wǎng)絡(luò)聊天程序,要求:
1、基于TCP/IP設(shè)計聊天程序
2、采用圖形界面設(shè)計
3、能夠進(jìn)行一對多聊天
項目截圖
服務(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é)點定義,標(biāo)簽、輸入框、按鈕 ? ? private JLabel lblLocalPort = new JLabel("本機(jī)服務(wù)器監(jiān)聽端口:"); ? ? protected JButton butStart = new JButton("啟動服務(wù)器"); ? ? protected JTextField tfLocalPort = new JTextField(25); ? ? ? // panMid 區(qū)域的子節(jié)點定義,顯示框 以及 滾動條 ? ? protected JTextArea taMsg = new JTextArea(25, 25); ? ? JScrollPane scroll = new JScrollPane(taMsg); ? ? ? // panDown 區(qū)域的子節(jié)點定義,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<>(); ? ? ? ?// 用戶連接對象數(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()); ? // 注冊 "啟動服務(wù)器" 按鈕點擊事件 ? ? ? ? ? // 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); ? ? ? ? ? // 圖形界面的總體初始化 + 啟動圖形界面 ? ? ? ? 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 “啟動服務(wù)器”按鈕的動作事件監(jiān)聽處理類 ? ? private class startServerHandler implements ActionListener { ? ? ? ? @Override ? ? ? ? public void actionPerformed(ActionEvent e) { ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? // 當(dāng)點擊按鈕時,獲取端口設(shè)置并啟動新進(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 + ")已啟動 ****\n"); ? ? ? ? ? ? } catch (Exception ex) { ? ? ? ? ? ? ? ? System.out.println(ex); ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? ? // TODO 接受用戶連接請求的線程關(guān)聯(lián)類 ? ? private class AcceptRunnable implements Runnable { ? ? ? ? public void run() { ? ? ? ? ? ? // 持續(xù)監(jiān)聽端口,當(dāng)有新用戶連接時 再開啟新進(jìn)程 ? ? ? ? ? ? while (true) { ? ? ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? ? ? Socket socket = serverSocket.accept(); ? ? ? ? ? ? ? ? ? ? // 新的用戶已連接,創(chuàng)建 Client 對象 ? ? ? ? ? ? ? ? ? ? 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ù)器存放用戶對象的客戶類(主要編程)。每當(dāng)有新的用戶連接時,該類都會被調(diào)用 ? ? ? ? // TODO 該類繼承自 Runnable,內(nèi)部含有 run()方法 ? ? ? ? private class Client implements Runnable { ? ? ? ? ? ? private Socket socket; ? ? ?// 用來保存用戶的連接對象 ? ? ? ? ? ? private BufferedReader in; ? // IO 流 ? ? ? ? ? ? private PrintStream out; ? ? ? ? ? ? private String nickname; ? ? ? ?// 保存用戶昵稱 ? ? ? ? ? ? ? // Client類的構(gòu)建方法。當(dāng)有 新用戶 連接時會被調(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"); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? ? ? ? //客戶類線程運行方法 ?? ? ? ? ? ? ? public void run() { ? ? ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? ? ? while (true) { ? ? ? ? ? ? ? ? ? ? ? ? String usermsg ? = in.readLine(); ? //讀用戶發(fā)來消息 ? ? ? ? ? ? ? ? ? ? ? ? String secondMsg = usermsg.substring(usermsg.lastIndexOf(":") + 1); ? // 字符串輔助對象 ? ? ? ? ? ? ? ? ? ? ? ? ? // 如果用戶發(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)有新用戶連接時,服務(wù)器就會接收到 USERS 請求 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?* 當(dāng)服務(wù)器接收到此請求時,就會要求現(xiàn)在所有用戶更新 在線用戶數(shù)量 的列表 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?* */ ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (usermsg.equals("USERS")) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? updateUsers(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? continue; ? ? ? ? ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 當(dāng)用戶發(fā)出的消息都不是以上兩者時,消息才會被正常發(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>對象,用來存放所有用戶的名字 ? ? ? ? ? ? ? ? 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() + "個)")); ? ? ? ? ? ? ? ? // 要求所有的用戶端同步更新 ? ? ? ? ? ? ? ? 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é)點定義,3個標(biāo)簽、3個輸入框、2個按鈕 ? ? 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é)點定義,顯示框、滾動條 ? ? protected JTextArea taMsg = new JTextArea(25, 25); ? ? JScrollPane scroll = new JScrollPane(taMsg); ? ? ? // panMid 區(qū)域的子節(jié)點定義,lstUsers在線用戶界面 ? ? JList lstUsers = new JList(); ? ? ? // panDown 區(qū)域的子節(jié)點定義,標(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個標(biāo)簽、3個輸入框,2個按鈕 ? ? ? ? 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)該為 不可點擊,只有連接服務(wù)器之后才能點擊 ? ? ? ? ? // 添加 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()); ? ? ? ? ? // 圖形界面的總體初始化 + 啟動圖形界面 ? ? ? ? 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ù)器”按鈕的動作事件監(jiān)聽處理類: ? ? private class linkServerHandlerStart implements ActionListener { ? ? ? ? @Override ? ? ? ? public void actionPerformed(ActionEvent e) { ? ? ? ? ? ? // 當(dāng)點擊"連接服務(wù)器"按鈕之后,該按鈕被禁用(不可重復(fù)點擊)。同時"斷開服務(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ù)器”按鈕的動作事件監(jiān)聽處理類 ? ? private class linkServerHandlerStop implements ActionListener { ? ? ? ? /** ? ? ? ? ?* 當(dāng)點擊該按鈕之后,斷開服務(wù)器連接、清空圖形界面所有數(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ù)器時,應(yīng)該向服務(wù)器發(fā)送自己的用戶名、方便服務(wù)器區(qū)分 ? ? ? ? ? ? ? ? taMsg.append("——本人【" + nickname + "】成功連接到服務(wù)器......\n"); ? ? ? ? ? ? ? ? out.println("USERS"); ? ? ? // 向服務(wù)器發(fā)送"神秘代碼",請求 當(dāng)前在線用戶 列表 ? ? ? ? ? ? ? ? while (true) { ? ? ? ? ? ? ? ? ? ? msg = in.readLine(); ? ? ? // 讀取服務(wù)器端的發(fā)送的數(shù)據(jù) ? ? ? ? ? ? ? ? ? ? // 此 if 語句的作用是:過濾服務(wù)器發(fā)送過來的 更新當(dā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)離開請求bye 的時候,用戶真正離線 ? ? ? ? ? ? ? ? ? ? msg = msg.substring(msg.lastIndexOf(":") + 1); ? ? ? ? ? ? ? ? ? ? if (msg.equals(nickname)) { ? ? ? ? ? ? ? ? ? ? ? ? socket.close(); ? ? ? ? ? ? ? ? ? ? ? ? clientNames.remove(nickname); ? ? ? ? ? ? ? ? ? ? ? ? updateUsers(); ? ? ? ? ? ? ? ? ? ? ? ? break; ? ? ? // 終止線程 ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } catch (Exception e) { ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? ? // TODO "發(fā)送消息文本框" 的動作事件監(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)閉的動作事件監(jiān)聽處理類 ? ? // 當(dāng)用戶點擊 "x" 離開窗口時,也會向服務(wù)器發(fā)送 bye 請求,目的是為了同步更新數(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() + "個)")); ? ? ? ? lstUsers.setListData(clientNames); ? ? } ? ? ? // TODO 主方法 ? ? public static void main(String[] args) { ? ? ? ? new Client(); ? ? } }
如何同時開啟兩個客戶端進(jìn)行聊天?
將上述的 Client 類復(fù)制一份,改名為 Client2 ,然后同時啟動 Client 和 Client2 程序。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- java中UDP簡單聊天程序?qū)嵗a
- 詳解基于java的Socket聊天程序——客戶端(附demo)
- java網(wǎng)絡(luò)編程學(xué)習(xí)java聊天程序代碼分享
- java基于TCP協(xié)議實現(xiàn)聊天程序
- java基于C/S模式實現(xiàn)聊天程序(客戶端)
- 詳解基于java的Socket聊天程序——服務(wù)端(附demo)
- java實現(xiàn)基于Tcp的socket聊天程序
- 詳解基于java的Socket聊天程序——初始設(shè)計(附demo)
- java實現(xiàn)簡單TCP聊天程序
- 基于Java的Socket多客戶端Client-Server聊天程序的實現(xiàn)
相關(guān)文章
mybatis?mapper.xml?注釋帶參數(shù)的坑及解決
這篇文章主要介紹了mybatis?mapper.xml?注釋帶參數(shù)的坑及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01SpringBoot 文件或圖片上傳與下載功能的實現(xiàn)
這篇文章主要介紹了SpringBoot 文件或圖片上傳與下載功能的實現(xiàn),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-02-02