网络编程 总结三

一、并发服务器模型

【1】 循环服务器

1>一次只能处理一个客户端的请求,等待这个客户端退出后,才能处理下一个客户端

2>缺点:循环服务器所处理的客户端不能有耗时操作

//*****模型******

sfd = socket();
bind();
listen();
while(1)
{
    newfd = accept();
    while(1)
    {
        recv();
        send();
    }
    close(newfd);
}
close(sfd);

【2】并发服务器

1>可以同时处理多个客户端请求

2>父进程 / 主线程专门用于负责连接,创建子进程 / 分支线程用来与客户端交互

~多线程:

//*****模型******

sfd = socket();
bind();
listen();
while(1)
{
    newfd = accept();

    pthread_create();

    pthread_detach(tid);

}

close(sfd);

void * callBack(void * arg)

{

      recv();
      send();
      close(newfd);

      pthread_exit(NULL);
}

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>
#include<sys/wait.h>
#include<signal.h>
#include<stdlib.h>
#include<pthread.h>

#define ERR_MSG(msg) do{\
	fprintf(stderr,"liine %d",__LINE__);\
	perror(msg);\
}while(0)

#define IP "192.168.0.79"  //本机IP 
#define PORT 6666          // 1024-49151

void* deal_cli_msg(void *arg);
//需要传递给线程处理函数的参数
struct cli_msg
{
	int newfd;
	struct sockaddr_in cin;
};

int main(int argc, const char *argv[])
{
	//创建流式套接字
	int sfd = socket(AF_INET,SOCK_STREAM,0);
	if(sfd<0)
	{
		ERR_MSG("socket");
		return -1;
	}
	printf("sfd=%d\n",sfd);
	//允许端口快速重用
	int reuse=1;
	if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))<0)
	{
		ERR_MSG("setsockopt");
		return -1;
	}
	//填充地址信息结构体
	//真是的地址信息结构体根据地址族制定  AF_INET: man 7 ip
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;//必须填 AF_INET
	sin.sin_port = htons(PORT);//端口号, 1024-49151
	sin.sin_addr.s_addr = inet_addr(IP);//本机IP,ifconfig
	//将IP和端口号绑定到套接字上
	if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
	{
		ERR_MSG("bind");
		return -1;
	}
	printf("bind sucess __%d__\n",__LINE__);

	//将套接字设置为被动监听状态,监听是否有客户端连接成功
	if(listen(sfd,128)<0)
	{
		ERR_MSG("listen");
		return -1;
	}
	printf("listen success __%d__\n",__LINE__);
	struct sockaddr_in cin;        // 存储连接成功的客户端地址信息  
	socklen_t addrlen = sizeof(cin);
	
	pthread_t tid;
	int newfd=-1;
	struct cli_msg info;
	while(1)
	{
		//阻塞函数,从已完成连接的队列头中获取一个客户端信息
		//该文件描述符才是与客户端通信的文件描述符
		newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen);
		if(newfd<0)
		{
			ERR_MSG("accept");
			return -1;
		}
		printf("[%s:%d] newfd=%d 连接成功 __%d__\n",\
			inet_ntoa(cin.sin_addr),ntohs(cin.sin_port), newfd,__LINE__);
		
		info.newfd=newfd;
		info.cin=cin;
		//能运行到当前位置
		if(pthread_create(&tid,NULL,deal_cli_msg,&info)!=0)
		{
			fprintf(stderr,"line:%d pthread_createfailed\n",__LINE__);
			return -1;
		}
		pthread_detach(tid); //分离线程
	}
	close(sfd);
	return 0;
}

void* deal_cli_msg(void *arg)
{
	int newfd=((struct cli_msg*)arg)->newfd;
	struct sockaddr_in cin=((struct cli_msg*)arg)->cin;
	char buf[128]="";
	ssize_t res=0;
	while(1)
	{
		//接收
		res=recv(newfd,buf,sizeof(buf),0);
		if(res<0)
		{
			ERR_MSG("recv");
			break;
		}
		else if(0==res)
		{
			printf("[%s:%d] newfd=%d 连接成功 __%d__\n",\
			inet_ntoa(cin.sin_addr),ntohs(cin.sin_port), newfd,__LINE__);
			break;
		}
		printf("[%s:%d] newfd=%d 连接成功 __%d__\n",\
			inet_ntoa(cin.sin_addr),ntohs(cin.sin_port), newfd,__LINE__);
		//发送
		strcat(buf,"*_*");
		if(send(newfd,buf,sizeof(buf),0)<0)
		{
			ERR_MSG("send");
			break;
		}
		printf("send sucess\n");
	}
	close(newfd);
	pthread_exit(NULL);
}

