[Java] network communication program design based on GUI

Keywords: Java websocket GUI

catalogue

1, Program content

2, Requirement analysis

3, Programming

0. Program structure

1. GUI design of server program

2. Preparation of service side business logic

3. Bind button events for GUI interface

4. After copying the source code of the server, reconstruct it and modify it to the client

4, Source code

1, Program content

This is the content of Experiment 2 of Java programming course for software engineering major of Hegong University. The experiment requires writing Java programs to complete the following functions:

1. Design a client server communication application based on GUI, as shown in Figure 1 and Figure 2.

Figure 1 Socket communication server interface

Figure 2 Socket communication client interface

two   Figure 1 shows the Socket communication server interface. Click the [Start] button in the interface to Start the server listening service (the words "Server starting..." are displayed in the multi line text area in the middle of Figure 1). Figure 2 shows the Socket communication client interface. Click the [Connect] button in the interface to establish a link with the server, and the words "Connect to server..." are displayed in the multi line text area in the middle of the interface shown in Figure 2. When the server monitors the connection of the client, a line of "Client connected..." is added in the multi line text area in the middle of Figure 1, And establish a Socket connection with the client.

3. After the server shown in Figure 1 and the client shown in Figure 2 establish a Socket connection, program to realize the "one-way communication" between the server and the client: Send a message in the input interface of the client, receive the message at the server, and display the received data in the multi line text box.

4. On the basis of completing the above experimental contents, try to realize the "two-way communication" function, that is, the server and client can send and receive messages to each other, which can be used as the bonus basis for the evaluation of experimental results.

2, Requirement analysis

In general, we need to complete the following tasks in turn:

one   GUI design of server program.

2. Preparation of service side business logic.

3. Bind button events for GUI interface.

4. After copying the source code of the server, reconstruct it and modify it to the client.

5. Test the connectivity between the server and the client.

After sorting out our ideas, we can start writing our program.

3, Programming

0. Program structure

There are three classes:

1. The main class is used to encapsulate the main function.

2. The public class ServerWindow inherited from JFrame encapsulates the GUI interface of the server program.

3. The public class Server inherited from Thread encapsulates the business logic of the Server.

  Main class code:

import javax.swing.*;

public class Main {

    public static void main(String[] args) {

        ServerWindow mainWindow = new ServerWindow();

    }
}

1. GUI design of server program

I. principle introduction

Swing is a GUI toolkit designed for Java, which provides many more sophisticated screen display elements than AWT. It supports replaceable panels and themes. The disadvantage is that the execution speed is slow. The advantage is that it can adopt a unified style and behavior on all platforms.

Java Swing sample program: Introduction to Java Swing | rookie tutorial (runoob.com)https://www.runoob.com/w3cnote/java-swing-demo-intro.html

II specific ideas

  The structure of the whole GUI interface is shown in the figure above.

We divide the interface into upper, middle and lower parts and use three JPanel packages respectively (to facilitate layout, it is recommended to place components in JPanel rather than directly in the top-level container JFrame). These components are also added to the ServerWindow class.

Declare all GUI components in the ServerWindow class as follows:

    JPanel serverSettings;
    JTextField portField;
    JButton startBtn;

    JPanel areaPanel;
    JTextArea messageArea;

    JPanel sendPanel;
    JTextField sendField;
    JButton sendBtn;

Then, the above variables need to be initialized in the constructor of this class:

public ServerWindow() {
        super("Server");

        this.setSize(500,300);
        this.setResizable(false);
        this.setLayout(new BorderLayout());


        initializeServerSettings();

        initializeAreaPanel();

        initializeSendPanel();


        this.add(serverSettings,BorderLayout.NORTH);
        this.add(areaPanel,BorderLayout.CENTER);
        this.add(sendPanel,BorderLayout.SOUTH);

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);


    }

In order to optimize code readability, the initialization codes of components in the three jpanels are listed as private functions separately, as follows:

    private void initializeServerSettings() {
        serverSettings = new JPanel();
        portField = new JTextField(30);
        startBtn = new JButton("Start");
        serverSettings.setBorder(new EmptyBorder(10, 5, 10, 5));

        serverSettings.add(new JLabel("Port: "));
        serverSettings.add(portField);
        serverSettings.add(startBtn);
    }

    private void initializeSendPanel() {
        sendPanel = new JPanel();
        sendBtn = new JButton("Send");
        sendField = new JTextField(30);
        sendPanel.setBorder(new EmptyBorder(10, 5, 10, 5));

        sendPanel.add(new JLabel("Send: "));
        sendPanel.add(sendField);
        sendPanel.add(sendBtn);
    }

    private void initializeAreaPanel() {
        areaPanel = new JPanel();
        messageArea = new JTextArea(9, 40);
        areaPanel.add(new JScrollPane(messageArea));
    }

