TCP编程及基础知识

news2024/12/28 5:21:53

一、端口号

  • 为了区分一台主机接收到的数据包应该转交给哪个进程来进行处理,使用端口号来区分
  • TCP端口号与UDP端口号独立
  • 端口用两个字节来表示    2byte(65535个)

众所周知端口:1~10231~255之间为众所周知端口,256~1023端口通常由UNIX系统占用)
已登记端口:1024~49151    (选1000以上10000以下) 
动态或私有端口:49152~65535

二、字节序  

   小端序(little-endian)  - 低序字节存储在低地址

   大端序(big-endian)    - 高序字节存储在低地址

网络中传输一字节以上的带类型的数据(比如short、int),必须使用网络字节序,即大端字节序。

查看主机是大端序还是小端序。

网络传输中,需要将每个主机的主机字节序(CPU决定),转换为网络中统一顺序的网络字节序

才能供双方主机去识别

只需要转换IP和port就可以,不需要转换传输的数据包的字节序

因为IP和port为 4个字节和2个字节,  而数据报一般都为char类型, 占一个字节

根据字节序的性质,内存存储大于一个字节类型的数据在内存中的存放顺序

所以char类型并不具有字节序的概念

1.主机字节序到网络字节序 (小端序->大端序)

#include <arpa/inet.h>
u_long htonl (u_long hostlong); //host to internet long
功能:将无符号整数hostlong从主机字节顺序转换为网络字节顺序。
#include <arpa/inet.h>
u_short htons (u_short short);  //掌握这个
功能:将无符号短整数hostshort从主机字节顺序到网络字节顺序。

2.网络字节序到主机字节序(大端序->小端序)

#include <arpa/inet.h>
u_long ntohl (u_long hostlong);
功能:将无符号整数netlong从网络字节顺序转换为主机字节顺序。
#include <arpa/inet.h>
u_short ntohs (u_short short);//端口 2byte
功能:将无符号短整数netshort从网络字节顺序转换为主机字节顺序。的

#include <stdio.h>
#include <arpa/inet.h>

int main(int argc, char const *argv[])
{
    int a = 0x12345678;
    //小端转大端
    int b = htonl(a);
    printf("%#x\n", b);
    //大端转小端
    int c = ntohl(b);
    printf("%#x\n", c);
    return 0;
}

三、IP地址转换

1、inet_addr主机字节序转换为网络字节序

#include<sys/socket.h>   
#include<netinet/in.h>               
#include<arpa/inet.h>
in_addr_t  inet_addr(const char *strptr);  //该参数是字符串
 
typedef uint32_t in_addr_t;
struct in_addr 
{
    in_addr_t s_addr;
};
功能:  主机字节序转为网络字节序
参数:  const char *strptr: 字符串
返回值: 返回一个无符号长整型数(无符号32位整数用十六进制表示), 
      否则NULL

2、inet_ntoa 网络字节序转换为主机字节序

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
char *inet_ntoa(struct in_addr inaddr);
功能:   将网络字节序二进制地址转换成主机字节序。 
参数:  struct in_addr in addr  : 只需传入一个结构体变量
返回值:  返回一个字符指针, 否则NULL;

四、TCP编程

C/S   B/S

client/server              browser/server

客户端/服务器 浏览器/服务器

1、套接字工作流程

客户端:   发送请求

服务器端:  相应请求

服务器:

1.创建流式套接字(socket())------------------------>  有手机

2.指定本地的网络信息(struct sockaddr_in)----------> 有号码

3.绑定套接字(bind())------------------------------>绑定手机

4.监听套接字(listen())---------------------------->待机

5.链接客户端的请求(accept())---------------------->接电话

6.接收/发送数据(recv()/send())-------------------->通话

7.关闭套接字(close())----------------------------->挂机

客户端:

1.创建流式套接字(socket())----------------------->有手机

2.指定服务器的网络信息(struct sockaddr_in)------->有对方号码

3.请求链接服务器(connect())---------------------->打电话

4.发送/接收数据(send()/recv())------------------->通话

5.关闭套接字(close())--------------------------- >挂机

服务器端(server):

1) socket(),创建套接字文件,创建出用于连接的套接字文件

