简单来说:阻塞就是说完了就回不来了。看看有没有其他的东西,发现有卡住的,第一时间向领导报告。我们以最常用的send和recv函数为例...比如你调用send函数发送某个Byte,那么send在系统中所做的工作实际上只是将数据传输(复制)到TCP/IP协议栈Buffer的输出,它执行成功并不代表数据已经发送成功。如果TCP/IP协议栈没有足够的可用缓冲区来保存你复制的数据...这时候体现阻塞和非阻塞的区别是:对于阻塞模式socketsend函数直到系统返回才会返回buffer有足够的空间在返回之前复制你要发送的数据,但是对于非阻塞socket,send会立即返回WSAEWOULDDBLOCK告诉调用作者说:“发送操作被阻塞!!!你可以想办法去处理它……”对于recv函数,也是如此。这个函数内部的工作机制其实就是在等待TCP/IP协议栈的接收缓冲区通知它:嘿,你的数据来了。对于阻塞模式的socket,如果TCP/IP协议栈的接收缓冲区没有通知它一个结果,它永远不会返回:它消耗系统资源....对于非阻塞模式,socket的功能将立即返回,然后告诉你:WSAEWOULDDBLOCK---“现在没有数据,我们回头再看”扩展:在做网络编程的时候,我们经常会看到四种调用方式:同步、异步、阻塞和非阻塞方式。这些方法彼此不容易理解。以下是我对这些术语的理解。1.同步所谓同步,就是当一个函数调用发出后,直到得到结果后调用才会返回。按照这个定义,其实大部分函数都是同步调用的(比如sin、isdigit等)。但一般来说,当我们说同步和异步时,特指需要其他组件配合或需要一定时间才能完成的任务。最常见的示例是SendMessage。该函数向某个窗口发送消息,直到对方处理完该消息后,该函数才返回。对方完成处理后,函数将消息处理函数返回的LRESULT值返回给调用方。2.异步和异步的概念是相对于同步而言的。当发出异步过程调用时,调用者不能立即得到结果。实际处理调用的组件会在完成状态、通知和回调时通知调用者。以CAsycSocket类为例(注意CSocket是从CAsyncSocket派生出来的,但是函数已经由异步转为同步),当客户端调用Connect函数发送连接请求时,调用者线程可以立即跑下来。当连接真正建立时,socket底层会发送消息通知对象。这里提到执行组件和调用者通过三种方式返回结果:状态、通知和回调。使用哪一个取决于执行组件的实现,不受调用者的控制,除非执行组件提供多种选择。如果状态通知执行组件,调用者需要定时查看,效率很低(有些刚接触多线程编程的人总喜欢用循环查看变量的值,这实际上是一个严重的错误)。如果采用通知的方式,效率非常高,因为执行部分几乎不需要做额外的操作。至于回调函数,和通知没有太大区别。3.阻塞阻塞调用是指在调用结果返回之前,当前线程将被挂起。函数只有在有结果后才返回。有些人可能会将阻塞调用等同于同步调用,但实际上它们是不同的。对于同步调用,很多情况下当前线程还是活跃的,但逻辑上当前函数并没有返回。比如我们调用CSocket中的Receive函数,如果缓冲区中没有数据,这个函数就会等到有数据再返回。这时,当前线程会继续处理各种消息。如果主窗口和调用函数在同一个线程,除非你在专门的界面操作函数中调用,否则主界面应该还是可以刷新的。socket接收数据的另一个函数recv是一个阻塞调用的例子。当socket工作在阻塞模式时,如果在没有数据的情况下调用该函数,则当前线程会被挂起,直到有数据为止。4.非阻塞非阻塞的概念对应于阻塞,是指函数在无法立即获取结果之前不会阻塞当前线程,而是立即返回。对象的阻塞模式与阻塞函数调用对象是否处于阻塞模式与函数是否阻塞调用有很强的相关性,但并不存在一一对应关系。阻塞对象上可以有一个非阻塞调用方法。我们可以通过一定的API轮询状态,在合适的时候调用阻塞函数来避免阻塞。对于非阻塞对象,调用特殊函数也可以进入阻塞调用。函数select就是一个例子。
