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

非阻塞TCP缓冲区问题

  •  1
  • Poni  · 技术社区  · 16 年前

    我在堆栈上分配要发送的缓冲区,如果我理解正确,那么这样做是错误的,因为这些缓冲区应该保持在我发送它们时的状态,直到我从IOCP得到“write complete”通知。

    举个例子:

    void some_function()
    {
        char cBuff[1024];
    
        // filling cBuff with some data
    
        WSASend(...); // sending cBuff, non-blocking mode
    
        // filling cBuff with other data
    
        WSASend(...); // again, sending cBuff
    
        // ..... and so forth!
    }
    

    如果我理解正确,每个WSASend()调用都应该有自己的唯一缓冲区,并且只有在发送完成时才能重用该缓冲区。
    对的?


    而且,如果我要使用缓冲区,这意味着我应该将要从源缓冲区发送的数据复制到临时缓冲区,因此,我将每个套接字上的sou SNDBUF设置为零,这样系统就不会重新复制我已经复制的内容。你和我在一起吗?如果我不清楚,请告诉我。

    3 回复  |  直到 16 年前
        1
  •  3
  •   Nikolai Fetissov    16 年前

    认真看看 boost::asio . 异步IO是它的专长(顾名思义),它现在已经是相当成熟的库了 Boost examples 在文档中。

    有一件事是肯定的,那就是 buffers

    处理突发输入的基本思想是 排队 .

    • 自由的 缓冲器,一个用于 待处理 待发送 数据。
    • 自由的 列表(如果空闲列表为空,则分配一个新列表),填充数据,将其放到 列表。
    • 每次你需要接收东西的时候-从屏幕上取下一个缓冲区 自由的
    • 定期取下缓冲器 待发送 排队,把他们交给发送程序。
    • 发送完成时(内联或异步)-将它们放回 自由的 列表。
    • 接收完成时-将缓冲区放入
    • 列表。

    然后,突发将填充该输入队列,直到您能够处理它们。您可能需要限制队列大小,以避免占用所有内存。

        2
  •  1
  •   Sliq    16 年前

    同样,我不认为在发送完成之前更改缓冲区是个好主意。

    您将需要一个关键部分(或类似的部分)来在线程之间很好地共享队列,如果没有数据准备就绪,则可能需要一个事件或信号量供发送线程等待。

        3
  •  0
  •   Doug T.    16 年前

    现在,为了维护一大袋这样的缓冲区,我可以实现什么策略,我应该如何处理它们,如何避免性能损失,等等?

    如果不了解您的具体设计,就很难知道答案。一般来说,我会避免维护自己的“缓冲区包”,而是使用操作系统内置的缓冲区包——堆。

    struct Foo
    {
       int x;
       int y;
    };
    
    // foo will be consumed by SendFoo, and deallocated, don't use it after this call
    void SendFoo(Foo* foo);
    

    我会要求SendFoo的用户分配一个带有new的Foo实例,并告诉他们在调用SendFoo之后,内存不再由他们的代码“拥有”,因此他们不应该使用它。

    你可以通过一些小技巧来进一步实施:

    // After this operation the resultant foo ptr will no longer point to
    // memory passed to SendFoo
    void SendFoo(Foo*& foo);
    

    此接口还强制每个WSASend使用一块内存。在两个WSASend调用之间共享一个缓冲区时,您真的踏入了一个危险的领域。