代码之家  ›  专栏  ›  技术社区  ›  hollow

在读写C中的套接字时,为什么要使用循环缓冲区?

  •  0
  • hollow  · 技术社区  · 2 年前

    我正在做一项任务,目标是用C创建一个基本的FTP服务器,能够同时处理多个客户端。 主题告诉我们“明智地使用循环缓冲区”,但我真的不明白为什么或如何使用?

    我已经在使用 select 知道何时可以在不阻塞的情况下读取或写入套接字,因为我不允许使用 recv ,则, send O_NONBLOCKING

    每个连接都有一个结构,我在其中存储与此客户端相关的所有内容,如通信文件描述符、网络信息和缓冲区。

    为什么我不能用 read 在我的套接字上输入一个固定大小的缓冲区,然后将该缓冲区传递给解析函数?

    写作也是如此:为什么我不能 dprintf 我的反应是什么?

    在我看来,使用循环缓冲区会增加一层无用的复杂性,只是为了转换回字符串来解析命令或发送回响应。

    我是否误解了主题?我应该将命令和响应存储为字符串的循环缓冲区,而不是存储单个字符吗?

    0 回复  |  直到 2 年前
        1
  •  1
  •   John Bollinger    2 年前

    在读写C中的套接字时,为什么要使用循环缓冲区?

    套接字接口本身并没有提供使用循环缓冲区的理由( a、 k.a。 环形缓冲区)。相反,您应该查看使用套接字的应用程序的协议要求,在本例中是FTP协议。这将被底层网络协议(TCP for FTP)的特性及其对套接字层行为的影响所影响。

    为什么我不能在套接字上使用read进入一个固定大小的缓冲区,然后将这个缓冲区传递给解析函数?

    您当然可以不使用循环缓冲区,但这并不像您想象的那么简单。这不是你应该问的问题:这不是循环缓冲区是否 必需的 ,但它们能提供哪些您可能无法获得的好处。稍后再详细介绍。

    还有,你当然可以 固定大小 循环缓冲区——“循环”和“固定大小”是正交特性。然而,使用循环缓冲区来最小化或消除动态调整缓冲区大小的需要通常是目标之一。

    写作也是如此:为什么我不能 dprintf 我的反应是什么?

    再说一次,你可能会按照你所描述的去做。问题是,插入循环缓冲区会带来什么好处?再说一次,以后再说。

    在我看来,使用循环缓冲区会添加一层无用的 将复杂性转换回字符串以解析 命令或返回响应。

    我是否误解了主题?

    你说的是从字符串到字符串的翻译,这让我觉得你确实误解了这个主题。

    而不是单独存储 字符应将命令和响应存储为循环缓冲区 字符串的数量?

    再说一次,你认为“弦”是从哪里来的?为什么假设缓冲区的元素代表(整个)消息?

    A. circular buffer 更像是 使用方式 一个普通的、平坦的、通常大小固定的缓冲区,比它本身是一个单独的数据结构。然而,这涉及到一点额外的簿记数据,因此我不会与任何想将其本身称为数据结构的人争论。

    用于输入的循环缓冲区

    循环缓冲区有用性的主要上下文是使用流语义(如TCP提供)而不是消息语义(如UDP提供)到达的数据。关于您的分配,请考虑以下问题:当服务器读取命令输入时,它如何知道命令的结束位置?我怀疑你是在假设你会得到一个完整的命令 read() ,但无论客户端的实现如何,这绝不是一个安全的假设。您可能会在每个 读取() ,你需要做好应对的准备。

    例如,假设您在一个 读取() 。您可以解析和响应第一个,但需要读取更多数据才能对第二个进行操作。你把这些数据放在哪里?好的,您将其读入缓冲区的末尾。如果下一次 读取() 你不仅得到了一条消息的其余部分,还得到了另一条消息的一部分?

    即使您根据需要动态分配更多空间,也不能在缓冲区的末尾无限期地添加数据。你 能够 在某个时刻,将未经处理的数据从缓冲区的尾部移动到开头,从而在结尾处打开空间,但这是昂贵的,在这一点上,我们已经远远超过了您心目中的简单性。(这种简单总是想象出来的。)或者,您可以在循环缓冲区中执行读取操作,以便从缓冲区的(逻辑)开头使用数据时,自动在(逻辑)结尾提供可用空间。

    输出循环缓冲区

    类似的情况也适用于面向流的网络协议的编写端。认为你不能 write() 一次包含任意数量的数据,很难事先知道您 可以 写这更可能在数据连接上而不是在控制连接上影响到您,但原则上,它适用于两者。如果一次只有一个客户机,那么您可以保留 写入() 在成功传输所有数据之前,请在循环中进行初始化,这就是 dprintf() 可以。但这可能是一种阻塞操作,因此当您同时为多个客户端提供服务时,它会削弱您的响应能力,甚至可能在每个客户端都有多个连接的情况下(与FTP一样)只使用一个客户端。

    您需要在服务器上缓冲数据,尤其是对于数据连接,现在您遇到的问题与在读取端遇到的问题几乎相同:当您只写入了要发送的部分数据,而套接字还没有准备好让您发送更多数据时,您该怎么办?您可以跟踪缓冲区中的位置,并尽可能发送更多的片段,直到缓冲区为空。但是,在处理缓冲区之前,您正在浪费从源文件读取更多数据或缓冲更多控制响应的机会。同样,循环缓冲区可以缓解这种情况,它为您提供了一个缓冲更多数据的位置,而不需要从缓冲区的开头开始 受到缓冲区物理端之前可用空间的限制。