So far, the drawing part of the GUI is basically completed.

2. Preparation of service side business logic

I principle + concrete implementation

The business logic of the whole Server, that is, starting the service, waiting for the connection, sending and receiving messages, and closing the connection, is completed in the Server class.

The basic principle of WebSocket is explained in this blog post. I won't repeat making wheels here: WebSocket tutorial - Ruan Yifeng's Weblog (ruanyifeng.com)https://www.ruanyifeng.com/blog/2017/05/websocket.html

In Java, the realization of WebSocket communication mainly depends on two classes: java.net.Socket and java.net.ServerSocket.

In the server, two objects, ServerSocket and Socket, are required.

Socket client;
ServerSocket server;

ServerSocket is used to establish a listening service on the specified port of the server computer and respond to client requests that may come at any time. Consider the following statement:

Socket LinkSocket = MyListener.accept();

This statement calls the accept() method of the ServerSocket object. The execution of this method will make the program on the Server side wait, and the program will block (due to the use of multithreading) until a request from the Client side is captured and a Socket object link Socket used to communicate with the Client is returned. After that, as long as the Server program reads and writes data to the Socket object, it can read and write data to the remote Client.

For a simple example, SeverSocket is like a welcoming lady standing at the door of a hotel, and Socket is like a receptionist who receives customers in the lobby. The job of the welcoming lady is to welcome incoming customers and deliver them to the receptionist in the lobby.

In order to display the specific connection information and sent and received data on the GUI, you need to pass in the reference of messageArea in the GUI interface at the same time.

JTextArea messageArea;

The specific code of this paragraph is shown in the figure below:

server = new ServerSocket(port);
messageArea.append("- The service is already on port " + port + "Start on.\n");
//Wait for a newly connected Socket from ServerSocket.
client = server.accept();
messageArea.append("- " + client.getInetAddress().getLocalHost() + " Connected to service.\n");

The above code blocks the program, so it needs to run in a new Thread. I chose to implement multithreading by inheriting the Thread class. In the constructor of the Server class, after processing the incoming parameters, you can directly call the start() function of the object to start a new Thread.

    Server(int port,JTextArea msgArea) {
        this.port = port;
        this.messageArea = msgArea;
        this.start();
    }

Java multithreading: Java multithreading is enough to read this article (hematemesis super detailed summary) - Java head - blog Garden (cnblogs.com)https://www.cnblogs.com/java1024/archive/2019/11/28/11950129.html

Socket object has two key methods, one is getInputStream method, the other is getoutputstream method. The getInputStream method can get an input stream. The input stream obtained by the getInputStream method on the socket object of the server is actually the data stream sent back from the client. The getoutputstream method obtains an output stream. The output stream returned by the getoutputstream method on the server socket object is the data stream to be sent to the client (in fact, it is a buffer that temporarily stores the past data to be sent).

BufferedReader br;
BufferedWriter bw;
InputStream is;
OutputStream os;

Therefore, the data transmission between the server and the client needs to be completed by the InputStream and OutputStream of the Socket object, as follows:

is = client.getInputStream();
os = client.getOutputStream();
br = new BufferedReader(new InputStreamReader(is));
bw = new BufferedWriter(new OutputStreamWriter(os));
while(true) {
    String newMsg = br.readLine();
    if (newMsg != null) //It means that the client sends a new message.
    {
         messageArea.append(">> " + newMsg + "\n");
    }

In the above code, the new message sent by the client is obtained by constantly reading the InputStream, and the new message is displayed in the messageArea. This code will also block the program.

Because exceptions may occur in the Socket connection, the whole code is completely wrapped in the try statement, and the exception is determined and displayed through the following exception handling statements:

            catch (IOException e) {
                e.printStackTrace();
                if (e instanceof java.net.ConnectException)
                    messageArea.append("- Service startup failed, please try again or change the port." + "\n");
                else
                    messageArea.append("- The connection with the client was disconnected and the service stopped.\n");
            } finally {
                try {
                    server.close();//Call anyway
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }

In any case, you should finally call the server.close() statement to close the occupation of the port by the ServerSocket.

Finally, the Server class should also provide a sendMsg method to actively send information to the client:

public void sendMsg(String msg) {
        System.out.println("sendMsg");
        try {
            bw.write(msg + "\n");//Be sure to add a line feed after a message to indicate that the transmission is complete.
            bw.flush();
            messageArea.append("<< " + msg + "\n");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

3. Bind button events for GUI interface

Next, let's go back to the GUI interface and bind events for two of the buttons.

The first is the Start button for starting the service. When you press the button, you should create a new Server object and pass in the port number and messageArea component, as follows:

        startBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    int port = Integer.parseInt(portField.getText());
                    server = new Server(port,messageArea);
                }
                catch(java.lang.NumberFormatException exception) {
                    messageArea.append("- The port format is incorrect, please re-enter.\n");
                }

                System.out.println(portField.getText());
            }
        });

