Java中的网络编程------基于Socket的TCP编程和基于UDP的网络编程,netstat指令

news2024/11/27 2:35:21

Socket

在Java中,Socket是一种用于网络通信的编程接口,它允许不同计算机之间的程序进行数据交换和通信。Socket使得网络应用程序能够通过TCP或UDP协议在不同主机之间建立连接、发送数据和接收数据。以下是Socket的基本介绍:

  • Socket类型:在Java中,有两种主要类型的Socket,分别用于不同类型的通信协议:

  • TCP Socket:使用TCP协议进行通信,提供可靠的、面向连接的数据传输。TCP Socket使用Socket类进行创建和管理。

  • UDP Socket:使用UDP协议进行通信,提供不可靠的、面向无连接的数据传输。UDP Socket使用DatagramSocket类进行创建和管理。

  • 套接字连接Socket允许两台计算机之间建立连接,一台计算机充当服务器,另一台计算机充当客户端服务器Socket等待客户端连接请求,客户端Socket通过指定服务器地址和端口号来连接服务器。客户端和服务器端都有Socket,是两台机器通信的端点

  • 通信协议:Socket可以使用不同的通信协议,最常见的是TCP和UDP。TCP提供可靠的、面向连接的通信,确保数据按顺序到达和错误处理。UDP提供不可靠的、面向无连接的通信,适用于低延迟应用。

  • 数据传输Socket允许应用程序通过输入和输出流(InputStream和OutputStream)进行数据传输。应用程序可以使用这些流发送和接收数据。

  • 阻塞和非阻塞模式:Socket可以以阻塞或非阻塞模式工作。在阻塞模式下,Socket操作将等待直到完成,而在非阻塞模式下,Socket操作可以立即返回。

  • 安全性:Socket通信可以通过安全套接字层(SSL)或传输层安全性(TLS)来加密,以提供数据的保密性和完整性。

TCP网络通信编程

TCP(传输控制协议)是一种可靠的、面向连接的网络通信协议,它用于在计算机网络上可靠地传输数据。TCP通信是客户端-服务器模型的基础,它确保了数据的可靠性和有序性。以下是TCP网络通信编程的基本介绍:

  1. 面向连接:TCP是一种面向连接的协议,通信的两端(客户端和服务器)在开始通信之前必须建立连接。连接建立后,数据可以在两端之间可靠地传输。

  2. 可靠性:TCP提供可靠的数据传输。它使用确认机制来确保数据的完整性和有序性。如果接收方收到数据,它会发送一个确认(ACK)给发送方,如果发送方没有收到确认,它会重新发送数据。

  3. 有序性:TCP保证数据按发送的顺序到达接收方。即使数据包在传输过程中可能以不同的顺序到达,TCP会重新排列它们,以确保接收方按正确的顺序接收数据。

  4. 流式数据传输:TCP提供了流式数据传输,数据被视为连续的字节流,而不是分成离散的数据包。这使得TCP适用于传输大文件和多媒体数据。

  5. 双向通信:TCP连接是全双工的,允许双方同时发送和接收数据。客户端和服务器都可以发送请求和响应。

  6. 端口号:TCP通信使用端口号来标识不同的服务或应用程序。服务器应用程序通常监听特定端口,客户端通过指定目标主机和端口来连接到服务器。

  7. 阻塞式通信:TCP通信默认是阻塞的,这意味着发送和接收数据的操作会一直阻塞,直到完成。这可以通过多线程或非阻塞I/O来处理,以确保应用程序的响应性。

  8. 安全性:TCP通信可以通过安全套接字层(SSL)或传输层安全性(TLS)来加密,以提供数据的保密性和完整性。

在这里插入图片描述

在Java中,你可以使用java.net包中的SocketServerSocket类来实现TCP网络通信。客户端使用Socket类来建立与服务器的连接,而服务器使用ServerSocket类来监听客户端连接请求。以下是一些简单的Java TCP服务器和客户端的示例,以便更好地理解TCP通信的基本原理:

1.使用字节流的方式发送数据和接收数据

服务器端代码