2) bind(), 绑定,把socket()函数返回的文件描述符和IP、端口号进行绑定;

3) listen(), 监听,将socket()返回的文件描述符,由主动套接字变为被动套接字;

4) accept(), 阻塞函数,阻塞等待客户端的连接请求, 返回一个用于通信的套接字文件;

5) recv(), 接收客户端发来的数据;(read)    

//6) send(), 发送数据;(write)

  1. close(), 关闭文件描述符; 至少要关闭: 连接、通信

客户端(client):

  1. socket(),创建套接字文件,既用于连接,也用于通信; 

    填充结构体:  填充服务器的ip和端口 , 用于connect连接

2) connect(); 用于发起连接请求,阻塞等待连接服务器;

3) send(), 发送数据;

//4) recv(), 接收数据;

5)close(), 关闭文件描述符;

2、函数接口

1)socket 创建套接字

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
功能:创建套接字
参数:
   domain:协议族
     AF_UNIX, AF_LOCAL  本地通信
     AF_INET            ipv4
     AF_INET6            ipv6
   type:套接字类型
     SOCK_STREAM:流式套接字
     SOCK_DGRAM:数据报套接字
   protocol:协议 - 填0 自动匹配底层 ,根据type系统默认自动帮助匹配对应协议
       传输层:IPPROTO_TCP、IPPROTO_UDP、IPPROTO_ICMP
       网络层:htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL)
 返回值:
    成功 文件描述符 0 -> 标准输入  1->标准输出  2->标准出错 
                  3->socket
    失败 -1,更新errno

2)bind 绑定   ipv4  ip和端口 

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能:绑定   ipv4  ip和端口 
参数
   sockfd:文件描述符
   addr:通用结构体,根据socket第一个参数选择的通信方式最终确定这需要真正填充传递的结构体是那个类型。强转后传参数。
   addrlen:填充的结构体的大小   
返回值:成功0 失败-1、更新errno

通用结构体:相当于预留一个空间
struct sockaddr 
{
    sa_family_t sa_family;
    char        sa_data[14];
}

ipv4的结构体 
 struct sockaddr_in 
 {
     sa_family_t    sin_family;  //协议族AF_INET
     in_port_t      sin_port;  //端口号
     struct in_addr sin_addr;  //ip地址
 };
  struct in_addr 11
 {
     uint32_t       s_addr;   //IP地址  
 };
 
 本地址通信结构体:
  struct sockaddr_un 
  {
     sa_family_t sun_family;  //AF_UNIX  
     char        sun_path[108]; //在本地创建的套接字文件的路径及名字
 };
 
ipv6通信结构体:
struct sockaddr_in6 
{
    sa_family_t     sin6_family;   
    in_port_t       sin6_port;     
    uint32_t        sin6_flowinfo; 
    struct in6_addr sin6_addr;     
    uint32_t        sin6_scope_id; 
};
struct in6_addr 
{
    unsigned char   s6_addr[16];   
};
//如果绑定使用通用地址可使用 INADDR_ANY宏(结合代码讲的时候再添加)
含义是自动绑定所有本机网卡的地址,

11.2作业

3)listen 监听,将主动套接字变为被动套接字

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
功能:监听,将主动套接字变为被动套接字
参数:
 sockfd:套接字
 backlog:同时响应客户端请求链接的最大个数,不能写0.
不同平台可同时链接的数不同,一般写6-8
返回值:成功 0   失败-1,更新errno  

4)accept 阻塞函数

#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

accept(sockfd,NULL,NULL);
阻塞函数,阻塞等待客户端的连接请求,如果有客户端连接,
accept()函数返回,返回一个用于通信的套接字文件描述符(4);
参数:
   Sockfd :套接字
   addr: 链接客户端的ip和端口号
      如果不需要关心具体是哪一个客户端,那么可以填NULL;
   addrlen:结构体的大小
     如果不需要关心具体是哪一个客户端,那么可以填NULL;
     需要查看链接的客户端ip和端口号
     accept(sockfd,NULL,NULL);
     需要查看链接的客户端ip和端口号
     accept(sockfd,(struct sockaddr *)&saddr,&len);
  返回值: 
     成功:文件描述符; //用于通信
