linux下IO模及其特点及select

ftp实现

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

功能要求:

1.项目基于tcp连接进行编写

2.  客户端命令行传参,传入ip、port、文件路径,实现把指定目录下的文件发送到服务器

3.  服务器接收并放到指定文件路径

linux下IO模及其特点

场景假设

假设妈妈有一个孩子,孩子在房间里睡觉,妈妈需要及时获知孩子是否醒了,如何做?

1.  进到房间陪着孩子一起睡觉,孩子醒了会吵醒妈妈:不累,但是不能干别的了

2.  时不时进房间看一下:简单,空闲时间还能干点别的,但是很累

3.  妈妈在客厅干活,小孩醒了他会自己走出房门告诉妈妈:互不耽误

一、Linux下四种模型的特点: 

阻塞式IO    非阻塞式IO    信号驱动IO(了解)     IO多路复用(帮助TCP实现并发)

1、阻塞式IO(BIO)

特点:简单、常用、效率低

● 当程序调用某些接口时,如果期望的动作无法触发,那么进程会进入阻塞态(等待状态,让出CPU的调度),当期望动作可以被触发了,那么会被唤醒,然后处理事务。

● 重点理解相对于进程而言的影响;

● 阻塞I/O模式是最普遍使用的I/O模式,大部分程序使用的都是阻塞模式的I/O 。

● 前面学习的很多读写函数在调用过程中会发生阻塞。

阻塞I/O 模式是最普遍使用的I/O 模式,大部分程序使用的都是阻塞模式的I/O 。
缺省情况下(及系统默认状态),套接字建立后所处于的模式就是阻塞I/O 模式。
学习的读写函数在调用过程中会发生阻塞相关函数如下:
•读操作中的read、recv、recvfrom读阻塞--》需要读缓冲区中有数据可读,读阻塞解除
•写操作中的write、send写阻塞--》阻塞情况比较少,主要发生在写入的缓冲区的大小小于要写入的数据量的情况下,写操作不进行任何拷贝工作,将发生阻塞,一旦缓冲区有足够的空间,内核将唤醒进程,将数据从用户缓冲区拷贝到相应的发送数据缓冲区。 
注意:sendto没有写阻塞1)无sendto函数的原因:
sendto不是阻塞函数,本身udp通信不是面向连接的,udp无发送缓冲区,即sendto没有发送缓冲区,send是有发送缓存区的,即sendto不是阻塞函数。2)UDP不用等待确认,没有实际的发送缓冲区,所以UDP协议中不存在缓冲区满的情况,在UDP套接字上进行写操作永远不会阻塞。
•其他操作:accept、connect

udp与tcp缓存区  仅作为了解

UDP通信没有发送缓存区, 它不保证数据的可靠性。因此,UDP通信是将数据尽快发送出去,不关心数据是否到达目标主机. 但是UDP有接受缓存区, 因为数据发送过快, 如果接收缓存区内数据已满, 则继续发送数据, 可能会出现丢包

丢包出现原因:  接收缓存区满       网络拥堵, 传输错误    

相比之下,TCP是一种面向连接的传输协议,它需要保证数据的可靠性和顺序性。TCP有发送缓存区和接收缓存区, 如果发送频率过快, 且内容小于发送缓存区的大小 , 可能会导致多个数据的粘包。如果发送的数据大于发送缓存区, 可能会导致拆包

UDP不会造成粘包和拆包,  TCP不会造成丢包

UDP是基于数据报文发送的,每次发送的数据包,在UDP的头部都会有固定的长度, 所以应用层能很好的将UDP的每个数据包分隔开, 不会造成粘包。

TCP是基于字节流的, 每次发送的数据报,在TCP的头部没有固定的长度限制,也就是没有边界,那么很容易在传输数据时,把多个数据包当作一个数据报去发送,成为了粘包,或者传输数据时, 要发送的数据大于发送缓存区的大小,或者要发送的数据大于最大报文长度, 就会拆包;

TCP不会丢包,因为TCP一旦丢包,将会重新发送数据包。(超时/错误重传)

