【网络编程开发】4.socket套接字及TCP的实现框架 5.TCP多进程并发

4.socket套接字及TCP的实现框架

Socket套接字

Socket套接字是网络编程中用于实现不同计算机之间通信的一个基本构建块

在现代计算机网络中,Socket套接字扮演着至关重要的角色。它们为应用程序提供了一种方式,通过这种方式,程序能够通过网络发送和接收数据包。以下是对socket的相关介绍:

  1. 定义功能
    • Socket,译为“套接字”,是一种软件形式的"插座",使得不同主机之间的进程可以通过网络进行通信。它基本上充当了应用程序、操作系统与网络硬件之间的接口。
  2. 核心作用
    • Socket套接字允许一个程序通过网络将信息传递给另一个程序。这涉及到底层的网络协议操作,如TCP/IP,但Socket API提供了一个更简单的抽象,使得程序员无需深入了解这些复杂协议的细节即可进行网络编程。
  3. 类型应用
    • 流式套接字(SOCK_STREAM)基于TCP协议,提供面向连接的可靠数据传输服务,适用于需要确保数据完整性的应用,如网页浏览。
    • 数据报套接字(SOCK_DGRAM)基于UDP协议,提供无连接的服务,适用于对实时性要求高但可以容忍少量数据丢失的应用,如视频通话。
  4. 工作过程
    • 服务器端创建一个Socket并绑定到一个特定的IP地址和端口上,然后开始监听来自客户端的连接请求。
    • 客户端创建一个Socket,并尝试连接到服务器的IP地址和端口。一旦连接建立,双方就可以通过这个Socket进行数据的发送和接收。
  5. 高级功能
    • 使用Socket,可以实现多种网络应用程序,包括聊天应用、文件传输、远程控制等。在多用户游戏、实时数据处理等方面也广泛应用Socket技术。
    • 在多线程或多进程的环境中,Socket也能有效地处理并发连接,提高系统的响应速度和处理能力。

TCP实现框架

在这里插入图片描述

以下是C语言中常见的Socket API及其功能:

以下是C语言中常见的Socket API及其功能:

  1. socket函数:该函数用于创建一个套接字,并返回一个套接字描述符。

    #include <sys/types.h>
    #include <sys/socket.h>
    int socket(int domain, int type, int protocol);
    /*
    参数:
    	domain:指定协议族,如AF_INET表示IPv4地址。
    	type:指定套接字类型,如SOCK_STREAM表示提供有序、可靠、双向字节流的连接。
    	protocol:通常设置为0,表示系统将选择与指定类型相匹配的默认协议。
    返回值:
    	成功时返回一个非负整数,表示新创建的套接字描述符。
    	失败时返回-1,并设置errno为相应的错误码。
    */
    
  2. bind函数:此函数用于将套接字绑定到一个特定的地址和端口号上。这对于服务器来说尤其重要,因为它们需要在已知的地址上监听来自客户端的连接请求。

    #include <sys/types.h>
    #include <sys/socket.h>
    int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    /*
    参数:
    	sockfd:表示套接字的描述符。
    	addr:指向特定于域的套接字地址结构的指针,该结构包含了要绑定的地址信息。
    	addrlen:指定地址结构的大小。
    返回值:
    	成功时返回0。
    	失败时返回-1,并设置errno为相应的错误码。
    */
    
  3. listen函数:服务器使用此函数将套接字设置为监听状态,等待客户端的连接请求。可以指定一个队列限制,以控制同时可处理的连接数。

    #include <sys/types.h>
    #include <sys/socket.h>
    int listen(int sockfd, int backlog);
    /*
    参数:
    	sockfd:表示套接字的描述符。
    	backlog:指定在未完成连接队列中允许的最大连接数。
    返回值:
    	成功时返回0。
    	失败时返回-1,并设置errno为相应的错误码。
    */
    
  4. accept函数:当有客户端连接请求时,服务器使用此函数接受连接,并返回一个新的套接字,用于与客户端通信。

    #include <sys/types.h>
    #include <sys/socket.h>
    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    /*
    参数:
    	sockfd:表示套接字的描述符。
    	addr:指向特定于域的套接字地址结构的指针,该结构用于接收客户端的地址信息。
    	addrlen:指向一个变量的指针,该变量用于接收地址结构的大小。
    返回值:
    	成功时返回一个新的套接字描述符,用于与客户端通信。
    	失败时返回-1,并设置errno为相应的错误码。
    */
    
  5. connect函数:该函数用于建立一个到服务器的连接。对于TCP套接字,这将触发TCP的三次握手过程。

    #include <sys/types.h>
    #include <sys/socket.h>
    int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    /*
    参数:
    	sockfd:表示套接字的描述符。
    	addr:指向特定于域的套接字地址结构的指针,该结构包含了服务器的地址信息。
    	addrlen:指定地址结构的大小。
    返回值:
    	成功时返回0。
    	失败时返回-1,并设置errno为相应的错误码。
    */
    
  6. send和recv函数:这两个函数分别用于发送和接收数据。它们是TCP通信中常用的数据传输函数。

    #include <sys/types.h>
    #include <sys/socket.h>
    ssize_t send(int sockfd, const void *buf, size_t len, int flags);
    ssize_t recv(int sockfd, void *buf, size_t len, int flags);
    /*
    参数:
    	sockfd:表示套接字的描述符。
    	buf:指向要发送或接收数据的缓冲区的指针。
    	len:指定要发送或接收的数据的长度。
    	flags:可选的标志位,用于控制发送或接收的行为。
    返回值:
    	成功时返回实际发送或接收的字节数。
    	失败时返回-1,并设置errno为相应的错误码。
    */
    
  7. sendto和recvfrom函数:对于UDP通信,不需要建立连接,直接使用sendto和recvfrom函数进行数据报文的发送和接收。

    #include <sys/types.h>
    #include <sys/socket.h>
    ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
    ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
    /*
    参数:
    	sockfd:表示套接字的描述符。
    	buf:指向要发送或接收数据的缓冲区的指针。
    	len:指定要发送或接收的数据的长度。
    	flags:可选的标志位,用于控制发送或接收的行为。
    	dest_addr:指向目标地址结构的指针,用于UDP发送操作。
    	src_addr:指向源地址结构的指针,用于UDP接收操作。
    	addrlen:指向一个变量的指针,用于UDP接收操作,该变量用于接收源地址结构的大小。
    返回值:
    	成功时返回实际发送或接收的字节数。
    	失败时返回-1,并设置errno为相应的错误码。
    */
    

