手摸手教你使用java GUI开发一客户一线程案例

3 篇文章 0 订阅

0、前言

没有前言,直接开搞!!!

1、准备

集成开发环境:IDEA
JDK:1.8

2、创建项目

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述

3、 项目结构

需创建项目文件如下图
在这里插入图片描述

4、代码

ClientUI.java
package client;

import javax.swing.*;
import java.awt.*;

/**
 * Echo客户机:根据Echo协议,向服务器发送消息,接收服务器回送的消息
 *
 * @author KonBAI
 * @version 1.0
 * Create by 2020/04/21 16:25
 */
public class ClientUI extends JFrame {

    public static void main(String[] args) {

        // TODO 在窗口标题里写上自己的学号
        JFrame frame = new JFrame("Client: 1707");

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.getContentPane().add(new MyPanel());
        // 设置窗口宽度和高度
        frame.setPreferredSize(new Dimension(600, 300));
        frame.pack();
        frame.setVisible(true);
    }
}

MyListError.java
package client;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;

/**
 * @author KonBAI
 * @version 1.0
 * Create by 2020/04/21 21:03
 */
class MyListError implements ActionListener {

    MyPanel myPanel;

    public MyListError(MyPanel myPanel) {
        this.myPanel = myPanel;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // 从文本框中读取用户输入
        String sendStr = myPanel.tf.getText();
        // 将文本框中的字符清空
        myPanel.tf.setText("");
        // TODO 向服务器发送字符串
        myPanel.out.println(sendStr);
        myPanel.out.flush();

        myPanel.ta.append("To server: " + sendStr + "\n");// 将字符串显示在文本区域

        // TODO 接收服务器回复的字符串,并显示在文本区域
        try {
            myPanel.ta.append(myPanel.in.readLine() + '\n');
        } catch (IOException ex) {
            System.out.println("异常信息:" + ex.getMessage());

        }

    }
}

MyPanel.java
package client;

import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;

/**
 * @author KonBAI
 * @version 1.0
 * Create by 2020/04/21 21:02
 */
class MyPanel extends JPanel {

    JTextField tf;
    JTextArea ta;

    /**
     * 声明客户机套接字
     */
    Socket clientSocket = null;
    /**
     * 声明网络输入流
     */
    BufferedReader in;
    /**
     * 声明网络输出流
     */
    PrintWriter out;

    public MyPanel() {
        this.setLayout(new BorderLayout());
        JPanel p1 = new JPanel();
        JLabel lb1 = new JLabel();
        lb1.setText("消息:");
        p1.add(lb1);
        tf = new JTextField(25);
        p1.add(tf);
        JButton btn = new JButton("发送");
        btn.addActionListener(new MyListError(this));
        p1.add(btn);


        this.add(p1, BorderLayout.NORTH);

        JPanel p2 = new JPanel();
        p2.setLayout(new BorderLayout());
        JScrollPane sp1 = new JScrollPane();
        sp1.setPreferredSize(new Dimension(8, 250));
        ta = new JTextArea(5, 10);
        ta.setEditable(false);
        sp1.setViewportView(ta);
        p2.add(sp1, BorderLayout.CENTER);
        this.add(p2, BorderLayout.CENTER);

        try {
            clientSocket = new Socket();
            // TODO 新建SocketAddress的对象,指定要连接的服务器;
            // 2)调用Socket的方法连接服务器
            SocketAddress address = new InetSocketAddress("localhost", 1024);

            // 连接服务器
            clientSocket.connect(address);

            in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            // TODO 上面已给出输入流的代码,请补充输出流的
            out = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream()));

        } catch (IOException ex) {
            System.out.println("异常信息:" + ex.getMessage());
        }
    }


}

Layout.java
package server;

import javax.swing.*;

/**
 * 布局类
 *
 * @author KonBAI
 * @version 1.0
 * Create by 2020/04/21 22:50
 */
public class Layout {

    private JButton btnStart;
    private JLabel jLabel1;
    private JLabel jLabel2;
    private JScrollPane jScrollPane1;
    /**
     * 创建内容面板容器
     */
    private JPanel midPanel;
    private JPanel topPanel;
    public static JTextArea txtArea;
    private JTextField txtHostName;
    private JTextField txtHostPort;

    public Layout() {
        this.btnStart = new JButton();
        this.jLabel1 = new JLabel();
        this.jLabel2 = new JLabel();
        this.jScrollPane1 = new JScrollPane();
        this.midPanel = new JPanel();
        this.topPanel = new JPanel();
        this.txtHostName = new JTextField();
        this.txtHostPort = new JTextField();
    }

