Linux C——网络编程

news2024/11/14 20:55:06
本案例运行环境:Ubuntu 12.04.1 LTS
1、基本概念

网络的七层模型:

  1.     物理层
  2.     数据链路层
  3.     网络层
  4.     传输层
  5.     会话层
  6.     表示层
  7.     应用层

    其中:1、2、3层主要面向通过网络端到端的数据流, 4、5、6、7层定义了程序的功能
    
TCP/IP的四层模型

  •     应用层:应用层和传输层之间的接口由端口号和套接字所定义,包含Telnet和文件传输协议(FTP)
  •     传输层:端到端的数据传输,从一个应用传输到它的远程对等实体,包含UDP,TCP协议
  •     网络层:网络上传输的基本信息单位,有IP、ICMP、ARP、RARP等
  •     网络接口层:也叫链路层,数据链路层,实际网络硬件接口

    
TCP协议
    传输控制协议,为应用程序提供可靠的通信连接,他具有可靠的、面向连接的、不容易拥塞的、具有流量控制功能的协议。适用于一次传输大批量数据的情况并可要求得到相应的应用程序提供全双工可交付服务,采取许多机制确保端到端结点之间的可靠数据传输,如采用序列号、确认重传和滑动窗口
    TCP具有重传功能的积极确认技术
    确认:指接收端在正确收到报文后向接收端发一个确认(ACK)信息。发送端将每个已发送的报文备份在自己的缓冲区,在收到相应的确认之前不会丢弃保存的报文段
    积极:发送端在每一个报文发送完成后,同时启动一个定时器,若加入定时器的定时期满而关于报文段的确认信息还没有达到,则认为已经丢失并主动重发
    三次握手
        第一次握手:客户端将syn(同步)设置为1,同时产生一个随机数seq发送给服务端
        第二次握手:服务端接收到报文,将syn=1,产生随机数seq根ack=端口seq+1的确认报文发送给客户端
        第三次握手:客户端接受到服务端报文,同时发送一个确认报文ack=服务端seq+1
        
UDP协议
    用户数据报协议,一种无连接协议。它适用于对数据可靠性的要求不那么高,实时性高、网络状况良好的情况下

2、套接字

套接字是操作系统内核中的一个数据结构,他是网络中的结点进行相互通信的门户,是网络进程的ID。 网络通信本质上是进程间通信(不同计算机上的进程间通信) 套接字中包含端口号,而在一个计算机中,一个端口号一次只能分配给一个进程。从而精确到不同计算机上进程间通信

2.1 Socket

概念
    它是一种特殊的I/O接口,也是一种文件描述符。每一个Socket用一个半相关描述{协议、本地地址、本地端口}来表示;一个完整的套接字则用一个相关描述{协议、本地地址、本地端口、远程地址、远程端口}

类型

  •     流式Socket:用于TCP通信,流式套接字提供可靠的、面向连接的通信流
  •     数据报Socket:用于UDP通信,数据报套接字定义了一种无连接的服务,数据通过相互独立的数据报文进行传输
  •     原始Socket:用于新的网络协议实现的测试,允许对底层协议IP或ICMP进行直接访问
网络编程中基本信息数据结构
    struct sockaddr
    {
        unsigned short sa_family;    /*地址族*/
        char sa_data[14];            /*14字节的地址协议,包含Socket的IP地址和端口号*/
    };
    
    struct sockaddr_in
    {
        short int sin_family;                //地址族,在<netinet/in.h>中。AF_INET表示IPv4,AF_INET6表示IPv6
        unsigned short int sin_port;        //端口号
        struct in_addr sin_addr;            //IP地址
        unsigned char sin_zero[8];          //填充0以保持与struct sockaddr同样大小
    };
    
    struct in_addr
    {
        unsigned long int s_addr;  //32位IPv4地址,网络字节序
    }
2.2 数据存储优先顺序转换
同为小端,异为大端:
    内低数低,内高数高:小端
    内低数高,内高数低:大端
​
网络字节序都是大端
​
相互转换的4个函数:
    htons()、ntohs()、htonl()、ntohl()
    h:host,主机
    n:network,网络
    s:short 16位
    l:long  32位