示例-服务端

TCP_socket.c

#include <stdio.h> // 引入标准输入输出库
#include <sys/socket.h> // 引入套接字库
#include <sys/types.h> // 引入类型定义库
#include <stdlib.h> // 引入标准库
#include <arpa/inet.h> // 引入互联网协议库
#include <unistd.h> // 引入Unix标准库
#include <string.h> 


#define PORT 5001 // 定义端口号为5001
#define BACKLOG 5 // 定义最大连接数为5

int main(int argc, char *argv[]) // 主函数,参数为命令行参数个数和参数列表
{

    int fd,newfd,ret; // 定义文件描述符变量
    char buf[BUFSIZ] = {}; //BUFSIZ 8142
    struct sockaddr_in addr; // 定义IPv4地址结构体

	if(argc < 3){
		fprintf(stderr,"%s<addr><PORT>",argv[0]);
	}

    // 创建套接字
    fd = socket(AF_INET, SOCK_STREAM, 0);
    if(fd < 0){
        perror("socket"); 
        exit(0); 
    }

    // 设置地址结构体
    addr.sin_family = AF_INET; // 使用IPv4协议
    addr.sin_port = htons(atoi(argv[2])); // 设置端口号,atoi()将字符串转换为整数
	if(inet_aton(argv[1],&addr.sin_addr)==0){//inet_aton()函数将字符串形式的IP地址转换为网络字节序的二进制形式
		fprintf(stderr,"Invalid address\n");
		exit(EXIT_FAILURE);
	}

    // 绑定通信结构体
    if(bind(fd, (struct sockaddr *)&addr, sizeof(addr) ) == -1){
        perror("bind"); 
        exit(0); 
    }

    // 设置套接字为监听模式
    if(listen(fd, BACKLOG) == -1){
        perror("listen"); 
        exit(0); 
    }

    // 接受客户端的连接请求,生成新的用于和客户端通信的套接字
    newfd = accept(fd, NULL, NULL);
    if(newfd < 0){
        perror("accept"); 
        exit(0);
    }
    
    /*循环接收*/
	while(1){
		memset(buf,0,BUFSIZ);
		ret = read(newfd,buf,BUFSIZ);
		if(ret < 0){
			perror("read");
			exit(0);
		}
		else if(ret == 0)
			break;
		else
			printf("buf = %s\n",buf);
	}
	close(newfd);
    close(fd); // 关闭套接字
    return 0; 
}

