【问题标题】:Does every Linux fd have a buffer?每个 Linux fd 都有缓冲区吗?
【发布时间】:2021-02-16 19:17:58
【问题描述】:

客户端连接服务器后,服务器端的输入会被阻塞,直到客户端断开连接。这是终端缓冲区中的阻塞数据吗? 如果输入数据大于终端的缓冲区会怎样?

tcp 栈中有一个类似的缓冲区。当应用程序不处理缓冲区中的数据时,tcp 会调整窗口大小,使发送方不再发送数据。终端有这样的机制吗?

是否每个 Linux fd 都有这样的缓冲区?缓冲区的大小是由实现决定的吗?


void echo(const clientinfo &ci){
    size_t n;
    char buff[MAXLEN];
    rio_t rio;
    Rio_readinitb(&rio,ci.fd);
    while((n = Rio_readlineb(&rio,buff,MAXLEN)) != 0){
        std::cout << "server received " << n  << " bytes from "<< ci.client_hostname << " port " <<ci.client_port  <<std::endl;
        std::cout << buff;
        Rio_writen(ci.fd,buff,n); 
    }
}

void command(){
    char buf[MAXLEN];
    if(!fgets(buf,MAXLEN,stdin))
        return;
    std::cout << buf;
}
int main(int argc,char **argv){
    int listenfd,connfd;
    socklen_t clientlen;
    sockaddr_storage clientaddr;
    fd_set read_set,ready_set;
    clientinfo ci;
    if(argc != 2){
        std::cerr << "usage: " << argv[0] << " <port>" << std::endl;
        exit(0);
    }
    listenfd = open_listenfd(argv[1]);
    FD_ZERO(&read_set);
    FD_SET(STDIN_FILENO,&read_set);
    FD_SET(listenfd,&read_set);

    while(1){
        ready_set = read_set;
        if(select(listenfd+1,&ready_set,NULL,NULL,NULL) < 0)
            unix_error("select error");
        if(FD_ISSET(STDIN_FILENO,&ready_set))
            command();
        if(FD_ISSET(listenfd,&ready_set)){
            clientlen = sizeof(sockaddr_storage);
            ci.fd = accept(listenfd,(sockaddr*)&clientaddr,&clientlen);
            getnameinfo((sockaddr*)&clientaddr,clientlen,ci.client_hostname,MAXLEN,ci.client_port,MAXLEN,0);
            std::cout << "connect from " << ci.client_hostname << " port " << ci.client_port <<std::endl;
            echo(ci);
            close(ci.fd);
        }
    }

}

【问题讨论】:

  • 文件描述符没有缓冲区。像 C 库这样的库提供缓冲区。
  • 是的,但是每个 fd 都有一个与之关联的缓冲区
  • 如果你知道,为什么还要问?
  • 不知道我的理解是否正确
  • 取决于驱动程序。串行端口通常在硬件中缓冲 8 或 16 个字符。一些实时音频代码不会缓冲以避免延迟。网络设备可能有相当大的数据包缓冲区。所以不能保证所有的 fd 都有缓冲区。

标签: linux io linux-kernel


【解决方案1】:

内核为进程创建了一个file descriptor。通常这是使用open 完成的。 open 将进程特定编号(文件描述符)与由内核管理的设备相关联。

之后,进程可以从其文件描述符中读取数据。这通常使用readrecv 完成。两个系统调用都写入缓冲区。这是否意味着文件描述符拥有缓冲区,该缓冲区是进程内存的一部分?我不这么认为。

但是当人们谈论缓冲区时,read 写入缓冲区的事实通常并不意味着。通常人们谈论pipe buffer,它由内核管理,如果两个进程相互通信。每个进程都有自己的文件描述符,中间是缓冲区。这是否意味着缓冲区由两个文件描述符之一拥有?我也不这么认为。

但是是的:缓冲区无处不在。硬件设备正在缓冲。设备驱动程序正在缓冲。内核缓存(缓冲)内存页面。管道缓冲区。 C 库缓冲区。用户模式程序缓冲区。

NO:没有缓冲区,有很多。

【讨论】:

    猜你喜欢
    • 2011-07-09
    • 1970-01-01
    • 2018-03-26
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多