【网络编程】TCP传输控制协议(Transmission Control Protocol)
- (꒪ꇴ꒪ ),Hello我是祐言QAQ
- 我的博客主页:C/C++语言,数据结构,Linux基础,ARM开发板,网络编程等领域UP🌍
- 快上🚘,一起学习,让我们成为一个强大的攻城狮!
- 送给自己和读者的一句鸡汤🤔:集中起来的意志可以击穿顽石!
- 作者水平很有限,如果发现错误,请在评论区指正,感谢🙏
Socket编程是通过使用Socket API接口来实现的,这些接口允许开发人员创建网络应用程序,实现数据的传输和通信。下面我们就一些常见的Socket API接口示例和讲解,来实现TCP/IP通信。
一、TCP通信相关函数
① socket():创建套接字
socket(socket_family, socket_type, protocol=0)函数用于创建一个套接字对象。socket_family表示地址族(例如,socket.AF_INET表示IPv4),socket_type表示套接字类型(例如,socket.SOCK_STREAM表示TCP套接字),protocol通常默认为0。
// 创建套接字socketint ser_socket = socket(AF_INET, SOCK_STREAM, 0);if (ser_socket == -1){perror("socket");return -1;}
②初始化地址结构体
// 初始化地址结构体 // IP地址+PORT端口号struct sockaddr_in addr;addr.sin_family = AF_INET; //地址簇addr.sin_port = 56789; //端口(一般以传参的传进来)addr.sin_addr.s_addr = inet_addr("192.168.159.128"); //IP地址// addr.sin_addr.s_addr = htonl(INADDR_ANY); //用特殊的"0.0.0.0"这个IP来绑定本机IP地址
③ bind():绑定本机地址和端口
bind((host, port))函数用于将套接字与本地地址和端口绑定,以便在特定地址和端口上监听连接请求。
// 绑定地址结构体bindint b = bind(ser_socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));if(b == -1){perror("bind");return -1;}printf("绑定成功\n");
④ connect():建立连接
connect((host, port))函数用于建立到远程主机的TCP连接。它连接到指定的远程地址和端口。
// 建立连接connectint c = connect(cli_socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));if (c == -1){perror("connect");return -1;}printf("连接成功\n");
⑤ listen():设置监听端口
listen(backlog)函数用于设置套接字为监听模式,backlog指定了可以等待连接的最大客户端数量。
// 开启监听listenint l = listen(ser_socket, 3);if (l == -1){perror("listen");return -1;}printf("监听成功\n");//ser_socket由 待链接套接字 变成 监听套接字
⑥ accept():接受TCP连接
accept()函数用于接受客户端的TCP连接请求,并返回一个新的套接字对象,以便与客户端进行通信。
// 等待连接acceptstruct sockaddr_in c_addr; //用来存放客户端链接成功之后的IP加端口int addrlen = sizeof(c_addr);int new_socekt = accept(ser_socket, (struct sockaddr *)&c_addr, &addrlen);if (new_socekt == -1){perror("accept");return -1;}// new_socekt 链接成功之后,用来通信的套接字printf("客户端[%s][%u]连接成功\n", inet_ntoa(c_addr.sin_addr), c_addr.sin_port);//客户端的IP跟端口,IP是你客户端本身自带的,但是端口是系统随机分配的
⑦ recv(), read():数据接收
这些函数用于从套接字接收数据。recv()和read()用于TCP套接字,它们接收数据并将其存储在指定的缓冲区中。
int new_socekt = *((int *)arg);while(1){sem_wait(space);//P操作 空间资源-1char buf[1024];bzero(buf, sizeof(buf));read(new_socekt, buf, sizeof(buf));printf("服务器接收到消息: %s\n", buf);sem_post(data);//V操作 数据资源+1}
⑧ send(), write():数据发送
这些函数用于向套接字发送数据。send()和write()用于TCP套接字,它们将数据从缓冲区发送到目标套接字。
int new_socekt = *((int *)arg);while(1){sem_wait(data);//P操作 数据资源-1char buf[1024];printf("请输入发送给客户端的消息:");fgets(buf, sizeof(buf), stdin);write(new_socekt, buf, strlen(buf));sem_post(space);//V操作 空间资源+1}
二、网络地址转换和套接字属性的管理
在网络编程中,有时候需要进行网络地址的转换,以及设置和获取套接字的属性。这些操作是网络通信中的基本需求之一。在本部分中,我们将介绍与网络地址转换相关的函数以及如何获取和设置套接字属性。
2.1 网络地址转换相关函数
1. inet_aton
( )和 inet_addr
( )
这两个函数允许将点分十进制字符串形式的IP地址转换为32位网络字节序的二进制地址。
-
inet_aton(const char *cp, struct in_addr *inp)
:将点分十进制字符串cp
转换为32位网络字节序的二进制地址,并存储在inp
结构中。 -
inet_addr(const char *cp)
:将点分十进制字符串cp
转换为32位网络字节序的二进制地址,并返回结果。
2. inet_network
( )
inet_network(const char *cp)
函数用于将点分十进制字符串形式的IP网络地址(例如 "192.168.1.0")转换为32位网络字节序的二进制地址。
3. inet_ntoa
( )
inet_ntoa(struct in_addr in)
函数用于将32位网络字节序的二进制地址转换为点分十进制字符串形式的IP地址,例如将 “11111111111111111111111111111111
”转换为 "192.168.1.47"。
4. inet_lnaof
( ) 和 inet_netof
( )
这两个函数用于从 struct in_addr
结构中提取主机位和网络位的部分。inet_lnaof(struct in_addr in)
返回主机位,inet_netof(struct in_addr in)
返回网络位。
2.2 获取和设置套接字属性
1. getsockopt
( )
getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen)
函数用于获取套接字 sockfd
的属性。你可以指定属性的级别 level
和选项名 optname
,并将结果存储在 optval
中。optlen
用于指定 optval
缓冲区的大小。
2. setsockopt
( )
setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen)
函数用于设置套接字 sockfd
的属性。你可以指定属性的级别 level
和选项名 optname
,并提供要设置的值 optval
以及值的大小 optlen
。
这些函数是在网络编程中非常有用的,它们允许你在应用程序中轻松地进行网络地址的转换和管理套接字属性。网络编程需要处理各种网络相关操作,这些函数提供了一种有效的方式来处理这些需求。无论是将字符串形式的IP地址转换为二进制形式,还是获取和设置套接字的属性,这些函数都是网络程序员的强大工具。
三、TCP/IP实现服务器与客户端相互通信
服务器与客户端对比图:
服务器端和客户端分别创建了两个线程,task1
和 task2
,分别用于接收和发送消息。它们之间通过有名信号量 space
和 data
进行同步和通信。在客户端中,通过 connect
连接到服务器。最终实现服务器与客户端相互通信:
server.c
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>#define SPACE "/my_space" // 使用唯一的路径名
#define DATA "/my_data"sem_t *space;
sem_t *data;//线程任务函数1
void *task1(void *arg)
{ int new_socekt = *((int *)arg);while(1){sem_wait(space);//P操作 空间资源-1char buf[1024];bzero(buf, sizeof(buf));read(new_socekt, buf, sizeof(buf));printf("服务器接收到消息: %s\n", buf);sem_post(data);//V操作 数据资源+1}
}//线程任务函数2
void *task2(void *arg)
{ int new_socekt = *((int *)arg);while(1){sem_wait(data);//P操作 数据资源-1char buf[1024];printf("请输入发送给客户端的消息:");fgets(buf, sizeof(buf), stdin);write(new_socekt, buf, strlen(buf));sem_post(space);//V操作 空间资源+1}
}int main(int argc, char const *argv[])
{// 删除已存在的同名信号量(如果有的话)sem_unlink(SPACE);sem_unlink(DATA);// 打开有名信号量space = sem_open(SPACE, O_CREAT, 0777, 1);data = sem_open(DATA, O_CREAT, 0777, 0);// (1)创建套接字socketint ser_socket = socket(AF_INET, SOCK_STREAM, 0);if (ser_socket == -1){perror("socket");return -1;}// (2)初始化地址结构体 // IP地址+PORT端口号struct sockaddr_in addr;addr.sin_family = AF_INET; //地址簇addr.sin_port = htons(56789); //端口(一般以传参的传进来)addr.sin_addr.s_addr = inet_addr("192.168.159.128"); //IP地址// addr.sin_addr.s_addr = INADDR_ANY; //用特殊的"0.0.0.0"这个IP来绑定本机IP地址// (3)绑定地址结构体bindint b = bind(ser_socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));if(b == -1){perror("bind");return -1;}printf("绑定成功\n");// (4)开启监听listenint l = listen(ser_socket, 3);if (l == -1){perror("listen");return -1;}printf("监听成功\n");//ser_socket由 待链接套接字 变成 监听套接字while(1){// (5)等待连接acceptstruct sockaddr_in c_addr; //用来存放客户端链接成功之后的IP加端口int addrlen = sizeof(c_addr);int new_socekt = accept(ser_socket, (struct sockaddr *)&c_addr, &addrlen);if (new_socekt == -1){perror("accept");return -1;}// new_socekt 链接成功之后,用来通信的套接字printf("客户端【%s】【%u】连接成功\n", inet_ntoa(c_addr.sin_addr), c_addr.sin_port);// 创建两个线程,用于双向通信pthread_t pid1, pid2;pthread_create(&pid1, NULL, task1, &new_socekt);pthread_create(&pid2, NULL, task2, &new_socekt);}// (7)关闭套接字close/shutdownclose(ser_socket);// shutdown(new_socekt, SHUT_RDWR);return 0;
}
client.c
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>#define SPACE "/my_space" // 使用唯一的路径名
#define DATA "/my_data"sem_t *space;
sem_t *data;//线程任务函数1
void *task1(void *arg)
{ int cli_socket = *((int *)arg);while(1){sem_wait(space);//P操作 空间资源-1char buf[1024];printf("请输入消息:");fgets(buf, sizeof(buf), stdin);write(cli_socket, buf, strlen(buf));sem_post(data);//V操作 数据资源+1}
}//线程任务函数2
void *task2(void *arg)
{ int cli_socket = *((int *)arg);while(1){sem_wait(data);//P操作 数据资源-1char buf[1024];bzero(buf, sizeof(buf));read(cli_socket, buf, sizeof(buf));printf("服务器返回消息: %s\n", buf);sem_post(space);//V操作 空间资源+1}
}int main(int argc, char const *argv[])
{// 删除已存在的同名信号量(如果有的话)sem_unlink(SPACE);sem_unlink(DATA);// 打开有名信号量space = sem_open(SPACE, O_CREAT, 0777, 1);data = sem_open(DATA, O_CREAT, 0777, 0);// (1)创建套接字socketint cli_socket = socket(AF_INET, SOCK_STREAM, 0);if (cli_socket == -1){perror("socket");return -1;}// (2)初始化地址结构体服务器的 // IP地址+PORT端口号struct sockaddr_in addr;addr.sin_family = AF_INET; //地址簇addr.sin_port = htons(56789); //服务器端的端口(一般以传参的传进来)addr.sin_addr.s_addr = inet_addr("192.168.159.128"); //服务器端的IP地址(一般以传参的传进来)// (3)建立连接connectint c = connect(cli_socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));if (c == -1){perror("connect");return -1;}printf("连接成功\n");// 创建两个线程,用于双向通信pthread_t pid1, pid2;pthread_create(&pid1, NULL, task1, &cli_socket);pthread_create(&pid2, NULL, task2, &cli_socket);while(1);// (5)关闭套接字close/shutdownclose(cli_socket);// shutdown(cli_socket, SHUT_RDWR);return 0;
}
如果遇到 bind:地址已被使用,我们只需在服务器初始化addr之前加上这段代码,来实现地址的复用即可。
int reuse 1;if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(void *)&reuse,sizeof(reuse))<0){perror("setsockopt error");return -1;}
四、 TCP协议如何保证可靠传输
TCP实现可靠传输的关键机制包括:
- 序列号:每个TCP报文段都有一个唯一的序列号,接收端根据序列号来重组数据,确保数据的顺序。
- 检验和:TCP在数据报文段中包含一个检验和字段,用于检测数据在传输过程中是否发生损坏,以便丢弃损坏的数据。
- 确认应答信号:接收端会向发送端发送确认应答,告知发送端哪些数据已成功接收。如果发送端未收到确认应答,它会重发数据。
- 重发控制:如果发送端未收到确认应答或检测到丢失的数据,它会重新发送这些数据,直到接收端确认接收。
- 连接管理:TCP建立连接时,使用三次握手确保双方都准备好通信,而关闭连接时,使用四次挥手确保数据的完整传输。
- 窗口控制:TCP使用滑动窗口机制来控制数据的流动,确保发送端不会发送过多数据,从而防止接收端被淹没。
- 流量控制:TCP通过接收端发送窗口大小来告知发送端可以发送多少数据,以避免接收端缓冲区溢出。
- 拥塞控制:TCP使用拥塞控制算法来避免网络拥塞,包括慢开始、拥塞避免、快重传、快恢复等算法。
五、 当网络发生拥塞时,TCP协议如何处理
TCP使用拥塞控制算法来应对网络拥塞情况,以防止网络丢包率过高、延迟增加等问题。主要的拥塞控制算法包括:
-
慢开始(Slow Start):在连接初始阶段,发送端发送的数据段数量较小,随着时间的推移逐渐增加,以便观察网络状况。
-
拥塞避免(Congestion Avoidance):一旦慢开始阶段完成,TCP进入拥塞避免阶段,每个传输轮次中发送的数据段数量逐渐增加,直到发生拥塞。
-
快重传(Fast Retransmit):如果接收端连续收到相同序列号的数据段(表明某个数据段丢失),它会立即向发送端发送重复确认,触发发送端的快速重传。
-
快恢复(Fast Recovery):当发送端接收到快重传的重复确认时,它不会进入慢开始,而是将拥塞窗口减半,然后继续逐渐增加。
这些算法共同确保TCP在遇到网络拥塞时能够降低发送速率,以减少网络负载,同时也通过快速重传和快速恢复来尽快恢复到正常传输状态。TCP的拥塞控制机制是维护网络稳定性和性能的关键部分。
更多C/C++语言、Linux系统、数据结构和ARM板实战相关文章,关注专栏:
手撕C语言
玩转linux
脚踢数据结构
系统、网络编程
探索C++
6818(ARM)开发板实战
📢写在最后
- 今天的分享就到这啦~
- 觉得博主写的还不错的烦劳
一键三连喔
~ - 🎉🎉🎉感谢关注🎉🎉🎉
相关文章:

【网络编程】TCP传输控制协议(Transmission Control Protocol)
(꒪ꇴ꒪ ),Hello我是祐言QAQ我的博客主页:C/C语言,数据结构,Linux基础,ARM开发板,网络编程等领域UP🌍快上🚘,一起学习,让我们成为一个强大的攻城狮࿰…...

云原生Kubernetes:kubectl管理命令
目录 一、理论 1.kubectl 管理命令 2.项目的生命周期 二、实验 1.kubectl 管理命令 2.项目的生命周期 三、总结 一、理论 1.kubectl 管理命令 (1)陈述式资源管理方法 kubernetes集群管理集群资源的唯一入口是通过相应的方法调用apiserver的接口…...

前端面试的话术集锦第 5 篇:高频考点( 类型转换 深浅拷贝 模块化机制等)
这是记录前端面试的话术集锦第五篇博文——高频考点(类型转换 & 深浅拷贝 & 模块化机制等),我会不断更新该博文。❗❗❗ 1. typeof类型判断: typeof是否能正确判断类型? instanceof能正确判断对象的原理是什么 typeof对于原始类型来说,除了null都可以显示正确的类…...

微服务·架构组件之网关
微服务架构组件之网关 引言 微服务架构已成为构建大型和复杂应用程序的流行范式之一。在微服务架构中,通常一个系统会被拆分为多个微服务,如果 客户端多次请求不同的微服务,会增加客户端代码和配置的复杂性,维护成本比较高。每…...

Google 开源库Guava详解
一、概述 Guava是一组来自Google的核心Java库,包括新的集合类型(如多映射和多集)、不可变集合、图库和并发、I/O、哈希、原语、字符串等实用程序!它广泛用于Google中的大多数Java项目,也被许多其他公司广泛使用。 Gua…...

ISP——3A算法
目录 前沿一. 自动曝光AE1.1. 自动曝光1.2. 18%灰1.3. 测光区域1.4. 摄影曝光加法系统1.5. AE算法1.5.1. 考虑事项1.5.2. AE实现过程 1.6. AE算法 二. 自动对焦AF2.1. 什么是自动对焦2.2. 图像清晰度评价方法2.2.1. Brenner 梯度函数2.2.2. Tenengrad 梯度函数2.2.3. Laplacian…...

Go语言入门指南
Go语言入门指南 Go语言,通常称为Golang,是一门由Google开发的开源编程语言。它因其简洁、高效和强大的特性而备受开发者欢迎。本篇博客将带你深入了解Go语言的基础知识,让你能够开始编写自己的Go程序。 为什么选择Go语言? 在学…...

【Hive SQL 每日一题】统计用户连续下单的日期区间
文章目录 测试数据需求说明需求实现 测试数据 create table test(user_id string,order_date string);INSERT INTO test(user_id, order_date) VALUES(101, 2021-09-21),(101, 2021-09-22),(101, 2021-09-23),(101, 2021-09-27),(101, 2021-09-28),(101, 2021-09-29),(101, 20…...

RabbitMQ 镜像集群部署
镜像集群原理 特征 默认情况下,队列只保存在创建该队列的节点上。而镜像模式下,创建队列的节点被称为该队列的主节点,队列还会拷贝到集群中的其它节点,也叫做该队列的镜像节点。 但是,不同队列可以在集群中的任意节…...

SpringMVC框架学习
java 学习笔记指路 基础知识 Python转java补充知识 Java中常见的名词解释 前端 【黑马程序员pink老师前端】HTML 【黑马程序员pink老师前端】JavaScript基础大总结 【黑马程序员pink老师前端】JavaScript函数与作用域 【黑马程序员pink老师前端】JavaScript对象 数据库 【黑马程…...

多通道振弦数据记录仪应用桥梁安全监测的解决方案
多通道振弦数据记录仪应用桥梁安全监测的解决方案 城市化进程的加快和交通运输的发展,桥梁作为连接城市的重要交通工具,其安全性也变得越来越重要。为了保证桥梁的安全性,需要进行定期的监测和维护。其中,多通道振弦数据记录仪是…...

RDMA 相关bug记录
对于 Client 来讲,setupConnection 中的 cm_id 应该是本地的,意味着后续 create pd \ cq \ qp 等等传入的 cm_id 都是本地 id。但是对于 Server 来讲,收到 client 的链接请求时将 client 的 cm_id 传入 setupConnection,意味着后续…...

TDengine函数大全-时序库特有函数
以下内容来自 TDengine 官方文档 及 GitHub 内容 。 以下所有示例基于 TDengine 3.1.0.3 TDengine函数大全 1.数学函数 2.字符串函数 3.转换函数 4.时间和日期函数 5.聚合函数 6.选择函数 7.时序数据库特有函数 8.系统函数 时序库特有函数 TDengine函数大全CSUMDERIVATIVEDIFF…...

vue-cli3项目本地启用https,并用mkcert生成证书
在项目根目录下的vue.config.js文件中: // vue.config.js module.exports {devServer: {host:dev.nm.cngc// 此处开启 https,并加载本地证书(否则浏览器左上角会提示不安全)https: {cert: fs.readFileSync(path.join(_dirname,./cert.crt)…...

包装类笔记
包装类 5.1 概述 Java 提供了两个类型系统,基本类型与引用类型,使用基本类型在于效率,然而很多情况,会创建对象使用,因为对象可以做更多的功能,如果想要我们的基本类型像对象一样操作,就可以使…...

TC和TG油封有什么区别?
油封是各种机械系统(包括发动机和工业机械)中的重要部件,因为它们可以防止润滑剂和污染物的泄漏。在可用的不同类型的油封中,常用的是TC和TG密封件。在本文中,我们将讨论TC和TG油封之间的差异,帮助您了解它们的独特特性和应用。 …...

大数据之MapReduce
MapReduce概述 是一个分布式的编程框架,MapReduce核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序,并发运行在一个Hadoop集群上。 优点: 易于编程,简单的实现一些接口,就可以完成一…...

《机器人学一(Robotics(1))》_台大林沛群 第 5 周【机械手臂 轨迹规划】 Quiz 5
我又行了!🤣 求解的 位置 可能会有 变动,根据求得的A填写相应值即可。注意看题目。 coursera链接 文章目录 第1题 Cartesian space求解 题1-3 的 Python 代码 第2题第3题第4题 Joint space求解 题4-6 的 Python 代码 第5题第6题其它可参考代…...

嵌入式面试/笔试C相关总结
1、存储 单片机端编译后分为code ro rw zi几个区域,其中code是执行文件,ro(read only)只读区域,存放const修饰常量、字符串。rw(read write)存放已初始化变量。zi存放未初始化变量。编译完成后bin大小为coderorw。运行时所需内存为rwzi。 在电…...

支付宝使用OceanBase的历史库实践分享
为解决因业务增长引发的数据库存储空间问题,支付宝基于 OceanBase 数据库启动了历史库项目,通过历史数据归档、过期数据清理、异常数据回滚,实现了总成本降低 80%。 历史数据归档:将在线库(SSD 磁盘)数据归…...

accelerate 分布式技巧(一)
accelerate分布式技巧 简单使用 Accelerate是一个来自Hugging Face的库,它简化了将单个GPU的PyTorch代码转换为单个或多台机器上的多个GPU的代码。 Accelerate精确地抽象了与多GPU/TPU/fp16相关的模板代码,并保持Pytorch其余代码不变。 import torchim…...

密码找回安全
文章目录 密码找回安全任意秘密重置 密码找回安全 用户提交修改密码请求;账号认证:服务器发送唯一ID (例如信验证码)只有账户所有者才能看的地方,完成身份验证;身份验证:用户提交验证码完成身份验证;修改密码:用户修改密码。 任意秘密重置 登录metinfo4…...

Spring Boot + Vue的网上商城之商品管理
Spring Boot Vue的网上商城之商品管理 在网上商城中,商品管理是一个非常重要的功能。它涉及到商品的添加、编辑、删除和展示等操作。本文将介绍如何使用Spring Boot和Vue来实现一个简单的商品管理系统。 下面是一个实现Spring Boot Vue的网上商城之商品管理的思路…...

B站:提高你的词汇量:如何用英语谈论驾驶
视频链接:提高你的词汇量:如何用英语谈论驾驶_哔哩哔哩_bilibili 英文音标中文hood/hʊd/n. 汽车的引擎盖go over仔细检查;认真讨论;用心思考There are plenty of videos go over this.有很多关于这个的视频unlockvt. 发现;揭开&…...

大前端面试注意要点
前端面试:从IT专家角度全面解析 在数字时代,前端开发工程师的角色变得越来越重要。随着网站和应用程序的复杂性和交互性越来越高,对具有专业技能的前端开发人员的需求也在不断增长。对于正在寻找前端开发职位的开发者,或者正在寻…...

稻盛和夫-如是说(读书笔记)
本书解答的核心问题: “今天,我们需要的不是短期有效的处方。作为人,何谓正确?作为人,应该如何度过人生?这才是一切问题的根源。 有几个要点和认知比较深的地方谈一谈。 1、利他 类似于阳明心学࿰…...

Jmeter是用来做什么的?
JMeter是一个开源的Java应用,主要用于性能测试和功能测试。它最初由Apache软件基金会设计用于测试Web应用程序,但现在已经扩展到其他测试功能。JMeter的主要功能如下: 性能测试:性能测试是JMeter的核心功能,主要分为两…...

Docker基础教程
Docker基础教程 Docker简介 Docker基本操作 Docker应用 Docker自定义镜像 Docker compose 为什么使用DockerDocker简介安装DockerDocker的中央仓库Docker镜像操作Docker容器操作准备一个web项目创建MySQL容器创建Tomcat容器将项目部署到TomcatDocker数据卷DockerfileDock…...

Linux命令200例:who用于显示当前登录到系统的用户信息
🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌。CSDN专家博主,阿里云社区专家博主,2023年6月csdn上海赛道top4。 🏆数年电商行业从业经验,历任核心研发工程师࿰…...

HGDB-修改分区表名称及键值
瀚高数据库 目录 环境 文档用途 详细信息 环境 系统平台:N/A 版本:4.5.7 文档用途 使用存储过程拼接SQL,修改分区名称、分区键值、并重新加入主表,适用于分区表较多场景。 详细信息 说明:本文档为测试过程࿱…...