HFUT Java Experiment:基于GUI的网络通信程序设计

一.实验目的

    1.掌握Java中GUI程序的编写,包括事件监听机制。

    2.掌握Java的网络通信编程,ServerSocket,Socket类的使用。

    3.掌握Java中多线程的编程,Thread类,Runnable接口的使用。

    4.掌握用面向对象的方法分析和解决复杂问题。

二.实验内容

编写程序完成以下功能:

  1. 设计一个基于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连接后,编程实现服务端、客户端之间的“单向通信”:在客户端的输入界面发送消息,在服务端接收该消息,并将接收到对方的数据追加显示在多行文本框中。

如果有问题,加QQ群623914970,可以来问

希望同学们学习其中的思路,而不是直接复制粘贴代码。

因为在CSDN上找不到合适的材料,就自己上传一个材料吧,希望能帮助到后来者。

使用Socket传递消息的机制

服务端首先通过一个端口(port)来创建一个ServerSocket,于是在此端口上可以传递信息。

 serverSocket = new ServerSocket(port);

同时服务端也需要创建一个Socket(clientSocket),来接受客户端通过Socket传递来的流(输入输出流)

服务器端通过ServerSocket的accept方法等待客户端连接

一旦有客户端连接成功,serverSocket.accept() 将返回一个 Socket 对象,表示与客户端建立的连接。这个 Socket 对象被赋值给 clientSocket 变量。

通过 clientSocket.getOutputStream() 获取客户端的输出流。这样就可以通过 bufferedWriter 向客户端发送数据。

通过 clientSocket.getInputStream() 获取客户端的输入流。这样就可以通过 bufferedReader 从客户端接收数据。

 clientSocket = serverSocket.accept();
 ServerFrame.textArea.append("Client connected…" + "\n");
 bufferedWriter = new BufferedWriter(
new OutputStreamWriter(clientSocket.getOutputStream()));
 bufferedReader = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));

客户端接收和发送消息

socket=new Socket(serverIP,port);
this.bufferedReader=new BufferedReader(
new InputStreamReader(socket.getInputStream()));
this.bufferedWriter=new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream()));

首先创建一个名为 socketSocket 对象,用于与服务端建立连接。构造方法中传入了服务端的 IP 地址 serverIP 和端口号 port

然后通过 socket.getInputStream() 获取服务端的输入流,通过socket.getOutputStream()获取服务端的输出流,这样就可以通过 bufferedReader 从服务端接收数据,通过 bufferedWriter 向服务端发送数据。

设计思路

1.设计Client和Server的图形化界面,分别在ClientFrame和ServerFrame类中实现。如图

2. 设计Server类和Client类,图形化界面的具体功能(从port框中获取端口,开启服务器、服务器端发送消息,客户端输入ip、端口号与主机连接、客户端发送信息)在这两个类中实现。

同时设计了一些对用户输入错误信息、错误操作的处理,更符合实际需要。如:服务器页面不输入port直接点start提示用户要输入端口值,客户端只输入ServerIP和ServerPort其中的一项或者都没输入,提示用户输入。如图

 

服务器端没有开启时,客户端就连接,提示

ServerFrame类中显示消息的框设置为public static,在Server类中接受到信息后需要在框中显示新的信息。ClientFrame类中同理。

3. 为图形化的界面按钮等添加监听器,实现具体功能。

测试结果如下:

ClientFrame类的设计

这个使用了JFormDesigner来设计,省去了很多麻烦

如图 可以在框中任意添加和拖动各种组件,很方便,同时也可以设置字体、大小等。

如果想添监听器,就对着组件右键,有各种监听器,可以直接生成监听函数

 更多关于JFormDesigner请自己探索

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
/*
 * Created by JFormDesigner on Sat Apr 08 19:21:43 CST 2023
 */



/**
 * @author archi
 */
public class ClientFrame {
    public ClientFrame() {
        initComponents();
    }
    private Client client;
    private String server_IP;
    private int server_Port=-1;//初始化为-1,表示未输入

    private String msgToSend;
    private void bt_connectMouseClicked(MouseEvent e) {
        if(e.getButton()==1){
            if(server_IP==null) {
                textArea.append("请输入Server IP!"+"\n");
            } else if (server_Port==-1) {
                textArea.append("请输入Server Port!"+"\n");
            }else{
                client=new Client(server_IP,server_Port);
                textArea.append("Connect to server…"+"\n");
                client.listenForMessage();
            }
        }


    }

