[Java -- network programming]

Keywords: Java

1.1 software structure

  • C/S structure: the full name is Client/Server structure, which refers to client and server structure. Common programs include QQ, Xunlei and other software.

  • B/S structure: fully known as Browser/Server structure, it refers to browser and server structure. Common browsers include Google, Firefox, etc.

    The two architectures have their own advantages, but no matter which architecture, it is inseparable from the support of the network. Network programming is a program that realizes the communication between two computers under a certain protocol.

1.2 network communication protocol

  • **Network communication protocol: * * multiple computers can be connected through the computer network. Computers located in the same network need to abide by certain rules when connecting and communicating, just as cars driving on the road must abide by traffic rules. In the computer network, these connection and communication rules are called network communication protocol. It makes unified provisions on the data transmission format, transmission rate and transmission steps. Both sides of the communication must abide by them at the same time to complete the data exchange.

  • TCP/IP protocol: Transmission Control Protocol / Internet protocol, which is the most basic and extensive protocol on the Internet. It defines standards for how computers connect to the Internet and how data is transmitted between them. It contains a series of protocols for processing data communication, and adopts a 4-layer layered model. Each layer calls the protocols provided by its next layer to complete its own requirements.

    In the figure above, the four layers of TCP/IP protocol are application layer, transmission layer, network layer and link layer, and each layer is responsible for different communication functions.

  • Link layer: the link layer is used to define the physical transmission channel. It is usually the driving protocol for some network connection devices, such as the driver provided for optical fiber and network cable.

  • Network layer: the network layer is the core of the whole TCP/IP protocol. It is mainly used to group the transmitted data and send the packet data to the target computer or network.

  • Transport layer: it mainly enables network programs to communicate. TCP protocol or UDP protocol can be used for network communication.

  • Application layer: mainly responsible for the application protocol, such as HTTP protocol, FTP protocol, etc.

1.3 protocol classification

The communication protocol is still relatively complex. The classes and interfaces contained in the java.net package provide bottom-level communication details. We can directly use these classes and interfaces to focus on network program development without considering the details of communication.
The java.net package provides support for two common network protocols:

  • UDP: user datagram protocol. UDP is a connectionless communication protocol, that is, during data transmission, the sender and receiver of data do not establish a logical connection. In short, when a computer sends data to another computer, the sender will send data without confirming whether the receiver exists. Similarly, when the receiver receives data, it will not feed back whether it has received data to the sender. Because UDP protocol consumes less resources and has high communication efficiency, it is usually used for the transmission of audio, video and ordinary data. For example, video conference uses UDP protocol, because even if one or two packets are lost occasionally, it will not have a great impact on the receiving results.

Features: the data is limited to 64kb, beyond which it cannot be sent.

Datagram: the basic unit of network transmission
TCP: transmission control protocol. TCP protocol is a connection oriented communication protocol, that is, before transmitting data, establish a logical connection between the sender and the receiver, and then transmit data. It provides reliable error free data transmission between two computers.

In TCP connection, the client and server must be specified. The client sends a connection request to the server. Each connection creation needs to go through "three handshakes".
Three handshakes: in TCP protocol, three interactions between the client and the server in the preparation stage of sending data to ensure the reliability of the connection.

  • The first handshake, the client sends a connection request to the server and waits for the server to confirm.
  • In the second handshake, the server sends back a response to the client to notify the client that it has received the connection request.
  • For the third handshake, the client sends a confirmation message to the server again to confirm the connection. The whole interaction process is shown in the figure below.

After three handshakes are completed and the connection is established, the client and server can start data transmission. Because of this connection oriented feature, TCP protocol can ensure the security of data transmission, so it is widely used, such as downloading files, browsing web pages and so on.

1.4 three elements of network programming

agreement

  • Protocol: the rules that must be observed in computer network communication

IP address

  • IP address: refers to the Internet Protocol Address, commonly known as IP. IP addresses are used to uniquely number computer devices in a network. If we compare "personal computer" to "a telephone", then "IP address" is equivalent to "telephone number".