public class Server {
    public static void main(String[] args) throws IOException {
        //1. 在本机 的 9999 端口监听, 等待连接
        // 细节: 要求在本机没有其它服务在监听 9999,客户端的端口号只能被一个服务监听
        // 细节:这个 ServerSocket 可以通过 accept() 返回多个 Socket[多个客户端连接服务器的并发]
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服务端,在 9999 端口监听,等待连接..");
        //2. 当没有客户端连接 9999 端口时,程序会 阻塞, 等待连接
        // 如果有客户端连接,则会返回 Socket 对象,程序继续
        Socket socket = serverSocket.accept();
        //3.从一个已建立的网络套接字(Socket)中获取输入流,以便从该套接字接收数据
        InputStream inputStream = socket.getInputStream();
        //4.通过输入流从网络套接字中读取数据
        byte[] buf = new byte[1024];
        int readLen = 0;
        while ((readLen = inputStream.read(buf)) != -1) {
            System.out.println(new String(buf,0,readLen));
        }
        //5.从一个已建立的网络套接字(Socket)中获取输出流,以便将数据发送到该套接字
        OutputStream outputStream = socket.getOutputStream();
        //6.通过输出流 (outputStream) 发送内容到网络套接字
        outputStream.write("hello,client".getBytes());
        //7.设置结束标记。用于关闭套接字(Socket)的输出流。具体来说,它关闭套接字的输出流,表示在此之后不再发送数据到套接字的另一端
        socket.shutdownOutput();
        //8.关闭流和 socket
        inputStream.close();
        outputStream.close();
        socket.close();
        serverSocket.close();

    }
}

客户端代码

public class Client {
    public static void main(String[] args) throws IOException {
        //1. 连接服务端 (ip , 端口)
        //连接本机的 9999 端口, 如果连接成功,返回 Socket 对象
        Socket socket = new Socket(InetAddress.getLocalHost(),9999);
        //2.从一个已建立的网络套接字(Socket)中获取输出流,以便将数据发送到该套接字
        OutputStream outputStream = socket.getOutputStream();
        //3.通过输出流 (outputStream) 发送内容到网络套接字
        outputStream.write("hello,server".getBytes());
        //4.设置结束标记。用于关闭套接字(Socket)的输出流。具体来说,它关闭套接字的输出流,表示在此之后不再发送数据到套接字的另一端
        socket.shutdownOutput();
        //5.从一个已建立的网络套接字(Socket)中获取输入流,以便从该套接字接收数据
        InputStream inputStream = socket.getInputStream();
        //6.通过输入流从网络套接字中读取数据
        byte[] buf = new byte[1024];
        int readLen = 0;
        while ((readLen = inputStream.read(buf)) != -1){
            System.out.println(new String(buf,0,readLen));
        }
        //7.关闭流和 socket
        outputStream.close();
        inputStream.close();
        socket.close();
        System.out.println("客户端退出");
    }
}

2.使用字符流的方式发送数据和接收数据
服务器端代码