Then the Send button for sending the message is pressed. After pressing the button, the Server object's sendMsg method is called to send in the message to send.

        sendBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                server.sendMsg(sendField.getText());
                sendField.setText("");
            }
        });

4. After copying the source code of the server, reconstruct it and modify it to the client

At this point, the server-side code is complete. The client code only needs to be slightly modified on the basis of the server.

It is recommended to use the code refactoring function of IDEA, right-click the class name and variable name to be modified, and use refactoring rename to automatically replace all the identifiers in the whole code with new names.

Except that ServerSocket is not required on the Client side, the specific business logic is basically the same as that on the Server side. I won't elaborate here. It is recommended to directly refer to the source code change.

4, Source code

Server.Java

package exp.server;


import javax.swing.*;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.Buffer;
import java.util.ArrayList;

//The server class is used to handle the creation task of the initial PortWaiter and send messages to the client.
class Server extends Thread{
    Socket client;
    ServerSocket server;
    JTextArea messageArea;
    BufferedReader br;
    BufferedWriter bw;
    InputStream is;
    OutputStream os;
    int port;
    Server(int port,JTextArea msgArea) {
        this.port = port;
        this.messageArea = msgArea;
        this.start();
    }

    @Override
    public void run() {
        super.run();
            try {
                server = new ServerSocket(port);
                messageArea.append("- The service is already on port " + port + "Start on.\n");
                //Wait for a newly connected Socket from ServerSocket.
                client = server.accept();
                messageArea.append("- " + client.getInetAddress().getLocalHost() + " Connected to service.\n");
                is = client.getInputStream();
                os = client.getOutputStream();
                br = new BufferedReader(new InputStreamReader(is));
                bw = new BufferedWriter(new OutputStreamWriter(os));
                while(true) {
                    String newMsg = br.readLine();
                    if (newMsg != null) {
                        messageArea.append(">> " + newMsg + "\n");
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
                if (e instanceof java.net.ConnectException)
                    messageArea.append("- Service startup failed, please try again or change the port." + "\n");
                else
                    messageArea.append("- The connection with the client was disconnected and the service stopped.\n");
            } finally {
                try {
                    server.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
    }

    public void sendMsg(String msg) {
        System.out.println("sendMsg");
        try {
            bw.write(msg + "\n");
            bw.flush();
            messageArea.append("<< " + msg + "\n");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

ServerWindow.Java

package exp.server;

import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;


public class ServerWindow extends JFrame{

    JPanel serverSettings;
    JTextField portField;
    JButton startBtn;

    JPanel areaPanel;
    JTextArea messageArea;

    JPanel sendPanel;
    JTextField sendField;
    JButton sendBtn;

    Server server;

    public ServerWindow() {
        super("Server");

        this.setSize(500,300);
        this.setResizable(false);
        this.setLayout(new BorderLayout());


        initializeServerSettings();

        initializeAreaPanel();

        initializeSendPanel();


        this.add(serverSettings,BorderLayout.NORTH);
        this.add(areaPanel,BorderLayout.CENTER);
        this.add(sendPanel,BorderLayout.SOUTH);

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);

        startBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    int port = Integer.parseInt(portField.getText());
                    server = new Server(port,messageArea);
                }
                catch(java.lang.NumberFormatException exception) {
                    messageArea.append("- The port format is incorrect, please re-enter.\n");
                }

                System.out.println(portField.getText());
            }
        });

        sendBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                server.sendMsg(sendField.getText());
                sendField.setText("");
            }
        });

    }

    private void initializeServerSettings() {
        serverSettings = new JPanel();
        portField = new JTextField(30);
        startBtn = new JButton("Start");
        serverSettings.setBorder(new EmptyBorder(10, 5, 10, 5));

        serverSettings.add(new JLabel("Port: "));
        serverSettings.add(portField);
        serverSettings.add(startBtn);
    }

    private void initializeSendPanel() {
        sendPanel = new JPanel();
        sendBtn = new JButton("Send");
        sendField = new JTextField(30);
        sendPanel.setBorder(new EmptyBorder(10, 5, 10, 5));

        sendPanel.add(new JLabel("Send: "));
        sendPanel.add(sendField);
        sendPanel.add(sendBtn);
    }

    private void initializeAreaPanel() {
        areaPanel = new JPanel();
        messageArea = new JTextArea(9, 40);
        areaPanel.add(new JScrollPane(messageArea));
    }

}

 Client.Java