IP address classification

  • IPv4: it is a 32-bit binary number, which is usually divided into 4 bytes and expressed in the form of a.b.c.d, such as 192.168.65.100. Where a, B, C and D are decimal integers between 0 and 255, it can represent 4.2 billion at most.

  • IPv6: due to the vigorous development of the Internet, the demand for IP address is increasing, but the limited network address resources make the allocation of IP more and more tense.

    In order to expand the address space, it is proposed to redefine the address space through IPv6. The 128 bit address length is adopted, a group of 16 bytes is divided into 8 groups of hexadecimal numbers, expressed as ABCD:EF01:2345:6789:ABCD:EF01:2345:6789. It is said that it can compile a network address for every grain of sand in the world, which solves the problem of insufficient network address resources.

Common commands

  • To view the local IP address, enter:
ipconfig
  • Check whether the network is connected. Enter:
ping Space IP address
ping 220.181.57.216

Special IP address

  • Local IP address: 127.0.0.1, localhost.

Port number

Network communication is essentially the communication between two processes (Applications). Each computer has many processes, so how to distinguish these processes in network communication?

If the IP address can uniquely identify the device in the network, the port number can uniquely identify the process (application) in the device.

  • **Port number: an integer represented by two bytes. Its value range is 065535 * *. Among them, the port numbers between 01023 are used for some well-known network services and applications, and ordinary applications need to use port numbers above 1024. If the port number is occupied by another service or application, the current program will fail to start.

Using the ternary combination of protocol + IP address + port number, the processes in the network can be identified, and the communication between processes can use this identification to interact with other processes.

TCP communication program

2.1 general

TCP communication can realize the data interaction between two computers. The two ends of communication should be strictly divided into Client and Server.

Steps for communication between two ends:

  1. The server program needs to be started in advance and wait for the connection of the client.
  2. The client actively connects to the server and can communicate only after the connection is successful. The server cannot actively connect to the client.

In Java, two classes are provided to implement TCP communication programs:

  1. Client: represented by java.net.Socket class. Create a Socket object, send a connection request to the server, and the server responds to the request. The two establish a connection and start communication.
  2. Server: represented by java.net.ServerSocket class. Creating a ServerSocket object is equivalent to starting a service and waiting for the client to connect.

2.2 Socket class

Socket class: this class implements client socket. Socket refers to the endpoint of communication between two devices.

Construction method

  • public Socket(String host, int port): creates a socket object and connects it to the specified port number on the specified host. If the specified host is null, it is equivalent to that the specified address is the loopback address.

    Tip: the Loopback Address (127.x.x.x) is the Loopback Address of the local machine. It is mainly used for network software testing and local machine interprocess communication. No matter what program uses the Loopback Address to send data, it will return immediately without any network transmission.

For example, the code is as follows:

Socket client = new Socket("127.0.0.1", 6666);

Member method

  • public InputStream getInputStream(): returns the input stream of this socket.

    • If this socket has an associated channel, all operations of the generated InputStream are also associated with that channel.
    • Closing the generated InputStream will also close the relevant Socket.
  • public OutputStream getOutputStream(): returns the output stream of this socket.

    • If this socket has an associated channel, all operations of the generated OutputStream are also associated with the channel.
    • Closing the generated OutputStream will also close the relevant Socket.
  • public void close(): close this socket.

    • Once a socket is closed, it can no longer be used.
    • Closing this socket will also close the associated InputStream and OutputStream.
  • public void shutdownOutput(): disables the output stream of this socket.

    • Any previously written data will be sent, and then the output stream will be terminated.

    2.3 ServerSocket class

ServerSocket class: this class implements the server socket, which waits for requests through the network.

Construction method

  • public ServerSocket(int port): when creating a ServerSocket object using this construction method, you can bind it to a specified port number. The parameter port is the port number.

For example, the code is as follows:

ServerSocket server = new ServerSocket(6666);

Member method

  • public Socket accept(): listen and accept the connection, and return a new Socket object for communication with the client. This method blocks until a connection is established.

2.4 simple TCP network program

TCP communication analysis diagram

  1. Start the server, create a ServerSocket object, and wait for the connection.
  2. [Client] start, create Socket object and request connection.
  3. [server] receives the connection, calls the accept method, and returns a Socket object.
  4. [Client] Socket object, obtain OutputStream and write data to the server.
  5. [server] socket object, get InputStream and read the data sent by the client.

At this point, the client successfully sends data to the server.

Since then, the server writes back data to the client.

  1. [server] Socket object, obtain OutputStream and write back data to the client.
  2. [Client] socket object, get InputStream, parse and write back data.
  3. [Client] release resources and disconnect.