public class Server {
    public static void main(String[] args) throws IOException {
        //1. 在本机 的 9999 端口监听, 等待连接
        // 细节: 要求在本机没有其它服务在监听 9999,客户端的端口号只能被一个服务监听
        // 细节:这个 ServerSocket 可以通过 accept() 返回多个 Socket[多个客户端连接服务器的并发]
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服务端,在 9999 端口监听,等待连接..");
        //2. 当没有客户端连接 9999 端口时,程序会 阻塞, 等待连接
        // 如果有客户端连接,则会返回 Socket 对象,程序继续
        Socket socket = serverSocket.accept();
        //3.从一个已建立的网络套接字(Socket)中获取输入流,以便从该套接字接收数据
        InputStream inputStream = socket.getInputStream();
        //4.将字节流转换为字符流
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
        //5.对字符流进行包装,提供了更方便的读取方法,如readLine()可以一次读取一行数据
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        //6.通过输入流从网络套接字中读取数据
        String line = "";
        while ((line = bufferedReader.readLine()) != null) {
            System.out.println(line);
        }
        //7.从一个已建立的网络套接字(Socket)中获取输出流,以便将数据发送到该套接字
        OutputStream outputStream = socket.getOutputStream();
        //8.将字节流转换为字符流
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
        //9.对字符流进行包装,提供了更方便的写入方法,如writer()可以直接写入字符串而不用转换为字符数组
        BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
        //10.通过输出流发送内容到网络套接字
        bufferedWriter.write("hello,client");
        //11.当我们使用缓冲写入数据时,数据会先被写入到缓冲区中,而不是直接写入到目标文件或流中。
        // 调用flush()方法会强制将缓冲区中的数据立即写入到目标文件或流中,确保数据的及时更新。
        // 这样可以避免数据在缓冲区中滞留而没有被写入到目标文件或流中的情况发生。
        bufferedWriter.flush();
        //12.设置结束标记。用于关闭套接字(Socket)的输出流。具体来说,它关闭套接字的输出流,表示在此之后不再发送数据到套接字的另一端
        socket.shutdownOutput();
        //13.关闭流和 socket
        bufferedReader.close();
        bufferedWriter.close();
        socket.close();
        serverSocket.close();

    }
}

客户端代码

public class Client {
    public static void main(String[] args) throws IOException {
        //1. 连接服务端 (ip , 端口)
        //连接本机的 9999 端口, 如果连接成功,返回 Socket 对象
        Socket socket = new Socket(InetAddress.getLocalHost(),9999);
        //2.从一个已建立的网络套接字(Socket)中获取输出流,以便将数据发送到该套接字
        OutputStream outputStream = socket.getOutputStream();
        //3.将字节流转换为字符流
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
        //4..对字符流进行包装,提供了更方便的写入方法,如如writer()可以直接写入字符串而不用转换为字符数组
        BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
        //5.通过输出流发送内容到网络套接字
        bufferedWriter.write("hello,server");
        //6.当我们使用缓冲写入数据时,数据会先被写入到缓冲区中,而不是直接写入到目标文件或流中。
        // 调用flush()方法会强制将缓冲区中的数据立即写入到目标文件或流中,确保数据的及时更新。
        // 这样可以避免数据在缓冲区中滞留而没有被写入到目标文件或流中的情况发生。
        bufferedWriter.flush();//需要刷新否则写不进去
        //7.设置结束标记。用于关闭套接字(Socket)的输出流。具体来说,它关闭套接字的输出流,表示在此之后不再发送数据到套接字的另一端
        socket.shutdownOutput();
        //8.从一个已建立的网络套接字(Socket)中获取输入流,以便从该套接字接收数据
        InputStream inputStream = socket.getInputStream();
        //9.将字节流转换为字符流
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
        //10.对字符流进行包装,提供了更方便的读取方法,如readLine()可以一次读取一行数据
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        //11.通过输入流从网络套接字中读取数据
        String line = "";
        while ((line = bufferedReader.readLine()) != null) {
        System.out.println(line);}
        //12.关闭流和 socket
        bufferedWriter.close();
        bufferedReader.close();
        socket.close();
        System.out.println("客户端退出");
    }
}

3.发送图片的代码:
服务器端代码

public class Server {
    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket = new ServerSocket(6666);
        System.out.println("服务端,在 6666 端口监听,等待连接..");
        Socket socket = serverSocket.accept();

        //通过将socket的输入流包装在BufferedInputStream中,可以在读取数据时先将数据存储在缓冲区中,
        // 然后再从缓冲区中读取数据,减少了直接从输入流中读取数据的次数,提高了读取数据的效率。
        //当然可以不用缓冲流也是可以的,但是效率不高,最好还是用缓冲流
        BufferedInputStream bufferedInputStream = new BufferedInputStream(socket.getInputStream());
        byte[] bytes = StreamUtils.streamToByteArray(bufferedInputStream);

        String descFile = "src\\main\\java\\com\\example\\retcode\\test\\net\\socket\\tcp\\tcp4\\线程状态.bmp";
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(descFile));
        bufferedOutputStream.write(bytes);
        bufferedOutputStream.close();

        //通过 socket 获取到输出流(字符)
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        bufferedWriter.write("收到图片");
        bufferedWriter.flush();
        socket.shutdownOutput();

        bufferedOutputStream.close();
        bufferedInputStream.close();
        bufferedWriter.close();
        socket.close();

    }
}

