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

news2025/1/15 23:08:39

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; 
}

在这里插入图片描述

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

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

相关文章

【技巧】系统语音是英文 影刀如何设置中文-作者:【小可耐教你学影刀RPA】

写在前面 嘿哈&#xff01; 有些跨境或香港的小伙伴&#xff0c;可能需要使用英文操作界面的影刀 该功能目前还没有现成的可视化按钮&#x1f518; 但其实这个效果可以实现&#xff5e; 1、效果图 2、实现原理 %影刀安装目录%\ShadowBot-版本号\ShadowBot.Shell.dll.confi…

十四、返回Insert操作自增索引值

分为两部分&#xff0c;解析初始化和使用 拿含有selectkey标签的insert语句解析来说 解析部分 1.解析时看有没有selectkey标签&#xff0c;有的话先解析selectkey的内容&#xff0c;包括对其SQL的解析并封装成一个MappedStatement和创建KeyGenerator放入configuration中 2.解…

Android WebView上传文件/自定义弹窗技术,附件的解决方案

安卓内核开发 其实是Android的webview默认是不支持<input type"file"/>文件上传的。现在的前端页面需要处理的是&#xff1a; 权限 文件路径AndroidManifest.xml <uses-permission android:name"android.permission.WRITE_EXTERNAL_STORAGE"/&g…

NumPy应用(一)

NumPy学习篇1 NumPy是一个强大的Python库&#xff0c;它提供了高效的多维数组对象和各种用于数组操作的函数。以下是NumPy学习大纲&#xff0c;详细介绍了NumPy的核心功能和概念。 1. NumPy 简介 NumPy是一个用于处理多维数组的Python库&#xff0c;它提供了一个强大的数组对…

测试记录3:WLS2运行Linux界面

1.WLS1转到WLS2 &#xff08;1&#xff09;根据自己的平台&#xff0c;下载WLS2安装包 x64: https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi arm64: https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_arm64.msi &#xff08;2&…

高清矩阵是什么?

在数学中&#xff0c;矩阵是一个按照长方阵列排列的复数或实数集合&#xff0c;最早来自于方程组的系数及常数所构成的方阵。如图为m行n列的矩阵&#xff1a; 由此延伸可以想到矩阵图片是把一个三维空间分切成多个行和列的区域进行图像捕获&#xff0c;将捕获图像再进行拼合成为…

Spring系统学习 - Spring入门

什么是Spring&#xff1f; Spring翻译过来就是春天的意思&#xff0c;字面意思&#xff0c;冠以Spring的意思就是想表示使用这个框架&#xff0c;代表程序员的春天来了&#xff0c;实际上就是让开发更加简单方便&#xff0c;实际上Spring确实做到了。 官网地址&#xff1a;ht…

k8s 1.28.x 配置nfs

1.安装nfs&#xff0c;在每个节点上安装 yum install -y nfs-utils 2.创建共享目录(主节点上操作) mkdir -p /opt/nfs/k8s 3.编写NFS的共享配置 /opt/nfs/k8s *(rw,no_root_squash) #*代表对所有IP都开放此目录&#xff0c;rw是读写 4.启动nfs systemctl enable nfs-ser…

基于STC12C5A60S2系列1T 8051单片机实现串口调试助手软件与单片机相互发送数据的RS485通信功能

基于STC12C5A60S2系列1T 8051单片机实现串口调试助手软件与单片机相互发送数据的RS485通信功能 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机串口通信介绍STC12C5A60S2系列1T 8051单片机串口通信的结构基于STC12C5A60S2系列1T 8051单片机串口通信的特殊功…

Wireshark Lua插件入门

摘要 开发中经常通过抓包分析协议&#xff0c;对于常见的协议如 DNS wireshark 支持自动解析&#xff0c;便于人类的理解&#xff0c;对于一些私有协议&#xff0c;wireshark 提供了插件的方式自定义解析逻辑。 1 动手 废话少说&#xff0c;直接上手。 第一步当然是装上wiresh…

Java基础27,28(多线程,ThreadMethod ,线程安全问题,线程状态,线程池)