TCP: 

UDP: 

2、非阻塞式IO(NIO)

     特点:可以处理多路IO;需要轮询,浪费CPU资源

•当我们将一个套接字设置为非阻塞模式,我们相当于告诉了系统内核:“当我请求的I/O 操作不能够马上完成,你想让我的进程进行休眠等待的时候,不要这么做,请马上返回一个错误给我。”
•(引导着让大家说出来)当一个应用程序使用了非阻塞模式的套接字,它需要使用一个循环来不停地测试是否一个文件描述符有数据可读(称做polling)。---轮询
•应用程序不停的polling 内核来检查是否I/O操作已经就绪。这将是一个极浪费CPU 资源的操作。
•这种模式使用中不普遍。

如何设置非阻塞

1)  通过函数自带参数设置

2)  通过设置文件描述符属性fcntl (file control)

#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ...);
功能:获取/改变文件属性(linux中一切皆文件)
文件描述符:stdin 0、stdout 1stderr 2参数:fd:文件描述符cmd: 操作功能选项 (可以定义个变量,通过vi -t F_GETFL 来找寻功能赋值 )F_GETFL:获取文件描述符的原有的状态信息 //不需要第三个参数,返回值为获取到的属性F_SETFL:设置文件描述符的状态信息 - 需要填充第三个参数//需要填充第三个参数  O_RDONLY, O_RDWR ,O_WRONLY ,O_CREATO_NONBLOCK 非阻塞   O_APPEND追加O_ASYNC 异步        O_SYNC  同步 F_SETOWN:    可以用于实现异步通知机制。//当文件描述符上发生特定事件时(例如输入数据到达),内核会向拥有该  文件描述符的进程发送 SIGIO 信号(异步),以便进程能够及时处理这些事件。
第三个参数:由第二个参数决定,set时候需要设置的值,get时候填0
arg:文件描述符的属性     ----------同上参数,一般填0返回值: 特殊选择:根据功能选择返回 (int 类型)   其他:  成功0   失败: -1;
设置流程:int flag;//文件状态的标志 flag = fcntl(fd, F_GETFL); //读 flag |= O_NONBLOCK;//改  O_NONBLOCK = 0x00004000fcntl(fd, F_SETFL, flag);//写

3、信号驱动IO(异步IO模型  非重点)

特点:异步通知模式,需要底层驱动的支持

操作系统中的同步与异步
在操作系统中,特别是在Linux中,同步和异步是描述I/O操作方式的两个概念。它们主要区分在于操作完成的通知方式和程序执行的流程。同步(Synchronous):同步I/O操作是指在执行I/O操作时,程序必须等待操作完成才能继续执行。在同步操作中,程序提交一个I/O请求后,操作系统会阻塞该程序,直到请求操作完成。此时,程序才能继续执行后续的代码。因此,同步操作会导致程序执行流程暂停,直至I/O操作完成。
同步I/O的例子:read(), write(), recv(), send() 等。异步(Asynchronous):
异步I/O操作是指程序在发起I/O请求后,无需等待操作完成,可以继续执行其他任务。当异步I/O操作完成时,程序会通过某种方式(如回调函数、事件通知、信号等)得到通知。因此,异步操作使程序执行流程得以继续,而不必等待I/O操作完成。

●  通过信号方式,当内核检测到设备数据后,会主动给应用发送信号SIGIO。

SIGIO
文件描述符准备就绪, 可以开始进行输入/输出操作.

● 应用程序收到信号后做异步处理即可。

● 应用程序需要把自己的进程号告诉内核,并打开异步通知机制。

● 标准模板

//将APP进程号告诉驱动程序
fcntl(fd, F_SETOWN, getpid());//使能异步通知
int flag;
flag = fcntl(fd, F_GETFL);
flag |= O_ASYNC;  //也可以用FASYNC标志
fcntl(fd, F_SETFL, flag);signal(SIGIO, handler);

signal信号处理相关函数

头文件: #include <signal.h>

        typedef void (*sighandler_t)(int);

        sighandler_t   signal(int signum, sighandler_t handler)