客户端代码

public class Client {
    public static void main(String[] args) throws Exception {
        Socket socket = new Socket(InetAddress.getLocalHost(),6666);
        String filePath = "d:\\线程状态.bmp";
        BufferedInputStream bufferedInputStream  = new BufferedInputStream(new FileInputStream(filePath));
        byte[] bytes = StreamUtils.streamToByteArray(bufferedInputStream);
        OutputStream outputStream = socket.getOutputStream();
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
        bufferedOutputStream.write(bytes);
        socket.shutdownOutput();

        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String line ="";
        while ((line = bufferedReader.readLine())!=null){
        System.out.println(line);}

        bufferedOutputStream.close();
        bufferedInputStream.close();
        bufferedReader.close();
        socket.close();

        System.out.println("客户端退出");
    }
}

StreamUtils类:

public class StreamUtils {
	/**
	 * 功能:将输入流转换成byte[], 即可以把文件的内容读入到byte[]
	 * @param is
	 * @return
	 * @throws Exception
	 */
	public static byte[] streamToByteArray(InputStream is) throws Exception{
		ByteArrayOutputStream bos = new ByteArrayOutputStream();//创建输出流对象
		byte[] b = new byte[1024];//字节数组
		int len;
		while((len=is.read(b))!=-1){//循环读取
			bos.write(b, 0, len);//把读取到的数据,写入bos	
		}
		byte[] array = bos.toByteArray();//然后将bos 转成字节数组
		bos.close();
		return array;
	}
	/**
	 * 功能:将InputStream转换成String
	 * @param is
	 * @return
	 * @throws Exception
	 */
	
	public static String streamToString(InputStream is) throws Exception{
		BufferedReader reader = new BufferedReader(new InputStreamReader(is));
		StringBuilder builder= new StringBuilder();
		String line;
		while((line=reader.readLine())!=null){
			builder.append(line+"\r\n");
		}
		return builder.toString();
		
	}

}

netstat指令

netstat 是一个用于显示网络连接和路由表信息的命令行工具,它可以在不同的操作系统中使用,包括Windows、Linux和macOS。netstat 可以帮助你监视和诊断网络连接问题,了解网络活动情况。以下是 netstat 命令的基本介绍:

在命令行中执行 netstat 命令时,通常需要提供一些选项和参数以获取特定的网络信息。以下是一些常见的 netstat 选项和用法:

  1. 查看所有活动连接

    netstat -a
    

    这会显示所有的活动网络连接,包括TCP和UDP连接,以及监听中的端口。

  2. 查看活动TCP连接

    netstat -at
    

    这会显示所有的活动TCP连接,包括本地地址、远程地址、状态等信息。

  3. 查看活动UDP连接

    netstat -au
    

    这会显示所有的活动UDP连接,包括本地地址、远程地址等信息。

  4. 显示监听端口

    netstat -l
    

    这会显示当前正在监听的端口,包括TCP和UDP。

  5. 显示路由表信息

    netstat -r
    

    这会显示操作系统的路由表信息,包括网络地址、网关、接口等。

  6. 显示统计信息

    netstat -s
    

    这会显示各种协议的统计信息,如TCP、UDP、ICMP等。

  7. 显示PID和程序名

    netstat -b
    

    这会显示每个连接的相关进程的PID和程序名。在Windows系统中,需要以管理员权限运行才能查看程序名。

  8. 显示数字格式

    netstat -n
    

    这会以数字格式显示网络地址和端口,而不是尝试解析主机名和服务名。

这只是 netstat 命令的一些常见选项和用法。根据你的需求,你可以根据操作系统和情况选择不同的选项以查看所需的网络信息。netstat 是网络管理和故障排除的有用工具,它可以帮助你了解网络连接、端口使用情况、路由信息等,以便更好地管理和维护计算机网络。

UDP编程