在网络编程中端口号和IP地址均要进行顺序转化,IP地址通过地址格式转化会自动变为网络字节序,故若IP地址通过地址格式转换了,就只要将端口号进行转换即可

 函数详解

表头文件
    #include <netinet/in.h>
    
定义函数
    unsigned long int htonl(unsigned long int hostlong);
​
函数说明
    将32位主机字节转换成网络字节
    
返回值
    返回对应的网络字节序

 综合案例

#include <stdio.h>
#include <netinet/in.h>    
#include <stdlib.h>

int main(int argc,char *argv[])
{
	char port[] = "1000";
	struct sockaddr_in sockaddr;

	sockaddr.sin_port = htons(atoi(port));

	printf("转换前字节序:%x\n",atoi(port));
	printf("转换后字节序:%x\n",sockaddr.sin_port);
	
	return 0;
}

运行结果

linux@ubuntu:~/test$ gcc to.c  //文件名为to.c
linux@ubuntu:~/test$ ./a.out 
转换前字节序:3e8
转换后字节序:e803
2.3 地址格式转换
将点分十进制表示的数值转换成Socket编程时使用的32位网络字节序的二进制值

 函数详解

表头文件
    #include <netinet/in.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    
定义函数
    unsigned long int inet_addr(const char* cp);
​
函数说明
    将参数cp所指的网络地址字符串(以数字和点组成的字符串)转换成二进制数字
    
返回值
    成功返回对应的网络二进制的数字,失败返回-1
表头文件
    #include <netinet/in.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    
定义函数
    int inet_aton(const char* cp,struct in_addr *inp);
​
函数说明
    将参数cp所指的网络地址字符串(以数字和点组成的字符串)转换成二进制数字,然后存于参数inp所指的in_addr结构中
    
返回值
    成功返回非0值,失败返回-1
表头文件
    #include <netinet/in.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    
定义函数
    char * inet_ntoa(struct in_addr in);
​
函数说明
    将参数in所指的二进制数字转换成网络地址字符串(以数字和点组成的字符串),然后指向此网络地址字符串的值返回
    
返回值
    成功返回字符串指针,失败返回NULL

综合案例 

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main(int argc,char *argv[])
{
	char ip[] = "192.168.0.101";
	struct in_addr myaddr;         //存储32位IPv4网络字节序的结构体

	/*inet_aton   网络地址换成二进制数字*/
	int iRet = inet_aton(ip,&myaddr);
	printf("%x\n",myaddr.s_addr);
	
	/*inet_addr  网络地址换成二进制数字*/
	myaddr.s_addr = inet_addr(ip);
	printf("%x\n",myaddr.s_addr);

	/*inet_ntoa  二进制数字转换成网络地址*/
	myaddr.s_addr = 0xac100ac4;
	char* IPv4 = inet_ntoa(myaddr);
	printf("%s\n",IPv4);
	return 0;
}

运行结果

linux@ubuntu:~/test$ gcc wl01.c     //文件名叫wl01.c
linux@ubuntu:~/test$ ./a.out 
6500a8c0
6500a8c0
196.10.16.172
3、网络编程

3.1 建立Socket通信

 函数详解 

表头文件
    #include <sys/types.h>
    #include <sys/socket.h>
    
定义函数
    int socket(int domain,int type,int protocol)
​
函数说明
    用来建立一个新的Socket,也就是向系统注册,通知系统建立一个通信端口
    domain:指定使用何种地址类型
        PF_INET/AF_INET:IPv4网络协议
        PF_INET6/AF_INET6:IPv6网络协议
        ....
    type:
        SOCK_STREAM:提供双向连续可信赖的数据流,即TCP连接,支持OOB机制,在所有数据传送前必须使用connect()来建立连线状态
        SOCK_DGRAM:提供不连续不可信赖的数据包连接
        SOCK_SEQPACKET:提供连续可信赖的数据包连接
        SOCK_RAW:提供原始网络协议存取
        SOCK_RDM:提供可信赖的数据包连接
        SOCK_PACKET:提供网络驱动程序的直接通信
    protocol:
        指定Socket所使用的传输协议编号,通常默认设置为0
    
