高性能网络编程中的几个基本概念

阻塞(blocking)和非阻塞(non-blocking):阻塞和非阻塞是指用户进程在做read(), write()等系统调用的时候,根据系统调用当前所处的状态而采取的不同的处理策略。拿read()函数来说,阻塞情况下,如果没有数据到达,则用户进 程一直等待(睡眠),直到数据到达,这个过程中用户进程处于睡眠状态,干不了其他事情;非阻塞情况下,如果数据没有到达,则立即返回给用户进程一个状态信息(EAGAIN,EWOULDBLOCK等),用户进程根据这个状态信息选择继续调用read()还是去干其他事情。

同步(synchronous)和异步(asynchronous):同步和异步是整个IO操作中用户进程的参 与程度。还是拿read()来说,同步的情况下,用户进程会全程参与到read()系统调用中,不管是以阻塞的方式还是非阻塞的方式,用户进程跟内核不断 地交互,直到所有的数据都收到;而在异步的情况下,用户进程只需要告知内核我要做read()操作,你给我把该网络fd上到来的数据都存到buf中,存好 了告诉我,然后用户进程就去做其他事情了,当内核把所有的数据都存到buf中时,再通知用户进程,用户进程再做相应的处理。可以看出,比起同步IO,异步 IO充分解放了用户进程,使得它在相同的时间内干更多的活。

 

系统IO可以分为: blocking IO, ornon-blocking synchronous IO, 和non-blocking asynchronousIO三种

关于它们三者的区别,我想下面的三段话解释得够非常好:

BlockingI/O means that the calling system does notreturn control to the caller until the operation is finished. As a result, thecaller is blocked and cannot perform other activities during that time. Mostimportant, the caller thread cannot be reused for other request processingwhile waiting for the I/O to complete, and becomes a wasted resource duringthat time. For example, a read() operation on a socketin blocking mode will not return control if the socket buffer is empty untilsome data becomes available.

a non-blocking synchronous call returns control to the callerimmediately. The caller is not made to wait, and the invoked system immediatelyreturns one of two responses: If the call was executed and the results areready, then the caller is told of that. Alternatively, the invoked system cantell the caller that the system has no resources (no data in the socket) toperform the requested action. In that case, it is the responsibility of thecaller may repeat the call until it succeeds. For example, a read() operationon a socket in non-blocking mode may return the number of read bytes or aspecial return code -1 with errno set to EWOULBLOCK/EAGAIN,meaning "not ready; try again later."

In a non-blocking asynchronous call, the calling functionreturns control to the caller immediately, reporting that the requested actionwas started. The calling system will execute the caller's request usingadditional system resources/threads and will notify the caller (by callback forexample), when the result is ready for processing. For example, a Windows ReadFile() orPOSIX aio_read() API returns immediately and initiatesan internal system read operation. Of the three approaches, this non-blockingasynchronous approach offers the best scalability and performance.

 

 

Ps:滑动窗口和TCP内核协议栈缓冲区的关系,对于一个send操作来说来说,尤其是一个非阻塞的操作,send函数的返回值就是内核缓冲区有多少空间,也就是send的返回值是拷贝到内核缓冲区的字节数;但是滑动窗口是从内核缓冲区能否通过协议栈发送给对端的前提条件,如果仍然有窗口可以使用,那么内核就进行发送,如果没有窗口可以使用,就暂停发送

TCP 数据的发送存在 2 个过程:
1. 拷贝到发送缓冲区,这就是 send 干的事情
2. 协议栈将发送缓冲区中的数据发送出去,是否能发、发多少字节,取决于滑动窗口的大小(实际上不光是滑动窗口,还有一个拥塞窗口的概念,协议栈取的是最小值),并且在收到 ACK 后清除缓冲区中被确认的数据。
所以,send 成功与否,跟滑动窗口是没有直接关系的,不管是 block 还是 nonblock。跟是否收到 ACK 更没关系。
你可以写个 socket 测试下:
三次握手之后,拔掉交换机上的网线(不能拔本机网线,否则会导致接口 down),然后再反复调用 send。你会发现,send 会一直成功,直到缓冲区满掉。而事实上,在缓冲区满掉之前,滑动窗口早就满了。而在这个过程中,接收方的 ACK 也肯定是过不来的。

你可能感兴趣的:(c,网络编程)