UDP(User Datagram Protocol,用户数据报协议)是一种无连接的、不可靠的网络通信协议,它用于在计算机网络上进行数据传输。UDP通信的特点是速度快,但不保证数据的可靠性。以下是Java中UDP编程的基本介绍:

  1. 无连接性:UDP是无连接的协议,通信双方在发送和接收数据之前不需要建立连接。这使得UDP通信的速度较快,因为不需要进行连接和断开的握手过程。

  2. 不可靠性:UDP不保证数据的可靠性,数据包可能会丢失、乱序到达或重复到达。因此,如果需要可靠的数据传输,必须在应用层进行额外的处理。

  3. 面向数据报:UDP通信是面向数据报的,每个UDP数据包都是独立的,没有关联性。这使得应用程序可以发送和接收独立的消息。

  4. 低开销:由于UDP没有建立连接和维护状态的开销,因此它在某些情况下比TCP更高效。UDP通常用于实时音频、视频和在线游戏等需要快速传输数据的应用。

  5. 广播和多播:UDP支持广播和多播,允许一个主机向多个接收者发送相同的数据包,而无需建立多个连接。

在Java中,你可以使用java.net包中的DatagramSocketDatagramPacket类来实现UDP编程。以下是基本的UDP编程步骤:

发送端(客户端)

  1. 创建一个DatagramSocket对象,用于发送数据。
  2. 创建一个DatagramPacket对象,将要发送的数据放入其中,并指定目标主机的IP地址和端口号。
  3. 使用DatagramSocketsend()方法发送数据包。
  4. 关闭DatagramSocket以释放资源。

接收端(服务器端)

  1. 创建一个DatagramSocket对象,用于接收数据,并指定监听的端口号。
  2. 创建一个DatagramPacket对象,用于接收数据。
  3. 使用DatagramSocketreceive()方法接收数据包。
  4. 从接收到的数据包中提取数据。
  5. 关闭DatagramSocket以释放资源。

以下是一个简单的UDP发送端和接收端的示例:

发送端代码

public class UDPSender {
    public static void main(String[] args) throws IOException {
        //1.创建 DatagramSocket 对象,准备在 9998 端口 接收数据
        DatagramSocket socket = new DatagramSocket(9998);
        //2. 将需要发送的数据,封装到 DatagramPacket 对象
        byte[] data = "hello 明天吃火锅~".getBytes();
        //说明: 封装的 DatagramPacket 对象 data 内容字节数组 , data.length , 主机(IP) , 端口
        DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName("172.21.10.13"), 9999);
        socket.send(packet);
        //3.=== 接收从 A 端回复的信息
        //(1) 构建一个 DatagramPacket 对象,准备接收数据
        // 在前面讲解 UDP 协议时,一个数据包最大 64k
        byte[] data1 = new byte[1024];
        DatagramPacket packet1 = new DatagramPacket(data1, data1.length);
        //(2) 调用 接收方法, 将通过网络传输的 DatagramPacket 对象
        // 填充到 packet 对象
        //当有数据包发送到 本机的 9998 端口时,就会接收到数据
        // 如果没有数据包发送到 本机的 9998 端口, 就会阻塞等待. socket.receive(packet);
        socket.receive(packet1);
        //(3) 可以把 packet 进行拆包,取出数据,并显示. int length = packet.getLength();//实际接收到的数据字节长度
        int length = packet1.getLength();
        data1 = packet1.getData();//接收到数据
        String s = new String(data1, 0, length);
        System.out.println(s);
        //关闭资源
        socket.close();
        System.out.println("B 端退出");
    }
}

接收端代码

public class UDPReceiver {
    public static void main(String[] args) throws IOException {
        //1. 创建一个 DatagramSocket 对象,准备在 9999 接收数据
        System.out.println("9999端口等待数据的请求");
        DatagramSocket socket = new DatagramSocket(9999);
        //2. 构建一个 DatagramPacket 对象,准备接收数据
        // 在前面讲解 UDP 协议时,老师说过一个数据包最大 64k
        byte[] buf = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buf, buf.length);
        //3. 调用 接收方法, 将通过网络传输的 DatagramPacket 对象
        // 填充到 packet 对象
        // 当有数据包发送到 本机的 9999 端口时,就会接收到数据
        // 如果没有数据包发送到 本机的 9999 端口, 就会阻塞等待. System.out.println("接收端 A 等待接收数据..");
        socket.receive(packet);