功能:信号处理函数(注册信号)

参数: int signum:要处理的信号(要修改的信号)

           sighandler_t handler: 函数指针: void(*handler)(int) (修改的功能:)

           handler:------void handler(int num) 自定义的信号处理函数指针

返回值: 成功:设置之前的信号处理方式

失败:   SIG_ERR

用非阻塞方式监听鼠标的数据

查看自己使用的鼠标:/dev/input    

检查鼠标设备:sudo cat /dev/input/mouse0

 注意:执行的时候需要加sudo

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
int fd;
#define N 64
char buf[N] = {0};
void handler(int sig)
{int ret;ret = read(fd, buf, N);if (ret < 0){perror("READ ERR.");return;}else{printf("len= %d\n", ret);}
}
int main(int argc, char const *argv[])
{fd = open("/dev/input/mouse0", O_RDONLY);if (fd < 0){perror("open err");return -1;}// 将APP进程号告诉驱动程序fcntl(fd, F_SETOWN, getpid());// 使能异步通知int flag;flag = fcntl(fd, F_GETFL);flag |= O_ASYNC; // 也可以用FASYNC标志fcntl(fd, F_SETFL, flag);signal(SIGIO, handler);while (1){printf("-----------\n");sleep(1);}close(fd);return 0;
}

4.IO多路复用

4.1、IO多路复用场景假设

假设妈妈有三个孩子,分别不同的房间里睡觉,需要及时获知每个孩子是否醒了,如何做?

1.  挨个房间跑

4.2、IO多路复用机制 

 I/O多路复用  -  帮助TCP实现并发服务器

1.  进程中若需要同时处理多路输入输出 ,在使用单进程和单线程的情况下, 可使用IO多路复用处理多个请求;

2.  IO多路复用不需要创建新的进程和线程, 有效减少了系统的资源开销。

场景就比如服务员给50个顾客点餐,分两步:

       顾客思考要吃什么(等待客户端数据发送)

       顾客想好了,开始点餐(接收客户端数据)

要提高效率有几种方法? 

1.   安排50个服务员   (类似于多进程/多线程实现服务器连接多个客户端,太占用资源)

2.  哪个顾客想好了吃啥, 那个顾客来柜台点菜 (类似IO多路复用机制实现并发服务器)

实现IO多路复用的方式:  select   poll   epoll

基本流程是:

1. 先构造一张有关文件描述符的表;  

2. 清空表   

3. 将你关心的文件描述符加入到这个表中;   

4. 调用select函数。 

5. 判断是哪一个或哪些文件描述符产生了事件(IO操作);   

6. 做对应的逻辑处理;

● 使用I/O多路复用技术。其基本思想是:

○ 先构造一张有关描述符的表,然后调用一个函数。

○ 当这些文件描述符中的一个或多个已准备好进行I/O时函数才返回。

○ 函数返回时告诉进程哪个描述符已就绪,可以进行I/O操作。

基本流程:
1. 先构造一张有关文件描述符的表(集合、数组);    
2. 将你关心的文件描述符加入到这个表中;          
3. 然后循环调用一个函数。 select / poll          
4. 当这些文件描述符中的一个或多个已准备好进行I/O操作的时候
该函数才返回(阻塞)。                            
5. 判断是哪一个或哪些文件描述符产生了事件(IO操作);
6. 做对应的逻辑处理;

4.3、select :用于监测是哪个或哪些文件描述符产生事件;