返回值
    成功返回Socket处理代码,即通信文件指针或叫做通信句柄,失败返回-1

常用实例

/*此为经常使用的用法,并不是一个完整的可以编译的源代码*/
int sockfd;
sockfd = socket(AF_INET,SOCK_STREAM,0);    //表示建立一个IPv4的地址的TCP连接通信
if(sockfd == -1)
{
    perror("error!");
    exit(-1);
}
3.2 绑定地址
表头文件
    #include <sys/types.h>
    #include <sys/socket.h>
    
定义函数
    int bind(int sockfd,struct sockaddr *my_addr,int addrlen);
​
函数说明
    用于对Socket进行定位
    给参数sockfd的Socket绑定IP地址和端口号等。IP地址端口号等参数my_addr指向一sockaddr结构
    *my_addr:sockaddr结构
    addrlen:sockaddr的结构长度
    
返回值
    成功返回0,失败返回-1

常用实例

/*******************************************************************
 *此为经常使用的用法,并不是一个完整的可以编译的源代码                  
 *绑定地址的步骤为:                                                                
 *1.定义一个struct sockaddr_in类型的变量                            
 *2.将变量内数据清空                                                
 *3.为三个变量sa_family 地址族,sin_port 端口号,sin_addr IP地址赋值  
 *4.地址绑定
 ******************************************************************/

struct sockaddr_in my_addr;
memset(&my_addr,0,sizeof(struct sockaddr));
//或 bzero(&my_addr,sizeof(struct sockaddr));

my_addr.sa_family = AF_INET;   //采用IPv4网络协议
my_addr.sin_port = htons(atoi("8080"));  //表示端口号为8080,通常是一个大于1024的端口值
//htons() 用来将指定的16位hostshort转换成网络字节序,本质上就是将存在主机上的两个字节内数据的数据转化成网络字节顺序
//atoi() 用于将数字字符串转换成int型数字,若是一个整数,则不需要这个函数进行转换

//inet_addr() 用于将点分十进制的IP地址字符串转换成二进制数字,若位INADDR_ANY表示自动填充本机IP地址
my_addr.sin_addr = inet_addr("192.168.1.1");

//sockfd为上一步创建的通信句柄(通信文件指针),参数2为强制类型转换,因为第二个参数的类型是strcut sockaddr,往结构体内填充具体数据又要用struct sockaddr_in这个结构体,故需要强制类型转换,为什么不直接使用struct sockaddr_in这个结构体呢,因为使用IPv4和IPv6所需要的字长是不一样的
if(bind(sockfd,(struct sockaddr *)&myaddr,sizeof(struct sockaddr)) == -1)
{
    perror("bind error!");
}
3.3 监听

  函数详解 

表头文件
    #include <sys/socket.h>
    
定义函数
    int listen(int sockfd,int backlog);
​
函数说明
    用于等待连接,用来等待参数sockfd的Socket连线。
    backlog:指定同时能处理的最大连接要求
    
返回值
    成功返回0,失败返回-1
    
注意
    listen()只适用于SOCK_STREAM或SOCK_SEQPACKET的Socket类型。若为AF_INET,则参数backlog的最大值可为128

 常用实例

/*此为经常使用的用法,并不是一个完整的可以编译的源代码*/
if(listen(sockfd,10) == -1)
{
    perror("listen");
    close(sockfd);
    exit(-1);
}
3.4 接受请求

 函数详解  

表头文件
    #include <sys/types.h>
    #include <sys/socket.h>
    
定义函数
    int accept(int sockfd,struct sockaddr *addr,int *addrlen);
​
函数说明
    用于接收Socket连线,接收参数sockfd的Socket连线,参数sockfd必须经过bind()和listen()处理过
    当有连线进来时,accept()会返回新的Socket处理代码,之后的数据传送于读取就由新的Socket处理,原来参数sockfd的Socket能继续使用accept()来接收新的连线要求,连线成功后,参数sddr所指的结构会被系统填入远程主机的地址数据
    addrlen为scokaddr的结构长度
    