失败:-1,更新errno
同时返回客户端的ip和端口号。保存到结构体struct sockaddr *addr中。
通过结构体访问到:inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)
打印时记得使用 inet_ntoa()和ntohs()转换为主机字节序

5)recv 接收数据 

#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能: 接收数据 
参数: 
    sockfd: acceptfd ;
    buf  存放位置
    len  大小
    flags  一般填0,相当于read()函数
    MSG_DONTWAIT  非阻塞
返回值: 
   < 0  失败出错  更新errno
   ==0  表示客户端退出
   >0   成功接收的字节个数

发送端协议类型为TCP Client,远程目标ip地址为服务器IP地址

端口号也应该一致

先关闭客户端,再关闭服务器。

6)connect 用于连接服务器;

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能:用于连接服务器;
参数:
     sockfd:socket函数的返回值
     addr:填充的结构体是服务器端的;
     addrlen:结构体的大小
返回值 
      -1 失败,更新errno
      正确 0 

7)send 发送数据,用来发送消息到一个套接字中。

#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
功能:发送数据,用来发送消息到一个套接字中。只能在套接字处于连接状态的时候才能使用。
参数:
    sockfd:socket函数的返回值
    buf:发送内容存放的地址
    len:发送内存的长度
    flags:如果填0,相当于write();
返回值;
    成功 发送的字节数
    失败 -1
可以使用write代替send,  都属于往发送缓存区内写入数据
read代替recv , 都属于往接收缓存区内提取数据

测试注意:

1. 如果使用客户端软件进行连接,必须保证windows和虚拟机在同一个局域网(桥接),并能互相ping通。服务器的IP地址必须指定为虚拟机自己的IP。

2. 必须保证客户端正常退出后在关闭服务器程序,在客户端连接状态情况下强制关闭服务器程序,下次启动服务器程序后会提示bind err。这是因为没有正常释放绑定的端口,等1~2分钟就可以了。

3、代码优化

1。端口和ip地址通过命令行传参到代码中。(如果参数不一致,应该提示并退出)
2。服务器端IP地址可由“0.0.0.0”自动获取,或者由宏定义自动获取

3。客户端发送去掉fgets获取的多余的'\n'.

fgets(实际读到的内容小于等于指定个数-1,自动读到的内容后添加’\0’,会将’\n’也读入)

  if(buf[strlen(buf)-1] == '\n')//去掉fgets获取的'\n'

         buf[strlen(buf)-1] ='\0';

4.设置来电显示功能,获取到请求链接服务器的客户端的ip和端口。

 int acceptfd = accept(sockfd,(struct sockaddr *)&caddr,&len);

打印时记得使用 inet_ntoa()和ntohs()转换为主机字节序

printf("client ip:%s ,port:%d\n", inet_ntoa(saddr.sin_addr),ntohs(saddr.sin_port));

5、当客户端输入quit的时候,客户端退出

   strncmp

6.实现循环服务器,服务器不退出,当链接服务器的客户端退出,服务器等到下一个客户端链接。

  accept处使用while到接受数据结束。

/*服务器创建代码 */
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
    if (argc < 2)
    {
        printf("plase input <ip><port>\n");
        return -1;
    }
    //1.创建套接字,用于链接
    int sockfd;
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket err");
        return -1;
    }
    //文件描述符 0 -> 标准输入  1->标准输出  2->标准出错  3->socket
    printf("sockfd:%d\n", sockfd);

    //2.绑定 ip+port 填充结构体
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;            //协议族ipv4
    saddr.sin_port = htons(atoi(argv[1])); //端口号,htons将无符号短整数hostshort从主机字节顺序到网络字节顺序。
//atoi(),字符串转整型
//saddr.sin_addr.s_addr = inet_addr(argv[1]);//ip地址,转化为16进制表示
#if 0
    saddr.sin_addr.s_addr = inet_addr("0.0.0.0");//ip地址,转化为16进制表示
#else
    saddr.sin_addr.s_addr = INADDR_ANY;