#include<sys/select.h>   
#include<sys/time.h>   
#include<sys/types.h>   
#include<unistd.h>
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);功能:select用于监测是哪个或哪些文件描述符产生事件; 参数:nfds:监测的最大文件描述个数(文件描述符从0开始,这里是个数,记得+1)
(这里是个数,使用的时候注意,与文件中最后一次打开的文件描述符所对应的值的关系是什么?)readfds:  读事件集合; // 键盘鼠标的输入,客户端连接都是读事件writefds: 写事件集合;  //NULL表示不关心exceptfds:异常事件集合;  //NULL 表示不关心timeout:   设为NULL,等待直到某个文件描述符发生变化;设为大于0的值,有描述符变化或超时时间到才返回。超时时间检测:如果规定时间内未完成函数功能,返回一个超时的信息,我们可以根据该信息设定相应需求;如果设置了超时检测时间:&tvselect返回值:<0 出错>0 表示有事件产生;==0 表示超时时间已到;struct timeval {long    tv_sec;      /* seconds */以秒为单位,指定等待时间long    tv_usec;    /* microseconds */以毫秒为单位,指定等待时间
 };void FD_CLR(int fd, fd_set *set);//将fd从表中清除int  FD_ISSET(int fd, fd_set *set);//判断fd是否在表中void FD_SET(int fd, fd_set *set);//将fd添加到表中void FD_ZERO(fd_set *set);//清空表1

select特点:

1. 一个进程最多只能监听1024个文件描述符 (32位)   [64位为 2048]

2. select被唤醒之后要重新轮询(0-1023)一遍驱动,效率低(消耗CPU资源)

       3. select每次会清空未响应的文件描述符,每次都需要拷贝用户空间的表到内核空间,效率低,开销较大

   (0~3G是用户态,3G~4G是内核态,两个状态来回切换  拷贝是非常耗时,耗资源的)

select机制(辅助理解): 

              1. 头文件检测1024个文件描述符  0-1023

              2. 在select中0~2存储标准输入、标准输出、标准出错    

        3. 监测的最大文件描述个数为fd+1(如果fd = 3,则最大为 4) :  //因为从0开始的    

              4. select只对置1的文件描述符感兴趣                  假如事件产生,select检测时 , 产生的文件描述符会保持1,未产生事件的会置0; 

         5. select每次轮询都会清空表(置零的清空)   //需要在select前备份临时表

练习1: 如何通过select实现 响应鼠标事件同时响应键盘事件

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>//响应鼠标的时候, 打印鼠标事件 
//输入键盘的时候, 打印键盘内容int main(int argc, char const *argv[]) 
{//1.打开鼠标文件int fd = open("/dev/input/mouse0",O_RDONLY);if(fd < 0){perror("open is err:");return -1;}//1.创建文件描述符的表fd_set readfds,tempfds;//2.清空表FD_ZERO(&readfds);//3.添加关心的文件描述符FD_SET(0,&readfds);FD_SET(fd,&readfds);int maxfd = fd;char buf[128];while(1){tempfds = readfds;//4.select检测   阻塞select(maxfd+1,&tempfds,NULL,NULL,NULL);if(FD_ISSET(0,&tempfds)){//1.键盘fgets(buf,sizeof(buf),stdin);if(buf[strlen(buf)-1] == '\n')buf[strlen(buf)-1] = '\0';printf("key: %s\n",buf);}if(FD_ISSET(fd,&tempfds)){//2.鼠标int ret = read(fd,buf,sizeof(buf));buf[ret] = '\0';printf("mouse: %s\n",buf);}}close(fd);return 0;
}

练习:select实现客户端服务器全双工通信并发服务器的建立

在tcp的服务器端, 有两类文件描述符监听的文件描述符
1.只需要有一个
2.不负责和客户端通信, 负责检测客户端的连接请求, 检测到之后调用accept就可以建立新的连接通信的文件描述符
1.负责和建立连接的客户端通信
2.如果有N个客户端和服务器建立了新的连接, 通信的文件描述符就有N个,每个客户端和服务器都对应一个通信的文件描述符

总结select实现IO多路复用特点

1. 一个进程最多只能监听1024个文件描述符 (千级别)
2. select被唤醒之后需要重新轮询一遍驱动的poll函数,效率比较低(消耗CPU资源);
3. select每次会清空表,每次都需要拷贝用户空间的表到内核空间,效率低(一个进程0~4G,0~3G是用户态,3G~4G是内核态,拷贝是非常耗时的);
4.跨平台

(1)客户端              