The client sends data to the server

Server implementation:

/**
 TCP Protocol server: ServerSocket
 Socket accept() Client listening for links
 */
public class NewTcpServer {
    public static List<MyChannel> all;
    //Create a collection ArrayList; Used to store received customer objects
    public static void main(String[] args) throws IOException {
        //Instantiate the server ServerSocket and listen for the specified port number
        ServerSocket server = new ServerSocket(9999);
        all = new ArrayList<>();
        int count=0;
        while (true){
            //The server can listen to who the connected client is;; Socket accept() method;
            Socket client = server.accept();
            System.out.println("One socket connect...");
            //Receive data from the client / send information to the client
            count++;
            MyChannel channel = new MyChannel(count,client,all);
            new Thread(channel).start();
            all.add(channel);
        }
    }
}

Server thread program class

public class MyChannel implements Runnable {
    //Socket for receiving clients
    private Socket accept;
    //The server reads the client data stream DataInputStream
    private DataInputStream dis;
    //console output 
    private BufferedReader console;
    //The server outputs data to the client
    private DataOutputStream dos;
    //Executable ID
    private boolean isRunning = true;
    private int id;
    private List<MyChannel> all;

    public MyChannel(int count, Socket accept, List<MyChannel> all) {
        id = count;
        this.all = all;
        this.accept = accept;
        try {
            //The server reads client messages
            dis = new DataInputStream(accept.getInputStream());
            dos = new DataOutputStream(accept.getOutputStream());
            //Console write message
            console = new BufferedReader(new InputStreamReader(System.in));
        } catch (IOException e) {
            IOUtilss.closeAll(dis, dos, accept, console);
            isRunning = false;
        }
    }

    @Override
    public void run() {
        //Receive data from client Receive() method
        while (isRunning) {
            String msg = receive();
            if (msg.contains("@")){
//                Chat(msg);
            }else {
                allChat(msg);
            }
            System.out.println(msg);
//            String sfc = getStrFromConsole();

        }
    }

    private void Chat(String msg) {
        String s = msg.replace("@", "");


    }