#endif
    socklen_t len = sizeof(saddr); //结构体大小
    //bind绑定ip和端口
    if (bind(sockfd, (struct sockaddr *)&saddr, len) < 0)
    {
        perror("bind err");
        return -1;
    }
    printf("bind success\n");
    //3.启动监听,把主动套接子变为被动套接字
    if (listen(sockfd, 6) < 0)
    {
        perror("listen err");
        return -1;
    }
    printf("listen success\n");
    //4.阻塞等待客户端的链接请求
    int acceptfd;
    // acceptfd = accept(sockfd,NULL,NULL);
    while (1)
    {
        acceptfd = accept(sockfd, (struct sockaddr *)&saddr, &len);
        //获取客户端的ip和端口,(struct sockaddr *)&saddr:用来存放返回的ip,和端口
        if (acceptfd < 0)
        {
            perror("accept err");
            return -1;
        }
        printf("client ip:%s ,port:%d\n", inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
        printf("connect success\n");
    //5.接收数据
    char buf[64];
    int ret;
    while (1)
    {
        ret = recv(acceptfd, buf, sizeof(buf), 0);
        if (strncmp(buf, "quit", 4) == 0) //接收到quit退出
        {
            break;
        }
        if (ret < 0)
        {
            perror("recv err.");
            return -1;
        }
        else if (ret == 0) //客户端退出
        {
            printf("client exit\n");
            break;
        }
        else
        {
            printf("buf:%s\n", buf);
        }
    }
    }
    close(sockfd);
    close(acceptfd);
    return 0;
}

/*客户端创建代码 */
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
    if (argc < 3)
    {
        printf("plase input <ip><port>\n");
        return -1;
    }
    //1.创建套接字,用于链接
    int sockfd;
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket err");
        return -1;
    }
    //文件描述符 0 -> 标准输入  1->标准输出  2->标准出错  3->socket
    printf("sockfd:%d\n", sockfd);
    //2.绑定 ip+port 填充结构体
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;                 //协议族ipv4
    saddr.sin_port = htons(atoi(argv[2]));      //端口号,htons将无符号短整数hostshort从主机字节顺序到网络字节顺序。
    saddr.sin_addr.s_addr = inet_addr(argv[1]); //ip地址,转化为16进制表示
    socklen_t len = sizeof(saddr);              //结构体大小
    //3用于连接服务器;
    if (connect(sockfd, (struct sockaddr *)&saddr, len) < 0)
    {
        perror("connect err");
        return -1;
    }
    //4发送信息
    char buf[64] = {0};
    while (1)
    {
        fgets(buf, sizeof(buf), stdin);   //从终端获取内容存放到数组中
        if (strncmp(buf, "quit", 4) == 0) //输入quit退出客户端
        {
            break;
        }
        if (buf[strlen(buf)] == '\0')
        {
            buf[strlen(buf) - 1] = '\0';
        }                                  //将fgets自动补的\n去掉
        send(sockfd, buf, sizeof(buf), 0); //将数组中的内容发送到主机端
    }
    close(sockfd);
    // close()
    return 0;
}

ftp文件传输协议

tcp实现ftp功能:

模拟FTP核心原理:客户端连接服务器后,向服务器发送一个文件。文件名可以通过参数指定,服务器端接收客户端传来的文件(文件名随意),如果文件不存在自动创建文件,如果文件存在,那么清空文件然后写入。

项目功能介绍:

均有服务器和客户端代码,基于TCP写的。

在同一路径下,将客户端可执行代码复制到其他的路径下,接下来再不同的路径下运行服务器和客户端。

相当于另外一台电脑在访问服务器。

客户端和服务器链接成功后出现以下提示:四个功能

***************list**************//列出服务器所在目录下的文件名(除目录不显示)

***********put filename**********//客户端给服务器上传一个文件

***********get filename**********//客户端从服务器所在路径下载文件

**************quit***************//退出(可只退出客户端,服务器等待下一个客户端链接)

//读文件,读到最后一次,最后再发送end

//粘包:1.延时 2.读多少发多少

服务器

  1. 搭建tcp框架
  2. 服务器接收消息

//list 列出服务器所在目录下的文件名 目录操作 文件属性获取--发送给客户端

//put filename //接收文件 recv --》新建文件---》 写文件 

//get filename //读文件--》发送给客户端

//quit  while(1)accpet;

客户端

  1. 搭建tcp框架
  2. 列出功能
  3. 给服务器发消息