/*客户端创建代码 */
#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>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
// #include "head.h"
enum type_t
{login, //登录chat,  //发送信息quit,  //退出
};
typedef struct mag_t
{int type;       //功能char name[32];  //ipchar text[128]; //内容
} MSG_t;
int main(int argc, char const *argv[])
{if (argc < 3){printf("plase input <ip><port>");return -1;}//1.创建套接字,用于链接int sockfd;sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){perror("socket err");return -1;}printf("sockfd:%d\n", sockfd);//2.填充结构体struct sockaddr_in saddr;saddr.sin_family = AF_INET;//协议族saddr.sin_port = htons(atoi(argv[2]));//端口saddr.sin_addr.s_addr = inet_addr(argv[1]);//IPMSG_t msg; //消息包socklen_t len = sizeof(saddr); //结构体大小int num=0;//交互次数pid_t pid = fork();//创建父子进程if (pid < 0){perror("fork err");return -1;}else if (pid == 0) //子进程接收消息{while (1){//接受信息if (recvfrom(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&saddr, &len) < 0){perror("recvfrom err");return -1;}printf("ip:%s 状态:%d 内容:%s\n", msg.name, msg.type, msg.text);}}else //父进程发送消息{while (1){strncpy(msg.name, "xiaoyang", 8);//客户端昵称//发送信息memset(msg.text, 0, sizeof(msg.text)); //清空数组内容printf("发送内容:");fgets(msg.text, sizeof(msg.text), stdin); //从终端获取内容存放到数组中if (strncmp(msg.text, "quit", 4) == 0)    //输入quit退出客户端{msg.type = quit;//退出状态sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&saddr, len);exit(0);}if (msg.text[strlen(msg.text)] == '\0'){msg.text[strlen(msg.text) - 1] = '\0';}if (num == 0) //第一次登入{msg.type == login;//登录状态}else{msg.type = chat;//交互状态}sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&saddr, len);//发送信号}}close(sockfd);return 0;
}

(2)  服务器