示例-客户端

TCP_socket2.c

#include <stdio.h> // 引入标准输入输出库
#include <sys/socket.h> // 引入套接字库
#include <sys/types.h> // 引入类型定义库
#include <stdlib.h> // 引入标准库
#include <arpa/inet.h> // 引入互联网协议库
#include <unistd.h> // 引入Unix标准库
#include <string.h>


#define PORT 5001 // 定义端口号为5001
#define BACKLOG 5 // 定义最大连接数为5
#define STR "Hello World!" // 定义要发送的字符串为"Hello World!"

int main(int argc, char *argv[]) // 主函数,参数为命令行参数个数和参数列表
{
  int fd; // 定义文件描述符变量
  struct sockaddr_in addr; // 定义IPv4地址结构体
  char buf[BUFSIZ] = {}; //BUFSIZ 8142

	if(argc < 3){
		fprintf(stderr,"%s<addr><port>\n",argv[0]);
		exit(0);
	}

  // 创建套接字
  fd = socket(AF_INET, SOCK_STREAM, 0);
  if(fd < 0){
      perror("socket"); // 如果创建失败,打印错误信息
      exit(0); // 退出程序
  }

  // 设置地址结构体
	addr.sin_family = AF_INET; // 使用IPv4协议
  addr.sin_port = htons(atoi(argv[2])); // 设置端口号,atoi()将字符串转换为整数
	if(inet_aton(argv[1],&addr.sin_addr)==0){//inet_aton()函数将字符串形式的IP地址转换为网络字节序的二进制形式
		fprintf(stderr,"Invalid address\n");
		exit(EXIT_FAILURE);
	}    

  // 向服务端发起连接请求
  if(connect(fd, (struct sockaddr *)&addr, sizeof(addr) ) == -1){
      perror("connect"); 
      exit(0); 
  }
  /*循环发送*/
  while(1){
		printf(">");
		fgets(buf,BUFSIZ,stdin);
		write(fd,buf,strlen(buf));
	}

  // 关闭套接字
  close(fd);

  return 0; // 返回0表示程序正常结束
}

在这里插入图片描述

通信成功

如果结束程序,再次运行服务端程序,会出现报错如下(地址已经被使用)

在这里插入图片描述

解决办法:

在程序中加入如下程序段:

/*地址快速重用*/
int flag=1,len= sizeof (int); 
if ( setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, len) == -1) { 
	perror("setsockopt"); 
	exit(1); 
} 

5.TCP多进程并发

示例-服务端

my_sever.c

#include <stdio.h> // 引入标准输入输出库
#include <sys/socket.h> // 引入套接字库
#include <sys/types.h> // 引入类型定义库
#include <stdlib.h> // 引入标准库
#include <arpa/inet.h> // 引入网络地址库
#include <unistd.h> // 引入Unix系统调用库
#include <string.h> // 引入字符串处理库
#include <strings.h> // 引入字符串操作库
#include <signal.h> // 引入信号处理库
#include <sys/wait.h> // 引入进程等待库

#define BACKLOG 5 // 定义最大连接数为5

void ClinetHandle(int newfd); // 客户端处理函数

/*信号处理函数,防止出现僵尸进程*/
void SigHandle(int sig){ 
	if(sig == SIGCHLD){ // 如果接收到SIGCHLD信号
		printf("client exited\n"); // 打印客户端退出信息
		wait(NULL); // 等待子进程结束
	}
}