二、IO模型

【1】阻塞IO

创建套接字文件描述符后,默认处于阻塞IO模式 (read, write, recv, send, recvfrom, sendto)

【2】阻塞IO

1>防止进程阻塞在IO函数上,但是如果想要获取到有效数据,需要轮询

2>当一个程序使用了非阻塞IO模式的套接字,那么它需要使用一个循环来不停地判断该文件描述符是否有数据可读,称之为 polling

3>应用程序不停地polling 内核监测IO 事件是否产生, CPU消耗高

1)fcntl 函数

 【3】信号驱动IO

1>异步通信方式

2>信号驱动IO是指:预先告诉内核,某个文件描述符发生IO事件的时候,内核会通知相关进程: SIGIO

3> 对于TCP而言,信号驱动IO对TCP没有用,因为信号产生过于频繁,而且不能区分是哪个文件描述符发送的

【4】IO 多路复用(重点)

1>进程中如果同时需要处理多路输入输出流,在使用单进程单线程的情况下,同时处理多个输入输出请求

2>在无法用多进程多线程,可以选择用IO多路复用

3>由于不需要创建建新的进程和线程,减少系统的资源开销,减少上下文切换的次数

4>允许同时对多个IO进行操作,内核一旦发现进程执行一个或多个IO 事件,会通知该进程。

1)select  

 模型:

 代码:

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>
#include<sys/time.h>
#include<sys/select.h>

#define ERR_MSG(msg) do{\
	fprintf(stderr,"liine %d",__LINE__);\
	perror(msg);\
}while(0)

#define IP "192.168.0.211"  //本机IP 
#define PORT 6666          // 1024-49151