//list 接收--》列出服务器所在目录下的文件名

//put filename 找到文件--》读文件   -》发送

//get filename //接收文件 recv --》新建文件---》 写文件 

//quit   

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

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

相关文章

软件测试/测试开发丨Python安装指南(macOS)

点此获取更多相关资料 下载 Python 解释器 下载地址: https://www.Python.org/downloads/macos 通过下载页面&#xff0c;可以在该页面上看到下载链接。 下载完成后会得到 Python-3.10.11-macos11.pkg安装文件 。 安装 Python 解释器 双击Python-3.10.11-macos11.pkg文件&a…

Vue3指令

Vue 指令&#xff08;Directives&#xff09;是 Vue.js 的一项核心功能&#xff0c;它们可以在 HTML 模板中以 v- 开头的特殊属性形式使用&#xff0c;用于将响应式数据绑定到 DOM 元素上或在 DOM 元素上进行一些操作。 Vue 指令是带有前缀 v- 的特殊 HTML 属性&#xff0c;它赋…

Linux操作系统中软件安装:用RPM包管理器安装软件步骤

安装软件的一般步骤如下&#xff1a; 1.打开终端&#xff0c;作为root用户或使用sudo命令获取管理员权限。 2.使用RPM命令进行软件包的安装。例如&#xff0c;使用“rpm -ivh 软件包名称.rpm”命令来安装软件包&#xff0c;其中“-i”表示安装&#xff0c;“-v”表示显示详细安…

【入门Flink】- 07Flink DataStream API【万字篇】

DataStream API 是 Flink 的核心层 API。一个 Flink 程序&#xff0c;其实就是对DataStream的各种转换。 代码基本上都由以下几部分构成&#xff1a; 执行环境&#xff08;Execution Environment&#xff09; 1&#xff09;创建执行环境StreamExecutionEnvironment StreamExe…

【启扬方案】基于RK3568核心板的激光打标机应用解决方案

激光打标机是一种利用激光技术进行标记和刻字的设备&#xff0c;作为激光技术应用的一个细分领域&#xff0c;是最早引入工业市场的一类激光装备&#xff0c;它采用激光束在工件表面进行刻印、打标&#xff0c;常用于工业生产中的物料标识、产品追溯、防伪标记等应用&#xff0…

centos7安装mysql-阿里云服务器

1.背景 2.安装 2.1.下载安装包 wget https://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm2.2.安装mysql rpm -ivh mysql57-community-release-el7-8.noarch.rpm 3.安装mysql服务 3.1.进入目录 首先进入cd /etc/yum.repos.d/目录 cd /etc/yum.repos.d/ 3.…

Netty 高性能原因之一 采用了高性能的NIO 模式

java IO简介 I/O 全称Input/Output&#xff0c;即输入/输出&#xff0c;通常指数据在内部存储器和外部存储器或其他周边设备之间的输入/输出。 涉及 I/O 的操作&#xff0c;不仅仅局限于硬件设备的读写&#xff0c;还要网络数据的传输。无论是从磁盘中读写文件&#xff0c;还…

【广州华锐互动】VR综合布线虚拟实验教学系统

随着科技的不断发展&#xff0c;虚拟现实&#xff08;VR&#xff09;技术已经逐渐渗透到各个领域&#xff0c;为人们的生活和工作带来了前所未有的便利。在建筑行业中&#xff0c;VR技术的应用也日益广泛&#xff0c;尤其是在综合布线方面。 广州华锐互动开发的VR综合布线虚拟实…

百度上线“文心一言”付费版本,AI聊天机器人市场竞争加剧

原创 | 文 BFT机器人 百度不愧是我国AI技术领域的先行者&#xff0c;每年致力于人工智能领域取得技术产品的突破和创新。据爆料称&#xff0c;百度的文心一言有突破了新境界&#xff0c;开创了文心大模型4.0会员版本。从线上的to C产品到试水商业化&#xff0c;百度都是争先走…

Python的requests库爬取商城优惠券

首先&#xff0c;我们需要了解要抓取的网页的结构和数据格式。在这个例子中&#xff0c;我们使用Python的requests库来发送HTTP请求&#xff0c;并使用BeautifulSoup库来解析HTML内容。 import requests from bs4 import BeautifulSoup然后&#xff0c;我们需要使用requests库的…

