由于不想学GUI、所以很大程度上是面向GPT完成的实验。
**************程序仅供参考**************
实验题目及其要求
1.掌握Java中GUI程序的编写,包括事件监听机制。
2.掌握Java的网络通信编程,ServerSocket,Socket类的使用。
3.掌握Java中多线程的编程,Thread类,Runnable接口的使用。
4.掌握用面向对象的方法分析和解决复杂问题。
实验内容
编写程序完成以下功能:
- 设计一个基于GUI的客户-服务器的通信应用程序,如图1、图2所示。
| |
图1 Socket通信服务器端界面 | 图2 Socket通信客户端界面 |
2.图1为Socket通信服务器端界面,点击该界面中的【Start】按钮,启动服务器监听服务(在图1界面中间的多行文本区域显示“Server starting…”字样)。图2为Socket通信客户端界面,点击该界面中的【Connect】按钮与服务器建立链接,并在图2所示界面中间的多行文本区域显示“Connect to server…”字样,当服务器端监听到客户端的连接后,在图1界面中间的多行文本区域追加一行“Client connected…”字样,并与客户端建立Socket连接。
3.当图1所示的服务器端和图2所示的客户机端建立Socket连接后,编程实现服务端、客户端之间的“单向通信”:在客户端的输入界面发送消息,在服务端接收该消息,并将接收到对方的数据追加显示在多行文本框中。
思考题
1. 对整个实验进行总结,写出实验心得。
2. 在完成上述实验内容的基础上,尝试实现“双向通信”功能,即服务端、客户端之间可以相互发送、接收消息,并以此作为实验成绩评优的加分依据。
--------------------------------------------------------------------------------------------------------
实验代码及部分解析
先放上实验结果。根据实验要求,实现了双向通信,并且允许多个客户端进行连接(此处服务端的通信逻辑是“广播”形式,这一点可以拓展成“指定某客户端进行通信”的形式)。
客户端与服务端的代码基本一致,这里只说下服务端的代码。
在服务端中,主要的代码内容有3块儿,分别是UI的编写、发送消息的逻辑、监听进程的编写。
监听进程我是使用“Runnable接口实现”的方式做的,这一点可以换成“Thread子类”来实现,并且每当监听到一个用户的socket连接请求时,会将该用户的信息加入到一个“List”中。
private List<PrintWriter> clientWriters = new ArrayList<>();//用于存放所有连接的客户端
服务端发送消息时会根据上面的“List”,将消息广播给所有客户端。
代码的文件格式如下:
其中ClientGUI_Test与ClientGUI一模一样(注意修改public class的类名等),这里是为了更好地展现“1Server、2Client” 。
下面是具体的代码实现:
ServerGUI.java
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class ServerGUI extends JFrame {
private JTextArea textArea;//消息显示区域
private JTextField portTextField;//端口输入框
private JTextField messageTextField;
private List<PrintWriter> clientWriters = new ArrayList<>();//用于存放所有连接的客户端
private Thread serverThread;//服务端的监听进程
public ServerGUI() {
setTitle("Socket通信服务器端");
setSize(560, 350);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//服务器设置区域,首先创建一个面板用于包装"服务器设置"部分
JPanel serverSettingsPanel = new JPanel(new BorderLayout());
serverSettingsPanel.setBorder(BorderFactory.createTitledBorder("服务端设置区:")); // 添加标题
portTextField = new JTextField(5);
portTextField.setText("8888");
serverSettingsPanel.add(new JLabel("Port: "), BorderLayout.WEST);
serverSettingsPanel.add(portTextField, BorderLayout.CENTER);
JButton startButton = new JButton("Start");
startButton.addActionListener(e -> startServer());
serverSettingsPanel.add(startButton, BorderLayout.EAST);
// 添加"服务器设置"面板到主界面
add(serverSettingsPanel, BorderLayout.NORTH);
//消息显示区域
JPanel messageShowPanel = new JPanel(new BorderLayout());
messageShowPanel.setBorder(BorderFactory.createTitledBorder("消息接收区:"));
textArea = new JTextArea();
textArea.setEditable(false);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
JScrollPane scrollPane = new JScrollPane(textArea);
messageShowPanel.add(scrollPane, BorderLayout.CENTER);
add(messageShowPanel, BorderLayout.CENTER);
//消息编辑区域
JPanel messageEditPanel = new JPanel(new BorderLayout());
messageEditPanel.setBorder(BorderFactory.createTitledBorder("消息编辑区:"));
messageTextField = new JTextField(20);
JButton sendButton = new JButton("Say");
sendButton.addActionListener(e -> sendMessageToClients());
messageEditPanel.add(new JLabel("Say: "), BorderLayout.WEST);
messageEditPanel.add(messageTextField);
messageEditPanel.add(sendButton, BorderLayout.EAST);
add(messageEditPanel, BorderLayout.SOUTH);
}
private void startServer() {
try {
int port = Integer.parseInt(portTextField.getText());
ServerSocket serverSocket = new ServerSocket(port);
appendText("Server starting on port " + port + "...");
serverThread = new Thread(() -> {
try {
while (true) {
Socket clientSocket = serverSocket.accept();
String IP_and_Port = clientSocket.getInetAddress().getHostAddress() + ": " + clientSocket.getPort();
appendText("Client(" + IP_and_Port + ") connected...");
clientWriters.add(new PrintWriter(clientSocket.getOutputStream(), true));
//启动监听进程
ClientReceiver handler = new ClientReceiver(clientSocket, IP_and_Port);
new Thread(handler).start();
}
} catch (IOException e) {
e.printStackTrace();
}
});
serverThread.start();
} catch (IOException e) {
e.printStackTrace();
}
}
private void sendMessageToClients() {
String message = messageTextField.getText();
//广播形式发送消息
for (PrintWriter writer : clientWriters) {
if(writer != null){
writer.println(message);
}
}
messageTextField.setText("");
}
private void appendText(String message) {
SwingUtilities.invokeLater(() -> {
textArea.append(message + "\n");
System.out.println(message);
});
}
private class ClientReceiver implements Runnable {
private Socket clientSocket;
private String clientInfo;
private BufferedReader reader;
public ClientReceiver(Socket socket, String clientInfo) {
this.clientSocket = socket;
this.clientInfo = clientInfo;
try {
reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
String message;
while ((message = reader.readLine()) != null) {
appendText("Client(" + clientInfo + "): " + message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
ServerGUI server = new ServerGUI();
server.setVisible(true);
});
}
}
ClientGUI.java
import javax.swing.*;
import java.awt.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class ClientGUI extends JFrame {
private JTextArea textArea;
private JTextField ipAddressTextField;
private JTextField portTextField;
private JTextField messageTextField;
private Socket socket;
private PrintWriter out;
public ClientGUI() {
setTitle("Socket通信客户端");
setSize(560, 350);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//客户端设置区域
JPanel clientSettingsPanel = new JPanel();
clientSettingsPanel.setBorder(BorderFactory.createTitledBorder("客户端设置区:"));
ipAddressTextField = new JTextField(15);
ipAddressTextField.setText("localhost");
clientSettingsPanel.add(new JLabel("IP Address:"), BorderLayout.WEST);
clientSettingsPanel.add(ipAddressTextField);
portTextField = new JTextField(5);
portTextField.setText("8888");
clientSettingsPanel.add(new JLabel("Port:"));
clientSettingsPanel.add(portTextField);
JButton connectButton = new JButton("Connect");
connectButton.addActionListener(e -> connectToServer());
clientSettingsPanel.add(connectButton, BorderLayout.EAST);
// 添加"服务器设置"面板到主界面
add(clientSettingsPanel, BorderLayout.NORTH);
//消息显示区域
//消息显示区域
JPanel messageShowPanel = new JPanel(new BorderLayout());
messageShowPanel.setBorder(BorderFactory.createTitledBorder("消息接收区:"));
textArea = new JTextArea();
textArea.setEditable(false);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
JScrollPane scrollPane = new JScrollPane(textArea);
messageShowPanel.add(scrollPane, BorderLayout.CENTER);
add(messageShowPanel, BorderLayout.CENTER);
//消息编辑区域
JPanel messageEditPanel = new JPanel(new BorderLayout());
messageEditPanel.setBorder(BorderFactory.createTitledBorder("消息编辑区:"));
messageTextField = new JTextField(20);
JButton sendButton = new JButton("Say");
sendButton.addActionListener(e -> sendMessageToServer());
messageEditPanel.add(new JLabel("Say: "), BorderLayout.WEST);
messageEditPanel.add(messageTextField);
messageEditPanel.add(sendButton, BorderLayout.EAST);
add(messageEditPanel, BorderLayout.SOUTH);
}
private void connectToServer() {
String ipAddress = ipAddressTextField.getText();
int port = Integer.parseInt(portTextField.getText());
try {
socket = new Socket(ipAddress, port);
out = new PrintWriter(socket.getOutputStream(), true);
String IP_and_Port = socket.getLocalAddress() + ": " + socket.getLocalPort();
appendText("Connected to server at " + ipAddress + ":" + port + " Current: " + IP_and_Port);
//启动监听线程
ServerReceiver handle = new ServerReceiver(socket);
new Thread(handle).start();
} catch (Exception e) {
e.printStackTrace();
appendText("Connection failed.");
}
}
private void sendMessageToServer() {
String message = messageTextField.getText();
if (out != null) {
out.println(message);
}
messageTextField.setText("");
}
private void appendText(String message) {
SwingUtilities.invokeLater(() -> {
textArea.append(message + "\n");
System.out.println(message);
});
}
private class ServerReceiver implements Runnable {
private BufferedReader reader;
public ServerReceiver(Socket socket) {
try {
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
String message;
while ((message = reader.readLine()) != null) {
appendText("Server: " + message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
ClientGUI client = new ClientGUI();
client.setVisible(true);
});
}
}