Echo通信图形化界面实现

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                   
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值