admin管理员组

文章数量:1037775

【Linux网络】I/O 世界的技术之旅:探索五种模型与 fcntl 函数的魅力

怎么理解IO?

IO就是input,output,参照物是计算机本身,是计算机系统内部和外部设备进行交互的过程。

input,output参考的对象计算机本身,input就是相对计算机来说就是向计算机输入,output就是相对计算机来说是向外部设备输出

IO执行的行为差不多就是等待+拷贝。

IO=等待+拷贝(等待是主要矛盾)

等待外部设备就绪,当外部设备准备好了以后,通过CPU的针脚发送中断信号告知操作系统。操作系统转入内核态,进行拷贝工作。

所以IO基本上就是等待+拷贝这个两个动作。

高效IO

上面说的IO=等待+拷贝

在大多数情况下,时间都浪费在等待上面,因为和等待相比,拷贝要花的时间比等待的时间少的多。

高效的IO就是等待时间变少,拷贝的时间的比重增加。

第一种IO模型:阻塞IO模型

理解阻塞IO

阻塞IO相当于当上层进行系统调用,当外部设备没有准备好的时候,就会一直在等待数据准备好,如果没有准备好,就会一直在等待,不会做任何事情。准备好了以后,就把数据从内核拷贝到用户空间。然后向上层返回成功标识符

在钓鱼的例子中: 张三去钓鱼,大部分时间在等待鱼上钩(是外界的准备条件,和张三没有关系,也就是说外部设备多久准备好是和计算机无关的)(Like us,we are not meet again,meeting is something l can't determine)。 张三在等待鱼上钩的这段时间,一直看着鱼漂,不做其他的事情。

代码语言:javascript代码运行次数:0运行复制
ssize_t recv(int sockfd, void *buf, size_t len, int flags);

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                        struct sockaddr *src_addr, socklen_t *addrlen);
代码语言:javascript代码运行次数:0运行复制
ssize_t send(int sockfd, const void *buf, size_t len, int flags);

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                      const struct sockaddr *dest_addr, socklen_t addrlen);

第二种IO模型:非阻塞IO模型

非阻塞IO和阻塞IO最大额区别就是,非阻塞IO在没有数据的时候,直接进行返回,不会等待,并且返回EWOULDBLOCK错误码。

非阻塞IO减少

在man手册中,也有说明。

代码语言:javascript代码运行次数:0运行复制
#include <iostream>
#include <fcntl.h>
#include <unistd.h>

using namespace std;

void SetNoBlock(int fd)
{
    int info=fcntl(fd,F_GETFL);
    if(info<0)
    {
        perror("fcntl error");
        return;
    }
    fcntl(fd,F_SETFL,info|O_NONBLOCK);
    return;
}

int main()
{
    SetNoBlock(0);
    while(1)
    {
        sleep(3);
        char buff[1024]={0};
        ssize_t n=read(0,buff,sizeof(buff)-1);
        if(n<0)
        {
            perror("read error");
            
            continue;
        }

        buff[n]=0;
        cout<<buff<<endl;

    }
    return 0;
}

在钓鱼例子中: 李四在把鱼竿抛出去以后,就去干了一会其他的事情,然后就看一下鱼漂有没有动,看一下有没有鱼,然后发现没有鱼,又去干其他的事情。过了一会又来看有没有鱼,又没有鱼,又去干其他的事情。一直这么循环(轮询),到有鱼的时候,就起竿钓上鱼。


第三种IO模型:信号驱动IO模型

内核将数据准备好的时候, 使用 SIGIO 信号通知应用程序进行 IO操作。

和非阻塞IO的区别就是,不会去循环检测(不会去做无用工),而是真正有数据的时候,会发SIGIO信号,这样再次IO的时候,就会成功了。

在钓鱼例子中: 王五不再和李四一样,时不时就去看一下鱼漂有没有动,而是在鱼漂上直接挂了一个铃铛