    //用于监听输入ip的框
    private void ipFieldKeyReleased(KeyEvent e) {
        if(e.getSource()==ipField){
            server_IP= ipField.getText();
        }
    }

    //监听输入serverPort的框
    private void portFieldKeyReleased(KeyEvent e) {
        if(e.getSource()==portField){
            server_Port= Integer.parseInt(portField.getText());
        }
    }

    //监听发送信息的框
    private void wordsFieldKeyReleased(KeyEvent e) {
        if(e.getSource()==wordsField){
            msgToSend=wordsField.getText();//获取框中的信息
        }
    }

    //监听发送的框
    private void bt_sayMouseClicked(MouseEvent e) {
        if(e.getButton()==1){
            if(msgToSend!=null){
                textArea.append(msgToSend+"\n");//在显示消息的区域附加新的信息
                client.sendMessage(msgToSend);
                wordsField.setText(null);//发送后设置发送框为空
                msgToSend=null;//设置发送的信息为空
            }

        }
    }

    
    private void initComponents() {
        // JFormDesigner - Component initialization - DO NOT MODIFY  //GEN-BEGIN:initComponents  @formatter:off
        ServerUI = new JFrame();
        panel1 = new JPanel();
        serverIP = new JLabel();
        ipField = new JTextField();
        serverPort = new JLabel();
        portField = new JTextField();
        bt_connect = new JButton();
        scrollPane1 = new JScrollPane();
        textArea = new JTextArea();
        wordsField = new JTextField();
        bt_say = new JButton();

        //======== ServerUI ========
        {
            ServerUI.setTitle("\u5ba2\u6237\u7aef");
            Container ServerUIContentPane = ServerUI.getContentPane();
            ServerUIContentPane.setLayout(null);

            //======== panel1 ========
            {
                panel1.setBorder(new TitledBorder("\u5ba2\u6237\u7aef\u8bbe\u7f6e\uff1a"));
                panel1.setLayout(null);

                //---- serverIP ----
                serverIP.setText("Server IP:");
                serverIP.setFont(new Font("JetBrains Mono Medium", Font.BOLD, 16));
                panel1.add(serverIP);
                serverIP.setBounds(10, 30, 110, serverIP.getPreferredSize().height);

                //---- ipField ----
                ipField.setFont(new Font("JetBrains Mono Medium", Font.PLAIN, 16));
                ipField.addKeyListener(new KeyAdapter() {
                    @Override
                    public void keyReleased(KeyEvent e) {
                        ipFieldKeyReleased(e);
                    }
                });
                panel1.add(ipField);
                ipField.setBounds(115, 25, 145, 35);

                //---- serverPort ----
                serverPort.setText("Server Port:");
                serverPort.setFont(new Font("JetBrains Mono Medium", Font.BOLD, 16));
                panel1.add(serverPort);
                serverPort.setBounds(270, 30, 130, 27);

                //---- portField ----
                portField.setFont(new Font("JetBrains Mono Medium", Font.PLAIN, 16));
                portField.addKeyListener(new KeyAdapter() {
                    @Override
                    public void keyReleased(KeyEvent e) {
                        portFieldKeyReleased(e);
                    }
                });
                panel1.add(portField);
                portField.setBounds(390, 25, 145, 35);

                //---- bt_connect ----
                bt_connect.setText("Connect");
                bt_connect.setFont(new Font("JetBrains Mono Medium", Font.BOLD, 16));
                bt_connect.addMouseListener(new MouseAdapter() {
                    @Override
                    public void mouseClicked(MouseEvent e) {
                        bt_connectMouseClicked(e);
                    }
                });
                panel1.add(bt_connect);
                bt_connect.setBounds(545, 25, bt_connect.getPreferredSize().width, 35);

                {
                    // compute preferred size
                    Dimension preferredSize = new Dimension();
                    for(int i = 0; i < panel1.getComponentCount(); i++) {
                        Rectangle bounds = panel1.getComponent(i).getBounds();
                        preferredSize.width = Math.max(bounds.x + bounds.width, preferredSize.width);
                        preferredSize.height = Math.max(bounds.y + bounds.height, preferredSize.height);
                    }
                    Insets insets = panel1.getInsets();
                    preferredSize.width += insets.right;
                    preferredSize.height += insets.bottom;
                    panel1.setMinimumSize(preferredSize);
                    panel1.setPreferredSize(preferredSize);
                }
            }
            ServerUIContentPane.add(panel1);
            panel1.setBounds(15, 10, 655, 70);

            //======== scrollPane1 ========
            {

                //---- textArea ----
                textArea.setFont(new Font("JetBrains Mono Medium", Font.BOLD, 16));
                textArea.setEditable(false);
                scrollPane1.setViewportView(textArea);
            }
            ServerUIContentPane.add(scrollPane1);
            scrollPane1.setBounds(15, 90, 655, 280);

            //---- wordsField ----
            wordsField.setFont(new Font("JetBrains Mono Medium", Font.PLAIN, 16));
            wordsField.addKeyListener(new KeyAdapter() {
                @Override
                public void keyReleased(KeyEvent e) {
                    wordsFieldKeyReleased(e);
                }
            });
            ServerUIContentPane.add(wordsField);
            wordsField.setBounds(10, 390, 560, 45);

            //---- bt_say ----
            bt_say.setText("Say");
            bt_say.setFont(new Font("JetBrains Mono Medium", Font.BOLD, 16));
            bt_say.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    bt_sayMouseClicked(e);
                }
            });
            ServerUIContentPane.add(bt_say);
            bt_say.setBounds(585, 395, 100, 40);

            {
                // compute preferred size
                Dimension preferredSize = new Dimension();
                for(int i = 0; i < ServerUIContentPane.getComponentCount(); i++) {
                    Rectangle bounds = ServerUIContentPane.getComponent(i).getBounds();
                    preferredSize.width = Math.max(bounds.x + bounds.width, preferredSize.width);
                    preferredSize.height = Math.max(bounds.y + bounds.height, preferredSize.height);
                }
                Insets insets = ServerUIContentPane.getInsets();
                preferredSize.width += insets.right;
                preferredSize.height += insets.bottom;
                ServerUIContentPane.setMinimumSize(preferredSize);
                ServerUIContentPane.setPreferredSize(preferredSize);
            }
            ServerUI.setSize(705, 500);
            ServerUI.setLocationRelativeTo(ServerUI.getOwner());
        }
        // JFormDesigner - End of component initialization  //GEN-END:initComponents  @formatter:on
        ServerUI.setVisible(true);
        ServerUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    // JFormDesigner - Variables declaration - DO NOT MODIFY  //GEN-BEGIN:variables  @formatter:off
    private JFrame ServerUI;
    private JPanel panel1;
    private JLabel serverIP;
    private JTextField ipField;
    private JLabel serverPort;
    private JTextField portField;
    private JButton bt_connect;
    private JScrollPane scrollPane1;
    public static JTextArea textArea;
    private JTextField wordsField;
    private JButton bt_say;
    // JFormDesigner - End of variables declaration  //GEN-END:variables  @formatter:on
    public static void main(String[] args) {
        new ClientFrame();
    }
}