int main(int argc, const char *argv[])
{
	//创建流式套接字
	int sfd = socket(AF_INET,SOCK_STREAM,0);
	if(sfd<0)
	{
		ERR_MSG("bind");
		return -1;
	}
	printf("bind sucess __%d__\n",__LINE__);

	//允许端口快速使用
	int reuse=-1;
	if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))<0)
	{
		ERR_MSG("setsockopt");
		return -1;
	}
	printf("允许端口快速重用成功\n");

	struct sockaddr_in sin;
	sin.sin_family =AF_INET;
	sin.sin_port=htons(PORT);//端口号
	sin.sin_addr.s_addr=inet_addr(IP);//本机号

	if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
	{
		ERR_MSG("bind");
		return -1;
	}
	printf("bind sucess__%d__\n",__LINE__);

	//将套接字设置为被动监听状态,监听是否有客户端连接成功
	if(listen(sfd,128)<0)
	{
		ERR_MSG("listen");
		return -1;
	}
	printf("listen success __%d__\n",__LINE__);

	//设置一个读集合
	fd_set  readfds,tmpfds;

	//由于readfds中需要防止要检测的文件描述符,所以不能让他是随机值
	//所以需要将readfds清空
	FD_ZERO(&readfds);
	FD_ZERO(&tmpfds);

	//将需要的文件描述符添加到集合中
	FD_SET(0,&readfds);
	FD_SET(sfd,&readfds);

	int s_res=0;
	char buf[128]="";
	struct sockaddr_in cin;        // 存储连接成功的客户端地址信息  
	socklen_t addrlen = sizeof(cin);

	struct sockaddr_in saveCin[1024-4];//另存客户端地址信息,0,1,2,sfd不可能有对应的客户端
	int newfd =-1;
	ssize_t res=0;
	int maxfd=sfd;//最大文件描述符

	while(1)
	{
		tmpfds=readfds;
		s_res=select(maxfd+1,&tmpfds,NULL,NULL,NULL);
		if(s_res<0)
		{
			ERR_MSG("select");
			return -1;
		}
		else if(0==res)
		{
			printf("time out\n");
			return -1;
		}

		//能运行到当前位置,则代表有文件描述符准备就绪
		//走触发事件的文件描述符对应的处理函数

		//当前集合中有文件描述符准备就绪了
		//当准备就绪,集合会只保留0
		//当sfd准备就绪,集合就会只保留sfd
		//当0和sfd都准备就绪,集合中保留0和sfd

		for(int i=0;i<=maxfd;i++)
		{
			if(!FD_ISSET(i,&tmpfds))//如果不在集合中,则直接往后继续变量
			{
				continue;
			}
			//能运行到当前位置,则说明i代表的文件描述符在tmpfds中
			//要判断i所代表的文件描述符需要走什么对应的函数
			if(0==i)
			{
				printf("触发键盘输入事件>>");
				int sndfd=-1;
				res=scanf("%d %s",&sndfd,buf);
				while(getchar()!=10);
				if(res!=2)
				{
					fprintf(stderr,"请输入正确格式:int string\n");
					continue;
				}
				//能运行到当前位置,则代表输入的格式整数
				if(sndfd<=sfd||sndfd>=1024||!FD_ISSET(sndfd,&readfds))
				{
					fprintf(stderr,"sndfd=%d文件描述符\n",sndfd);
					continue;
				}
				if(send(sndfd,buf,sizeof(buf),0)<0)
				{
					ERR_MSG("send");
					return -1;
				}
			}
			else if(sfd==i)
			{	
				printf("触发客户端连接事件>>");
				fflush(stdout);
				int newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen);
				if(newfd<0)
				{
					ERR_MSG("accept");
					return -1;
				}
				printf("[%s:%d] newfd=%d 连接成功 __%d__\n",\
						inet_ntoa(cin.sin_addr),ntohs(cin.sin_port), newfd,__LINE__);

				saveCin[newfd-4]=cin;

				//将newfd添加到读集合中
				FD_SET(newfd,&readfds);

				//更新maxfd
				maxfd=maxfd>newfd?maxfd:newfd;

			}
			else
			{
				bzero(buf,sizeof(buf));
				//接收
				res=recv(i,buf,sizeof(buf),0);
				if(res<0)
				{
					ERR_MSG("recv");
					return -1;
				}
				else if(0==res)
				{
					printf("[%s:%d] newfd=%d 连接成功 __%d__\n",\
							inet_ntoa(cin.sin_addr),ntohs(cin.sin_port), newfd,__LINE__);

					//关闭文件描述符
					close(i);
					//从集合中剔除该文件描述符
					FD_CLR(i,&readfds);

					//更新maxfd
					//从目前最大的文件描述符中往小的判断
					int j=0;
					for(int j=maxfd;j>=0;j--)
					{
						if(FD_ISSET(j,&readfds))
						{
							maxfd=j;
							break;
						}
					}
					if(j<0)
						maxfd=-1;

					continue;
				}
				printf("[%s:%d] newfd=%d 连接成功 __%d__\n",\
						inet_ntoa(cin.sin_addr),ntohs(cin.sin_port), newfd,__LINE__);

				strcat(buf,"*_*");
				if(send(i,buf,sizeof(buf),0)<0)
				{
					ERR_MSG("send");
					return -1;
				}
				printf("send sucess\n");
			}
		}
	}
	close(sfd);
	return 0;
}

2)poll

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>
#include<sys/time.h>
#include<sys/select.h>
#include<poll.h>

#define ERR_MSG(msg) do{\
	fprintf(stderr,"liine %d",__LINE__);\
	perror(msg);\
}while(0)

#define IP "192.168.0.211"  //本机IP 
#define PORT 6666          // 1024-49151