package exp.server;


import javax.swing.*;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

//The server class is used to handle the creation task of the initial PortWaiter and send messages to the client.
class Client extends Thread{
    Socket server;
    JTextArea messageArea;
    BufferedReader br;
    BufferedWriter bw;
    InputStream is;
    OutputStream os;
    int port;
    String address;
    Client(int port, JTextArea msgArea, String address) {
        this.port = port;
        this.messageArea = msgArea;
        this.address = address;
        this.start();
    }

    @Override
    public void run() {
        super.run();
        try {
            server = new Socket(address, port);
            messageArea.append("- Connected to host " + server.getInetAddress().getLocalHost() + "\n");
            is = server.getInputStream();
            os = server.getOutputStream();
            br = new BufferedReader(new InputStreamReader(is));
            bw = new BufferedWriter(new OutputStreamWriter(os));
            while(true) {
                String newMsg = br.readLine();
                if (newMsg != null) {
                    messageArea.append(">> " + newMsg + "\n");
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            if(e instanceof java.net.ConnectException)
                messageArea.append("- Unable to connect to the host, please try again or check the address and port." + "\n");
            else
                messageArea.append("- The connection to the remote host has been disconnected.\n");
        }
    }

    public void sendMsg(String msg) {
        System.out.println("sendMsg");
        try {
            bw.write(msg + "\n");
            bw.flush();
            messageArea.append("<< " + msg + "\n");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

ClientWindow.Java

package exp.server;

import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;


public class ClientWindow extends JFrame{

    JPanel clientSettings;
    JTextField addressField;
    JTextField portField;
    JButton connectBtn;

    JPanel areaPanel;
    JTextArea messageArea;

    JPanel sendPanel;
    JTextField sendField;
    JButton sendBtn;

    Client client;

    public ClientWindow() {
        super("client");

        this.setSize(500,300);
        this.setResizable(false);
        this.setLayout(new BorderLayout());


        initializeServerSettings();

        initializeAreaPanel();

        initializeSendPanel();


        this.add(clientSettings,BorderLayout.NORTH);
        this.add(areaPanel,BorderLayout.CENTER);
        this.add(sendPanel,BorderLayout.SOUTH);

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);

        connectBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    int port = Integer.parseInt(portField.getText());
                    client = new Client(port,messageArea, addressField.getText());
                }
                catch(java.lang.NumberFormatException exception) {
                    messageArea.append("- The port format is incorrect, please re-enter.\n");
                }

                System.out.println(portField.getText());
            }
        });

        sendBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println(sendField.getText());
                client.sendMsg(sendField.getText());
                sendField.setText("");
            }
        });

    }

    private void initializeServerSettings() {
        clientSettings = new JPanel();
        addressField = new JTextField(20);
        portField = new JTextField(10);
        connectBtn = new JButton("Connect");
        clientSettings.setBorder(new EmptyBorder(10, 5, 10, 5));

        clientSettings.add(new JLabel("IP: "));
        clientSettings.add(addressField);
        clientSettings.add(new JLabel("Port: "));
        clientSettings.add(portField);
        clientSettings.add(connectBtn);
    }

    private void initializeSendPanel() {
        sendPanel = new JPanel();
        sendBtn = new JButton("Send");
        sendField = new JTextField(30);
        sendPanel.setBorder(new EmptyBorder(10, 5, 10, 5));

        sendPanel.add(new JLabel("Send: "));
        sendPanel.add(sendField);
        sendPanel.add(sendBtn);
    }

    private void initializeAreaPanel() {
        areaPanel = new JPanel();
        messageArea = new JTextArea(9, 40);
        areaPanel.add(new JScrollPane(messageArea));
    }

}

Posted by xeq on Wed, 29 Sep 2021 13:37:18 -0700