Network programming [Java]

Today, people widely use computer networks to realize the connection and data exchange between multiple computers; and if you want to realize the communication between computers in the same network, you need to write network programs to achieve it, which is the so-called network programming. That is, for hosts on the network, data transmission between networks is realized by programming through different processes.


network communication protocol

Network communication protocols are actually the rules for connection and communication between computer networks; similar to traffic rules, only when both parties to the communication abide by this agreement can the exchange of data and information be successfully completed.
There are many protocols for network communication, but the most widely used one is the TCP/IP protocol. Here we do not elaborate on the content of the protocol, but only learn how to program network based on the network communication protocol;

Concepts related to network programming

  • client and server

Client: The party that obtains the service actively sends network data;
Server: The party that provides the service passively receives network data;

  • sender and receiver

Sending end: the source host in network communication, the sender of data;
receiving end: the destination host in network communication, the receiver of data;

  • request and response

Request: the data sent by the client to the server;
Response: the data returned by the server to the client;

  • How the client interacts with the server

One question and one answer: the client sends a request, and the server returns one response;
multiple questions and one answer: the client sends multiple requests, and the server returns one response;
one question and multiple answers: the client sends one request, and the server returns multiple responses;
Multiple questions and multiple answers: the client sends multiple requests, and the server returns multiple responses;

Socket

Socket is the basic operation unit of network communication based on TCP/IP protocol. Through advanced abstraction of network connection, it provides the convenience of operating network connection. Socket is like the standard of network programming. Using the Socket interface, even if different TCP/IP runs on different systems, it can also run successfully;

Three different types of sockets

Sockets can be divided into three categories according to the transport layer protocol:

  • Stream socket: use the transport layer TCP protocol;
  • Datagram socket: use the transport layer UDP protocol;
  • raw socket;

Socket programming

UDP version Socket programming

  • server
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;


public class UdpServer {
    
    
    //创建UDP服务器,首先打开一个socket文件
    private DatagramSocket socket=null;

    public UdpServer(int port) throws SocketException {
    
    
        //创建UDP服务器,指定端口,可以发送和接收数据报
        socket=new DatagramSocket(port);
    }
    //启动服务器
    public void start() throws IOException {
    
    
        System.out.println("服务器启动!");
        //使用循环不断接收客户端UDP数据报
        while(true){
    
    
            //使用DatagramPacket的构造方法,创建一个字节数组用于接收数据,
            DatagramPacket requestPacket=new DatagramPacket(new byte[4096],4096);
            //使用receive方法从此套接字接收数据报
            socket.receive(requestPacket);
            //对客户端发来的请求进行解析,把DatagramPacket转化成String类型
            String request=new String(requestPacket.getData(),0,requestPacket.getLength());
            //对请求进行处理,进行响应
            String response=process(request);
            //构造响应对象,为DatagramPacket对象,
            DatagramPacket responsePacket =new DatagramPacket(response.getBytes(),response.getBytes().length,requestPacket.getSocketAddress());
            //将响应从此套接字发送数据报包
            socket.send(responsePacket);
            System.out.printf("[%s:%d] req=%s; resp=%s\n", requestPacket.getAddress().toString(), requestPacket.getPort(),
                    request, response);

        }
    }
    //单独的一个方法用来处理响应,这里是一个回显服务器,直接返回请求内容即可
    public String process (String req){
    
    
        return req;
    }

    public static void main(String[] args) throws IOException {
    
    
        //实例化一个UDP服务器,同时指定端口
        UdpServer server=new UdpServer(8000);
        server.start();
    }
}

DatagramPacket class

Since UDP is a connectionless protocol, the sending end and the receiving end do not need to establish a connection during communication;
JDK provides a DatagramPacket class for encapsulating data sent or received in UDP communication;

The constructor of the DatagramPacket class
  • DatagramPacket(byte[]buf, int length): Specifies the byte array and data size of the encapsulated data, which is only used for the receiving end;
  • DatagramPacket(byte[]buf, int length, InetAddress addr, int port): Specifies the byte array of the encapsulated data, data size, target IP address and port number, often used at the sender;
  • DatagramPacket(byte[]buf, int offset, int length): When specifying the byte array and data size, a parameter is added to indicate that the received data starts from the specified position when it is put into the array;
  • DatagramPacket(byte[] buf, int offset, int length, InetAddress addr, int port): Similar to the above one, it also specifies the destination IP address and port number;