int main(int argc, const char *argv[])
{
	//创建流式套接字
	int sfd = socket(AF_INET,SOCK_STREAM,0);
	if(sfd<0)
	{
		ERR_MSG("bind");
		return -1;
	}
	printf("bind sucess __%d__\n",__LINE__);

	//将套接字设置为被动监听状态,监听是否有客户端连接成功
	if(listen(sfd,128)<0)
	{
		ERR_MSG("listen");
		return -1;
	}
	printf("listen success __%d__\n",__LINE__);

	//设置一个读集合
	fd_set  readfds,tmpfds;

	//由于readfds中需要防止要检测的文件描述符,所以不能让他是随机值
	//所以需要将readfds清空
	FD_ZERO(&readfds);
	FD_ZERO(&tmpfds);

	//将需要的文件描述符添加到集合中
	FD_SET(0,&readfds);
	FD_SET(sfd,&readfds);

	int s_res=0;
	char buf[128]="";
	struct sockaddr_in cin;        // 存储连接成功的客户端地址信息  
	socklen_t addrlen = sizeof(cin);

	int newfd =-1;
	ssize_t res=-1;
	int maxfd=sfd;

	while(1)
	{
		
		tmpfds=readfds;
		s_res=select(maxfd+1,&tmpfds,NULL,NULL,NULL);
		if(s_res<0)
		{
			ERR_MSG("select");
			return -1;
		}
		if(0==res)
		{
			printf("time out\n");
			return -1;
		}
		
		//能运行到当前位置,则代表有文件描述符准备就绪
		//走触发事件的文件描述符对应的处理函数

		for(int i=0;i<=maxfd;i++)
		{
			if(!FD_ISSET(i,&tmpfds))//如果不在集合中,则直接往后继续变量
			{
				continue;
			}
		//能运行到当前位置,则说明i代表的文件描述符在tmpfds中
		//要判断i所代表的文件描述符需要走什么对应的函数
			if(0==i)
			{
				printf("触发键盘输入事件>>");
				fgets(buf,sizeof(buf),stdin);
				buf[strlen(buf)-1]=0;
				printf("%s\n",buf);
			}
			else if(sfd==1)
			{	
				printf("触发客户端连接事件>>");
				fflush(stdout);
				int newfd=accept(sfd,(struct sockaddr*)&cin,&addrlen);
				if(newfd<0)
				{
					ERR_MSG("accept");
					return -1;
				}
				printf("[%s:%d] newfd=%d 连接成功 __%d__\n",\
					inet_ntoa(cin.sin_addr),ntohs(cin.sin_port), newfd,__LINE__);
	
				//将newfd添加到读集合中
				FD_SET(newfd,&readfds);

				//更新maxfd
				maxfd=maxfd>newfd?maxfd:newfd;

			}
			else
			{
				bzero(buf,sizeof(buf));
			//接收
				res=recv(i,buf,sizeof(buf),0);
				if(res<0)
				{
					ERR_MSG("recv");
					return -1;
				}
				else if(0==res)
				{
					printf("[%s:%d] newfd=%d 连接成功 __%d__\n",\
						inet_ntoa(cin.sin_addr),ntohs(cin.sin_port), newfd,__LINE__);
				
					//关闭文件描述符
					close(i);
					//从集合中剔除该文件描述符
					FD_CLR(i,&readfds);
				
					//更新maxfd
					//从目前最大的文件描述符中往小的判断
					int j=0;
					for(int j=maxfd;j>=0;j--)
					{
						if(FD_ISSET(j,&readfds))
						{
							maxfd=j;
							break;
						}
					}
					if(j<0)
						maxfd=-1;

					continue;
				}
				printf("[%s:%d] newfd=%d 连接成功 __%d__\n",\
					inet_ntoa(cin.sin_addr),ntohs(cin.sin_port), newfd,__LINE__);

				strcat(buf,"*_*");
				if(send(i,buf,sizeof(buf),0)<0)
				{
					ERR_MSG("send");
					return -1;
				}
				printf("send sucess\n");
			}
		}
	}
	return 0;
}

三、函数库

【1】库的概念

1>库是一个二进制可执行文件,相比较于二进制可执行程序,库是不能单独运行的。

        a. 库中存放的都是功能函数,只能放功能函数

        b. 库中不允许存放main函数

        c.库是写好的,可以被服用的功能代码

2>库需要被载入到内存中使用

3>每个操作系统都有自己得库,不兼容

库的分类:

静态库、动态库

 【2】静态库

1)静态库原理:通过静态库封装的函数,在程序编译到链接库步骤的时候,会将函数继承到可执行程序中。

优点: 1>程序运行的时候,与静态库没有任何关系,方便移植

            2>静态库的运行效率会更快

缺点:1>程序的更新部署比较麻烦

           2>大、存储的时候浪费磁盘空间,加载运行的时候浪费内存空间

2)静态库地 制作指令

 步骤:

1>分文件,将功能函数与主函数分离,func.c  main.c

2>给功能函数写头文件:func.h

3>将main.c 和 func.c 联合编译,测试分文件是否成功

4>用上述指令将func.c 封装成静态库

5>注意:libxxx.a  ,  xxx才是库的名字

3)静态库的使用

【3】动态库(共享库)

 1)动态库的原理:动态库把库函数的链接步骤推迟到程序运行的时候,当程序执行到库函数的时候,会去找动态库函数

1>如果在内存中不存在该动态库函数,则会将动态库函数加载到内存中执行

2>如果在内存中存在该动态库函数,则直接调用,不会加载第二份

3>所以内存中会仅存在一份动态库函数

优点:

1>小、存储的时候节省磁盘空间,运行的时候节省内存空间

2>程序的更新部署比较方便,不需要重新编译可执行程序

缺点:

1>程序运行的时候,如果没有找到动态库,则会导致程序崩溃,所以用动态库生成二进制程序移植性低