目录 一、多线程 1. 概述 2. 进程与线程 2.1 程序 2.2 进程 2.3 线程 2.4 进程与线程的区别 3. 线程基本概念 4.并发与并行 5. 线程的创建方式 方式一&#xff1a;继承Thread类 方式二&#xff1a;实现Runable接口 方式三&#xff1a;实现Callable接口 方式四&…

【wiki知识库】05.分类管理模块--后端SpringBoot模块

&#x1f4dd;个人主页&#xff1a;哈__ 期待您的关注 目录 一、&#x1f525;今日目标 二、☀SpringBoot代码修改 1.使用逆向工程生成Category表结构 2. 新增CategoryQueryParam 3.新增CategorySaveParam 4.新增CategotyQueryVo 三、&#x1f916;新增分类管理的相关接口…

数字化营销有哪些模式?企业采用数字营销方式有什么意义?

在当今快速发展的商业环境中&#xff0c;营销已经远远超越了传统的推广和销售概念&#xff0c;演变成一种复杂而全面的组织职能。随着信息技术的飞速发展&#xff0c;数字化营销应运而生&#xff0c;为企业与消费者之间的互动带来了革命性的改变。数字化营销不仅为企业提供了全…

为何PHP使用率 大幅度下降!需求量几乎为零!

用PHP的人越来越少的主要原因包括&#xff1a;市场竞争加剧、新技术的出现、性能和安全问题、以及开发者社区的变化。市场竞争加剧是其中一个突出的因素。随着Python、Node.js等现代编程语言的崛起&#xff0c;它们提供了更好的性能、更简洁的语法和更丰富的框架&#xff0c;逐…

【Text2SQL 论文】DBCopilot:将 NL 查询扩展到大规模数据库

论文&#xff1a;DBCopilot: Scaling Natural Language Querying to Massive Databases ⭐⭐⭐⭐ Code: DBCopilot | GitHub 一、论文速读 论文认为目前的 Text2SQL 研究大多只关注具有少量 table 的单个数据库上的查询&#xff0c;但在面对大规模数据库和数据仓库的查询时时却…

PPT文件损坏且无法读取怎样修复?文档损坏修复方法推荐

PPT文件已经成为工作汇报、商务演示、学术交流以及教学培训中最常用到的文件&#xff0c;随着文件数量的增多和存储设备的频繁使用&#xff0c;我们有时会遇到PPT文件损坏无法打开的情况&#xff0c;这无疑给工作和学习带来了极大的困扰。 PPT文件损坏的原因可能多种多样&#…

技术回眸一笑

回忆一下一年前的出差日记吧&#xff0c;那个时候真的是一点经验没有&#xff0c;干硬件又干软件&#xff0c;只能一步一步慢慢摸索&#xff0c;努力过后慢慢成长起来的吧。那个时候甚至开学了都没有正常报道&#xff0c;但是也收获了不少东西&#xff0c;并且也将作为我后来继…

【JS】详解reduce()方法及其奇技淫巧、性能

历史小剧场 或许到人生的最后一刻&#xff0c;他都不知道自己为什么会死&#xff0c;他永远也不会知道&#xff0c;在这个世界上&#xff0c;有着许多或明或暗的规则&#xff0c;必须适应&#xff0c;必须放弃原则&#xff0c;背离良知&#xff0c;与光同尘&#xff0c;否则你有…

PCL 抛物线回归拟合(Quadratic,二维)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 这里仍然是最小二乘法的应用,其推导过程如下所述: 1.二次函数模型: 其中,a、b 和 c 是需要确定的参数。 2.最小二乘法 假设我们有一组数据点 ( x 1 ​ , y

python中的函数概念

一段可以被重复使用的代码。 关于函数的定义 defdefine &#xff08;定义&#xff09; def 函数名&#xff08;形参列表&#xff09;&#xff1a;形参列表中&#xff0c;可以有多个形参&#xff0c;多个形参之间使用逗号分隔&#xff0c; 关于函数的调用 &#xff08;开始完…