返回值
    成功返回新的Socket处理代码,也就是一个新的通信句柄,后续的数据传输和读取都要通过新的这个句柄进行操作,原来的句柄继续使用,继续监听其他客户机的请求,失败返回-1

  常用实例

/*此为经常使用的用法,并不是一个完整的可以编译的源代码*/
struct sockaddr_in clientaddr;     //定义一个变量,用于存储远程主机的地址数据
memset(&clientaddr,0,sizeof(struct sockaddr));   //清空结构体

int new_sockfd = accept(sockfd,(struct sockaddr*)&clientaddr,sizeof(struct sockaddr));

if(new_sockfd == -1)
{
    perror("accept error!");
    close(sockfd);
    exit(-1);
}
3.5 连接服务器

 函数详解  

表头文件
    #include <sys/types.h>
    #include <sys/socket.h>
    
定义函数
    int connect(int sockfd,struct sockaddr *serv_addr,int addrlen);
​
函数说明
    用于接收Socket连线,将参数sockfd的Socket连至参数serv_addr指定的网络地址
    addrlen:sockaddr的结构长度
    
返回值
    成功返回0,失败返回-1

  常用实例

/*此为经常使用的用法,并不是一个完整的可以编译的源代码*/
struct sockaddr_in seraddr;     //定义一个变量,用来存储所需连接的服务器地址信息
memset(&seraddr,0,sizeof(struct sockaddr));
seraddr.family = AF_INET;                              //IPv4协议
seraddr.sin_port = htons(10000);                       //服务器的端口号
seraddr.sin_addr.s_addr = inet_addr("192.168.2.19");   //服务器的IP地址

if(connect(sockfd,(struct sockaddr*)&sockaddr_in,sizeof(struct sockaddr)) == -1)
{
    perror("connect error!");
    close("sockfd");
    exit(-1);
}
3.6 发送数据

 函数详解  

表头文件
    #include <sys/types.h>
    #include <sys/socket.h>
    
定义函数
    int send(int s,const void *msg,int len,unsigned int falgs);
​
函数说明
    用于通过Socket传送数据,将数据由指定的Socket传给对方主机。
    s:已建立好连接的Socket
    msg:欲指向连线的数据内容
    len:数据长度
    flags:一般设为0,也有其他数值定义,可自行查询
    
返回值
    成功返回实际传送出去的字符数,失败返回-1
表头文件
    #include <sys/types.h>
    #include <sys/socket.h>
    
定义函数
    int sendto(int s,const void *msg,int len,unsigned int falgs,const struct sockaddr* to,int tolen);
​
函数说明
    用于通过Socket传送数据,将数据由指定的Socket传给对方主机。
    s:已建立好连接的Socket
    msg:欲指向连线的数据内容
    len:数据长度
    flags:一般设为0,也有其他数值定义,可自行查询
    to:欲传送的网络地址
    tolen:sockaddr的结果长度
    
返回值
    成功返回实际传送出去的字符数,失败返回-1

   常用实例

/*此为经常使用的用法,并不是一个完整的可以编译的源代码*/
char data[256] = "hello C.";
if(send(new_sockfd,data,sizeof(data),0) == -1)
{
    perror("send error!");
    close(new_sockfd);
    close("sockfd");
    exit(-1);
} 
3.7 接收数据

 函数详解  

表头文件
    #include <sys/types.h>
    #include <sys/socket.h>
    
定义函数
    int recv(int s,void *buf,int len,unsigned int falgs);
​
函数说明
    用于通过Socket接收数据,将接收由指定的Socket传来的数据。
    s:已建立好连接的Socket
    buf:存储数据的内存空间地址
    len:;可接收数据最大长度
    flags:一般设为0
        MSG_OOB:接收以out-of-band送出的数据
        MSG_PEEK:返回来的数据并不会在系统内删除,若再次调用recv()会返回相同的数据内容
        MSG_WAITALL:强迫接收到len大小的数据后才能返回,除非有错误发生
        MSG_NOSIGNAL:此操作不愿被SIGPIPE信号中断
    