2>运行效率低

2)动态库的制作指令

  步骤:

1>分文件,将功能函数与主函数分离,func.c  main.c

2>给功能函数写头文件:func.h

3>将main.c 和 func.c 联合编译,测试分文件是否成功

4>用上述指令将func.c 封装成静态库

5>注意:libxxx.so  ,  xxx才是库的名字

3)动态库的使用

 4)动态库的环境变量配置

1> 将动态库移动到 / lib/或者 /usr/lib 目录下

        a. sudo mv ./libmyfunc.so /usr/lib/

        b. sudo mv libmyfunc.so/lib/

2>配置环境变量:LD_LIBRARY_PATH

 3>修改环境变刘昂的配置文件

        a. cd / ec/ld.so.conf.d/

        b. sudo touch my.conf   创建一个 .conf结尾的文件

        c. sudo vim my.conf

        d. 将动态库所在的文件夹的绝对路径填写进去,注意一行只能填写一个动态库的绝对路径

        e. 保存退出后,执行sudo ldconfig 刷新环境变量

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

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

相关文章

js 操作数组内容

js 操作数组内容 数组添加元素&#xff08;更改原数组&#xff09; push和unshift会返回添加了新元素的数组长度 push从数组最后加入&#xff0c;unshift从数组最前面加入 const arr ["a", "b", "c"]; arr.push("d"); //返回4…

【高危】泛微 e-cology <10.57 存在 SQL注入漏洞(POC)(MPS-ndqt-0im5)

漏洞描述 泛微协同管理应用平台(e-cology)是一套企业大型协同管理平台。 泛微 e-cology 受影响版本存在SQL注入漏洞&#xff0c;未经授权的远程攻击者可通过发送特殊的HTTP请求来获取数据库的敏感信息。 漏洞名称GeoServer 存在 sql 注入漏洞漏洞类型SQL注入发现时间2023/4/…

解密PyTorch动态计算图:打破深度学习束缚的秘密武器

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

Linux 用户管理与文件权限

Linux 是一个多用户系统&#xff0c;它允许多个用户同时登陆主机&#xff0c;并为他们分配不同的资源和工作环境进行使用。当然&#xff0c;不同的用户都有文件的私有需求&#xff0c;所以设置不同用户文件的权限管理十分重要。 01 用户与用户组 Linux 中一般将文件访问权限的…

2023有哪些适合学生的蓝牙耳机?盘点四款适合学生的无线蓝牙耳机

随着时代的发展&#xff0c;人们更青睐于能够提升生活品质的产品。蓝牙耳机因为摆脱了线的束缚&#xff0c;使用体验会更好。接下来&#xff0c;我来给大家推荐几款适合学生用的无线蓝牙耳机&#xff0c;有需要的朋友可以当个参考。 一、南卡小音舱Lite2蓝牙耳机 参考价&…

【hello Linux】进程间通信——共享内存

目录 前言&#xff1a; 1. System V共享内存 1. 共享内存的理解 2. 共享内存的使用步骤 3. 共享内存的使用 1. 共享内存的创建 查看共享内存 2. 共享内存的释放 3. 共享内存的挂接 4. 共享内存的去挂接 4. 共享内存的使用示例 1. 两进程挂接与去挂接演示&#xff1a; 2. 两进程…

高性能:负载均衡

目录 什么是负载均衡 负载均衡分类 服务端负载均衡 服务端负载均衡——软硬件分类 服务端负载均衡——OSI模型分类 客户端负载均衡 负载均衡常见算法 七层负载均衡做法 DNS解析 反向代理 什么是负载均衡 将用户请求分摊&#xff08;分流&#xff09; 到不同的服务器上…

中移链控制台对接4A平台功能验证介绍

中移链控制台具备单独的注册登录页面&#xff0c;用户可通过页面注册或者用户管理功能模块进行添加用户&#xff0c;通过个人中心功能模块进行用户信息的修改和密码修改等操作&#xff0c;因业务要求&#xff0c;需要对中移链控制台的用户账号进行集中管理&#xff0c;统一由 4…

什么是分布式任务调度?怎样实现任务调度

通常任务调度的程序是集成在应用中的&#xff0c;比如&#xff1a;优惠卷服务中包括了定时发放优惠卷的的调度程序&#xff0c;结算服务中包括了定期生成报表的任务调度程序&#xff0c;由于采用分布式架构&#xff0c;一个服务往往会部署多个冗余实例来运行我们的业务&#xf…