【Linux网络】I/O 世界的技术之旅:探索五种模型与 fcntl 函数的魅力

怎么理解IO?

IO就是input,output,参照物是计算机本身,是计算机系统内部和外部设备进行交互的过程。

input,output参考的对象计算机本身,input就是相对计算机来说就是向计算机输入,output就是相对计算机来说是向外部设备输出

IO执行的行为差不多就是等待+拷贝。

IO=等待+拷贝(等待是主要矛盾)

等待外部设备就绪,当外部设备准备好了以后,通过CPU的针脚发送中断信号告知操作系统。操作系统转入内核态,进行拷贝工作。

所以IO基本上就是等待+拷贝这个两个动作。

高效IO

上面说的IO=等待+拷贝

在大多数情况下,时间都浪费在等待上面,因为和等待相比,拷贝要花的时间比等待的时间少的多。

高效的IO就是等待时间变少,拷贝的时间的比重增加。

第一种IO模型:阻塞IO模型

理解阻塞IO

阻塞IO相当于当上层进行系统调用,当外部设备没有准备好的时候,就会一直在等待数据准备好,如果没有准备好,就会一直在等待,不会做任何事情。准备好了以后,就把数据从内核拷贝到用户空间。然后向上层返回成功标识符

在钓鱼的例子中: 张三去钓鱼,大部分时间在等待鱼上钩(是外界的准备条件,和张三没有关系,也就是说外部设备多久准备好是和计算机无关的)(Like us,we are not meet again,meeting is something l can't determine)。 张三在等待鱼上钩的这段时间,一直看着鱼漂,不做其他的事情。

代码语言:javascript代码运行次数:0运行复制
ssize_t recv(int sockfd, void *buf, size_t len, int flags);

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                        struct sockaddr *src_addr, socklen_t *addrlen);
代码语言:javascript代码运行次数:0运行复制
ssize_t send(int sockfd, const void *buf, size_t len, int flags);

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                      const struct sockaddr *dest_addr, socklen_t addrlen);

第二种IO模型:非阻塞IO模型

非阻塞IO和阻塞IO最大额区别就是,非阻塞IO在没有数据的时候,直接进行返回,不会等待,并且返回EWOULDBLOCK错误码。

非阻塞IO减少

在man手册中,也有说明。

代码语言:javascript代码运行次数:0运行复制
#include <iostream>
#include <fcntl.h>
#include <unistd.h>

using namespace std;

void SetNoBlock(int fd)
{
    int info=fcntl(fd,F_GETFL);
    if(info<0)
    {
        perror("fcntl error");
        return;
    }
    fcntl(fd,F_SETFL,info|O_NONBLOCK);
    return;
}

int main()
{
    SetNoBlock(0);
    while(1)
    {
        sleep(3);
        char buff[1024]={0};
        ssize_t n=read(0,buff,sizeof(buff)-1);
        if(n<0)
        {
            perror("read error");
            
            continue;
        }

        buff[n]=0;
        cout<<buff<<endl;

    }
    return 0;
}

在钓鱼例子中: 李四在把鱼竿抛出去以后,就去干了一会其他的事情,然后就看一下鱼漂有没有动,看一下有没有鱼,然后发现没有鱼,又去干其他的事情。过了一会又来看有没有鱼,又没有鱼,又去干其他的事情。一直这么循环(轮询),到有鱼的时候,就起竿钓上鱼。


第三种IO模型:信号驱动IO模型

内核将数据准备好的时候, 使用 SIGIO 信号通知应用程序进行 IO操作。

和非阻塞IO的区别就是,不会去循环检测(不会去做无用工),而是真正有数据的时候,会发SIGIO信号,这样再次IO的时候,就会成功了。

在钓鱼例子中: 王五不再和李四一样,时不时就去看一下鱼漂有没有动,而是在鱼漂上直接挂了一个铃铛

本文标签: Linux网络IO 世界的技术之旅探索五种模型与 fcntl 函数的魅力