返回值
    成功返回接收到的字符数,失败返回-1
表头文件
    #include <sys/types.h>
    #include <sys/socket.h>
    
定义函数
    int recvfrom(int s,void *buf,int len,unsigned int falgs,struct sockaddr* from,int *fromlen);
​
函数说明
    用于通过Socket接收数据,将接收由指定的Socket传来的数据。
    s:已建立好连接的Socket
    buf:存储数据的内存空间地址
    len:;可接收数据最大长度
    flags:一般设为0
        MSG_OOB:接收以out-of-band送出的数据
        MSG_PEEK:返回来的数据并不会在系统内删除,若再次调用recv()会返回相同的数据内容
        MSG_WAITALL:强迫接收到len大小的数据后才能返回,除非有错误发生
        MSG_NOSIGNAL:此操作不愿被SIGPIPE信号中断
    from:指定欲传送的网络地址
    fromlen:sockaddr的结构长度
    
返回值
    成功返回接收到的字符数,失败返回-1
/*此为经常使用的用法,并不是一个完整的可以编译的源代码*/
char sock_buf[256] = {0};
if(recv(new_sockfd,buf,sizeof(buf),0) == -1)
{
    perror("recv error");
    close(new_sockfd);
    exit(-1);
}
puts(buf);
3.8 简单综合案例