C S S

目录 1.样式定义方式 1.1行内样式表 1.2内部样式表 1.3外部样式表 2.注解 3.选择器 3.1标签选择器 3.2 id选择器 3.3 类选择器 3.4 派生选择器 3.5 伪类选择器 链接伪类选择器&#xff1a; 位置伪类选择器&#xff1a; ​编辑 目标伪类选择器&#xff1a; 复合选…

Winform从入门到精通(37)——FolderBrowserDialog(史上最全)

文章目录 前言1、Name2、Description3、RootFolder4、SelectedPath5、ShowNewFolderButton前言 当需要获取一个可以通过用户自由选择路径的时候,这时候就需要FolderBrowserDialog控件 1、Name 获取FolderBrowserDialog对象 2、Description 用于指示对话框的描述,如下: …

Windows forfiles命令详解,Windows按时间搜索特定类型的文件。

「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 forfiles 一、结果输出格式二、按时间搜索三、搜索指定类型文件四、批量删除文件 forfile…

ATTCK v12版本战术介绍——防御规避(四)

一、引言 在前几期文章中我们介绍了ATT&CK中侦察、资源开发、初始访问、执行、持久化、提权战术理论知识及实战研究、部分防御规避战术&#xff0c;本期我们为大家介绍ATT&CK 14项战术中防御规避战术第19-24种子技术&#xff0c;后续会介绍防御规避其他子技术&#xf…

【Unity URP】Rendering Debugger和可视化MipMap方案

写在前面 最近开始学习Unity性能优化&#xff0c;是结合了《Unity游戏优化》这本书和教程《Unity性能优化》第叁节——静态资源优化(3)——纹理的基础概念一起学习。在学习纹理优化部分时候遇到了问题&#xff0c;固定管线下Unity的Scene窗口有一个可视化Mipmap的渲染模式&…

PMP/高项 05-项目进度管理

项目进度管理 概念 项目进度管理&#xff08;Schedule Management) 项目进度管理又叫项目工期管理&#xff08;Duration Management)或项目的时间管理(Time Management) 是一种为管理项目按时完成项目所需的各个过程 进度管理过程 规划进度管理 定义活动 排列活动顺序 估算活…

【LeetCode】 309.最佳买卖股票时机含冷冻期

309.最佳买卖股票时机含冷冻期&#xff08;中等&#xff09; 思路 状态定义 一、很容易想到四种状态&#xff1a; a.今天买入&#xff1b;b.今天卖出&#xff1b;c.昨天卖出&#xff0c;今天处于冷冻期&#xff0c;无法进行操作&#xff1b;d.今天不操作&#xff0c;处于持有…

太酷了,库昊

昨天晚上凌晨3点30&#xff0c;勇士和国王的第7场比赛开打。 在上一局在勇士主场干翻勇士后&#xff0c;国王队的信心倍增&#xff0c;他们用自己的节奏一次次击溃勇士&#xff0c;特别是今天的前两节&#xff0c;国王能能够回应勇士的进球&#xff0c;防守也更有侵略性。今天不…

图扑数字孪生助力智慧冷链园区实现大数据实时监控

前言 近年来&#xff0c;业界学者及企业就智慧冷链物流展开深入研究&#xff0c;2010 年 IBM 发布的《智慧的未来供应链》研究报告中提出智慧供应链概念&#xff0c;并由此延伸出智慧物流概念&#xff0c;即智慧物流是以信息化为依托并广泛应用物联网、人工智能、大数据、云计…

【2023 年第十三届 MathorCup 高校数学建模挑战赛】D 题 航空安全风险分析和飞行技术评估问题 27页论文及代码

【2023 年第十三届 MathorCup 高校数学建模挑战赛】D 题 航空安全风险分析和飞行技术评估问题 27页论文及代码 1 题目 D 题 航空安全风险分析和飞行技术评估问题 飞行安全是民航运输业赖以生存和发展的基础。随着我国民航业的快速发展&#xff0c;针对飞行安全问题的研究显得…

巧用千寻位置GNSS软件| 桥台锥坡放样操作技巧

桥台锥坡放样是针对道路施工中&#xff0c;路桥结合部桥台圆锥形斜坡面进行放样设计的专用程序。本期将给大家介绍如何使用千寻位置GNSS软件实现快速完成桥台锥坡放样。 点击【测量】->【桥台锥坡放样】&#xff0c;从线路库中选择桥台经过的线路或是单独增加桥台 锥坡放样&…