【Java】Java多執行緒實現的聊天客戶端和伺服器
主要涉及知識
·Java中GUI程式的編寫,包括事件監聽機制。
·Java的網路通訊程式設計,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("伺服器IP", JLabel.LEFT);
IPText = new JTextField(10);
PortLabel = new JLabel("伺服器埠", 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("確認");
sayLabel = new JLabel("訊息", JLabel.LEFT);
sayText = new JTextField(30);
sayButton = new JButton("確認");
}
// 構建GUI
private void buildGUI() {
// 視窗的設定
clientFrame.setTitle("客戶端");
clientFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
clientFrame.setSize(550, 550);
// 北區的元件
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);
// 南區的元件
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);
// 設定視窗可見
clientFrame.setVisible(true);
}
// 客戶端執行
public void startUp() {
buildGUI();
// 接收伺服器訊息的執行緒
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();
}
}
};
// 監聽Connect按鈕,實現伺服器的連線
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("伺服器已連線...\n");
Thread readerThread = new Thread(incomingReader);
readerThread.start();
} catch (Exception ex) {
JOptionPane.showMessageDialog(clientFrame, "連線不上伺服器!\n請確認 IP 和 埠 輸入正確。");
}
}
}
});
// 監聽nickname,設定暱稱
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;
}
}
});
// 傳送訊息到伺服器
ActionListener SayListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String aText = sayText.getText();
if (aText.equals("")) {
JOptionPane.showMessageDialog(clientFrame, "內容不能為空!");
} else {
try {
writer.println(nickname + ":" + aText);
writer.flush();
} catch (Exception ex) {
ex.printStackTrace();
}
sayText.setText("");
}
}
};
sayButton.addActionListener(SayListener);
sayText.addActionListener(SayListener);
}
}
伺服器
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 = "伺服器";
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("確認");
jPanelSouth0 = new JPanel();
jPanelSouth1 = new JPanel();
jPanelSouth2 = new JPanel();
sayLabel = new JLabel("訊息", JLabel.LEFT);
sayText = new JTextField(30);
sayButton = new JButton("確認");
}
// 構建GUI
private void buildGUI() {
// 視窗的設定
serverFrame.setTitle("伺服器");
serverFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
serverFrame.setSize(550, 550);
// 北區的元件
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);
// 南區的元件
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);
// 設定視窗可見
serverFrame.setVisible(true);
}
// 伺服器執行
public void startUp() {
buildGUI();
// 監聽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);
// 監聽nickname,設定暱稱
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;
}
}
});
// 監聽Say按鈕,傳送訊息
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, "內容不能為空!");
}
}
};
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();
}
}
}
// 傳送訊息給所有客戶端的方法
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執行截圖
相關文章
- Java多執行緒的實現Java執行緒
- Java實現多執行緒區域網聊天室Java執行緒
- Java多執行緒實現方式Java執行緒
- C/S(socket、執行緒 實現多個客戶端、伺服器端簡易通訊)執行緒客戶端伺服器
- socket實現服務端多執行緒,客戶端重複輸入服務端執行緒客戶端
- Java實現多執行緒的三種方式Java執行緒
- Qt實現基於多執行緒的檔案傳輸(服務端,客戶端)QT執行緒服務端客戶端
- Java多執行緒【三種實現方法】Java執行緒
- Java Netty伺服器客戶端聊天示範程式碼JavaNetty伺服器客戶端
- SpringBoot執行緒池和Java執行緒池的實現原理Spring Boot執行緒Java
- Java高併發與多執行緒(二)-----執行緒的實現方式Java執行緒
- 【Java多執行緒】輕鬆搞定Java多執行緒(二)Java執行緒
- Java建立多執行緒的幾種方式實現Java執行緒
- Java多執行緒-執行緒中止Java執行緒
- Java多執行緒-Callable和FutureJava執行緒
- java多執行緒Java執行緒
- Java - 多執行緒Java執行緒
- java——多執行緒Java執行緒
- java 多執行緒Java執行緒
- 使用Java實現多執行緒程式設計Java執行緒程式設計
- Java多執行緒之—Synchronized方式和CAS方式實現執行緒安全效能對比Java執行緒synchronized
- 【Java多執行緒】執行緒安全的集合Java執行緒
- Java多執行緒-執行緒池的使用Java執行緒
- Java多執行緒學習(一)Java多執行緒入門Java執行緒
- Java之實現多執行緒的方式二:實現Runnable介面Java執行緒
- Java多執行緒並行處理任務的實現Java執行緒並行
- Java多執行緒之守護執行緒實戰Java執行緒
- java執行緒實現方式Java執行緒
- 多執行緒伺服器的實現執行緒伺服器
- Java之實現多執行緒的方式三:實現Callable介面(結合執行緒池使用)Java執行緒
- Java中的多執行緒Java執行緒
- Java多執行緒-執行緒狀態Java執行緒
- Java多執行緒-執行緒通訊Java執行緒
- java多執行緒9:執行緒池Java執行緒
- java 多執行緒守護執行緒Java執行緒
- Java多執行緒(2)執行緒鎖Java執行緒
- 【java多執行緒】(二)執行緒停止Java執行緒
- Java多執行緒之執行緒中止Java執行緒
- 實現伺服器和客戶端資料互動,Java Socket有妙招伺服器客戶端Java