    public JButton getBtnStart() {
        return btnStart;
    }

    public void setBtnStart(JButton btnStart) {
        this.btnStart = btnStart;
    }

    public JLabel getjLabel1() {
        return jLabel1;
    }

    public void setjLabel1(JLabel jLabel1) {
        this.jLabel1 = jLabel1;
    }

    public JLabel getjLabel2() {
        return jLabel2;
    }

    public void setjLabel2(JLabel jLabel2) {
        this.jLabel2 = jLabel2;
    }

    public JScrollPane getjScrollPane1() {
        return jScrollPane1;
    }

    public void setjScrollPane1(JScrollPane jScrollPane1) {
        this.jScrollPane1 = jScrollPane1;
    }

    public JPanel getMidPanel() {
        return midPanel;
    }

    public void setMidPanel(JPanel midPanel) {
        this.midPanel = midPanel;
    }

    public JPanel getTopPanel() {
        return topPanel;
    }

    public void setTopPanel(JPanel topPanel) {
        this.topPanel = topPanel;
    }

    public static JTextArea getTxtArea() {
        return txtArea;
    }

    public static void setTxtArea(JTextArea txtArea) {
        Layout.txtArea = txtArea;
    }

    public JTextField getTxtHostName() {
        return txtHostName;
    }

    public void setTxtHostName(JTextField txtHostName) {
        this.txtHostName = txtHostName;
    }

    public JTextField getTxtHostPort() {
        return txtHostPort;
    }

    public void setTxtHostPort(JTextField txtHostPort) {
        this.txtHostPort = txtHostPort;
    }
}

ServerUI.java
package server;


import utils.ClientThread;

import javax.swing.*;
import javax.swing.border.TitledBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.net.*;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;


/**
 * Echo服务器:根据Echo协议,接收来自客户机消息,并立即回送
 *
 * @author KonBAI
 * @version 1.0
 * Create by 2020/04/21 17:12
 */
public class ServerUI extends JFrame {

    /**
     * 侦听套接字
     */
    private ServerSocket listenSocket = null;
    /**
     * 与客户机对话的套接字
     */
    private Socket toClientSocket = null;
    /**
     * 客户数量编号
     */
    public static Integer clientCounts = 0;
    /**
     * JLabel
     */
    private Layout layout;
    /**
     * 用户编号
     */
    public static JTextArea txtArea;

    public ServerUI() {
        initComponents();
    }

