到底该如何理解socket的阻塞/非阻塞/同步/异步

转载自:https://blog.csdn.net/voidccc/article/details/8619514

这4个名词的解释网络上有很多种版本和很多种比喻,个人不太喜欢打比方的方式来理解技术问题,因为很难有贴切的比喻,稍不注意就把人带到沟里.我们这里只通过技术模型来理解这4个术语,忽略这些名词广义上的定义,通过分析下面这个具体的场景来分享下我对他们的理解:


场景:假设要通过一个socket发送的数据是5k大小的一段文本,内核的发送缓冲区4k.

首先要搞明白一个基础问题,当我们在socket上调用一个发送操作时(send/write),虽然我们希望将数据发送到网络另一端,但是对于操作系统来说,它只要把用户态的数据成功拷贝到内核的发送缓冲区中排队等待发送,就可以给用户态的程序一个最后的交代了,操作系统给用户态发送的所有通知信息都是表明数据拷贝完成情况的,而操作系统从来不保证你的这些数据已经被网络另一端读取到了.即使对方读取到了,应用层也不会再获得什么通知.应用层完全无法获知数据是否真的到达了网络另一端.当在一个socket连接上应用写操作时,最好理解为拷贝数据到发送队列中并通知TCP队列中有了新数据(参考:高级TCP/IP编程15节) 

只从数据角度考虑,socket的发送函数最主要的参数就是一块用户态内存(void* buf, int length).对于发送操作(send/write),我们可以从下面两个方面理解
    1 函数调用完成后 多少数据拷贝完毕
    2 如果发送的数据超出发送缓冲区的大小,调用过程和影响是怎样的

     1 阻塞
    内核首先将5k里的前4k数据拷贝到发送缓冲区,4k拷贝完成后,要等待4k中的数据里最前端的1k数据发送到网络并且得到了对方SYN确认后,内核确认对方已经收到了这1k的数据,于是将这1k数据从缓冲区中清除,这样空余出1k的缓冲区,然后内核将剩余的1k数据拷贝到发送缓冲区,此后send/write返回.注意这里不会再等待剩余数据被对端接受才返回,因为数据已经拷贝到缓冲区,任务完成了可以给用户态交代了.待send/write返回后,用户态的5k数据对内核来说已经失效了,因为5k数据里的1k已经到达网络另一端机器的内核缓冲区,4k位于自己的内核缓冲区.用户态程序可以释放这5k数据了
     2 非阻塞
    内核将5k里的前4k数据拷贝到发送缓冲区,4k拷贝完毕后,内核发现发送缓冲区已满,就不再等待了,直接返回到用户态,通过send/write返回值告知用户态有多少数据被成功拷贝到
发送缓冲区.也就是说send/write调用返回后,用户态前4k数据已经拷贝完毕.目前这4k数据有两份,用户态一份发送缓冲区一份,当网络可用时,内核直接使用发送缓冲区的数据.在writ
e调用返回后用户态的5k数据里前4k就可以释放了,最后1k还必须留着,因为发送缓冲区里没有这1k数据的副本.与阻塞socket不同的是,当发送缓冲区之后因为数据的发送而有了一些空间的时候,非阻塞socket会通过某种方式(select poll epoll)通知用户态,这里不做详述.
     3 异步
    对于socket来说,异步意味着被send/write的实现体里(不一定是内核了,异步IO可能是库来提供的)只能做很少的记录工作,通常只限于几个值或指针的拷贝动作,而不能存在大量>的数据拷贝,比如把待发送的数据从用户态拷到发送缓冲区就属于大量数据拷贝,因为数据拷贝是要花费时间的,这个时间不像几条赋值语句一样短,算上这个时间这就不叫"同步"了.异步操作只做了记录工作而已,记录下了在用户态的xx地址处有个5k的缓冲区,后续内核要读取数据就可以将xx地址处的数据拷贝到内核态.也就是说当send/write函数返回时缓冲区没被拷贝,只记录下了有这么个数据块要发送.当函数返回后,如果你迅速修改了5k缓冲区里的内容还是有可能会影响到数据发送的,因为数据还没有发生拷贝,这里可以与上面的两种"同步socket"做对比.前两种都执行了数据拷贝的工作才返回.当然了发送完成后异步socket也会通过某种方式通知用户态,这里也不做详述
     4 同步
    在日常编程时,不存在一种单独的socket叫做"同步socket",上面的阻塞和非阻塞就是两种"同步socket",因为从行为上看这两种socket都要等待数据从用户缓冲区拷贝到协议栈发
送缓冲区才会返回,差别仅仅是缓冲区不足时的处理方式不同.只要缓冲区充足时,不管是阻塞还是非阻塞都会执行数据拷贝工作.从这个角度看所谓非阻塞也只是阻塞的时间短一些而已.如果发送的数据小于缓冲区,则阻塞和非阻塞socket的一次调用时间差异不大.总而言之,拷贝数据是需要花一点时间的,所以这两种socket都是同步socket

猜你喜欢

转载自blog.csdn.net/GDJ0001/article/details/80285447