/*服务器创建代码 */
#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>
enum type_t
{login,//登录chat,//发送信息quit,//退出
};
typedef struct mag_t
{int type;//功能char name[32];//ipchar text[128];//内容
} MSG_t;
MSG_t msg;
//链表节点结构体
typedef struct node_t
{struct sockaddr_in addr;//ip地址struct node_t *next;//链表下一个地址
}list_t;
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_DGRAM, 0);if (sockfd < 0){perror("socket err");return -1;}printf("sockfd:%d\n", sockfd);//2.绑定 ip+port 填充结构体struct sockaddr_in saddr;saddr.sin_family = AF_INET;            saddr.sin_port = htons(atoi(argv[1])); saddr.sin_addr.s_addr = inet_addr("0.0.0.0");socklen_t len = sizeof(saddr); //结构体大小//bind绑定ip和端口if (bind(sockfd, (struct sockaddr *)&saddr, len) < 0){perror("bind err");return -1;}printf("bind success\n");// char buf[128] = {0};while (1){//接收信息if (recvfrom(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&saddr, &len) < 0){perror("recvfrom err");return -1;}switch (msg.type){case login:Loginrecv();break;case chat:Chatrecv();break;case quit:Quitrecv();break;}//发送信息printf("server:");fgets(msg.text, sizeof(msg.text), stdin); //从终端获取内容存放到数组中if (strncmp(msg.text, "quit", 4) == 0) //输入quit退出客户端{break;}if (msg.text[strlen(msg.text)] == '\0'){msg.text[strlen(msg.text) - 1] = '\0';}sendto(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&saddr, len);}close(sockfd);return 0;
}
void Chatrecv()//chat 型
{// printf("client ip:%s ,port:%d buf:%s\n", inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port),msg.text);printf("ip:%s 状态:chat 内容:%s\n", msg.name,msg.text);}
void Loginrecv()//login 型 首次链接
{}
void Quitrecv()//quit 退出
{//接收信息if (recvfrom(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&saddr, &len) < 0){perror("recvfrom err");return -1;}// printf("client ip:%s ,port:%d buf:%s\n", inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port),msg.text);printf("ip:%s 状态:chat 内容:%s\n", msg.name,msg.text);
}

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

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

相关文章

阿里巴巴将开源720亿参数大模型;开源语言大模型演进史

&#x1f989; AI新闻 &#x1f680; 阿里巴巴将开源720亿参数大模型 摘要&#xff1a;在2023世界互联网大会乌镇峰会上&#xff0c;阿里巴巴集团CEO吴泳铭透露&#xff0c;阿里巴巴即将开源720亿参数大模型&#xff0c;这将是国内参数规模最大的开源大模型。目前&#xff0c…

Linux的基本指令(1)

目录 快速认识的几个指令 pwd指令 mkdir指令 touch指令 cd指令 clear指令 whoami指令 ls指令 ls -l ls -la ls 目录名 ls -ld 目录名 文件 路径 路径是什么&#xff1f; 路径的形成 ​ 怎么保证路径必须有唯一性&#xff1f; ls -la隐藏文件 隐藏文件的是什…

Haproxy实现七层负载均衡

目录 Haproxy概述 haproxy算法&#xff1a; Haproxy实现七层负载 ①部署nginx-server测试页面 ②(主/备)部署负载均衡器 ③部署keepalived高可用 ④增加对haproxy健康检查 ⑤测试 Haproxy概述 haproxy---主要是做负载均衡的7层&#xff0c;也可以做4层负载均衡 apache也可…

在Spring Boot中使用JTA实现对多数据源的事务管理

了解事务的都知道&#xff0c;在我们日常开发中单单靠事务管理就可以解决绝大多数问题了&#xff0c;但是为啥还要提出JTA这个玩意呢&#xff0c;到底JTA是什么呢&#xff1f;他又是具体来解决啥问题的呢&#xff1f; JTA JTA&#xff08;Java Transaction API&#xff09;是…

Leetcode 剑指 Offer II 052. 递增顺序搜索树

题目难度: 简单 原题链接 今天继续更新 Leetcode 的剑指 Offer&#xff08;专项突击版&#xff09;系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~ 题目描述 给你一棵二叉搜索树&#xff0c;请 按中序遍历 将其重新排列为一…

初识RabbitMQ - 安装 - 搭建基础环境

RabbitMQ 各个名词介绍 Broker&#xff1a;接收和分发消息的应用&#xff0c;RabbitMQ Server 就是 Message Broker Virtual host&#xff1a;出于多租户和安全因素设计的&#xff0c;把 AMQP 的基本组件划分到一个虚拟的分组中&#xff0c;类似于网络中的 namespace 概念。当…

使用ffmpeg 压缩视频

我有一批1080p的视频,在网上播放占用空间太大,需要进行压缩以后再上传,下面是记录一下ffmpeg命令的使用情况 原视频大小:288mb --压缩加修改分辨率 640p ffmpeg -y -i C4995.mp4 -vcodec libx264 -crf 18 -s vga C4995\C4995_2.MP4 -y: 强制覆盖 -i :输入文件 -vcodec lib…

整治PPOCRLabel中cv2文件读取问题(更新中)

PPOCRLabel 使用PPOCRLabel对ocr预标注结果进行纠正由于PaddleOCR代码库十分混乱,路径经常乱调pip和代码库的代码&#xff08;pip库和源码冲突&#xff09;,经常报错&#xff0c;因此paddleocr和ppocrlabel都是使用pip包; 安装 pip install PPOCRLabel2.1.3启动 PPOCRLabel…

软件之禅(七)面向对象(Object Oriented)

黄国强 2023/11/11 前文提到面向对象构建的模块控制器&#xff0c;根据第一性原理&#xff0c;从图灵机的角度&#xff0c;面向对象不是最基本的元素。那么面向对象是不是不重要呢&#xff1f; 答案是否定的&#xff0c;面向对象非常非常重要。当我们面对一个具体的领域…

拦截器学习(黑马程序员)

实现步骤&#xff1a; 定义拦截器注册配置拦截器 1 自定义拦截器&#xff1a;实现HandlerInterceptor接口&#xff0c;并重写其所有方法&#xff1a; //自定义拦截器 Component public class LoginCheckInterceptor implements HandlerInterceptor { //目标资源方法执行前执…

2022最新版-李宏毅机器学习深度学习课程-P50 BERT的预训练和微调

模型输入无标签文本&#xff08;Text without annotation&#xff09;&#xff0c;通过消耗大量计算资源预训练&#xff08;Pre-train&#xff09;得到一个可以读懂文本的模型&#xff0c;在遇到有监督的任务是微调&#xff08;Fine-tune&#xff09;即可。 最具代表性是BERT&…

3.1 IDA Pro编写IDC脚本入门

IDA Pro内置的IDC脚本语言是一种灵活的、C语言风格的脚本语言&#xff0c;旨在帮助逆向工程师更轻松地进行反汇编和静态分析。IDC脚本语言支持变量、表达式、循环、分支、函数等C语言中的常见语法结构&#xff0c;并且还提供了许多特定于反汇编和静态分析的函数和操作符。由于其…

Docker学习——⑥

文章目录 1、什么是存储卷?2、为什么需要存储卷?3、存储卷分类4、管理卷 Volume5、绑定卷 bind mount6、临时卷 tmpfs7、综合实战-MySQL 灾难恢复8、常见问题 1、什么是存储卷? 存储卷就是将宿主机的本地文件系统中存在的某个目录直接与容器内部的文件系统上的某一目录建立…

AI 引擎系列 5 - 以 AI 引擎模型为目标运行 AI 引擎编译器(2022.1 更新)

AI 引擎系列 5 - 以 AI 引擎模型为目标运行 AI 引擎编译器&#xff08;2022.1 更新&#xff09; 简介 在先前的 AI 引擎系列博文中&#xff0c;我们以 x86 模型为目标运行了 AI 引擎编译器&#xff0c;并运行了 X86 仿真器来验证 AI 引擎应用的功能模型。在本文中&#xff0c;…

2011年09月21日 Go生态洞察:Go图像处理包

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

Javaweb之javascript的BOM对象的详细解析

1.5.2 BOM对象 接下来我们学习BOM对象&#xff0c;BOM的全称是Browser Object Model,翻译过来是浏览器对象模型。也就是JavaScript将浏览器的各个组成部分封装成了对象。我们要操作浏览器的部分功能&#xff0c;可以通过操作BOM对象的相关属性或者函数来完成。例如&#xff1a…

【docker:容器提交成镜像】

容器创建部分请看&#xff1a;点击此处查看我的另一篇文章 容器提交为镜像 docker commit -a "sinwa lee" -m "首页变化" mynginx lxhnginx:1.0docker run -d -p 88:80 --name lxhnginx lxhnginx:1.0为啥没有变啊&#xff0c;首页&#xff1f; 镜像打包 …

【CCF-C解刊】4区逆袭到1区TOP,这本期刊实力强劲,34天录用,7天见刊!

计算机类 • 好刊解读 今天小编带来Elsevier旗下计算机领域好刊的解读&#xff0c;这本期刊从4区逆袭成为中科院1区&#xff08;TOP&#xff09;&#xff0c;如此实力强劲的期刊&#xff0c;究竟如何&#xff1f; 如有相关领域作者有意向投稿&#xff0c;可作为重点关注&…

离散Hopfield神经网络分类——高校科研能力评价

大家好&#xff0c;我是带我去滑雪&#xff01; 高校科研能力评价的重要性在于它对高等教育和科研体系的有效运作、发展和提高质量具有深远的影响。良好的科研能力评价可以帮助高校识别其在不同领域的强项和薄弱点&#xff0c;从而制定战略&#xff0c;改进教学和科研&#xff…

Linux 多线程控制详解

目录 多线程编临界资源访问 互斥锁 API 简述 初始化互斥量 互斥量加锁/解锁 互斥量加锁(非阻塞方式) 互斥量销毁 程序示例 多线程编执行顺序控制 信号量 API 简述 初始化信号量 信号量 P/V 操作 信号量申请(非阻塞方式) 信号量销毁 程序示例 条件变量 创建和销毁…