LeetCode | 160. 相交链表

LeetCode | 160. 相交链表 O链接 我们这里有两个问题&#xff0c;一是判断是否相交&#xff0c;二是找交点 思路一&#xff1a; 暴力求解 A链表所有节点依次取B链表找一遍&#xff08;时间复杂度是O(N^2)&#xff09; struct ListNode *getIntersectionNode(struct ListNod…

QT not in executable format:file truncated

今天在调研串口打印机的时候出现的&#xff0c;串口打印机有sdk&#xff0c;自己qt的编辑器用的 MinGW 64&#xff0c;编译出现次错误 出现这个错误&#xff0c;主要是sdk和编译器的版本位数不一致。 修改方法&#xff1a;把MinGW64 改为MinGW32&#xff0c;不过这个根据使用的…

为什么说制造企业需要部署MES管理系统

在数字化浪潮席卷的今天&#xff0c;每个企业都期望通过新技术、新模式来优化自身的运营。这其中&#xff0c;MES管理系统成为了不少企业的首选。那么&#xff0c;为何企业需要部署MES管理系统&#xff1f;又该如何搭建MES管理系统呢&#xff1f; 一、企业缘何钟情于MES系统&am…

LeetCode-20-有效的括号

1.我的暴力解法 class Solution {public boolean isValid(String s) {Stack<Character> stknew Stack<Character>();int i0;//奇数直接不可能是匹配的if(s.length()%2!0)return false;for (;i<s.length();i){if(s.charAt(i)(){stk.push(();}else if(s.charAt(i…

NVM安装node后提示没有对应npm包(即:无法将“npm”项识别为 cmdlet、函数、脚本文件)

背景 windows11 node版本降低到v12.22.12后&#xff0c;执行&#xff1a;nvm -v npm -v npm : 无法将“npm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写&#xff0c;如果 包括路径&#xff0c;请确保路径正确&#xff0c;然后再试一次。 所在位置 …

【bug-maven】(一)java: 错误: 不支持发行版本 5 (二):java: 错误: 无效的源发行版:15

【bug-maven】&#xff08;一&#xff09;java: 错误: 不支持发行版本 5 &#xff08;二&#xff09;&#xff1a;java: 错误: 无效的源发行版&#xff1a;15 &#xff08;一&#xff09;java: 错误: 不支持发行版本 5 报错截图&#xff1a; 出错原因&#xff1a; 打开Projec…

GoLong的学习之路(番外)如何使用依赖注入工具:wire

我为什么要直接写番外呢&#xff1f;其原因很简单。项目中会使用&#xff0c;其实在这里大家就可以写一些项目来了。 依赖注入的工具本质思想其实都大差不差。无非控制反转和依赖注入。 文章目录 控制反转为什么需要依赖注入工具 wire的概念提供者&#xff08;provider&#x…

易云维®工厂能耗管理平台系统方案,保证运营质量,推动广东制造企业节能减排

我国《关于完整准确全面贯彻新发展理念推进碳达峰碳中和工作的实施意见》出台&#xff0c;提出了推进碳达峰碳中和工作的总体目标。到2025年&#xff0c;广东具备条件的地区、行业和企业率先实现碳达峰&#xff0c;为全省实现碳达峰、碳中和奠定坚实基础&#xff1b;2030年前实…

51单片机+SIM800C(GSM模块)实现短信发送功能

一、前言 本项目利用51单片机和SIM800C GSM模块实现短信发送功能。短信作为一种广泛应用的通信方式&#xff0c;在许多领域具有重要的作用&#xff0c;如物联网、安防系统、远程监控等。通过将51单片机与SIM800C GSM模块相结合&#xff0c;可以实现在各种应用场景下的短信通信…

美国光量子计算解决方案公司QCI正式开启量子计算商业化道路!

​&#xff08;图片来源&#xff1a;网络&#xff09; Quantum Computing Inc&#xff08;QCI&#xff09;是一家率先实现上市的全栈式光量子计算解决方案公司&#xff0c;近日&#xff0c;美国量子计算公司QCI&#xff08;纳斯达克代码: QUBT&#xff09;宣布&#xff0c;其在…