ClientUI.java
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/GUIForms/JFrame.java to edit this template
*/
package cn.edu.gzhu;
import java.io.*;
import java.net.*;
import javax.swing.JOptionPane;
/**
*
* @author 17941
*/
public class ClientUI extends javax.swing.JFrame {
private Socket clientSocket = null;
private BufferedReader in;
private PrintWriter out;
/**
* Creates new form ClientUI
*/
public ClientUI() {
initComponents();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
topPanel = new javax.swing.JPanel();
jLabel1 = new javax.swing.JLabel();
jLabel2 = new javax.swing.JLabel();
jLabel3 = new javax.swing.JLabel();
TextInput = new javax.swing.JTextField();
TextRemoteName = new javax.swing.JTextField();
TextRemotePort = new javax.swing.JTextField();
btnConnect = new javax.swing.JButton();
btnSpeak = new javax.swing.JButton();
jLabel4 = new javax.swing.JLabel();
TextMessageCount = new javax.swing.JTextField();
btnBatchSend = new javax.swing.JButton();
midPanel = new javax.swing.JPanel();
jScrollPane1 = new javax.swing.JScrollPane();
txtArea = new javax.swing.JTextArea();
jScrollPane2 = new javax.swing.JScrollPane();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
topPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("通信面板"));
jLabel1.setText("服务器主机号:");
jLabel2.setText("发言:");
jLabel3.setText("服务器端口号:");
TextInput.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
TextInputActionPerformed(evt);
}
});
TextRemoteName.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
TextRemoteNameActionPerformed(evt);
}
});
btnConnect.setText("连接服务");
btnConnect.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnConnectActionPerformed(evt);
}
});
btnSpeak.setText("发言");
btnSpeak.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnSpeakActionPerformed(evt);
}
});
jLabel4.setText("消息条数:");
TextMessageCount.setText("jTextField1");
btnBatchSend.setText("批量发言");
btnBatchSend.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnBatchSendActionPerformed(evt);
}
});
javax.swing.GroupLayout topPanelLayout = new javax.swing.GroupLayout(topPanel);
topPanel.setLayout(topPanelLayout);
topPanelLayout.setHorizontalGroup(
topPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(topPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(jLabel2)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(TextRemotePort, javax.swing.GroupLayout.PREFERRED_SIZE, 366, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(29, 29, 29)
.addComponent(jLabel4, javax.swing.GroupLayout.PREFERRED_SIZE, 41, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(TextMessageCount, javax.swing.GroupLayout.PREFERRED_SIZE, 76, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(btnSpeak, javax.swing.GroupLayout.PREFERRED_SIZE, 78, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(88, 88, 88))
.addGroup(topPanelLayout.createSequentialGroup()
.addComponent(jLabel1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(TextRemoteName, javax.swing.GroupLayout.PREFERRED_SIZE, 280, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jLabel3)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(TextInput, javax.swing.GroupLayout.PREFERRED_SIZE, 72, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(62, 62, 62)
.addComponent(btnConnect, javax.swing.GroupLayout.PREFERRED_SIZE, 78, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, topPanelLayout.createSequentialGroup()
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(btnBatchSend, javax.swing.GroupLayout.PREFERRED_SIZE, 78, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(207, 207, 207))
);
topPanelLayout.setVerticalGroup(
topPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(topPanelLayout.createSequentialGroup()
.addGroup(topPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel1)
.addComponent(TextRemoteName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(btnConnect)
.addComponent(jLabel3)
.addComponent(TextInput, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(topPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(btnSpeak)
.addComponent(jLabel2)
.addComponent(TextRemotePort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel4)
.addComponent(TextMessageCount, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnBatchSend)
.addGap(0, 10, Short.MAX_VALUE))
);
midPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("服务器Echo消息面板"));
txtArea.setColumns(20);
txtArea.setRows(5);
jScrollPane1.setViewportView(txtArea);
javax.swing.GroupLayout midPanelLayout = new javax.swing.GroupLayout(midPanel);
midPanel.setLayout(midPanelLayout);
midPanelLayout.setHorizontalGroup(
midPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(midPanelLayout.createSequentialGroup()
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 739, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 9, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);
midPanelLayout.setVerticalGroup(
midPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 187, Short.MAX_VALUE)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, midPanelLayout.createSequentialGroup()
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 66, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(47, 47, 47))
);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(topPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addComponent(midPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(topPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(midPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
);
pack();
}// </editor-fold>
private void TextRemoteNameActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
}
private void TextInputActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
}
//连接服务器
private void btnConnectActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
try {
// 获取服务器参数
String remoteName = TextRemoteName.getText();
String remotePortStr = TextInput.getText();
// 检查端口号字符串是否为空
if (remotePortStr.isEmpty()) {
JOptionPane.showMessageDialog(null, "端口号不能为空", "错误提示", JOptionPane.ERROR_MESSAGE);
return;
}
// 将端口号字符串转换为整数
int remotePort = Integer.parseInt(remotePortStr);
// 构建服务器Socket格式的地址
SocketAddress remoteAddr = new InetSocketAddress(InetAddress.getByName(remoteName), remotePort);
// 1. 创建套接字clientSocket并连接到远程服务器
clientSocket = new Socket();
clientSocket.connect(remoteAddr);
txtArea.append("连接服务器成功,会话开始...\n");
// 2. 创建绑定到套接字clientSocket上的网络输入流与输出流
out = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream(), "UTF-8"), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), "UTF-8"));
} catch (NumberFormatException ex) {
JOptionPane.showMessageDialog(null, "端口号必须是有效的数字", "错误提示", JOptionPane.ERROR_MESSAGE);
return;
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, ex.getMessage(), "连接错误", JOptionPane.ERROR_MESSAGE);
return;
}
btnConnect.setEnabled(false);
}
private void btnSpeakActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
if (clientSocket == null) {
JOptionPane.showMessageDialog(null, "请先检查服务器连接情况。\n发言之前要确保客户机连接到服务器!", "错误提示", JOptionPane.ERROR_MESSAGE);
return;
}
String outStr = TextRemotePort.getText();
if (outStr == null || outStr.isEmpty()) {
JOptionPane.showMessageDialog(null, "请输入发送消息!", "提示", JOptionPane.INFORMATION_MESSAGE);
return;
}
String messageCountStr = TextMessageCount.getText();
if (messageCountStr == null || messageCountStr.isEmpty()) {
JOptionPane.showMessageDialog(null, "请输入消息条数!", "提示", JOptionPane.INFORMATION_MESSAGE);
return;
}
int messageCount = Integer.parseInt(messageCountStr);
try {
for (int i = 0; i < messageCount; i++) {
out.println(outStr);
Thread.sleep(10); // 间隔10ms
}
TextRemotePort.setText(""); // 将代发消息框置空
String inStr;
inStr = in.readLine();
txtArea.append("Echo:" + inStr + "\n");
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, "客户机接收消息错误!", "错误提示", JOptionPane.ERROR_MESSAGE);
} catch (InterruptedException ex) {
JOptionPane.showMessageDialog(null, "线程中断错误!", "错误提示", JOptionPane.ERROR_MESSAGE);
}
}
private void btnBatchSendActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
if (clientSocket == null) {
JOptionPane.showMessageDialog(null, "请先检查服务器连接情况。\n发言之前要确保客户机连接到服务器!", "错误提示", JOptionPane.ERROR_MESSAGE);
return;
}
String outStr = TextRemotePort.getText();
if (outStr == null || outStr.isEmpty()) {
JOptionPane.showMessageDialog(null, "请输入发送消息!", "提示", JOptionPane.INFORMATION_MESSAGE);
return;
}
String messageCountStr = TextMessageCount.getText();
if (messageCountStr == null || messageCountStr.isEmpty()) {
JOptionPane.showMessageDialog(null, "请输入消息条数!", "提示", JOptionPane.INFORMATION_MESSAGE);
return;
}
int messageCount = Integer.parseInt(messageCountStr);
try {
for (int i = 0; i < messageCount; i++) {
out.println(outStr);
Thread.sleep(10); // 间隔10ms
}
TextRemotePort.setText(""); // 将代发消息框置空
String inStr;
inStr = in.readLine();
txtArea.append("Echo:" + inStr + "\n");
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, "客户机接收消息错误!", "错误提示", JOptionPane.ERROR_MESSAGE);
} catch (InterruptedException ex) {
JOptionPane.showMessageDialog(null, "线程中断错误!", "错误提示", JOptionPane.ERROR_MESSAGE);
}
}
//按下回车键发送消息
private void txtInputActionPerformed(java.awt.event.ActionEvent evt){
btnSpeakActionPerformed(evt);
}
//关闭客户机时释放资源
private void formWindowClosing(java.awt.event.WindowEvent evt){
try{
if(in!=null)in.close();
if(out!=null)out.close();
if(clientSocket!=null)clientSocket.close();
}catch(IOException ex){}
}
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(ClientUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(ClientUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(ClientUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(ClientUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(ClientUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(ClientUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(ClientUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(ClientUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new ClientUI().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JTextField TextInput;
private javax.swing.JTextField TextMessageCount;
private javax.swing.JTextField TextRemoteName;
private javax.swing.JTextField TextRemotePort;
private javax.swing.JButton btnBatchSend;
private javax.swing.JButton btnConnect;
private javax.swing.JButton btnSpeak;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel jLabel3;
private javax.swing.JLabel jLabel4;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JScrollPane jScrollPane2;
private javax.swing.JPanel midPanel;
private javax.swing.JPanel topPanel;
private javax.swing.JTextArea txtArea;
// End of variables declaration
}
ClientThread.java
package cn.edu.gzhu;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.SwingWorker;
/**
*
* @author World
*/
public class ClientThread extends SwingWorker<String, String> {
private Socket toClientSocket = null; // 会话套接字
private BufferedReader in; // 网络输入流
private PrintWriter out; // 网络输出流
private int clientCounts = 0; // 在线客户机总数
private ServerUI serverUI; // 引用 ServerUI 实例
public ClientThread(Socket toClientSocket, int clientCounts, ServerUI serverUI) { // 构造函数
this.toClientSocket = toClientSocket;
this.clientCounts = clientCounts;
this.serverUI = serverUI;
}
@Override
protected String doInBackground() throws Exception {
try {
// 创建绑定到套接字 toClientSocket 上的网络输入流与输出流
in = new BufferedReader(new InputStreamReader(toClientSocket.getInputStream(), "UTF-8"));
out = new PrintWriter(new OutputStreamWriter(toClientSocket.getOutputStream(), "UTF-8"), true);
// 根据服务器协议,在网络流上进行读写操作
String recvStr;
while ((recvStr = in.readLine()) != null) { // 只要客户机不关闭,则反复等待和接收客户机消息
Date date = new Date();
DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time = format.format(date);
String message = toClientSocket.getRemoteSocketAddress() + " 客户机编号: " + clientCounts + " 消息:" + recvStr + " :" + time + "\n";
publish(message); // 发布消息到主线程
// 按照 echo 协议原封不动回送消息
out.println(toClientSocket.getLocalSocketAddress() + " 客户机编号: " + clientCounts + " Echo消息:" + recvStr + " : " + time);
} // end while
ServerUI.clientCounts--; // 客户机总数减1
// 远程客户机断开连接,线程释放资源
if (in != null) in.close();
if (out != null) out.close();
if (toClientSocket != null) toClientSocket.close();
} catch (IOException ex) {
ex.printStackTrace();
}
return "worker执行完成";
} // end doInBackground
@Override
protected void process(java.util.List<String> chunks) {
for (String message : chunks) {
serverUI.appendToTxtArea(message); // 调用 ServerUI 的 appendToTxtArea 方法
}
}
} // end class
ServerUI.java
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/GUIForms/JFrame.java to edit this template
*/
package cn.edu.gzhu;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
/**
*
* @author 17941
*/
public class ServerUI extends javax.swing.JFrame {
private ServerSocket listenSocket = null; //侦听套接字
private Socket toClientSocket = null; //与客户机对话的套接字
public static int clientCounts = 0; //客户数量编号
/**
* Creates new form ServerUI
*/
public ServerUI() {
initComponents();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
topPanel = new javax.swing.JPanel();
jLabel1 = new javax.swing.JLabel();
jLabel2 = new javax.swing.JLabel();
txtHostName = new javax.swing.JTextField();
txtHostPort = new javax.swing.JTextField();
btnStart = new javax.swing.JButton();
midPanel = new javax.swing.JPanel();
jScrollPane1 = new javax.swing.JScrollPane();
txtArea = new javax.swing.JTextArea();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
topPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("服务器启动面板"));
jLabel1.setText("服务器主机名:");
jLabel2.setText("服务器端口号:");
txtHostName.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
txtHostNameActionPerformed(evt);
}
});
btnStart.setText("启动服务器");
btnStart.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnStartActionPerformed(evt);
}
});
javax.swing.GroupLayout topPanelLayout = new javax.swing.GroupLayout(topPanel);
topPanel.setLayout(topPanelLayout);
topPanelLayout.setHorizontalGroup(
topPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(topPanelLayout.createSequentialGroup()
.addGroup(topPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(topPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 96, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(37, 37, 37)
.addComponent(txtHostName, javax.swing.GroupLayout.PREFERRED_SIZE, 76, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(41, 41, 41)
.addComponent(jLabel2)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(txtHostPort, javax.swing.GroupLayout.PREFERRED_SIZE, 76, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(topPanelLayout.createSequentialGroup()
.addGap(330, 330, 330)
.addComponent(btnStart, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addContainerGap(43, Short.MAX_VALUE))
);
topPanelLayout.setVerticalGroup(
topPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(topPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(topPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel1)
.addComponent(jLabel2)
.addComponent(txtHostName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(txtHostPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(18, 18, 18)
.addComponent(btnStart)
.addContainerGap(42, Short.MAX_VALUE))
);
midPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("服务器收到的客户机消息面板"));
txtArea.setColumns(20);
txtArea.setRows(5);
jScrollPane1.setViewportView(txtArea);
javax.swing.GroupLayout midPanelLayout = new javax.swing.GroupLayout(midPanel);
midPanel.setLayout(midPanelLayout);
midPanelLayout.setHorizontalGroup(
midPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(midPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 488, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
midPanelLayout.setVerticalGroup(
midPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(midPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 182, Short.MAX_VALUE))
);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(topPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(midPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(topPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(midPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
);
pack();
}// </editor-fold>
private void txtHostNameActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
}
private void btnStartActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
try {
btnStart.setEnabled(false); //禁用按钮,避免重复启动
String hostName = txtHostName.getText();//主机名
int hostPort = Integer.parseInt(txtHostPort.getText());//端口
//构建服务器的SocketAddress格式地址
SocketAddress serverAddr = new InetSocketAddress(InetAddress.getByName(hostName), hostPort);
listenSocket = new ServerSocket(); //创建侦听套接字
listenSocket.bind(serverAddr); //绑定到工作地址
txtArea.append("服务器开始等待客户机连接...\n");
} catch (IOException ex) {
}
//创建一个匿名线程,用于侦听和接受客户机连接,并创建响应客户机的会话线程
new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) { //处理客户机连接
toClientSocket = listenSocket.accept();//侦听并接受客户机连接
clientCounts++;//客户机数量加1
// txtArea.append(toClientSocket.getRemoteSocketAddress()+ " 客户机编号: "+clientCounts+ " 会话开始...\n");
//创建客户线程clientThread,实现一客户一线程
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
txtArea.append(toClientSocket.getRemoteSocketAddress() + " 客户机编号: " + clientCounts + " 会话开始...\n");
}
});
// 创建客户线程 clientThread,实现一客户一线程
// Thread clientThread = new ClientThread(toClientSocket, clientCounts, ServerUI.this);
// clientThread.start(); // 启动任务线程
// 使用 SwingWorker 启动任务线程
SwingWorker<String, String> worker = new ClientThread(toClientSocket, clientCounts, ServerUI.this);
worker.execute();
} // end while
} catch (IOException ex) {
JOptionPane.showMessageDialog(null, ex.getMessage(), "错误提示", JOptionPane.ERROR_MESSAGE);
}
} // end run()
}).start();
}
private void formWindowClosing(java.awt.event.WindowEvent evt) {
//关闭服务器之前释放套接字
if (listenSocket != null) {
listenSocket = null;
}
if (toClientSocket != null) {
toClientSocket = null;
}
}
/**
* @param args the command line arguments
*/
public void appendToTxtArea(String message) {
txtArea.append(message);
}
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(ServerUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(ServerUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(ServerUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(ServerUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(ServerUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(ServerUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(ServerUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(ServerUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
//</editor-fold>
//</editor-fold>
//</editor-fold>
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new ServerUI().setVisible(true);
}
});
}
// public static javax.swing.JTextArea txtArea;
// Variables declaration - do not modify
private javax.swing.JButton btnStart;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JPanel midPanel;
private javax.swing.JPanel topPanel;
private javax.swing.JTextArea txtArea;
private javax.swing.JTextField txtHostName;
private javax.swing.JTextField txtHostPort;
// End of variables declaration
}