/*主函数*/
int main(int argc, char *argv[])
{
	int fd, newfd; // 定义文件描述符变量
	struct sockaddr_in addr, clint_addr; // 定义套接字地址结构体
	socklen_t addrlen = sizeof(clint_addr); // 定义地址长度变量

#if 0
	struct sigaction act; // 定义信号处理结构体
	act.sa_handler = SigHandle; // 设置信号处理函数
	act.sa_flags = SA_RESTART; // 设置信号处理标志
	sigemptyset(&act.sa_mask); // 清空信号屏蔽集
	sigaction(SIGCHLD, &act, NULL); // 注册信号处理函数
#else
	signal(SIGCHLD, SigHandle); // 注册信号处理函数
#endif

	pid_t pid; // 定义进程ID变量
	
	if(argc < 3){ // 如果参数个数小于3
		fprintf(stderr, "%s<addr><port>\n", argv[0]);
		exit(0); 
	}

	/*创建套接字*/
	fd = socket(AF_INET, SOCK_STREAM, 0); // 创建TCP套接字
	if(fd < 0){ 
		perror("socket"); 
	}
	addr.sin_family = AF_INET; // 设置地址族为IPv4
	addr.sin_port = htons( atoi(argv[2]) ); // 设置端口号
	if ( inet_aton(argv[1], &addr.sin_addr) == 0) { // 如果转换IP地址失败
		fprintf(stderr, "Invalid address\n"); 
		exit(EXIT_FAILURE); 
	}

	/*地址快速重用*/
	int flag=1,len= sizeof (int); 
	if ( setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, len) == -1) { // 如果设置失败
		      perror("setsockopt"); 
			        exit(1); 
	} 
	/*绑定通信结构体*/
	if(bind(fd, (struct sockaddr *)&addr, sizeof(addr) ) == -1){ // 如果绑定失败
		perror("bind"); 
		exit(0); 
	}
	/*设置套接字为监听模式*/
	if(listen(fd, BACKLOG) == -1){ 
		perror("listen"); 
		exit(0); 
	}
	while(1){ // 循环监听连接请求
		/*接受客户端的连接请求,生成新的用于和客户端通信的套接字*/
		newfd = accept(fd, (struct sockaddr *)&clint_addr, &addrlen); // 接受连接请求
		if(newfd < 0){ 
			perror("accept"); 
			exit(0); 
		}
        /*打印客户端地址和端口号*/ 
        // inet_ntoa()将网络字节序转换为点分十进制IP地址格式的字符串;
        // ntohs()将一个16位数从网络字节顺序转换为主机字节顺序
		printf("addr:%s port:%d\n", inet_ntoa(clint_addr.sin_addr), ntohs(clint_addr.sin_port) ); 
		if( (pid = fork() ) < 0){ 
			perror("fork"); 
			exit(0); 
		}else if(pid == 0){ // 如果当前进程是子进程
			close(fd); // 关闭父进程的文件描述符
			ClinetHandle(newfd); // 处理客户端请求
			exit(0); 
		}
		else
			close(newfd); // 关闭子进程的文件描述符
	}
	close(fd); // 关闭服务器套接字
	return 0; 
}

/*客户端处理函数*/
void ClinetHandle(int newfd){
	int ret; // 定义返回值变量
	char buf[BUFSIZ] = {}; // 定义缓冲区数组并初始化为0
	while(1){ // 循环读取客户端数据
		//memset(buf, 0, BUFSIZ); // 清空缓冲区数组
		bzero(buf, BUFSIZ); // 使用bzero函数清空缓冲区数组
		ret = read(newfd, buf, BUFSIZ); // 从客户端读取数据
		if(ret < 0) 
		{
			perror("read"); 
			exit(0); 
		}
		else if(ret == 0) // 如果读取到EOF标志
			break; // 跳出循环
		else
			printf("buf = %s\n", buf); // 打印读取到的数据
	}
	close(newfd); // 关闭与客户端的连接
}

示例-客户端

my_client.c

#include <stdio.h> // 引入标准输入输出库
#include <sys/socket.h> // 引入套接字库
#include <sys/types.h> // 引入类型定义库
#include <stdlib.h> // 引入标准库
#include <arpa/inet.h> // 引入互联网协议族库
#include <unistd.h> // 引入Unix标准库
#include <string.h> // 引入字符串处理库

#define BACKLOG 5 // 定义最大连接数为5