Common methods of the DatagramPacket class
  • InetAddress getAddress(): returns the IP address of the sender or receiver;
  • int getPort(): returns the port number of the sender or receiver;
  • byte[] getData(): returns the data to be received or sent;
  • int getLength(): returns the length of received or to-be-sent data;

The following is the Socket programming on the client side:

  • client
import jdk.nashorn.internal.ir.WhileNode;

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class UdpClient {
    
    
    private DatagramSocket socket=null;

    public UdpClient() throws SocketException {
    
    
        //创建UDP客户端,不需要手动指定端口号,一般由操作系统自动分配
        socket=new DatagramSocket();
    }

    public void start() throws IOException {
    
    
        Scanner scanner=new Scanner(System.in);
        while (true){
    
    
            System.out.print("--->");
            //从控制台读取数据
            String request=scanner.next();
            //创建一个要发送的数据包,包括发送的数据,数据长度,接收端的IP地址以及端口号
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,
                    InetAddress.getByName("127.0.0.1"), 8000);
            //发送数据包给服务器
            socket.send(requestPacket);
            //创建数组用于读取数据
            DatagramPacket responsePacket=new DatagramPacket(new byte[4096],4096);
            //接收数据报,
            socket.receive(responsePacket);
            //将响应数据转化为String
            String response =new String(responsePacket.getData(),0, responsePacket.getLength());
            System.out.printf("req: %s; resp: %s\n", request, response);
        }
    }

    public static void main(String[] args) throws IOException {
    
    
        UdpClient client=new UdpClient();
        client.start();
    }
}

DatagramSocket class

The DatagramSocket class is used to send and receive DatagramPacket packets, which is similar to the role of "dock";

Constructor of the DatagramSocket class
  • DatagramSocket() : used to create the DatagramSocket object of the sender;
  • DatagramSocket(int port): specifies the port number, which can be used for sending or receiving;
  • DatagramSocket(int port, InetAddress addr): specifies the port number and related IP address;
Common methods of the DatagramSocket class
  • void receive(DatagramPacket p): Fill the received data into the DatagramPacket data packet and return it, and it is blocked when the data packet is not received;
  • void send(DatagramPacket p): used to send DatagramPacket packets;
  • void close(): close the current socket and release resources;

TCP version Socket programming

  • server
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.spec.RSAOtherPrimeInfo;
import java.util.Scanner;


public class TcpServer {
    
    
    //创建服务器
    private ServerSocket serverSocket=null;
    public TcpServer(int port) throws IOException {
    
    
        //创建服务器的同时与指定端口绑定
        serverSocket =new ServerSocket(port);
    }