        //4. 可以把 packet 进行拆包,取出数据,并显示. int length = packet.getLength();//实际接收到的数据字节长度
        int length = packet.getLength();
        byte[] data = packet.getData();//接收到数据
        String s = new String(data, 0, length);
        System.out.println(s);
        //===回复信息给 B 端
        //将需要发送的数据,封装到 DatagramPacket 对象
        byte[] data1 = "好的, 明天见".getBytes();
        //说明: 封装的 DatagramPacket 对象 data 内容字节数组 , data.length , 主机(IP) , 端口
        DatagramPacket packet1 = new DatagramPacket(data1, data1.length, InetAddress.getByName("172.21.10.13"), 9998);
        socket.send(packet1);//发送
        //5. 关闭资源
        socket.close();
        System.out.println("A 端退出...");
    }
}

UDP通信适用于需要快速传输数据且可以容忍一些数据丢失的场景,例如实时音视频传输和在线游戏。然而,由于UDP不保证数据的可靠性,因此在应用中需要考虑如何处理丢失的数据或保证数据的顺序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/969217.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习:可解释学习

文章目录 可解释学习为什么需要可解释机器学习可解释还是强模型可解释学习的目标可解释机器学习Local ExplanationGlobal Explanation 可解释学习 神马汉斯,只有在有人看的时候能够答对。 为什么需要可解释机器学习 贷款,医疗需要给出理由,让…

学生宿舍水电费自动缴费系统/基于javaweb的水电缴费系统

摘 要 “互联网”的战略实施后,很多行业的信息化水平都有了很大的提升。但是目前很多学校日常工作仍是通过人工管理的方式进行,需要在各个岗位投入大量的人力进行很多重复性工作,这样就浪费了许多的人力物力,工作效率较低&#x…

职场中的道德与伦理:如何在工作中坚守原则?

引言 在快节奏的职场环境中,道德与伦理问题时常出现,但却往往被忽视。面对各种压力和诱惑,如何在工作中坚守原则,不仅是个人修养的体现,也是职业成功的关键。本文将探讨职场中的道德与伦理问题,以及如何在…

Orangepi安装外设库 wiringPi

注意:mobaXterm传送文件要在SSH登陆环境下才可以。 同时电脑和orangepi都在同一个wifi下。

docker 笔记6:高级篇 DockerFile解析

目录 1.是什么? 2.构建三步骤 3.DockerFile构建过程解析 3.1 Dockerfile内容基础知识 3.2Docker执行Dockerfile的大致流程 总结 4.DockerFile常用保留字指令 5.案例:自定义镜像 5.1 要求: Centos7镜像具备vimifconfigjdk8 5.2编写 5…

deque容器

1 deque容器基本概念 功能: 双端数组,可以对头端进行插入删除操作 deque与vector区别: vector对于头部的插入删除效率低,数据量越大,效率越低deque相对而言,对头部的插入删除速度回比vector快vector访问…

如何在java中做基准测试

最近公司在搞新项目,由于是实验性质,且不会直接面对客户的项目,这次的技术选型非常激进,如,直接使用了Java 17。 作为公司里练习两年半的个人练习生,我自然也是深度的参与到了技术选型的工作中。不知道大家…

Gitea--私有git服务器搭建详细教程

一.官方文档 https://docs.gitea.com/zh-cn/说明 gitea 是一个自己托管的Git服务程序。他和GitHub, Gitlab等比较类似。他是从 Gogs 发展而来,gitea的创作团队重新fork了代码,并命名为giteagitea 功能特性多,能够满足我们所有的的代码管理需…

预推免,保研------长安大学保内,附加分面试准备【记录帖】

