Java多線程實現(xiàn)聊天客戶端和服務(wù)器
本文實例為大家分享了java聊天室代碼,供大家參考,具體內(nèi)容如下
主要涉及知識
- Java中GUI程序的編寫,包括事件監(jiān)聽機(jī)制。
- Java的網(wǎng)絡(luò)通信編程,ServerSocket,Socket類的使用。
- Java中多線程的編程,Thread類,Runnable接口的使用。
源代碼
客戶端
package project1; import java.awt.*; import java.awt.event.*; import java.io.*; import java.net.*; import javax.swing.*; public class Client { private JFrame clientFrame; private JLabel IPLabel; private JLabel PortLabel; private JLabel sayLabel; private JLabel nicknameLabel; private JTextField IPText; private JTextField PortText; private JTextField nicknameText; private JTextField sayText; private JButton connectButton; private JButton nicknameButton; private JButton sayButton; private JPanel jPanelNorth; private JPanel jPanelSouth0; private JPanel jPanelSouth1; private JPanel jPanelSouth2; private JTextArea clientTextArea; private JScrollPane scroller; private BufferedReader reader; private PrintWriter writer; private String nickname; public static void main(String args[]) { Client aClient = new Client(); aClient.startUp(); } // 初始化組件 public Client() { nickname = "客戶端"; clientFrame = new JFrame(); jPanelNorth = new JPanel(); IPLabel = new JLabel("服務(wù)器IP", JLabel.LEFT); IPText = new JTextField(10); PortLabel = new JLabel("服務(wù)器端口", JLabel.LEFT); PortText = new JTextField(10); connectButton = new JButton("連接"); clientTextArea = new JTextArea(); scroller = new JScrollPane(clientTextArea); jPanelSouth0 = new JPanel(); jPanelSouth1 = new JPanel(); jPanelSouth2 = new JPanel(); nicknameLabel = new JLabel("昵稱", JLabel.LEFT); nicknameText = new JTextField(nickname, 30); nicknameButton = new JButton("確認(rèn)"); sayLabel = new JLabel("消息", JLabel.LEFT); sayText = new JTextField(30); sayButton = new JButton("確認(rèn)"); } // 構(gòu)建GUI private void buildGUI() { // 窗口的設(shè)置 clientFrame.setTitle("客戶端"); clientFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); clientFrame.setSize(550, 550); // 北區(qū)的組件 jPanelNorth.add(IPLabel); jPanelNorth.add(IPText); jPanelNorth.add(PortLabel); jPanelNorth.add(PortText); jPanelNorth.add(connectButton); clientFrame.getContentPane().add(BorderLayout.NORTH, jPanelNorth); // 中間的組件 clientTextArea.setFocusable(false); scroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); scroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); clientFrame.getContentPane().add(BorderLayout.CENTER, scroller); // 南區(qū)的組件 jPanelSouth1.add(nicknameLabel); jPanelSouth1.add(nicknameText); jPanelSouth1.add(nicknameButton); jPanelSouth2.add(sayLabel); jPanelSouth2.add(sayText); jPanelSouth2.add(sayButton); jPanelSouth0.setLayout(new BoxLayout(jPanelSouth0, BoxLayout.Y_AXIS)); jPanelSouth0.add(jPanelSouth1); jPanelSouth0.add(jPanelSouth2); clientFrame.getContentPane().add(BorderLayout.SOUTH, jPanelSouth0); // 設(shè)置窗口可見 clientFrame.setVisible(true); } // 客戶端運(yùn)行 public void startUp() { buildGUI(); // 接收服務(wù)器消息的線程 Runnable incomingReader = new Runnable() { @Override public void run() { String message; try { while ((message = reader.readLine()) != null) { clientTextArea.append(message + "\n"); } } catch (Exception ex) { ex.printStackTrace(); } } }; // 監(jiān)聽Connect按鈕,實現(xiàn)服務(wù)器的連接 connectButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String aServerIP = IPText.getText(); String aServerPort = PortText.getText(); if (aServerIP.equals("") || aServerPort.equals("")) { JOptionPane.showMessageDialog(clientFrame, "請輸入 完整的 IP和端口!"); } else { try { @SuppressWarnings("resource") Socket clientSocket = new Socket(aServerIP, Integer.parseInt(aServerPort)); InputStreamReader streamReader = new InputStreamReader(clientSocket.getInputStream()); reader = new BufferedReader(streamReader); writer = new PrintWriter(clientSocket.getOutputStream()); clientTextArea.append("服務(wù)器已連接...\n"); Thread readerThread = new Thread(incomingReader); readerThread.start(); } catch (Exception ex) { JOptionPane.showMessageDialog(clientFrame, "連接不上服務(wù)器!\n請確認(rèn) IP 和 端口 輸入正確。"); } } } }); // 監(jiān)聽nickname,設(shè)置昵稱 ActionListener nicknameListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String aText = nicknameText.getText(); if (!aText.equals("")) { nickname = aText; } } }; nicknameButton.addActionListener(nicknameListener); nicknameText.addActionListener(nicknameListener); nicknameText.addFocusListener(new FocusListener() { @Override public void focusGained(FocusEvent e) { } @Override public void focusLost(FocusEvent e) { String aText = nicknameText.getText(); if (!aText.equals("")) { nickname = aText; } } }); // 發(fā)送消息到服務(wù)器 ActionListener SayListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String aText = sayText.getText(); if (aText.equals("")) { JOptionPane.showMessageDialog(clientFrame, "內(nèi)容不能為空!"); } else { try { writer.println(nickname + ":" + aText); writer.flush(); } catch (Exception ex) { ex.printStackTrace(); } sayText.setText(""); } } }; sayButton.addActionListener(SayListener); sayText.addActionListener(SayListener); } }
服務(wù)器
package project1; import java.awt.*; import java.awt.event.*; import java.io.*; import java.net.*; import java.util.ArrayList; import java.util.Iterator; import javax.swing.*; public class Server { private JFrame serverFrame; private JLabel portLabel; private JLabel sayLabel; private JLabel nicknameLabel; private JTextField portText; private JTextField sayText; private JTextField nicknameText; private JButton startButton; private JButton sayButton; private JButton nicknameButton; private JPanel jPanelNorth; private JPanel jPanelSouth0; private JPanel jPanelSouth1; private JPanel jPanelSouth2; private JScrollPane scroller; private JTextArea serverTextArea; private ArrayList<PrintWriter> clientOutputStreams; private String nickname; public static void main(String[] args) { Server aServer = new Server(); aServer.startUp(); } // 初始化組件 public Server() { nickname = "服務(wù)器"; serverFrame = new JFrame(); jPanelNorth = new JPanel(); portLabel = new JLabel("端口", JLabel.LEFT); portText = new JTextField(30); startButton = new JButton("開始"); serverTextArea = new JTextArea(); scroller = new JScrollPane(serverTextArea); nicknameLabel = new JLabel("昵稱", JLabel.LEFT); nicknameText = new JTextField(nickname, 30); nicknameButton = new JButton("確認(rèn)"); jPanelSouth0 = new JPanel(); jPanelSouth1 = new JPanel(); jPanelSouth2 = new JPanel(); sayLabel = new JLabel("消息", JLabel.LEFT); sayText = new JTextField(30); sayButton = new JButton("確認(rèn)"); } // 構(gòu)建GUI private void buildGUI() { // 窗口的設(shè)置 serverFrame.setTitle("服務(wù)器"); serverFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); serverFrame.setSize(550, 550); // 北區(qū)的組件 jPanelNorth.add(portLabel); jPanelNorth.add(portText); jPanelNorth.add(startButton); serverFrame.getContentPane().add(BorderLayout.NORTH, jPanelNorth); // 中間的組件 serverTextArea.setFocusable(false); scroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); scroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); serverFrame.getContentPane().add(BorderLayout.CENTER, scroller); // 南區(qū)的組件 jPanelSouth1.add(nicknameLabel); jPanelSouth1.add(nicknameText); jPanelSouth1.add(nicknameButton); jPanelSouth2.add(sayLabel); jPanelSouth2.add(sayText); jPanelSouth2.add(sayButton); jPanelSouth0.setLayout(new BoxLayout(jPanelSouth0, BoxLayout.Y_AXIS)); jPanelSouth0.add(jPanelSouth1); jPanelSouth0.add(jPanelSouth2); serverFrame.getContentPane().add(BorderLayout.SOUTH, jPanelSouth0); // 設(shè)置窗口可見 serverFrame.setVisible(true); } // 服務(wù)器運(yùn)行 public void startUp() { buildGUI(); // 監(jiān)聽Start按鈕,建立端口 ActionListener startListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { clientOutputStreams = new ArrayList<PrintWriter>(); String aPort = portText.getText(); if (aPort.equals("")) { JOptionPane.showMessageDialog(serverFrame, "請輸入正確的端口號!"); } else { try { // 等待客戶端連接的線程 Runnable serverRunnable = new Runnable() { @Override public void run() { ServerSocket serverSocket; try { serverSocket = new ServerSocket(Integer.parseInt(aPort)); serverTextArea.append("正在等待客戶端連接...\n"); while (true) { Socket clientSocket = serverSocket.accept(); serverTextArea.append("客戶端已連接...\n"); PrintWriter writer = new PrintWriter(clientSocket.getOutputStream()); clientOutputStreams.add(writer); Thread t = new Thread(new ClientHandler(clientSocket)); t.start(); } } catch (NumberFormatException | IOException e) { e.printStackTrace(); } } }; Thread serverThread = new Thread(serverRunnable); serverThread.start(); } catch (Exception ex) { ex.printStackTrace(); } } } }; startButton.addActionListener(startListener); portText.addActionListener(startListener); // 監(jiān)聽nickname,設(shè)置昵稱 ActionListener nicknameListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String aText = nicknameText.getText(); if (!aText.equals("")) { nickname = aText; } } }; nicknameButton.addActionListener(nicknameListener); nicknameText.addActionListener(nicknameListener); nicknameText.addFocusListener(new FocusListener() { @Override public void focusGained(FocusEvent e) { } @Override public void focusLost(FocusEvent e) { String aText = nicknameText.getText(); if (!aText.equals("")) { nickname = aText; } } }); // 監(jiān)聽Say按鈕,發(fā)送消息 ActionListener SayListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String aText = sayText.getText(); if (!aText.equals("")) { aText = nickname + ":" + aText; sendToEveryClient(aText); serverTextArea.append(aText + "\n"); sayText.setText(""); } else { JOptionPane.showMessageDialog(serverFrame, "內(nèi)容不能為空!"); } } }; sayButton.addActionListener(SayListener); sayText.addActionListener(SayListener); } // 多客戶端的線程 public class ClientHandler implements Runnable { BufferedReader bReader; Socket aSocket; public ClientHandler(Socket clientSocket) { try { aSocket = clientSocket; InputStreamReader isReader = new InputStreamReader(aSocket.getInputStream()); bReader = new BufferedReader(isReader); } catch (Exception ex) { ex.printStackTrace(); } } @Override public void run() { String message; try { while ((message = bReader.readLine()) != null) { sendToEveryClient(message); serverTextArea.append(message + "\n"); } } catch (Exception ex) { ex.printStackTrace(); } } } // 發(fā)送消息給所有客戶端的方法 private void sendToEveryClient(String message) { Iterator<PrintWriter> it = clientOutputStreams.iterator(); while (it.hasNext()) { try { PrintWriter writer = (PrintWriter) it.next(); writer.println(message); writer.flush(); } catch (Exception ex) { ex.printStackTrace(); } } } }
GUI運(yùn)行截圖:
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java通過httpclient比較重定向和請求轉(zhuǎn)發(fā)
這篇文章主要介紹了Java通過httpclient比較重定向和請求轉(zhuǎn)發(fā),HttpClient?4.x?版本,get請求方法會自動進(jìn)行重定向,而post請求方法不會自動進(jìn)行重定向,需要的朋友可以參考下2023-04-04IDEA使用JDBC導(dǎo)入配置jar包連接MySQL數(shù)據(jù)庫
這篇文章介紹了IDEA使用JDBC安裝配置jar包連接MySQL數(shù)據(jù)庫的方法,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-12-12JavaWeb JDBC + MySql 通訊錄實現(xiàn)簡單的增刪改查功能案例詳解
這篇文章主要介紹了JavaWeb JDBC + MySql 通訊錄實現(xiàn)簡單的增刪改查功能,結(jié)合具體案例形式詳細(xì)分析了JavaWeb JDBC + MySql數(shù)據(jù)庫連接、增刪改查等相關(guān)操作技巧與注意事項,需要的朋友可以參考下2019-08-08SpringMVC中Model與Session的區(qū)別說明
這篇文章主要介紹了SpringMVC中Model與Session的區(qū)別說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12vscode 配置java環(huán)境并調(diào)試運(yùn)行的詳細(xì)過程
這篇文章主要介紹了vscode 配置java環(huán)境并調(diào)試運(yùn)行的詳細(xì)過程,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-05-05