    public void start() throws IOException {
    
    
        System.out.println("服务器启动!");
        while (true){
    
    
            //返回一个与客户端连接的对象
            Socket clientSocket=serverSocket.accept();
            processConnect(clientSocket);
        }
    }
    /*
    * 为与客户端建立了连接的对象提供服务
    * */
    public void processConnect(Socket clientSocket) throws IOException {
    
    
        System.out.printf("[%s:%d] 建立连接!\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());
        try(InputStream inputStream=clientSocket.getInputStream();
            OutputStream outputStream=clientSocket.getOutputStream()){
    
    
            Scanner scanner=new Scanner(inputStream);
            PrintWriter printWriter=new PrintWriter(outputStream);
            while (true){
    
    
                if (!scanner.hasNext()){
    
    
                    System.out.printf("[%s:%d] 断开连接!\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());
                    break;
                }
                //读取请求并解析
                String request=scanner.next();
                //根据请求进行响应
                String response=process(request);
                //返回响应给客户端
                printWriter.println(response);
                //刷新缓冲区
                printWriter.flush();
                System.out.printf("[%s:%d] req: %s; resp: %s\n",
                        clientSocket.getInetAddress().toString(), clientSocket.getPort(),
                        request, response);
            }
        }finally {
    
    
            clientSocket.close();
        }

    }
    /*
    * 对请求做出响应
    * */
    public String process(String req){
    
    
        return req;
    }

    public static void main(String[] args) throws IOException {
    
    
        TcpServer server=new TcpServer(8000);
        server.start();
    }

}

ServerSocket class

The ServerSocket class is a class provided by JDK when creating a server for developing TCP programs. The instance object of this class can implement a server-side program;

Constructor of the ServerSocket class
  • ServerSocket( ): just create a ServerSocket object, no port number is bound, so it cannot be used directly;
  • ServerSocket(int port): Bind the port number while creating the object;
  • ServerSocket(int port,int backlog): The second parameter indicates the number of waiting clients that can keep connection requests with the server when the server is busy, and the default is 50;
  • ServerSocket(int port, int backlog, InetAddress bindAddr): On the basis of the above, specify the relevant IP address;
Common methods of the ServerSocket class
  • Socket accept(): It is used to wait for the connection of the client, and it is blocked until it is not connected;
  • InetAddress getInetAddress(): returns an InetAddress object, which is the IP address bound to ServerSocket;
  • void close() : close the socket and end this communication;

Here is the client:

  • client
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;


public class TcpClient {
    
    
    private Socket socket=null;
    public TcpClient() throws IOException {
    
    
        //创建客户端,通过IP地址和端口号与服务器建立连接
        socket=new Socket("127.0.0.1",8000);
    }
    public void start() throws IOException {
    
    
        Scanner scanner=new Scanner(System.in);
        try(InputStream inputStream=socket.getInputStream();
            OutputStream outputStream=socket.getOutputStream()){
    
    
            Scanner scanner1=new Scanner(inputStream);
            PrintWriter printWriter=new PrintWriter(outputStream);
            //循环实现输入
            while (true){
    
    
                System.out.println(">---");
                //从控制台读取输入数据
                String request=scanner.next();
                //发送请求给服务器
                printWriter.println(request);
                //刷新缓冲区
                printWriter.flush();
                //从服务器读取响应
                String response=scanner1.next();
                System.out.printf("req: %s; resp: %s\n", request, response);
            }
        }
    }
    public static void main(String[] args) throws IOException {
    
    
        TcpClient client=new TcpClient();
        client.start();
    }
}

Socket class

The Socket class is used to implement the TCP client program;

The constructor of the Socket class
  • Socket(): Only create a Socket object, that is, only create a client object without connecting to the server;
  • Socket(String host, int port): When creating an object, connect to the server according to the specified address and port number;
Common methods of Socket class
  • int getPort(): returns the port number of the Socket object connected to the server;
  • InetAddress getInetAddress() : Get the local IP address bound to the Socket object;
  • InputStream getInputStream(): Returns the input stream object of the socket. If the object is returned by the server object, it is used to read the data sent by the client, and vice versa;
  • void close() : close the socket and end this communication;
  • OutputStream getOutputStream() : returns the output stream object;

insert image description here

Long connection and short connection in TCP

Short connection: that is, the connection is closed every time data is received and a response is returned, and only one data interaction is performed for one connection;
long connection: that is, the two sides of the interaction continue to interact without closing the connection;

The difference between short connection and long connection:

Since the short connection needs to establish a connection and then close the connection every time it requests and responds, the efficiency of the long connection is relatively higher; the short connection
usually means that the client actively sends a request to the server, and the long connection means that both parties can actively send Requests;
short connections are more suitable for scenarios where the frequency of client requests is low, while long connections are more suitable for scenarios where the client interacts frequently with the server;

Improvement of TCP Version Socket Programming

In the TCP version Socket programming provided above, only a single-threaded method is provided for the implementation of the server. However, in actual application scenarios, it often happens that a server needs to provide services for multiple clients at the same time, so we try to implement a multi-threaded version of the server-side program:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.spec.RSAOtherPrimeInfo;
import java.util.Scanner;

public class TcpServer {
    
    
    //创建服务器
    private ServerSocket serverSocket=null;
    public TcpServer(int port) throws IOException {
    
    
        //创建服务器的同时与指定端口绑定
        serverSocket =new ServerSocket(port);
    }

    public void start() throws IOException {
    
    
        System.out.println("服务器启动!");
        while (true){
    
    
            //返回一个与客户端连接的对象
            Socket clientSocket=serverSocket.accept();
           
            //多线程版
            Thread t=new Thread(()->{
    
    
               try{
    
    
                   processConnect(clientSocket);
               } catch (IOException e){
    
    
                   e.printStackTrace();
               }
            });
            t.start();
        }
    }
    /*
    * 为与客户端建立了连接的对象提供服务
    * */
    public void processConnect(Socket clientSocket) throws IOException {
    
    
        System.out.printf("[%s:%d] 建立连接!\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());
        try(InputStream inputStream=clientSocket.getInputStream();
            OutputStream outputStream=clientSocket.getOutputStream()){
    
    
            Scanner scanner=new Scanner(inputStream);
            PrintWriter printWriter=new PrintWriter(outputStream);
            while (true){
    
    
                if (!scanner.hasNext()){
    
    
                    System.out.printf("[%s:%d] 断开连接!\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());
                    break;
                }
                //读取请求并解析
                String request=scanner.next();
                //根据请求进行响应
                String response=process(request);
                //返回响应给客户端
                printWriter.println(response);
                //刷新缓冲区
                printWriter.flush();
                System.out.printf("[%s:%d] req: %s; resp: %s\n",
                        clientSocket.getInetAddress().toString(), clientSocket.getPort(),
                        request, response);
            }
        }finally {
    
    
            clientSocket.close();
        }

    }
    /*
    * 对请求做出响应
    * */
    public String process(String req){
    
    
        return req;
    }

    public static void main(String[] args) throws IOException {
    
    
        TcpServer server=new TcpServer(8000);
        server.start();
    }

}

The client program is consistent with the above TCP version of Socket programming, the following is the actual operation:

insert image description here
Solving the problem of serving multiple clients, our implementation method has brought new problems. In the case of many client requests, using the ordinary thread creation method will inevitably create and destroy threads frequently, so It may increase the overhead of the system, so we can try the thread pool method:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.spec.RSAOtherPrimeInfo;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class TcpServer {
    
    
    //创建服务器
    private ServerSocket serverSocket=null;
    public TcpServer(int port) throws IOException {
    
    
        //创建服务器的同时与指定端口绑定
        serverSocket =new ServerSocket(port);
    }

    public void start() throws IOException {
    
    
        System.out.println("服务器启动!");
        //创建线程池
        ExecutorService service= Executors.newCachedThreadPool();
        while (true){
    
    
            //返回一个与客户端连接的对象
            Socket clientSocket=serverSocket.accept();
        
            service.submit(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    try {
    
    
                        processConnect(clientSocket);
                    }catch (IOException e){
    
    
                        e.printStackTrace();
                    }
                }
            });

        }
    }
    /*
    * 为与客户端建立了连接的对象提供服务
    * */
    public void processConnect(Socket clientSocket) throws IOException {
    
    
        System.out.printf("[%s:%d] 建立连接!\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());
        try(InputStream inputStream=clientSocket.getInputStream();
            OutputStream outputStream=clientSocket.getOutputStream()){
    
    
            Scanner scanner=new Scanner(inputStream);
            PrintWriter printWriter=new PrintWriter(outputStream);
            while (true){
    
    
                if (!scanner.hasNext()){
    
    
                    System.out.printf("[%s:%d] 断开连接!\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());
                    break;
                }
                //读取请求并解析
                String request=scanner.next();
                //根据请求进行响应
                String response=process(request);
                //返回响应给客户端
                printWriter.println(response);
                //刷新缓冲区
                printWriter.flush();
                System.out.printf("[%s:%d] req: %s; resp: %s\n",
                        clientSocket.getInetAddress().toString(), clientSocket.getPort(),
                        request, response);
            }
        }finally {
    
    
            clientSocket.close();
        }

    }
    /*
    * 对请求做出响应
    * */
    public String process(String req){
    
    
        return req;
    }

    public static void main(String[] args) throws IOException {
    
    
        TcpServer server=new TcpServer(8000);
        server.start();
    }

}

insert image description here
At this point, the knowledge about network programming is basically over~~


Finally, it is about IDEA's method of opening the same program without ending the program:

First, select which program to open at the same time in the drop-down box here:
insert image description hereClick the edit bar selected below:
insert image description hereCome to this interface, click the blue font Modify options:
insert image description here

Check the selected column below:
insert image description here
click apply;

Guess you like

Origin blog.csdn.net/weixin_54175406/article/details/127233820