首页 > 其他分享 >IO多路复用、服务器模型

IO多路复用、服务器模型

时间:2024-09-10 19:51:20浏览次数:12  
标签:acceptfd 多路复用 int 描述符 IO sockfd 服务器 include buf

IO多路复用:epoll

epoll的提出--》它所支持的文件描述符上限是系统可以最大打开的文件的数目;

eg:1GB机器上,这个上限10万个左右。

每个fd上面有callback(回调函数)函数,只有产生事件的fd才有主动调用callback,不需要轮询。

注意:

Epoll处理高并发,百万级

1. 红黑树: 是特殊的二叉树(每个节点带有属性),Epoll怎样能监听很多个呢?首先创建树的根节点,每个节点都是一个fd以结构体的形式存储(节点里面包含了一些属性,callback函数)

2. 就绪链表: 当某一个文件描述符产生事件后,会自动调用callback函数,通过回调callback函数来找到链表对应的事件(读时间还是写事件)。

1.特点

1.监听的文件描述符没有了限制

2.异步IO,epoll当有世纪那唤醒之后,发生事件的文件描述符会主动的调用callback回调函数,拿到对应的文件描述符。不需要要轮询,效率高

3.epoll不需要构造表,只需要从用户空间拷贝到内核空间一次

2.编程步骤

  1. 创建红黑树和就绪链表 epoll_create
  2. 将关心的文件描述符和事件上树 epoll_ctl
  3. 阻塞等待事件产生,一旦产生事件,则进行处理 epoll_wait
  4. 根据链表中准备好的文件描述符,进行处理

3.函数接口

int epoll_create(int size); 
功能:创建红黑树根节点(创建epoll实例) , 同时也会创建就绪链表
返回值:成功时返回一个实例epfd(二叉树句柄),失败时返回-1。
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
功能:控制epoll属性,比如给红黑树添加节点
参数: 1. epfd:   epoll_create函数的返回句柄。//一个标识符
     2. op:表示动作类型,有三个宏:			        
                EPOLL_CTL_ADD:注册新的fd到epfd中
			      EPOLL_CTL_MOD:修改已注册fd的监听事件
			      EPOLL_CTL_DEL:从epfd中删除一个fd
     3. 要操作的文件描述符
     4. 结构体信息: 
 typedef union epoll_data {
               int fd;      //要添加的文件描述符
               uint32_t u32;  typedef unsigned int
               uint64_t u64;   typedef unsigned long int
        } epoll_data_t;

   struct epoll_event {
       uint32_t events; 事件
       epoll_data_t data; //共用体(看上面)
		};

	  关于events事件:
			 EPOLLIN:  表示对应文件描述符可读
		    EPOLLOUT: 可写
			 EPOLLPRI:有紧急数据可读;
		    EPOLLERR:错误;
		    EPOLLHUP:被挂断;
			 EPOLLET:触发方式,边缘触发;(默认使用边缘触发)
			 ET模式:表示状态的变化;
           NULL: 删除一个文件描述符使用,无事件
           
返回值:成功:0, 失败:-1

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
功能:等待事件产生
   内核会查找红黑树中有事件响应的文件描述符, 并将这些文件描述符放入就绪链表
    就绪链表中的内容, 执行epoll_wait会同时复制到第二个参数events

参数: 	epfd:句柄;
		events:用来保存从就绪链表中响应事件的集合;
		maxevents:  表示每次在链表中拿取响应事件的个数;
		timeout:超时时间,毫秒,0立即返回  ,-1阻塞	

返回值: 成功: 实际从链表中拿出的文件描述符数目     失败时返回-1

4.总结

select

poll

epoll

监听个数

一个进程最多监听1024个文件描述符

由程序员自己决定

百万级

方式

每次都会被唤醒,都需要重新轮询

每次都会被唤醒,都需要重新轮询

红黑树内callback自动回调,不需要轮询

效率

文件描述符数目越多,轮询越多,效率越低

文件描述符数目越多,轮询越多,效率越低

不轮询,效率高

原理

每次使用select后,都会清空表

每次调用select,都需要拷贝用户空间的表到内核空间