    @SuppressWarnings("unchecked")
    private void initComponents() {
        layout = new Layout();
        txtArea = new JTextArea();

        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setTitle("My Server: 1707");
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent evt) {
                formWindowClosing(evt);
            }
        });
        setPreferredSize(new Dimension(600, 500));
        layout.getTopPanel().setBorder(BorderFactory.createTitledBorder(null, "Server Info Border", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION));

        layout.getjLabel1().setText("Host Name:");
        layout.getTxtHostName().setText("localhost");
        layout.getjLabel2().setText("Port:");
        layout.getTxtHostPort().setText("1024");
        layout.getBtnStart().setText("Start");

        layout.getBtnStart().addActionListener(evt -> btnStartActionPerformed(evt));
        // 创建分组布局
        GroupLayout topPanelLayout = new GroupLayout(layout.getTopPanel());
        layout.getTopPanel().setLayout(topPanelLayout);
        /**
         * 水平组(仅确定 X 轴方向的坐标/排列方式)
         */
        topPanelLayout.setHorizontalGroup(
                topPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
                        .addGroup(topPanelLayout.createSequentialGroup()
                                .addContainerGap()
                                .addComponent(layout.getjLabel1())
                                .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
                                .addComponent(layout.getTxtHostName(), GroupLayout.DEFAULT_SIZE, 131, Short.MAX_VALUE)
                                .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
                                .addComponent(layout.getjLabel2())
                                .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(layout.getTxtHostPort(), GroupLayout.PREFERRED_SIZE, 39, GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
                                .addComponent(layout.getBtnStart())
                                .addContainerGap())
        );
        /**
         * 垂直组(仅确定 Y 轴方向的坐标/排列方式)
         */
        topPanelLayout.setVerticalGroup(
                topPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
                        .addGroup(topPanelLayout.createSequentialGroup()
                                .addContainerGap()
                                .addGroup(topPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE)
                                        .addComponent(layout.getjLabel1())
                                        .addComponent(layout.getTxtHostName(), GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                                        .addComponent(layout.getjLabel2())
                                        .addComponent(layout.getTxtHostPort(), GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                                        .addComponent(layout.getBtnStart()))
                                .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        getContentPane().add(layout.getTopPanel(), BorderLayout.PAGE_START);

        layout.getMidPanel().setBorder(BorderFactory.createTitledBorder(null, "Information Border", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION));
        layout.getMidPanel().setLayout(new BorderLayout());

        txtArea.setEditable(false);
        txtArea.setColumns(20);
        txtArea.setRows(5);
        layout.getjScrollPane1().setViewportView(txtArea);

        layout.getMidPanel().add(layout.getjScrollPane1(), BorderLayout.CENTER);

        getContentPane().add(layout.getMidPanel(), BorderLayout.CENTER);
        // 调整此窗口的大小,以适合其子组件的首选大小和布局
        pack();
    }

    //启动服务器
    private void btnStartActionPerformed(ActionEvent evt) {
        try {
            // 禁用按钮,避免重复启动
            layout.getBtnStart().setEnabled(false);
            String hostName = layout.getTxtHostName().getText();//主机名
            Integer hostPort = Integer.parseInt(layout.getTxtHostPort().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,实现一客户一线程
                        Thread clientThread = new ClientThread(toClientSocket, clientCounts);
                        clientThread.start(); //启动任务线程
                    }
                } catch (IOException ex) {
                    JOptionPane.showMessageDialog(null, ex.getMessage(), "错误提示", JOptionPane.ERROR_MESSAGE);
                }
            }
        }).start();
    }

    //关闭服务器之前
    private void formWindowClosing(WindowEvent evt) {
        //关闭服务器之前释放套接字
        if (!Objects.isNull(listenSocket)) {
            listenSocket = null;
        }
        if (!Objects.isNull(toClientSocket)) {
            toClientSocket = null;
        }
    }

    public static void main(String[] args) {
        try {
            for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (Exception ex) {
            Logger.getLogger(ServerUI.class.getName()).log(Level.SEVERE, null, ex);
        }

        EventQueue.invokeLater(() -> new ServerUI().setVisible(true));
    }

}

ClientThread.java
package utils;

import server.ServerUI;

import java.io.*;
import java.net.Socket;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * 创建客户线程实现类,已实现服务器与客户机会话
 *
 * @author KonBAI
 * @version 1.0
 * Create by 2020/04/21 17:13
 */
public class ClientThread extends Thread {
    /**
     * 会话套接字
     */
    private Socket toClientSocket;
    /**
     * 网络输入流
     */
    private BufferedReader in;
    /**
     * 网络输出流
     */
    private PrintWriter out;
    /**
     * 在线客户机总数
     */
    private int clientCounts = 0;

    public ClientThread(Socket toClientSocket, int clientCounts) {
        this.toClientSocket = toClientSocket;
        this.clientCounts = clientCounts;
    }

    @Override
    public void run() {
        try {
            // 创建绑定到套接字toClientSocket上的网络输入流与输出流
            in = new BufferedReader(new InputStreamReader(toClientSocket.getInputStream(), "UTF-8"));
            out = new PrintWriter(new OutputStreamWriter(toClientSocket.getOutputStream(), "UTF-8"), true);
            //5. 根据服务器协议,在网络流上进行读写操作
            String recvStr;
            //只要客户机不关闭,则反复等待和接收客户机消息
            while ((recvStr = in.readLine()) != null) {
                DateTimeFormatter df = DateTimeFormatter.ofPattern("MM-dd HH:mm:ss");
                LocalDateTime time = LocalDateTime.now();
                String localTime = df.format(time);
                //解析并显示收到的消息
                ServerUI.txtArea.append(localTime + " [" + toClientSocket.getRemoteSocketAddress() +  "] - [客户机编号:" + clientCounts + "] 消息:" + recvStr + "\n");
                //按照echo协议原封不动回送消息
                out.println(localTime + " [" + toClientSocket.getLocalSocketAddress() + "] - [客户机编号:" + clientCounts   +  "] Echo消息:" + recvStr);
            }
            // 客户机总数减1
            ServerUI.clientCounts --;
            // 远程客户机断开连接,线程释放资源
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
            if (toClientSocket != null) {
                toClientSocket.close();
            }
        } catch (IOException ex) {
        }
    }

}

5、启动方法

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
开启多个客户端
在这里插入图片描述在这里插入图片描述### 5、启动可视化界面编写程序
在这里插入图片描述在这里插入图片描述
具体怎么使用,自己琢磨吧~

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值