Java网络编程(JAVA网络编程技术)
ztj100 2025-07-08 00:27 31 浏览 0 评论
网络编程三要素
1. IP地址:表示设备在网络中的地址,是网络中设备的唯一标识
2. 端口号:应用程序在设备中唯一的标识
3. 协议:连接和数据在网络中传输的规则。
InetAddress类
Java中也有一个类用来表IP地址,这个类是InetAddress类。我们在开发网络通信程序的时候,可能有时候会获取本机的IP地址,以及测试与其他地址是否连通,这个时候就可以使用InetAddress类来完成。下面学习几个InetAddress的方法。
package com.itheima.d1_ip;
import java.net.InetAddress;
/**
* 目标:掌握InetAddress类的使用。
*/
public class InetAddressTest {
public static void main(String[] args) throws Exception {
// 1、获取本机IP地址对象的
InetAddress ip1 = InetAddress.getLocalHost();
System.out.println(ip1.getHostName());
System.out.println(ip1.getHostAddress());
// 2、获取指定IP或者域名的IP地址对象。
InetAddress ip2 = InetAddress.getByName("www.baidu.com");
System.out.println(ip2.getHostName());
System.out.println(ip2.getHostAddress());
// ping www.baidu.com
System.out.println(ip2.isReachable(6000));
}
}
端口号
端口号:指的是计算机设备上运行的应用程序的标识,被规定为一个16位的二进制数据,范围(0~65535)
端口号分为一下几类(了解一下)
- 周知端口:0~1023,被预先定义的知名应用程序占用(如:HTTP占用80,FTP占用21)
- 注册端口:1024~49151,分配给用户经常或者某些应用程序
- 动态端口:49152~65536,之所以称为动态端口,是因为它一般不固定分配给某进程,而是动态分配的。
需要我们注意的是,同一个计算机设备中,不能出现两个应用程序,用同一个端口号
UDP通信代码
package com.itheima.d2_upd1;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/**
* 目标:完成UDP通信快速入门:实现1发1收。
*/
public class Client {
public static void main(String[] args) throws Exception {
// 1、创建客户端对象(发韭菜出去的人)
DatagramSocket socket = new DatagramSocket(7777);
// 2、创建数据包对象封装要发出去的数据(创建一个韭菜盘子)
/* public DatagramPacket(byte buf[], int length,
InetAddress address, int port)
参数一:封装要发出去的数据。
参数二:发送出去的数据大小(字节个数)
参数三:服务端的IP地址(找到服务端主机)
参数四:服务端程序的端口。
*/
byte[] bytes = "我是快乐的客户端,我爱你abc".getBytes();
DatagramPacket packet = new DatagramPacket(bytes, bytes.length
, InetAddress.getLocalHost(), 6666);
// 3、开始正式发送这个数据包的数据出去了
socket.send(packet);
System.out.println("客户端数据发送完毕~~~");
socket.close(); // 释放资源!
}
}
package com.itheima.d2_upd1;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/**
* 目标:完成UDP通信快速入门-服务端开发
*/
public class Server {
public static void main(String[] args) throws Exception {
System.out.println("----服务端启动----");
// 1、创建一个服务端对象(创建一个接韭菜的人) 注册端口
DatagramSocket socket = new DatagramSocket(6666);
// 2、创建一个数据包对象,用于接收数据的(创建一个韭菜盘子)
byte[] buffer = new byte[1024 * 64]; // 64KB.
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
// 3、开始正式使用数据包来接收客户端发来的数据
socket.receive(packet);
// 4、从字节数组中,把接收到的数据直接打印出来
// 接收多少就倒出多少
// 获取本次数据包接收了多少数据。
int len = packet.getLength();
String rs = new String(buffer, 0 , len);
System.out.println(rs);
// 获得客户端IP、端口
System.out.println(packet.getAddress().getHostAddress());
System.out.println(packet.getPort());
socket.close(); // 释放资源
}
}
UDP通信代码(多发多收)
package com.itheima.d3_udp2;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
/**
* 目标:完成UDP通信快速入门:实现客户端反复的发。
*/
public class Client {
public static void main(String[] args) throws Exception {
// 1、创建客户端对象(发韭菜出去的人)
DatagramSocket socket = new DatagramSocket();
// 2、创建数据包对象封装要发出去的数据(创建一个韭菜盘子)
/* public DatagramPacket(byte buf[], int length,
InetAddress address, int port)
参数一:封装要发出去的数据。
参数二:发送出去的数据大小(字节个数)
参数三:服务端的IP地址(找到服务端主机)
参数四:服务端程序的端口。
*/
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请说:");
String msg = sc.nextLine();
// 一旦发现用户输入的exit命令,就退出客户端
if("exit".equals(msg)){
System.out.println("欢迎下次光临!退出成功!");
socket.close(); // 释放资源
break; // 跳出死循环
}
byte[] bytes = msg.getBytes();
DatagramPacket packet = new DatagramPacket(bytes, bytes.length
, InetAddress.getLocalHost(), 6666);
// 3、开始正式发送这个数据包的数据出去了
socket.send(packet);
}
}
}
package com.itheima.d3_udp2;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/**
* 目标:完成UDP通信快速入门-服务端反复的收
*/
public class Server {
public static void main(String[] args) throws Exception {
System.out.println("----服务端启动----");
// 1、创建一个服务端对象(创建一个接韭菜的人) 注册端口
DatagramSocket socket = new DatagramSocket(6666);
// 2、创建一个数据包对象,用于接收数据的(创建一个韭菜盘子)
byte[] buffer = new byte[1024 * 64]; // 64KB.
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while (true) {
// 3、开始正式使用数据包来接收客户端发来的数据
socket.receive(packet);
// 4、从字节数组中,把接收到的数据直接打印出来
// 接收多少就倒出多少
// 获取本次数据包接收了多少数据。
int len = packet.getLength();
String rs = new String(buffer, 0 , len);
System.out.println(rs);
System.out.println(packet.getAddress().getHostAddress());
System.out.println(packet.getPort());
System.out.println("--------------------------------------");
}
}
}
TCP通信(一发一收)
Java提供了一个java.net.Socket类来完成TCP通信。
我们先讲一下Socket完成TCP通信的流程,再讲代码怎么编写就很好理解了。如下图所示
- 当创建Socket对象时,就会在客户端和服务端创建一个数据通信的管道,在客户端和服务端两边都会有一个Socket对象来访问这个通信管道。
- 现在假设客户端要发送一个“在一起”给服务端,客户端这边先需要通过Socket对象获取到一个字节输出流,通过字节输出流写数据到服务端
- 然后服务端这边通过Socket对象可以获取字节输入流,通过字节输入流就可以读取客户端写过来的数据,并对数据进行处理。
- 服务端处理完数据之后,假设需要把“没感觉”发给客户端端,那么服务端这边再通过Socket获取到一个字节输出流,将数据写给客户端
- 客户端这边再获取输入流,通过字节输入流来读取服务端写过来的数据。
TCP客户端
下面我们写一个客户端,用来往服务端发数据。由于原始的字节流不是很好用,这里根据我的经验,我原始的OutputStream包装为DataOutputStream是比较好用的。
TCP客户端
package com.itheima.d4_tcp1;
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
* 目标:完成TCP通信快速入门-客户端开发:实现1发1收。
*/
public class Client {
public static void main(String[] args) throws Exception {
// 1、创建Socket对象,并同时请求与服务端程序的连接。
Socket socket = new Socket("127.0.0.1", 8888);
// 2、从socket通信管道中得到一个字节输出流,用来发数据给服务端程序。
OutputStream os = socket.getOutputStream();
// 3、把低级的字节输出流包装成数据输出流
DataOutputStream dos = new DataOutputStream(os);
// 4、开始写数据出去了
dos.writeUTF("在一起,好吗?");
dos.close();
socket.close(); // 释放连接资源
}
}
TCP服务端
package com.itheima.d4_tcp1;
import java.io.DataInputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 目标:完成TCP通信快速入门-服务端开发:实现1发1收。
*/
public class Server {
public static void main(String[] args) throws Exception {
System.out.println("-----服务端启动成功-------");
// 1、创建ServerSocket的对象,同时为服务端注册端口。
ServerSocket serverSocket = new ServerSocket(8888);
// 2、使用serverSocket对象,调用一个accept方法,等待客户端的连接请求
Socket socket = serverSocket.accept();
// 3、从socket通信管道中得到一个字节输入流。
InputStream is = socket.getInputStream();
// 4、把原始的字节输入流包装成数据输入流
DataInputStream dis = new DataInputStream(is);
// 5、使用数据输入流读取客户端发送过来的消息
String rs = dis.readUTF();
System.out.println(rs);
// 其实我们也可以获取客户端的IP地址
System.out.println(socket.getRemoteSocketAddress());
dis.close();
socket.close();
}
}
TCP通信(多发多收)
TCP客户端
package com.itheima.d5_tcp2;
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
/**
* 目标:完成TCP通信快速入门-客户端开发:实现客户端可以反复的发消息出去
*/
public class Client {
public static void main(String[] args) throws Exception {
// 1、创建Socket对象,并同时请求与服务端程序的连接。
Socket socket = new Socket("127.0.0.1", 8888);
// 2、从socket通信管道中得到一个字节输出流,用来发数据给服务端程序。
OutputStream os = socket.getOutputStream();
// 3、把低级的字节输出流包装成数据输出流
DataOutputStream dos = new DataOutputStream(os);
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请说:");
String msg = sc.nextLine();
// 一旦用户输入了exit,就退出客户端程序
if("exit".equals(msg)){
System.out.println("欢迎您下次光临!退出成功!");
dos.close();
socket.close();
break;
}
// 4、开始写数据出去了
dos.writeUTF(msg);
dos.flush();
}
}
}
TCP服务端
package com.itheima.d5_tcp2;
import java.io.DataInputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 目标:完成TCP通信快速入门-服务端开发:实现服务端反复发消息
*/
public class Server {
public static void main(String[] args) throws Exception {
System.out.println("-----服务端启动成功-------");
// 1、创建ServerSocket的对象,同时为服务端注册端口。
ServerSocket serverSocket = new ServerSocket(8888);
// 2、使用serverSocket对象,调用一个accept方法,等待客户端的连接请求
Socket socket = serverSocket.accept();
// 3、从socket通信管道中得到一个字节输入流。
InputStream is = socket.getInputStream();
// 4、把原始的字节输入流包装成数据输入流
DataInputStream dis = new DataInputStream(is);
while (true) {
try {
// 5、使用数据输入流读取客户端发送过来的消息
String rs = dis.readUTF();
System.out.println(rs);
} catch (Exception e) {
System.out.println(socket.getRemoteSocketAddress() + "离线了!");
dis.close();
socket.close();
break;
}
}
}
}
TCP通信(多线程改进)
首先,我们需要写一个服务端的读取数据的线程类,代码如下
package com.itheima.d6_tcp3;
import java.io.DataInputStream;
import java.io.InputStream;
import java.net.Socket;
public class ServerReaderThread extends Thread{
private Socket socket;
public ServerReaderThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
InputStream is = socket.getInputStream();
DataInputStream dis = new DataInputStream(is);
while (true){
try {
String msg = dis.readUTF();
System.out.println(msg);
} catch (Exception e) {
System.out.println("有人下线了:" + socket.getRemoteSocketAddress());
dis.close();
socket.close();
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
服务端
package com.itheima.d6_tcp3;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 目标:完成TCP通信快速入门-服务端开发:要求实现与多个客户端同时通信。
*/
public class Server {
public static void main(String[] args) throws Exception {
System.out.println("-----服务端启动成功-------");
// 1、创建ServerSocket的对象,同时为服务端注册端口。
ServerSocket serverSocket = new ServerSocket(8888);
while (true) {
// 2、使用serverSocket对象,调用一个accept方法,等待客户端的连接请求
Socket socket = serverSocket.accept();
System.out.println("有人上线了:" + socket.getRemoteSocketAddress());
// 3、把这个客户端对应的socket通信管道,交给一个独立的线程负责处理。
new ServerReaderThread(socket).start();
}
}
}
客户端
package com.itheima.d6_tcp3;
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
/**
* 目标:完成TCP通信快速入门-客户端开发:实现客户端可以反复的发消息出去
*/
public class Client {
public static void main(String[] args) throws Exception {
// 1、创建Socket对象,并同时请求与服务端程序的连接。
Socket socket = new Socket("127.0.0.1", 8888);
// 2、从socket通信管道中得到一个字节输出流,用来发数据给服务端程序。
OutputStream os = socket.getOutputStream();
// 3、把低级的字节输出流包装成数据输出流
DataOutputStream dos = new DataOutputStream(os);
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请说:");
String msg = sc.nextLine();
// 一旦用户输入了exit,就退出客户端程序
if("exit".equals(msg)){
System.out.println("欢迎您下次光临!退出成功!");
dos.close();
socket.close();
break;
}
// 4、开始写数据出去了
dos.writeUTF(msg);
dos.flush();
}
}
}
案例拓展(群聊)
服务端
package com.itheima.d7_tcp4;
import java.io.*;
import java.net.Socket;
public class ServerReaderThread extends Thread{
private Socket socket;
public ServerReaderThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
InputStream is = socket.getInputStream();
DataInputStream dis = new DataInputStream(is);
while (true){
try {
String msg = dis.readUTF();
System.out.println(msg);
// 把这个消息分发给全部客户端进行接收。
sendMsgToAll(msg);
} catch (Exception e) {
System.out.println("有人下线了:" + socket.getRemoteSocketAddress());
Server.onLineSockets.remove(socket);
dis.close();
socket.close();
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void sendMsgToAll(String msg) throws IOException {
// 发送给全部在线的socket管道接收。
for (Socket onLineSocket : Server.onLineSockets) {
OutputStream os = onLineSocket.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
dos.writeUTF(msg);
dos.flush();
}
}
}
package com.itheima.d7_tcp4;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
/**
* 目标:完成TCP通信快速入门-服务端开发:要求实现与多个客户端同时通信。
*/
public class Server {
public static List<Socket> onLineSockets = new ArrayList<>();
public static void main(String[] args) throws Exception {
System.out.println("-----服务端启动成功-------");
// 1、创建ServerSocket的对象,同时为服务端注册端口。
ServerSocket serverSocket = new ServerSocket(8888);
while (true) {
// 2、使用serverSocket对象,调用一个accept方法,等待客户端的连接请求
Socket socket = serverSocket.accept();
onLineSockets.add(socket);
System.out.println("有人上线了:" + socket.getRemoteSocketAddress());
// 3、把这个客户端对应的socket通信管道,交给一个独立的线程负责处理。
new ServerReaderThread(socket).start();
}
}
}
BS架构程序(简易版)
服务端程序
package com.itheima.d8_tcp5;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 目标:完成TCP通信快速入门-服务端开发:要求实现与多个客户端同时通信。
*/
public class Server {
public static void main(String[] args) throws Exception {
System.out.println("-----服务端启动成功-------");
// 1、创建ServerSocket的对象,同时为服务端注册端口。
ServerSocket serverSocket = new ServerSocket(8080);
while (true) {
// 2、使用serverSocket对象,调用一个accept方法,等待客户端的连接请求
Socket socket = serverSocket.accept();
System.out.println("有人上线了:" + socket.getRemoteSocketAddress());
// 3、把这个客户端对应的socket通信管道,交给一个独立的线程负责处理。
new ServerReaderThread(socket).start();
}
}
}
package com.itheima.d8_tcp5;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
public class ServerReaderThread extends Thread{
private Socket socket;
public ServerReaderThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
// 立即响应一个网页内容:“黑马程序员”给浏览器展示。
try {
OutputStream os = socket.getOutputStream();
PrintStream ps = new PrintStream(os);
ps.println("HTTP/1.1 200 OK");
ps.println("Content-Type:text/html;charset=UTF-8");
ps.println(); // 必须换行
ps.println("<div style='color:red;font-size:120px;text-align:center'>黑马程序员666<div>");
ps.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
服务端主程序用线程池改进
先写一个给浏览器响应数据的线程任务
package com.itheima.d9_tcp6;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
public class ServerReaderRunnable implements Runnable{
private Socket socket;
public ServerReaderRunnable(Socket socket){
this.socket = socket;
}
@Override
public void run() {
// 立即响应一个网页内容:“黑马程序员”给浏览器展示。
try {
OutputStream os = socket.getOutputStream();
PrintStream ps = new PrintStream(os);
ps.println("HTTP/1.1 200 OK");
ps.println("Content-Type:text/html;charset=UTF-8");
ps.println(); // 必须换行
ps.println("<div style='color:red;font-size:120px;text-align:center'>黑马程序员666<div>");
ps.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
再改写服务端的主程序,使用ThreadPoolExecutor创建一个线程池,每次接收到一个Socket就往线程池中提交任务就行。
package com.itheima.d9_tcp6;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 目标:完成TCP通信快速入门-服务端开发:要求实现与多个客户端同时通信。
*/
public class Server {
public static void main(String[] args) throws Exception {
System.out.println("-----服务端启动成功-------");
// 1、创建ServerSocket的对象,同时为服务端注册端口。
ServerSocket serverSocket = new ServerSocket(8080);
// 创建出一个线程池,负责处理通信管道的任务。
ThreadPoolExecutor pool = new ThreadPoolExecutor(16 * 2, 16 * 2, 0, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(8) , Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
while (true) {
// 2、使用serverSocket对象,调用一个accept方法,等待客户端的连接请求
Socket socket = serverSocket.accept();
// 3、把这个客户端对应的socket通信管道,交给一个独立的线程负责处理。
pool.execute(new ServerReaderRunnable(socket));
}
}
}
相关推荐
- Linux集群自动化监控系统Zabbix集群搭建到实战
-
自动化监控系统...
- systemd是什么如何使用_systemd/system
-
systemd是什么如何使用简介Systemd是一个在现代Linux发行版中广泛使用的系统和服务管理器。它负责启动系统并管理系统中运行的服务和进程。使用管理服务systemd可以用来启动、停止、...
- Linux服务器日常巡检脚本分享_linux服务器监控脚本
-
Linux系统日常巡检脚本,巡检内容包含了,磁盘,...
- 7,MySQL管理员用户管理_mysql 管理员用户
-
一、首次设置密码1.初始化时设置(推荐)mysqld--initialize--user=mysql--datadir=/data/3306/data--basedir=/usr/local...
- Python数据库编程教程:第 1 章 数据库基础与 Python 连接入门
-
1.1数据库的核心概念在开始Python数据库编程之前,我们需要先理解几个核心概念。数据库(Database)是按照数据结构来组织、存储和管理数据的仓库,它就像一个电子化的文件柜,能让我们高效...
- Linux自定义开机自启动服务脚本_linux添加开机自启动脚本
-
设置WGCloud开机自动启动服务init.d目录下新建脚本在/etc/rc.d/init.d新建启动脚本wgcloudstart.sh,内容如下...
- linux系统启动流程和服务管理,带你进去系统的世界
-
Linux启动流程Rhel6启动过程:开机自检bios-->MBR引导-->GRUB菜单-->加载内核-->init进程初始化Rhel7启动过程:开机自检BIOS-->M...
- CentOS7系统如何修改主机名_centos更改主机名称
-
请关注本头条号,每天坚持更新原创干货技术文章。如需学习视频,请在微信搜索公众号“智传网优”直接开始自助视频学习1.前言本文将讲解CentOS7系统如何修改主机名。...
- 前端工程师需要熟悉的Linux服务器(SSH 终端操作)指令
-
在Linux服务器管理中,SSH(SecureShell)是远程操作的核心工具。以下是SSH终端操作的常用命令和技巧,涵盖连接、文件操作、系统管理等场景:一、SSH连接服务器1.基本连接...
- Linux开机自启服务完全指南:3步搞定系统服务管理器配置
-
为什么需要配置开机自启?想象一下:电商服务器重启后,MySQL和Nginx没自动启动,整个网站瘫痪!这就是为什么开机自启是Linux运维的必备技能。自启服务能确保核心程序在系统启动时自动运行,避免人工...
- Kubernetes 高可用(HA)集群部署指南
-
Kubernetes高可用(HA)集群部署指南本指南涵盖从概念理解、架构选择,到kubeadm高可用部署、生产优化、监控备份和运维的全流程,适用于希望搭建稳定、生产级Kubernetes集群...
- Linux项目开发,你必须了解Systemd服务!
-
1.Systemd简介...
- Linux系统systemd服务管理工具使用技巧
-
简介:在Linux系统里,systemd就像是所有进程的“源头”,它可是系统中PID值为1的进程哟。systemd其实是一堆工具的组合,它的作用可不止是启动操作系统这么简单,像后台服务...
- Linux下NetworkManager和network的和平共处
-
简介我们在使用CentoOS系统时偶尔会遇到配置都正确但network启动不了的问题,这问题经常是由NetworkManager引起的,关闭NetworkManage并取消开机启动network就能正...
你 发表评论:
欢迎- 一周热门
-
-
MySQL中这14个小玩意,让人眼前一亮!
-
旗舰机新标杆 OPPO Find X2系列正式发布 售价5499元起
-
面试官:使用int类型做加减操作,是线程安全吗
-
C++编程知识:ToString()字符串转换你用正确了吗?
-
【Spring Boot】WebSocket 的 6 种集成方式
-
PyTorch 深度学习实战(26):多目标强化学习Multi-Objective RL
-
pytorch中的 scatter_()函数使用和详解
-
与 Java 17 相比,Java 21 究竟有多快?
-
基于TensorRT_LLM的大模型推理加速与OpenAI兼容服务优化
-
这一次,彻底搞懂Java并发包中的Atomic原子类
-
- 最近发表
-
- Linux集群自动化监控系统Zabbix集群搭建到实战
- systemd是什么如何使用_systemd/system
- Linux服务器日常巡检脚本分享_linux服务器监控脚本
- 7,MySQL管理员用户管理_mysql 管理员用户
- Python数据库编程教程:第 1 章 数据库基础与 Python 连接入门
- Linux自定义开机自启动服务脚本_linux添加开机自启动脚本
- linux系统启动流程和服务管理,带你进去系统的世界
- CentOS7系统如何修改主机名_centos更改主机名称
- 前端工程师需要熟悉的Linux服务器(SSH 终端操作)指令
- Linux开机自启服务完全指南:3步搞定系统服务管理器配置
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)
- vmware17pro最新密钥 (34)
- mysql单表最大数据量 (35)