    private void allChat(String msg) {
        for (MyChannel myChannel : all) {
            if (myChannel == this) {
            } else {
                try {
                    myChannel.dos.writeUTF(msg);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    //The server receives client messages
    public String receive() {
        String data = "";
        try {
            String s = dis.readUTF();
            if (!s.equals("")) {
                data = s;
            }
        } catch (IOException e) {
            IOUtilss.closeAll(dis);
            isRunning = false;
        }
        return data;
    }

    //Read out information from the console
    public String getStrFromConsole() {
        try {
            String s = console.readLine();
            if (!s.equals("")) {
                return s;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }

    //The server sends a message to the client
    public void send(String msg) {
        try {
            dos.writeUTF(msg);
            dos.flush();
        } catch (IOException e) {
            isRunning = false;
            //IOUtilss.closeAll(dos);
        }
    }
}

Client implementation:

public class NewTcpClient {
    public static void main(String[] args) throws IOException {
        System.out.println("=====client====");
        //New basket
        //1. Specify ip + port number; Establish connection
        Socket socket = new Socket("127.0.0.1",9999);
        //2. Create two threads: ensure that the client sends & & receives messages without interference with each other
        //A class object Send(socket) for sending messages; Construction method with one parameter; Used to establish a connection by passing parameters
        //A class object Receive(socket) that receives messages; Construction method with one parameter; Used to establish a connection by passing parameters
        new Thread( new Send(socket)).start();
        new Thread(new Receive(socket)).start();
    }
}

Send thread implementation class

//Client send task
//1. Create customer connections
// 2. dataoutputStream stream of messages sent by customers
// 3. Get the BufferReader stream of the message from the keyboard
//In the run method: get the console message getStrFormConsole() and send the message send()
public class Send implements Runnable{
    //Socket for receiving clients
    private Socket client;              //Client connection
    private DataOutputStream dos;       //The client sends information; dataOutputStream stream implementation
    private BufferedReader console;     //The console receives keyboard information; BufferedReader implementation
    //Executable tag
    private boolean isRunning = true;
    public Send(Socket client) {
        this.client = client;
        try {
            //With the help of conversion flow, data is entered in the console
            console = new BufferedReader(new InputStreamReader(System.in));
            dos = new DataOutputStream(client.getOutputStream());
        } catch (IOException e) {
            //If an exception occurs, the client will send a message and the flow will be closed
            IOUtilss.closeAll(console,client,dos);
            isRunning=false;
        }
    }

    @Override
    public void run() {
        while (isRunning){
            //Get keyboard input data
            //Send a method to get data
            String strFormConsole = getStrFormConsole();
            //Judgment (if the data is not empty, output the data;)
            if(!strFormConsole.equals("")){
                send(strFormConsole);
            }
        }
    }
    //Get message from console
    private String getStrFormConsole(){
        try {
             return console.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }
    //Send the obtained message to the server
    public void send(String msg){
        try {
            dos.writeUTF(msg);
            dos.flush();
        } catch (IOException e) {
            e.printStackTrace();
            isRunning = false;
        }
    }
}

Client receiving class implementation;

/**
 * Client receiving task
 * 1,Establish Socket connection;
 * 2,Create a DataInputStream that reads in server data
 * 3,Design a representation to judge whether reading data stops
 * 4,run Method to receive data from the server
 */

public class Receive implements Runnable{
    private Socket client;
    private DataInputStream dis;
    private boolean isRunning = true;
    public Receive(Socket client) {
        this.client = client;
        try {
            //Create an input stream to connect to the client
            dis = new DataInputStream(client.getInputStream());
        } catch (IOException e) {
            //If an exception occurs, close the flow and end the thread
            IOUtilss.closeAll(dis);
            isRunning = false;
        }
    }

    @Override
    public void run() {
        while (isRunning){
            //Receive messages from the server
            String msg = receive();
            //Judgment: if the message from the server is not empty, output the message
            if(!msg.equals("")){
                System.out.println(msg);
            }
        }
    }
    //The client reads data from the server
    public String  receive(){
        String msg = "";
        try {
           msg = dis.readUTF();
        } catch (IOException e) {
            IOUtilss.closeAll(dis,client);
            isRunning = false;
        }
        return msg;
    }
}

Comprehensive case

3.1 file upload cases

  1. [Client] input stream to read file data from hard disk into program.
  2. [Client] output the stream and write out the file data to the server.
  3. [server] input the stream and read the file data to the server program.
  4. [server] output stream, write out file data to the server hard disk.
    Server implementation:
public class FileUpload_Server {
    public static void main(String[] args) throws IOException {
        System.out.println("Server startup.....  ");
        // 1. Create server ServerSocket
      	ServerSocket serverSocket = new ServerSocket(6666);
  		// 2. Establish connection 
        Socket accept = serverSocket.accept();
      	// 3. Create flow object
      	// 3.1 get the input stream and read the file data
        BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
        // 3.2 create an output stream and save it locally
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.jpg"));
		// 4. Read and write data
        byte[] b = new byte[1024 * 8];
        int len;
        while ((len = bis.read(b)) != -1) {
            bos.write(b, 0, len);
        }
        //5. Close resources
        bos.close();
        bis.close();
        accept.close();
        System.out.println("File upload saved");
    }
}

Client implementation:

public class FileUPload_Client {
	public static void main(String[] args) throws IOException {
        // 1. Create flow object
        // 1.1 create input stream and read local files  
        BufferedInputStream bis  = new BufferedInputStream(new FileInputStream("test.jpg"));
        // 1.2 create an output stream and write it to the server 
        Socket socket = new Socket("localhost", 6666);
        BufferedOutputStream   bos   = new BufferedOutputStream(socket.getOutputStream());

        //2. Write the data 
        byte[] b  = new byte[1024 * 8 ];
        int len ; 
        while (( len  = bis.read(b))!=-1) {
            bos.write(b, 0, len);
            bos.flush();
        }
        System.out.println("File sent");
        // 3. Release resources

        bos.close(); 
        socket.close();
        bis.close(); 
        System.out.println("File upload completed ");
	}
}

File upload optimization analysis

  1. The file name is dead

    On the server side, if the name of the saved file is written dead, only one file will be retained on the server hard disk. It is recommended to use system time optimization to ensure that the file name is unique. The code is as follows:

FileOutputStream fis = new FileOutputStream(System.currentTimeMillis()+".jpg") // File name
BufferedOutputStream bos = new BufferedOutputStream(fis);
  1. Circular reception problem

    The server is closed after saving a file, which is not practical. It can continuously receive files from different users by using circular improvement. The code is as follows:

// Each time a new connection is received, a Socket is created
while(true){
    Socket accept = serverSocket.accept();
    ......
}
  1. Efficiency issues

    The server may take a few seconds to receive large files. At this time, it cannot receive uploads from other users. Therefore, it is optimized using multithreading technology. The code is as follows:

while(true){
    Socket accept = serverSocket.accept();
    // accept to the child thread
    new Thread(() -> {
      	......
        InputStream bis = accept.getInputStream();
      	......
    }).start();
}

Optimized implementation

public class FileUpload_Server {
    public static void main(String[] args) throws IOException {
        System.out.println("Server startup.....  ");
        // 1. Create server ServerSocket
        ServerSocket serverSocket = new ServerSocket(6666);
      	// 2. Receive circularly and establish connection
        while (true) {
            Socket accept = serverSocket.accept();
          	/* 
          	3. socket Object is handed over to the child thread for reading and writing
               Runnable In the interface, there is only one run method, which uses lambda expressions to simplify the format
            */
            new Thread(() -> {
                try (
                    //3.1 get input stream object
                    BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
                    //3.2 create an output stream object and save it locally
                    FileOutputStream fis = new FileOutputStream(System.currentTimeMillis() + ".jpg");
                    BufferedOutputStream bos = new BufferedOutputStream(fis);) {
                    // 3.3 reading and writing data
                    byte[] b = new byte[1024 * 8];
                    int len;
                    while ((len = bis.read(b)) != -1) {
                      bos.write(b, 0, len);
                    }
                    //4. Close resources
                    bos.close();
                    bis.close();
                    accept.close();
                    System.out.println("File upload saved");
                } catch (IOException e) {
                  	e.printStackTrace();
                }
            }).start();
        }
    }
}

Information write back analysis diagram

The first four steps are consistent with the basic file upload

  1. [server] obtain the output stream and write back the data.
  2. [Client] obtain the input stream and parse the write back data.

Writeback implementation

public class FileUpload_Server {
    public static void main(String[] args) throws IOException {
        System.out.println("Server startup.....  ");
        // 1. Create server ServerSocket
        ServerSocket serverSocket = new ServerSocket(6666);
        // 2. Receive circularly and establish connection
        while (true) {
            Socket accept = serverSocket.accept();
          	/*
          	3. socket Object is handed over to the child thread for reading and writing
               Runnable In the interface, there is only one run method, which uses lambda expressions to simplify the format
            */
            new Thread(() -> {
                try (
                    //3.1 get input stream object
                    BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
                    //3.2 create an output stream object and save it locally
                    FileOutputStream fis = new FileOutputStream(System.currentTimeMillis() + ".jpg");
                    BufferedOutputStream bos = new BufferedOutputStream(fis);
                ) {
                    // 3.3 reading and writing data
                    byte[] b = new byte[1024 * 8];
                    int len;
                    while ((len = bis.read(b)) != -1) {
                        bos.write(b, 0, len);
                    }

                    // 4. ========= information update===========================
                    System.out.println("back ........");
                    OutputStream out = accept.getOutputStream();
                    out.write("Upload succeeded".getBytes());
                    out.close();
                    //================================

                    //5. Close resources
                    bos.close();
                    bis.close();
                    accept.close();
                    System.out.println("File upload saved");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

Client implementation:

public class FileUpload_Client {
    public static void main(String[] args) throws IOException {
        // 1. Create flow object
        // 1.1 create input stream and read local files
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("test.jpg"));
        // 1.2 create an output stream and write it to the server
        Socket socket = new Socket("localhost", 6666);
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());

        //2. Write the data
        byte[] b  = new byte[1024 * 8 ];
        int len ;
        while (( len  = bis.read(b))!=-1) {
            bos.write(b, 0, len);
        }
      	// Close the output stream and notify the server that the data is written out
        socket.shutdownOutput();
        System.out.println("File sent");
        // 3. = = = = parse writeback============
        InputStream in = socket.getInputStream();
        byte[] back = new byte[20];
        in.read(back);
        System.out.println(new String(back));
        in.close();
        // ============================

        // 4. Release resources
        socket.close();
        bis.close();
    }
}

Posted by dominicd on Wed, 01 Sep 2021 11:35:48 -0700