服务器端:server.c

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc,char *argv[])
{
	int sockfd;
	int new_sockfd;
	char data[512];
	char data_buf[512];
	struct sockaddr_in server_addr;

	memset(&server_addr,0,sizeof(struct sockaddr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(10000);
	server_addr.sin_addr.s_addr = inet_addr("192.168.124.177");

	//建立通信
	if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
	{
		perror("sockfd error.");
		exit(-1);
	}

	//绑定地址
	if(bind(sockfd,(struct sockaddr *)&server_addr,sizeof(struct sockaddr)) < 0)
	{
		perror("bind error.");
		close(sockfd);
		exit(-1);
	}

	printf("服务器启动\n");

	//监听
	if(listen(sockfd,10) == -1)
	{
		perror("sockfd error.");
		close(sockfd);
		exit(-1);
	}

	new_sockfd = accept(sockfd,NULL,NULL);
	if(new_sockfd < 0)
	{
		perror("accept error.");
		close(sockfd);
		exit(-1);
	}
	while(1)
	{


		if(recv(new_sockfd,data_buf,sizeof(data_buf),0) < 0)
		{
			perror("recv error.");
			close(sockfd);
			exit(-1);
		}

		printf("%s\n",data_buf);
		sprintf(data,"get data:%s\n",data_buf);

		if(send(new_sockfd,data,sizeof(data),0) < 0)
		{
			perror("send error.");
			close(sockfd);
			exit(-1);
		}
	}

	return 0;
}

客户端:server.c

#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc,char *argv[])
{
	int sockfd;
	char data[512];
	char data_buf[512];
	struct sockaddr_in server_addr;

	memset(&server_addr,0,sizeof(struct sockaddr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(10000);
	server_addr.sin_addr.s_addr = inet_addr("192.168.124.177");

	if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
	{
		perror("sockfd error.");
		exit(-1);
	}
	printf("启动成功\n");
	if(connect(sockfd,(struct sockaddr*)&server_addr,sizeof(struct sockaddr)) < 0)
	{
		perror("connect error.");
		close(sockfd);
		exit(-1);
	}
	printf("连接成功\n");
	while(1){
		printf("输入你想要发送的数据:");
		scanf("%s",data);
		getchar();
		if(send(sockfd,data,sizeof(data),0) < 0)
		{
			perror("send error.");
			close(sockfd);
			exit(-1);
		}

		if(recv(sockfd,data_buf,sizeof(data_buf),0) < 0)
		{
			perror("recv error.");
			close(sockfd);
			exit(-1);
		}
		printf("%s",data_buf);
	}
	return 0;
}

 编译代码

linux@ubuntu:~/test$ gcc server.c -o server -Wall
linux@ubuntu:~/test$ gcc client.c -o client -Wall

运行结果

/*服务器端*/
linux@ubuntu:~/test$ ./server
服务器启动
nihao
dajiahao
shijiediyi
shijiediyi
shijiediyi



/*客户端*/
linux@ubuntu:~/test$ ./client 
启动成功
连接成功
输入你想要发送的数据:nihao 
get data:nihao
输入你想要发送的数据:dajiahao
get data:dajiahao
输入你想要发送的数据:shijiediyi 
get data:shijiediyi
输入你想要发送的数据:^C

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

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

相关文章

静态链接和动态链接的Golang二进制文件

关注TechLead&#xff0c;复旦博士&#xff0c;分享云服务领域全维度开发技术。拥有10年互联网服务架构、AI产品研发经验、团队管理经验&#xff0c;复旦机器人智能实验室成员&#xff0c;国家级大学生赛事评审专家&#xff0c;发表多篇SCI核心期刊学术论文&#xff0c;阿里云认…

李沐 模型选择、过拟合和欠拟合相关代码【动手学深度学习v2】

多项式回归 生成数据集 给定x,我们将使用以下三阶多项式来生成训练和测试数据的标签: y=5+1.2x−3.4+5.6+ϵ where ϵ∼( ). 噪声项ϵ服从均值为0且标准差为0.1的正态分布。 在优化

GraphRAG与VectorRAG我都选:HybridRAG

从金融应用中产生的非结构化文本数据&#xff08;如财报电话会议记录&#xff09;提取和解释复杂信息&#xff0c;即使采用当前最佳实践使用检索增强生成&#xff08;RAG&#xff09;技术&#xff0c;对于大型语言模型&#xff08;LLMs&#xff09;来说仍存在重大挑战。这些挑战…

【游戏党必看】2024年最适合玩游戏的电脑系统推荐!

许多玩家都在问如果在电脑上玩游戏装什么系统好呢&#xff1f;以下系统之家小编给大家推荐两款专门为游戏玩家打造的操作系统&#xff0c;针对大型游戏进行了深度优化&#xff0c;显著提升了系统性能&#xff0c;确保游戏运行更为流畅无阻&#xff0c;能完美兼容各种类型的游戏…

三好夫人|最强“逼”婚神器,送完一次就领证

三好夫人&#xff5c;揭秘最强“逼”婚神器&#xff0c;让你的爱情甜蜜升级&#xff0c;速领见家长通行证&#xff01; 男人们请记住&#xff0c;如果一个女生给你送三好夫人&#xff0c;那么你赶快带她见家长把婚事定了。 在这个快节奏的时代&#xff0c;爱情似乎也被按下了快…

基于51单片机的电机控制和角度检测

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机&#xff0c;采用滑动变阻器连接ADC0832数模转换器模拟角度传感器&#xff0c;然后通过LCD1602显示数值&#xff0c;然后按键按下不动&#xff0c;电机正转&#xff0c;松开停止。第二…

显示和隐藏图片【JavaScript】

使用 JavaScript 来实现显示和隐藏图片。下面是一个简单的示例&#xff0c;展示如何通过按钮点击来切换图片的可见性。 实现效果: 代码&#xff1a; <!DOCTYPE html> <html lang"zh"><head><meta charset"UTF-8"><meta name&…

神奇的交互!Ethernet IP转Profinet网关与发那科机器人的数据交互

在当今的工业领域&#xff0c;随着自动化程度的不断提高&#xff0c;工业化升级已成为必然趋势。在这个过程中&#xff0c;对机器人的联网需求变得日益迫切。机器人作为工业生产中的重要组成部分&#xff0c;其高效运行和与其他设备的协同工作对于提高生产效率至关重要。然而&a…

EI-Bisynch协议

EI-Bisynch&#xff08;Extended Interface-Bisynchronous&#xff09;协议是一种早期用于设备通信的协议&#xff0c;主要用于工业控制系统中的串行通信。随着技术的发展&#xff0c;EI-Bisynch的使用已经大幅减少&#xff0c;逐渐被更现代化、灵活性更高的通信协议&#xff0…

【Linux】手把手教你制作一个简易shell——(进程创建fork进程替换wait与进程等待exec的应用)(自定义shell程序设计)

前言 大家好吖&#xff0c;欢迎来到 YY 滴Linux系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C Linux的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的…

华为昇腾智算中心-智算中心测试方案与标准

本方案是企业内训课程《华为昇腾智算中心深度技术研修》的一部分授课课件的样例。方案内容中详细阐述了华为昇腾环境下智算中心的测试方案和标准&#xff0c;以确保硬件和软件系统在实际部署和运行中的高效性和稳定性。主要内容包括集群硬件清单、节点拓扑配置以及环境配置。硬…

企业微信oauth2的code换用户身份一直40029解决方案

序&#xff1a; 雪狼的微信表情包&#xff0c;欢迎下载【程序员雪狼】微信表情 - 来自微信表情商店&#xff0c;扫二维码下载表情 正文&#xff1a; 雪狼在用oauth2返回的code要去请求getuserinfo3rd接口的时候&#xff0c;报错如下40029 一样&#xff0c;肝了一天&#xff0c…

本地部署高颜值某抑云音乐播放器Splayer并实现无公网IP远程听歌

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

湖北建筑类初级职称申报的全方位解读

湖北建筑类初级职称申报的全方位解读 湖北工程行业助理工程师/初级职称申报评审 湖北建筑类助理工程师/初级职称正常申报目前都是电子版证书&#xff0c;湖北省政务服务网查询生成&#xff0c;省网查询&#xff0c;后期都会同步G网查询。 湖北建筑类助理工程师纸质版 1.之前申…

kubernetes网络(一)之calico详解

摘要 本文介绍Kubernetes最流行的网络解决方案calico。 kubernetes中不同宿主上的pod需要相互通信&#xff0c;如果按TCP/IP协议分层进行分类&#xff1a; 二层方案&#xff1a;flannel的udp和vxlan模式 三层方案&#xff1a;flannel的host-gw模式&#xff1b;calico的IPIP模…

ReduceLROnPlateau学习率衰减设置

学习率衰减有多种方式&#xff0c;本次采用optim.lr_scheduler.ReduceLROnPlateau&#xff0c;这种方式代表在发现loss不再降低或者acc不再提高之后&#xff0c;降低学习率。 model GRU().to(device) criterion nn.CrossEntropyLoss().to(device) optimizer optim.AdamW(m…

YOLOv10独家改进:红外场景严重遮挡和重叠目标解决方案 | 一种新的自适应算法轻量级通道分割和变换(ALSS)模块,自适应特征提取优化策略

💡💡💡本文解决什么问题:红外检测场景存在严重遮挡和重叠目标时的局限性的问题点。 💡💡💡提出了一种新的自适应算法轻量级通道分割和变换(ALSS)模块。该模块采用自适应信道分裂策略优化特征提取,并集成信道变换机制增强信道间的信息交换。这改善了模糊特征的提…

简单多状态dp第一弹 leetcode -面试题17.16.按摩师 -213.打家劫舍II

a​​​​​​​面试题 17.16. 按摩师 按摩师 题目: 分析: 使用动态规划解决 状态表示: dp[i] 表示&#xff1a;选择到 i 位置时&#xff0c;此时的最长预约时长。 但是我们这个题在 i 位置的时候&#xff0c;会面临 选择 或者 不选择 两种抉择&#xff0c;所依赖的状态需要…

响应式的几种解决方案——媒体查询、flex、grid、多列布局、瀑布流和数据可视化屏幕的缩放处理

media媒体查询 媒体查询入门指南 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>Document<…

Java面试篇基础部分- Java中的阻塞队列

首先队列是一种前进后出的操作结构,也就是说它只允许从队列前端进入,从队列后端退出。这个前端和后端看个人如何理解,也就是通常所说的入队和出队,队头和队尾。 阻塞队列和一般队列的不同就在于阻塞队列是可以阻塞的,这里所说的并不是说队列中间或者队头队尾被拦截了,而是…