内核空间负责轮询监视表内的文件描述符,将发生事件的文件描述符拷贝到用户空间,再次调用select,如此循环

不会清空结构体数组

每次调用poll,都需要拷贝用户空间的结构体到内核空间

内核空间负责轮询监视结构体数组内的文件描述符,将发生事件的文件描述符拷贝到用户空间,再次调用poll,如此循环

不会清空表

epoll中每个fd只会从用户空间到内核空间只拷贝一次(上树时)

通过epoll_ctl将文件描述符交给内核监管,一旦fd就绪,内核就会采用callback的回调机制来激活该fd,epoll_wait便可以收到通知(内核空间到用户空间的拷贝

特点

  1. 一个进程最多能监听1024个文件描述符
  2. select每次被唤醒,都要重新轮询表,效率低
  3. select每次都清空未发生相应的文件描述符,每次都要拷贝用户空间的表到内核空间
  1. 优化文件描述符的个数限制
  2. poll每次被唤醒,都要重新轮询,效率比较低(耗费cpu)
  3. poll不需要构造文件描述符表(也不需要清空表),采用结构体数组,每次也需要从用户空间拷贝到内核空间
  1. 监听的文件描述符没有个数限制(取决于自己的系统)
  2. 异步IO,epoll当有事件产生被唤醒,文件描述符会主动调用callback函数拿到唤醒的文件描述符,不需要轮询,效率高
  3. epoll不需要构造文件描述符的表,只需要从用户空间拷贝到内核空间一次。

结构

文件描述符表(位表)

结构体数组

红黑树和就绪链表

开发复杂度

服务器模型

在网络通信中,通常一个服务器要连接多个客户端

为了处理多个客户端的请求,通常有多种表现形式

1.循环服务器: 一个服务器在同一时间只能处理一个客户端的请求

tcp:
socket();
bind();
listen();
while(1)
    accept();
    while(1)
        recv()/send();
close();

2.并发服务器一个服务器在同一时间可以处理多个客户端的请求

3.多进程每有一个客户连接创建一个进程进行通信

为什么要创建进程?------》通信

什么时间创建进程?------》accept之后fork

子进程:通信

父进程:循环等待下一个客户端连接

进程资源回收----》子进程退出-----》客户端退出

wait(); waitpid();

SIGCHLD:当子进程退出给父进程发送的信号

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

void handler(int sig)
{
    wait(NULL);
}

int main(int argc, char const *argv[])
{
    pid_t pid;
    char buf[128] = {0};
    int ret, acceptfd;
    // 1.创建套接字(socket)---------------》有手机
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket err");
        return -1;
    }
    printf("sockfd:%d\n", sockfd); // 3
    // 2.指定网络信息---------------------------》有号码
    struct sockaddr_in saddr, caddr;
    saddr.sin_family = AF_INET;            // IPV4
    saddr.sin_port = htons(atoi(argv[1])); // 端口号
    // saddr.sin_addr.s_addr = inet_addr("192.168.50.13"); // 虚拟机IP
    // saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
    saddr.sin_addr.s_addr = INADDR_ANY;
    int len = sizeof(caddr);
    // 3.绑定套接字(bind)------------------》绑定手机(插卡)
    if (bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
    {
        perror("bind err");
        return -1;
    }
    printf("bind ok\n");
    // 4.监听套接字(listen)-----------------》待机
    if (listen(sockfd, 6) < 0)
    {
        perror("listen err");
        return -1;
    }
    printf("listen ok\n");
    // 5.接收客户端连接连接请求(accept)--》接电话
    // tcp服务器一共有两类文件描述符,一类用于连接,一类用于通信
    // socket函数返回值:用于连接的文件描述符
    // accept函数返回值:用于通信的文件描述符
    signal(SIGCHLD, handler);//设置信号处理方式
    while (1)
    {
        acceptfd = accept(sockfd, (struct sockaddr *)&caddr, &len);
        if (acceptfd < 0)
        {
            perror("accept err");
            return -1;
        }
        printf("port:%d ip:%s\n", ntohs(caddr.sin_port), inet_ntoa(caddr.sin_addr));
        printf("acceptfd:%d\n", acceptfd);
        pid = fork();
        if (pid < 0)
        {
            perror("fork err");
            return -1;
        }
        else if (pid == 0)
        {
            // 6.接收、发送数据(recv send)---》通话
            while (1)
            {
                // read/write()
                ret = recv(acceptfd, buf, sizeof(buf), 0);
                if (ret < 0)
                {
                    perror("recv err");
                    break;
                }
                else if (ret == 0)
                {
                    printf("client exit\n");
                    break;
                }
                else
                {
                    printf("buf:%s\n", buf);
                    memset(buf, 0, sizeof(buf));
                }
            }
            // 7.关闭套接字(close)-----------------》挂电话
            close(acceptfd);
            exit(0);
        }
        else
            close(acceptfd);
    }

    close(sockfd);

    return 0;
}

多线程每有一个客户连接创建一个线程进行通信

为什么要创建线程-------》通信

什么时间创建线程-------》accept之后pthread_create

子线程:通信

主线程:循环等待下一个客户端连接

通信的文件描述符------》线程传参(11min)

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

void *handler(void *arg)
{
    int ret, acceptfd;
    acceptfd = *((int *)arg);
    char buf[128] = {0};
    // 6.接收、发送数据(recv send)---》通话
    while (1)
    {
        // read/write()
        ret = recv(acceptfd, buf, sizeof(buf), 0);
        if (ret < 0)
        {
            perror("recv err");
            return NULL;
        }
        else if (ret == 0)
        {
            printf("client exit\n");
            break;
        }
        else
        {
            printf("buf:%s\n", buf);
            memset(buf, 0, sizeof(buf));
        }
        // 7.关闭套接字(close)-----------------》挂电话
        }
    close(acceptfd);
    pthread_exit(NULL);
}

int main(int argc, char const *argv[])
{

    int acceptfd;
    pthread_t tid;
    // 1.创建套接字(socket)---------------》有手机
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket err");
        return -1;
    }
    printf("sockfd:%d\n", sockfd); // 3
    // 2.指定网络信息---------------------------》有号码
    struct sockaddr_in saddr, caddr;
    saddr.sin_family = AF_INET;            // IPV4
    saddr.sin_port = htons(atoi(argv[1])); // 端口号
    // saddr.sin_addr.s_addr = inet_addr("192.168.50.13"); // 虚拟机IP
    // saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
    saddr.sin_addr.s_addr = INADDR_ANY;
    int len = sizeof(caddr);
    // 3.绑定套接字(bind)------------------》绑定手机(插卡)
    if (bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
    {
        perror("bind err");
        return -1;
    }
    printf("bind ok\n");
    // 4.监听套接字(listen)-----------------》待机
    if (listen(sockfd, 6) < 0)
    {
        perror("listen err");
        return -1;
    }
    printf("listen ok\n");
    // 5.接收客户端连接连接请求(accept)--》接电话
    // tcp服务器一共有两类文件描述符,一类用于连接,一类用于通信
    // socket函数返回值:用于连接的文件描述符
    // accept函数返回值:用于通信的文件描述符
    while (1)
    {

        acceptfd = accept(sockfd, (struct sockaddr *)&caddr, &len);
        if (acceptfd < 0)
        {
            perror("accept err");
            return -1;
        }
        printf("port:%d ip:%s\n", ntohs(caddr.sin_port), inet_ntoa(caddr.sin_addr));
        printf("acceptfd:%d\n", acceptfd);

        pthread_create(&tid, NULL, handler, &acceptfd);
        pthread_detach(tid);
    }
    close(sockfd);

    return 0;
}

​​​​​​​IO多路复用

select poll epoll

​​​​​​​并发服务器总结

多进程:

优点:服务器更稳定,父子进程资源独立,安全性高

缺点:需要开辟多个进程,大量消耗资源,系统开销大

多线程:

优点:相对于多进程,资源开销小,多个线程共享同一个进程的资源

缺点:需要开辟多个线程,安全性较差

IO多路复用:

优点:节省资源、系统开销小,性能高

缺点:代码复杂度高

ftp项目参考代码

服务器

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

void list(int acceptfd);
void putfile(int acceptfd, char *p);
void getfile(int acceptfd, char *p);

int main(int argc, char const *argv[])
{
    char buf[128] = {0};
    int ret, acceptfd;
    // 1.创建套接字(socket)---------------》有手机
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket err");
        return -1;
    }
    printf("sockfd:%d\n", sockfd); // 3
    // 2.指定网络信息---------------------------》有号码
    struct sockaddr_in saddr, caddr;
    saddr.sin_family = AF_INET;            // IPV4
    saddr.sin_port = htons(atoi(argv[1])); // 端口号
    // saddr.sin_addr.s_addr = inet_addr("192.168.50.13"); // 虚拟机IP
    // saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
    saddr.sin_addr.s_addr = INADDR_ANY;
    int len = sizeof(caddr);
    // 3.绑定套接字(bind)------------------》绑定手机(插卡)
    if (bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
    {
        perror("bind err");
        return -1;
    }
    printf("bind ok\n");
    // 4.监听套接字(listen)-----------------》待机
    if (listen(sockfd, 6) < 0)
    {
        perror("listen err");
        return -1;
    }
    printf("listen ok\n");
    // 5.接收客户端连接连接请求(accept)--》接电话
    // tcp服务器一共有两类文件描述符,一类用于连接,一类用于通信
    // socket函数返回值:用于连接的文件描述符
    // accept函数返回值:用于通信的文件描述符
    while (1)
    {

        acceptfd = accept(sockfd, (struct sockaddr *)&caddr, &len);
        if (acceptfd < 0)
        {
            perror("accept err");
            return -1;
        }
        printf("port:%d ip:%s\n", ntohs(caddr.sin_port), inet_ntoa(caddr.sin_addr));
        printf("acceptfd:%d\n", acceptfd);

        // 6.接收、发送数据(recv send)---》通话
        while (1)
        {
            // read/write()
            ret = recv(acceptfd, buf, sizeof(buf), 0);
            if (ret < 0)
            {
                perror("recv err");
                return -1;
            }
            else if (ret == 0)
            {
                printf("client exit\n");
                break;
            }
            else
            {
                printf("buf:%s\n", buf);
                if (!strcmp(buf, "list"))
                    list(acceptfd);
                if (!strncmp(buf, "put ", 4))
                    putfile(acceptfd, buf);
                if (!strncmp(buf, "get ", 4))
                    getfile(acceptfd, buf);
                if (!strcmp(buf, "quit"))
                    break;
                memset(buf, 0, sizeof(buf));
            }
        }
        // 7.关闭套接字(close)-----------------》挂电话
        close(acceptfd);
    }
    close(sockfd);

    return 0;
}

void list(int acceptfd)
{
    struct dirent *d;
    // 打开目录文件
    DIR *dir = opendir(".");
    if (dir == NULL)
    {
        perror("opendir err");
        return;
    }
    // 循环读目录
    while ((d = readdir(dir)) != NULL)
    {
        // 判断是否为普通文件
        if (d->d_type == DT_REG)
            // 发送给客户端
            send(acceptfd, d->d_name, 128, 0);
    }
    // 发送一个结束的标志
    send(acceptfd, "end", 128, 0);
    return;
}

void putfile(int acceptfd, char *p)
{
    char buf[128] = {0};
    int ret;
    int fd = open(p + 4, O_WRONLY | O_CREAT | O_TRUNC, 0666);
    if (fd < 0)
    {
        perror("open err");
        return;
    }
    // 接受客户端传来的文件内容
    while (1)
    {
        ret = recv(acceptfd, buf, sizeof(buf), 0);
        if (ret < 0)
        {
            perror("recv err");
            return;
        }
        else
        {
            // 写到目标文件里面
            if (!strcmp(buf, "end"))
                break;
            write(fd, buf, strlen(buf));
            memset(buf, 0, sizeof(buf));
        }
    }
    close(fd);
    return;
}

void getfile(int acceptfd, char *p)
{
    char buf[128] = {0};
    ssize_t s;
    int fd = open(p + 4, O_RDONLY);
    if (fd < 0)
    {
        perror("open err");
        return;
    }
    // 循环读文件
    while (1)
    {
        s = read(fd, buf, sizeof(buf) - 1);
        buf[s] = '\0';
        if (s == 0)
        {
            printf("send end\n");
            send(acceptfd, "end", sizeof(buf), 0);
            break;
        }
        // 发送给服务器
        send(acceptfd, buf, sizeof(buf), 0);
        memset(buf, 0, sizeof(buf));
    }
    close(fd);
    return;
}

客户端

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

void show();
void list(int sockfd);
void putfile(int sockfd, char *p);
void getfile(int sockfd, char *p);

int main(int argc, char const *argv[])
{
    char buf[128] = {0};
    // 1.创建套接字(socket)------------》有手机
    int sockfd = socket(AF_INET, SOCK_STREAM, 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]);
    // 3.连接(connect)-------------------》拨打电话
    if (connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
    {
        perror("connect err");
        return -1;
    }
    printf("connect okk\n");
    // 4.接收发送消息(recv send)---》通话
    while (1)
    {
        show();
        fgets(buf, sizeof(buf), stdin);
        if (buf[strlen(buf) - 1] == '\n')
            buf[strlen(buf) - 1] = '\0';

        // write(sockfd, buf, sizeof(buf));
        send(sockfd, buf, sizeof(buf), 0);
        if (!strcmp(buf, "list"))
            list(sockfd);
        if (!strcmp(buf, "quit"))
            break;
        if (!strncmp(buf, "put ", 4))
            putfile(sockfd, buf);
        if (!strncmp(buf, "get ", 4))
            getfile(sockfd, buf);
    }
    // 5.关闭套接字(close)------------》挂电话
    close(sockfd);
    return 0;
}

void show()
{
    printf("----------------list----------------\n");
    printf("------------put filename------------\n");
    printf("------------get filename------------\n");
    printf("----------------quit----------------\n");
}

void list(int sockfd)
{
    char buf[128] = {0};
    int ret;
    while (1)
    {
        ret = recv(sockfd, buf, sizeof(buf), 0);
        if (ret < 0)
        {
            perror("recv err");
            return;
        }
        if (!strcmp(buf, "end"))
            break;
        printf("%s ", buf);
    }
    putchar(10);
    return;
}

void putfile(int sockfd, char *p)
{
    char buf[128] = {0};
    ssize_t s;
    int fd = open(p + 4, O_RDONLY);
    if (fd < 0)
    {
        perror("open err");
        return;
    }
    // 循环读文件
    while (1)
    {
        s = read(fd, buf, sizeof(buf) - 1);
        buf[s] = '\0';
        if (s == 0)
        {
            printf("send end\n");
            send(sockfd, "end", sizeof(buf), 0);
            break;
        }
        // 发送给服务器
        send(sockfd, buf, sizeof(buf), 0);
        memset(buf, 0, sizeof(buf));
    }
    close(fd);
    return;
}

void getfile(int sockfd, char *p)
{
    char buf[128] = {0};
    int ret;
    int fd = open(p + 4, O_WRONLY | O_CREAT | O_TRUNC, 0666);
    if (fd < 0)
    {
        perror("open err");
        return;
    }
    // 接受客户端传来的文件内容
    while (1)
    {
        ret = recv(sockfd, buf, sizeof(buf), 0);
        if (ret < 0)
        {
            perror("recv err");
            return;
        }
        else
        {
            // 写到目标文件里面
            if (!strcmp(buf, "end"))
                break;
            write(fd, buf, strlen(buf));
            memset(buf, 0, sizeof(buf));
        }
    }
    close(fd);
    return;
}

标签:acceptfd,多路复用,int,描述符,IO,sockfd,服务器,include,buf
From: https://blog.csdn.net/2301_77143270/article/details/142107788

相关文章

  • 线段树 transformation——hdu 4578
    问题描述:给定一个数列,数列中所有元素都初始化为0,对其执行多种区间操作操作1:add修改:对区间[L,R]内的所有数加c操作2:multi修改:对区间[L,R]内所有数乘以c操作3:change操作:把区间[L,R]内所有数改为c操作4:sum操作:对区间中的每个数的p次方求和。1<=p<=3输入:有不超过10个测试用例。......
  • 【Azure Service Bus】创建 ServiceBus 的Terraform脚本报错GetAuthorizationRule: In
    问题描述在使用Terraform部署ServiceBus时候,遇见了如下报错:Error:ErrormakingReadrequestonAzureServiceBusTopicAuthorizationRule:servicebus.TopicsClient#GetAuthorizationRule:Invalidinput:autorest/validation:validationfailed:parameter=authorizat......
  • 【五一省选集训day4】Mansion
    【五一省选集训day4】Mansion注意,本题要求输出最大值,不要把最大值看成编号……srds好像只有我看错了。这个东西一看就很能用莫队做。用莫队按\(l\)分块,再按\(r\)排序。维护一棵线段树,每次移动对线段树进行单点修改和区间求\(\max\),一共\(n\sqrt{n}\)次移动,总时间复杂度......
  • Day5网络编程:epoll+服务器模型+ftp
    1.io多路复用:epollepoll的提出--》它所支持的文件描述符上限是系统可以最大打开的文件的数目;eg:1GB机器上,这个上限10万个左右。每个fd上面有callback(回调函数)函数,只有产生事件的fd才有主动调用callback,不需要轮询。注意:Epoll处理高并发,百万级1.红黑树:是特殊的二叉......
  • 服务器中的清洗是什么
    在IDC服务里,有不少专用名词,没有深入行业了解,往往会感觉不知所云。在高防服务器租用中,我们会看到高防服务器清洗这样的说法,“清洗”是指什么服务呢?清洗的又是什么内容?高防服务器“清洗”一般指的是流量清洗,是提供给租用服务器的客户,针对对其发起的DOS/DDOS攻击的监控、告警和......
  • C++环境搭建(Visual Studio 2022软件安装)
    安装环境:Windows11家庭中文版VisualStudio2022下载地址:        https://pan.baidu.com/s/15U8AEIwThxp-fAZFJqnCgQ    提取码:0000 安装步骤:        1.下载后选择安装包进行解压。    2.以管理员身份运行安装程序。(企业版功能最全,这......
  • Linux iostat 命令详解
    Linuxiostat命令详解在Linux系统管理中,监控磁盘I/O性能是一项至关重要的任务。iostat是sysstat包中的一个实用工具,用于监控和显示系统输入输出设备和CPU的使用情况。它提供了丰富的数据,帮助系统管理员识别并解决潜在的I/O瓶颈问题。本文将详细介绍iostat命令的使用方法和关键参......
  • 如何查看服务器的磁盘存储容量?
    查看服务器的磁盘存储容量可以通过多种命令行工具来完成,以下是几种常见的方法,适用于大多数基于Linux和Unix的服务器:1.df命令df命令用于显示文件系统的磁盘空间使用情况。显示所有挂载点的磁盘使用情况:df-h这里-h选项表示以可读的格式(例如MB和GB)显示大小。显示特定文件系统的......
  • 论文笔记--See through Gradients. Image Batch Recovery via GradInversion
    SeethroughGradients.ImageBatchRecoveryviaGradInversion\(W^{FC}\in\mathbb{R}^{M\timesN}\),其输入为一个M维向量\(v\in\mathbb{R}^M\),\(\DeltaW^{FC}_{m,n,k}\)是损失函数对全连接层\(W\)的导数。对于一个特定的类别\(n\),(\(z\)为全连接层输出的logits),其......
  • 视频网站服务器存储多大
    视频网站服务器所需的存储空间大小取决于多种因素,包括视频的数量、视频的分辨率、视频的时长、视频编码格式、备份需求以及网站的其他数据存储需求。以下是一些评估视频网站服务器存储空间需求时需要考虑的关键点:视频文件大小:一个视频文件的大小可以从几MB到几个GB不等。例如,一个高......