int main(int argc, char *argv[]) // 主函数,参数为命令行参数个数和参数列表
{
	int fd; // 定义文件描述符变量
	struct sockaddr_in addr; // 定义套接字地址结构体
	char buf[BUFSIZ] = {}; // 定义缓冲区数组并初始化为0

	if(argc < 3){ // 如果参数个数小于3
		fprintf(stderr, "%s<addr><port>\n", argv[0]); // 打印错误信息
		exit(0); // 退出程序
	}

	/*创建套接字*/
	fd = socket(AF_INET, SOCK_STREAM, 0); // 创建TCP套接字
	if(fd < 0){ 
		perror("socket"); 
		exit(0); 
	}

	addr.sin_family = AF_INET; // 设置地址族为IPv4
	addr.sin_port = htons( atoi(argv[2]) ); // 设置端口号
	if ( inet_aton(argv[1], &addr.sin_addr) == 0) { 
		fprintf(stderr, "Invalid address\n"); 
		exit(EXIT_FAILURE); 
	}

	/*向服务端发起连接请求*/
	if(connect(fd, (struct sockaddr *)&addr, sizeof(addr) ) == -1){ // 如果连接失败
		perror("connect"); 
		exit(0); 
    }
	while(1){ // 循环读取用户输入的数据
		printf("Input->"); // 提示用户输入
		fgets(buf, BUFSIZ, stdin); // 从标准输入读取数据到缓冲区
		write(fd, buf, strlen(buf) ); // 将缓冲区的数据发送给服务器
	}
	close(fd); // 关闭套接字
	return 0; 
}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

人工智能芯片封装技术及应用趋势分析

简介人工智能&#xff08;AI&#xff09;、物联网&#xff08;IoT&#xff09;和大数据的融合正在开创全新的智能时代&#xff0c;以智能解决方案改变各行各业。人工智能芯片在支持人工智能学习和推理计算方面发挥着非常重要的作用&#xff0c;可实现各行各业的多样化应用。 本…

代码随想录算法训练营day29|491.递增子序列、46.全排列、47.全排列II

递增子序列 491. 非递减子序列 - 力扣&#xff08;LeetCode&#xff09; 非递减子序列&#xff0c;则答案的子集中&#xff0c;需保持下一个元素大于等于前一个元素的顺序&#xff0c;由于题目中指出&#xff0c;所有的子序列长度需大于等于2&#xff0c;考虑当条件为path.siz…

ChatTTS 保姆级教程从入门到精通

ChatTTS 保姆级教程从入门到精通 博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能…

DP动态规划(上)

文章目录 动态规划基本概念斐波那契数列问题C 实现Python 实现Java 实现 迷你结C、Python和Java在实现动态规划时有哪些性能差异&#xff1f;迷你结哪种语言在动态规划中更适合大规模数据处理?迷你结C有哪些知名的库适用于动态规划和大数据处理?动态规划辅助库大数据处理库 迷…

React中常见的面试题

本文是结合实践中和学习技术文章总结出来的笔记(个人使用),如有雷同纯属正常((✿◠‿◠)) 喜欢的话点个赞,谢谢! 1. 约束性组件与非约束性组件 1.1. 非约束性组件 非约束性组件其实就是不能控制状态的组件,比如: <input type"text" defaultValue"123&qu…

JVM之【字节码/Class文件/ClassFile 内容解析】

说在前面的话 Java语言:跨平台的语言(write once,run anywhere) 当Java源代码成功编译成字节码后&#xff0c;如果想在不同的平台上面运行&#xff0c;则无须再次编译这个优势不再那么吸引人了。Python、PHP、Perl、Ruby、Lisp等有强大的解释器。跨平台似乎已经快成为一门语言…

力扣hot100:138. 随机链表的复制(技巧,数据结构)

LeetCode&#xff1a;138. 随机链表的复制 这是一个经典的数据结构题&#xff0c;当做数据结构来学习。 1、哈希映射 需要注意的是&#xff0c;指针也能够当做unordered_map的键值&#xff0c;指针实际上是一个地址值&#xff0c;在unordered_map中&#xff0c;使用指针的实…

C++--DAY3

思维导图 设计一个Per类&#xff0c;类中包含私有成员:姓名、年龄、指针成员身高、体重&#xff0c;再设计一个Stu类&#xff0c;类中包含私有成员:成绩、Per类对象p1&#xff0c;设计这两个类的构造函数、析构函数。 #include <iostream>using namespace std; class …

小孩天赋是怎样炼成的 懂孩子比爱孩子更重要 详细天赋评估列表 观察非常细致 培养领导能力的方法

懂孩子比爱孩子更重要 “懂孩子比爱孩子更重要&#xff0c;懂才更准确的去爱” 这句话说得很有道理。理解孩子的内心世界、需求和独特个性&#xff0c;比单纯地给予爱更加重要。以下是一些解释&#xff1a; 理解孩子的需要&#xff1a;懂孩子意味着理解他们的需求、恐惧、欢乐…