Client类设计

public class Client {

    Socket socket;
    private BufferedReader bufferedReader;
    private BufferedWriter bufferedWriter;
    private final String  username="LocalClient";

    public Client(String serverIP,int port){
        try{
            socket=new Socket(serverIP,port);
            //初始化输入流缓冲区和输出流缓冲区,注意这里使用的是socket传递来的输入输出流
            //这样客户端就可以接受服务器端的消息(从输入流读入),向服务器端发送消息(向输出流写入)
            this.bufferedReader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
            this.bufferedWriter=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        }catch (IOException e){
            closeEverything();
        }
    }
    //发送信息时将信息写入到输出流即可
    public void sendMessage(String msgToSend) {
        try {
                bufferedWriter.write(username+": "+msgToSend);
                bufferedWriter.newLine();//每次写完一行后换行
                bufferedWriter.flush();//将缓冲区中的内容刷新到道输出流中
        } catch (IOException e) {
            closeEverything();
        }
    }

    //为client创建接收信息的新线程
    public void listenForMessage() {
        new Thread(() -> {
            try {
                while(socket.isConnected()) {
                    //接受到的信息显示在显示消息的那个框里
                    ClientFrame.textArea.append(bufferedReader.readLine()+"\n");
                }
            } catch (IOException e) {
                closeEverything();
            }

        }
        ).start();
    }
    //如果程序运行过程中发生错误,调用这个函数,关掉所有用到的东西,接受程序
    public void closeEverything() {
        try {
            if (socket != null) {
                socket.close();
            }
            if (bufferedReader != null) {
                bufferedReader.close();
            }
            if (bufferedWriter != null) {
                bufferedWriter.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

ServerFrame的设计

这个与ClientFrame的设计方法基本一样

直接贴代码

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javax.swing.border.*;
/*
 * Created by JFormDesigner on Sat Apr 08 17:35:15 CST 2023
 */

/**
 * @author archi
 */
public class ServerFrame {
    private String server_Port;

    private Server server;
    private String msgToSend;
    public ServerFrame() {
        initComponents();

    }

//点击start开始的框
    private void bt_startMouseClicked(MouseEvent e) {
        if (e.getButton() == 1) {//点击左键
            try {
                if (server_Port == null) {
                    textArea.append("未输入端口值!" + "\n");
                } else {
                    ServerFrame.textArea.append("Server starting..." + "\n");
                    server = new Server(Integer.parseInt(server_Port));
                }
               server.startServer();
            } catch (IOException e1) {
                e1.printStackTrace();
                server.closeEverything();
            }


        }
    }
//输入端口值的框
    private void portFieldKeyReleased(KeyEvent e) {
        if(e.getSource()==portField){
            this.server_Port=portField.getText();//端口值
        }

    }

    private void messageFieldKeyReleased(KeyEvent e) {
        if(e.getSource()==messageField){
            msgToSend=messageField.getText();
        }
    }

    //点击发送后将输入框中的内容置空
    private void bt_sayMouseClicked(MouseEvent e) {
        if(e.getButton()==1){//点击左键
            if(msgToSend!=null){
                server.sendMessage(msgToSend);
                textArea.append(msgToSend+"\n");
                msgToSend=null;
                messageField.setText(null);
            }
        }
    }

//say发送信息的框
    private void bt_sayKeyPressed(KeyEvent e) {
        if(e.getKeyCode()==KeyEvent.VK_ENTER){
            if(msgToSend!=null){
                server.sendMessage(msgToSend);
                textArea.append(msgToSend+"\n");
                msgToSend=null;
                messageField.setText(null);
            }
        }

    }

    private void initComponents() {
        // JFormDesigner - Component initialization - DO NOT MODIFY  //GEN-BEGIN:initComponents  @formatter:off
        ServerUI = new JFrame();
        scrollPane1 = new JScrollPane();
        textArea = new JTextArea();
        panel1 = new JPanel();
        label1 = new JLabel();
        portField = new JTextField();
        bt_start = new JButton();
        messageField = new JTextField();
        bt_say = new JButton();

        //======== ServerUI ========
        {
            ServerUI.setTitle("\u670d\u52a1\u5668");
            Container ServerUIContentPane = ServerUI.getContentPane();
            ServerUIContentPane.setLayout(null);

            //======== scrollPane1 ========
            {

                //---- textArea ----
                textArea.setFont(new Font("JetBrains Mono Medium", Font.BOLD, 16));
                textArea.setEditable(false);
                scrollPane1.setViewportView(textArea);
            }
            ServerUIContentPane.add(scrollPane1);
            scrollPane1.setBounds(25, 95, 650, 270);

            //======== panel1 ========
            {
                panel1.setBorder(new TitledBorder("\u670d\u52a1\u5668\u8bbe\u7f6e\uff1a"));
                panel1.setToolTipText("\u670d\u52a1\u5668\u8bbe\u7f6e\uff1a");
                panel1.setLayout(null);

                //---- label1 ----
                label1.setText("port:");
                label1.setFont(new Font("JetBrains Mono Medium", Font.BOLD, 16));
                panel1.add(label1);
                label1.setBounds(10, 30, 60, 30);

                //---- portField ----
                portField.setFont(new Font("JetBrains Mono Medium", Font.PLAIN, 16));
                portField.addKeyListener(new KeyAdapter() {
                    @Override
                    public void keyReleased(KeyEvent e) {
                        portFieldKeyReleased(e);
                    }
                });
                panel1.add(portField);
                portField.setBounds(60, 25, 465, 40);

                //---- bt_start ----
                bt_start.setText("Start");
                bt_start.setFont(new Font("Microsoft YaHei UI", Font.BOLD, 16));
                bt_start.addMouseListener(new MouseAdapter() {
                    @Override
                    public void mouseClicked(MouseEvent e) {
                        bt_startMouseClicked(e);
                    }
                });
                panel1.add(bt_start);
                bt_start.setBounds(530, 25, 90, 35);

                {
                    // compute preferred size
                    Dimension preferredSize = new Dimension();
                    for(int i = 0; i < panel1.getComponentCount(); i++) {
                        Rectangle bounds = panel1.getComponent(i).getBounds();
                        preferredSize.width = Math.max(bounds.x + bounds.width, preferredSize.width);
                        preferredSize.height = Math.max(bounds.y + bounds.height, preferredSize.height);
                    }
                    Insets insets = panel1.getInsets();
                    preferredSize.width += insets.right;
                    preferredSize.height += insets.bottom;
                    panel1.setMinimumSize(preferredSize);
                    panel1.setPreferredSize(preferredSize);
                }
            }
            ServerUIContentPane.add(panel1);
            panel1.setBounds(30, 0, 640, 85);

            //---- messageField ----
            messageField.setFont(new Font("JetBrains Mono Medium", Font.PLAIN, 16));
            messageField.addKeyListener(new KeyAdapter() {
                @Override
                public void keyReleased(KeyEvent e) {
                    messageFieldKeyReleased(e);
                }
            });
            ServerUIContentPane.add(messageField);
            messageField.setBounds(25, 380, 535, 40);

            //---- bt_say ----
            bt_say.setText("Say");
            bt_say.setFont(new Font("Microsoft YaHei UI", Font.BOLD, 16));
            bt_say.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    bt_sayMouseClicked(e);
                }
            });
            bt_say.addKeyListener(new KeyAdapter() {
                @Override
                public void keyPressed(KeyEvent e) {
                    bt_sayKeyPressed(e);
                }
            });
            ServerUIContentPane.add(bt_say);
            bt_say.setBounds(580, 380, 95, 40);

            ServerUIContentPane.setPreferredSize(new Dimension(700, 475));
            ServerUI.setSize(700, 475);
            ServerUI.setLocationRelativeTo(ServerUI.getOwner());
        }
        // JFormDesigner - End of component initialization  //GEN-END:initComponents  @formatter:on
            ServerUI.setVisible(true);
            ServerUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    // JFormDesigner - Variables declaration - DO NOT MODIFY  //GEN-BEGIN:variables  @formatter:off
    private JFrame ServerUI;
    private JScrollPane scrollPane1;
    public static JTextArea textArea;
    private JPanel panel1;
    private JLabel label1;
    private JTextField portField;
    private JButton bt_start;
    private JTextField messageField;
    private JButton bt_say;
    // JFormDesigner - End of variables declaration  //GEN-END:variables  @formatter:on

    public static void main(String[] args) {
        new ServerFrame();
    }


}

Server的设计

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @author archi
 */
public class Server {
    BufferedWriter bufferedWriter;
    BufferedReader bufferedReader;
    Socket clientSocket;
    ServerSocket serverSocket;


    public Server(int port) throws IOException {
        serverSocket = new ServerSocket(port);
    }

    public void startServer() {
        new Thread(() -> {
            try {
                clientSocket = serverSocket.accept();
                ServerFrame.textArea.append("Client connected…" + "\n");
                bufferedWriter = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
                bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
            } catch (IOException e) {
                e.printStackTrace();
                closeEverything();
            }
            try {
                while (clientSocket.isConnected()) {
                    String line = bufferedReader.readLine();
                    ServerFrame.textArea.append(line + "\n");//将读到的信息添加到textArea中
                }
            } catch (IOException e) {
                closeEverything();
                e.printStackTrace();
            }

        }
        ).start();

    }


    public void sendMessage(String msgToSend) {
        try {
            bufferedWriter.write("Server: " + msgToSend);
            bufferedWriter.newLine();
            bufferedWriter.flush();
        } catch (IOException e) {
            e.printStackTrace();
            closeEverything();
        }
    }

    public void closeEverything() {

        try {
            if (bufferedWriter != null) {
                bufferedWriter.close();
            }
            if (bufferedReader != null) {
                bufferedReader.close();
            }
            if (clientSocket != null) {
                clientSocket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

主类

public class Main {
    public static void main(String[] args) {
        new ServerFrame();
        new ClientFrame();
    }
}

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值