网络(4):socket中用户自定义缓冲区的原因及方式

我们在使用TCP/IP编程的时候除了socket有收发数据缓冲区之外,通常我们还要自己定一个数据的收发缓冲区:

1,为什么系统已经有收发缓冲区了,我们还要自定义收发缓冲区呢?

     a.假设应用程序需要发送40kB数据,但是操作系统的TCP发送缓冲区只有25kB剩余空间,那么剩下的15kB数据怎么办?如果等待OS缓冲区可用,会阻塞当前线程,因为不知道对方什么时候收到并读取数据。因此网络库应该把这15kB数据缓存起来,放到这个TCP连接的应用层发送缓冲区中,等socket变得可写的时候立刻发送数据,这样“发送”操作不会阻塞。如果应用程序随后又要发送50kB数据,而此时发送缓冲区中尚有未发送的数据(若干kB),那么网络库应该将这50kB数据追加到发送缓冲区的末尾,而不能立刻尝试write(),因为这样有可能打乱数据的顺序。

     b. 假如一次读到的数据不够一个完整的数据包,那么这些已经读到的数据是不是应该先暂存在某个地方,等剩余的数据收到之后再一并处理

2.在非阻塞网络编程中,如何设计并使用缓冲区?
     一方面希望减少系统调用,一次读的数据越多越划算,那么应该准备一个大的缓冲区。
     另一方面,希望减少内存占用。如果有10000个并发连接,每个连接一建立就分配各50kB的读写缓冲区(s)的话,将占用1GB内存,而大多数时候这些缓冲区的使用率很低。 可以readv(2)结合栈上空间解决了这个问题。

 

3.一下是几种建立缓冲区的方式:
  a.方法1: 每次接收到数据的时候开辟一个缓冲区(数据头是数据大小的);然后接受数据填入缓冲区,把缓冲区和IP信息付给任务,压入到任务队列,等任务线程处理; 发送亦然;(小数据可以用栈拷贝的形式)
            好处:是接收线程可以一直接收,任务线程一直处理,除了任务锁没有其他交互;
            缺点: 每次都重新申请空间,malloc(或new)消耗量大(可以使用内存池优化)

  b.方法2: 预先申请一块大的缓冲区(每个连接各申请一个接收缓冲区和发送缓冲区),接收线程有新数据到来的时候从缓冲区中数据结尾获得可用空间插入数据,把连接信息和整个缓冲区压入任务队列,任务线程处理一个任务的数据,就清空缓冲区该段的数据,然后将缓冲区中后面的数据前移(所以每次都是处理的第一个数据区的数据)
            好处:减少了malloc
            缺点:在数据插入和使用的时候都使用的锁,而且有严重的拷贝复制情况,(如果想任务处理和数据接收不互相锁,必须使用多的一份儿数据拷贝,情况就更糟)

  c.方法3:使用线程池,每个线程独立的读数据,当数据满足一个包的时候就当做任务处理;然后将链接信息和用户缓冲区添加到监听队列中;有新的数据来到就激活用一个新的线程处理

         好处:仅使用了线程间的锁,(可以使用无锁队列优化),减少数据拷贝

         缺点:线程上下文切换开销大, 数据接收分散

 D.方法4: 使用绑定线程(一个CPU核一个线程),线程分摊活动连接句(使用管道分发(hash)),单线程接收数据到缓存,然后结合协程做任务处理。

        优缺点:还没实现过,不确定

发布了34 篇原创文章 · 获赞 1 · 访问量 10万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览