🚀长安大学——人工智能系——程惠泽 🚌前六学期专业排名:7/82 🚌信息门户GPA:3.94 🚌平均成绩:89.83 🚌加权成绩:89.15 / ☁️本人比较菜,只能保研本校&…

认识doubbo和rpc

开个新坑,和大家一起学习Dubbo 3.X。我们按照一个由浅入深顺序来学习,先从使用Dubbo开始,再深入Dubbo的核心原理。 今天我们就从认识Dubbo开始,整体的内容可以分为3个部分: Dubbo是什么RPC是什么Dubbo的架构 正式开…

面试如何回答弹性盒子布局这个问题呢?

在我们面试中如果被问道css方面的面试题 那么极有可能被问到的一道面试题就是弹性盒子,本篇文章通过一张图带你拿捏这道面试题。 1、首先需要说一说弹性盒子的基本概念:弹性盒子是一种用于网页布局中创建灵活和响应式设计的CSS布局模型。 2、其次需要说…

父组件调用子组件 ref 不生效?组件暴露 ref ?

向你的组件暴露 ref 要暴露 ref 最关键的就是 forwardRef forwardRef 是 React 中的一个高阶函数,用于在函数组件中将 ref 属性向下传递给子组件。 在 React 中,我们可以使用 ref 属性来获取对一个组件实例的引用,以便在父组件中操作子组件。…

IDEA复制一个工程为多个并启动,测试负载均衡

1 找到服务按钮 2 选择复制配置 3 更改新的名称与虚拟机参数 复制下面的代码在VM参数中 -Dserver.port8082 4 最后启动即可

【80天学习完《深入理解计算机系统》】第十二天3.6数组和结构体

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客,如有问题交流,欢迎评论区留言,一定尽快回复!(大家可以去看我的专栏,是所有文章的目录)   文章字体风格: 红色文字表示&#…

排序之归并排序

文章目录 前言一、归并排序1、归并排序基本思想2、归并排序代码实现3、归并排序效率分析 二、归并排序非递归实现(循环实现)1、归并排序非递归实现(循环实现)基本思想2、归并排序非递归实现(循环实现)代码 三、计数排序1、计数排序基本思想2、计数排序代码实现3、计数排序效率分…

大数据-玩转数据-Flink状态编程(上)

一、Flink状态编程 有状态的计算是流处理框架要实现的重要功能,因为稍复杂的流处理场景都需要记录状态,然后在新流入数据的基础上不断更新状态。 SparkStreaming在状态管理这块做的不好, 很多时候需要借助于外部存储(例如Redis)来手动管理状态, 增加了编…

顺式元件热图+柱状图

写在前面 本教程来自粉丝投稿,主要做得是顺式元件的预测和热图绘制。类似的教程,在我们基于TBtools做基因家族分析也做过,流程基本一致。我们前期的教程,主要是基于TBtools,本教程主要是基于纯代码,也是值得学习收藏的…

【人工智能】—_线性分类器、感知机、损失函数的选取、最小二乘法分类、模型复杂性和过度拟合、规范化

文章目录 Linear predictions 线性预测分类线性分类器感知机感知机学习策略损失函数的选取距离的计算 最小二乘法分类求解最小二乘分类矩阵解法一般线性分类模型复杂性和过度拟合训练误差测试误差泛化误差复杂度与过拟合规范化 Linear predictions 线性预测 分类 从具有有限离…

2022年03月 C/C++(七级)真题解析#中国电子学会#全国青少年软件编程等级考试

C/C编程(1~8级)全部真题・点这里 第1题:红与黑 有一间长方形的房子, 地上铺了红色、 黑色两种颜色的正方形瓷砖。你站在其中一块黑色的瓷砖上, 只能向相邻的黑色瓷砖移动。 请写一个程序, 计算你总共能够到…

Aqs的CyclicBarrier。

今天我们来学习AQS家族的“外门弟子”:CyclicBarrier。 为什么说CyclicBarrier是AQS家族的“外门弟子”呢?那是因为CyclicBarrier自身和内部类Generation并没有继承AQS,但在源码的实现中却深度依赖AQS家族的成员ReentrantLock。就像修仙小说…