SVN安装详细教程

&#x1f4d6;SVN安装详细教程 ✅1. 下载✅2. 安装✅3. 使用 ✅1. 下载 官方地址&#xff1a;https://tortoisesvn.net/downloads.html 123云盘地址&#xff1a;https://www.123pan.com/s/4brbVv-rsoWA.html ✅2. 安装 双击TortoiseSVN-1.14.6.29673-x64-svn-1.14.3.msi安装…

【微信小程序】模板语法

数据绑定 对应页面的 js 文件中 定义数据到 data 中&#xff1a; 在页面中使用 {{}} 语法直接使用&#xff1a; 事件绑定 事件触发 常用事件&#xff1a; 事件对象的属性列表&#xff08;事件回调触发&#xff0c;会收到一个事件对象 event&#xff0c;它的详细属性如下&…

智慧医疗新纪元:可视化医保管理引领未来

在数字化浪潮席卷全球的今天&#xff0c;我们的生活正在经历前所未有的变革。其中&#xff0c;智慧医保可视化管理系统就像一股清新的风&#xff0c;为医疗保障领域带来了全新的活力与可能。 想象一下&#xff0c;在繁忙的医院里&#xff0c;患者和家属不再需要为了查询医保信息…

GPT-4 Turbo 和 GPT-4 的区别

引言 人工智能&#xff08;AI&#xff09;领域的发展日新月异&#xff0c;OpenAI 的 GPT 系列模型一直是这一领域的佼佼者。GPT-4 和 GPT-4 Turbo 是目前市场上最先进的语言模型之一。本文将详细探讨 GPT-4 和 GPT-4 Turbo 之间的区别&#xff0c;以帮助用户更好地理解和选择适…

NSIS 安装包默认支持的参数

NSIS 安装包默认支持的参数 NSIS 制作的安装包默认支持 /NCRC、/S、/D 三个参数&#xff0c;详见下文 3.2 Installer Usage&#xff08;来自 Command Line Usage&#xff09;。 以上三个参数对应的功能分别为禁止 CRC 校验、静默安装、设置安装路径&#xff0c;这三个功能不需…

数据资产入表-数据治理-标签设计标准

前情提要&#xff1a;数据价值管理是指通过一系列管理策略和技术手段&#xff0c;帮助企业把庞大的、无序的、低价值的数据资源转变为高价值密度的数据资产的过程&#xff0c;即数据治理和价值变现。上一讲介绍了数据清洗标准设计的基本逻辑和思路。 上一讲介绍了其他的通用标…

PyTorch 相关知识介绍

一、PyTorch和TensorFlow 1、PyTorch PyTorch是由Facebook开发的开源深度学习框架&#xff0c;它在动态图和易用性方面表现出色。它以Python为基础&#xff0c;并提供了丰富的工具和接口&#xff0c;使得构建和训练神经网络变得简单快捷。 发展历史和背景 PyTorch 是由 Fac…

几何裁剪技术在AI去衣应用中的革新作用

引言&#xff1a; 随着人工智能技术的飞速发展&#xff0c;其在图像处理领域的应用也日益广泛。特别是在AI去衣技术中&#xff0c;几何裁剪技术扮演着至关重要的角色。本文将深入探讨几何裁剪技术在AI去衣中的应用及其带来的影响。 一、几何裁剪技术概述 几何裁剪技术是一种基…

【python】python租房数据分析可视化(源码+数据+报告)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

completefuture造成的rpc重试事故

前言 最近经历了一个由于 completefuture 的使用&#xff0c;导致RPC重试机制触发而引起的重复写入异常的生产bug。复盘下来&#xff0c;并非是错误的使用了completefuture&#xff0c;而是一些开发时很难意识到的坑。 背景 用户反馈通过应用A使用ota批量升级设备时存在概率…

北航数据结构与程序设计第四次作业选填题复习

首先都是线性的&#xff0c;线性包括顺序和链式&#xff0c;栈和队都可以用两种方式实现。栈只能存于栈顶取于栈顶&#xff0c;队列先进先出&#xff0c;因此存取点是固定的。 函数栈帧创建原理 画图即可。 A.显然不行&#xff0c;5如果第一个出来说明5是最后一个进的&#xf…