从:http://blog.sina.com.cn/s/blog_5d0990c7010115ib.html 转载
Socket 阻塞与非阻塞模式
阻塞模式
Windows套接字在阻塞和非阻塞两种模式下执行I/O操作。在阻塞模式下,在I/O操作完成前,执行的操作函数一直等候而不会立即返回,该函数所在的线程会阻塞在这里。相反,在非阻塞模式下,套接字函数会立即返回,而不管I/O是否完成,该函数所在的线程会继续运行。
在阻塞模式的套接字上,调用任何一个Windows Sockets API都会耗费不确定的等待时间。图所示,在调用recv()函数时,发生在内核中等待数据和复制数据的过程。
当调用recv()函数时,系统首先查是否有准备好的数据。如果数据没有准备好,那么系统就处于等待状态。当数据准备好后,将数据从系统缓冲区复制到用户空间,然后该函数返回。在套接应用程序中,当调用recv()函数时,未必用户空间就已经存在数据,那么此时recv()函数就会处于等待状态。
当使用socket()函数创建套接字时,默认的套接字都是阻塞的。这意味着当调用Windows Sockets API不能立即完成时,线程处于等待状态,直到操作完成。
并不是所有Windows Sockets API以阻塞套接字为参数调用都会发生阻塞。例如,以阻塞模式的套接字为参数调用bind()、listen()函数时,函数会立即返回。将可能阻塞套接字的Windows Sockets API调用分为以下四种:
1.输入操作
recv()、recvfrom()、WSARecv()和WSARecvfrom()函数。以阻塞套接字为参数调用该函数接收数据。如果此时套接字缓冲区内没有数据可读,则调用线程在数据到来前一直睡眠。
2.输出操作
send()、sendto()、WSASend()和WSASendto()函数。以阻塞套接字为参数调用该函数发送数据。如果套接字缓冲区没有可用空间,线程会一直睡眠,直到有空间。
3.接受连接
accept()和WSAAcept()函数。以阻塞套接字为参数调用该函数,等待接受对方的连接请求。如果此时没有连接请求,线程就会进入睡眠状态。
4.外出连接
connect()和WSAConnect()函数。对于TCP连接,客户端以阻塞套接字为参数,调用该函数向服务器发起连接。该函数在收到服务器的应答前,不会返回。这意味着TCP连接总会等待至少到服务器的一次往返时间。
使用阻塞模式的套接字,开发网络程序比较简单,容易实现。当希望能够立即发送和接收数据,且处理的套接字数量比较少的情况下,使用阻塞模式来开发网络程序比较合适。
阻塞模式套接字的不足表现为,在大量建立好的套接字线程之间进行通信时比较困难。当使用“生产者-消费者”模型开发网络程序时,为每个套接字都分别分配一个读线程、一个处理数据线程和一个用于同步的事件,那么这样无疑加大系统的开销。其最大的缺点是当希望同时处理大量套接字时,将无从下手,其扩展性很差。
非阻塞模式
把套接字设置为非阻塞模式,即通知系统内核:在调用Windows Sockets API时,不要让线程睡眠,而应该让函数立即返回。在返回时,该函数返回一个错误代码。图所示,一个非阻塞模式套接字多次调用recv()函数的过程。前三次调用recv()函数时,内核数据还没有准备好。因此,该函数立即返回WSAEWOULDBLOCK错误代码。第四次调用recv()函数时,数据已经准备好,被复制到应用程序的缓冲区中,recv()函数返回成功指示,应用程序开始处理数据。
当使用socket()函数和WSASocket()函数创建套接字时,默认都是阻塞的。在创建套接字之后,通过调用ioctlsocket()函数,将该套接字设置为非阻塞模式。Linux下的函数是:fcntl().
套接字设置为非阻塞模式后,在调用Windows Sockets API函数时,调用函数会立即返回。大多数情况下,这些函数调用都会调用“失败”,并返回WSAEWOULDBLOCK错误代码。说明请求的操作在调用期间内没有时间完成。通常,应用程序需要重复调用该函数,直到获得成功返回代码。
需要说明的是并非所有的Windows Sockets API在非阻塞模式下调用,都会返回WSAEWOULDBLOCK错误。例如,以非阻塞模式的套接字为参数调用bind()函数时,就不会返回该错误代码。当然,在调用WSAStartup()函数时更不会返回该错误代码,因为该函数是应用程序第一调用的函数,当然不会返回这样的错误代码。
要将套接字设置为非阻塞模式,除了使用ioctlsocket()函数之外,还可以使用WSAAsyncselect()和WSAEventselect()函数。当调用该函数时,套接字会自动地设置为非阻塞方式。
由于使用非阻塞套接字在调用函数时,会经常返回WSAEWOULDBLOCK错误。所以在任何时候,都应仔细检查返回代码并作好对“失败”的准备。应用程序连续不断地调用这个函数,直到它返回成功指示为止。上面的程序清单中,在While循环体内不断地调用recv()函数,以读入1024个字节的数据。这种做法很浪费系统资源。
要完成这样的操作,有人使用MSG_PEEK标志调用recv()函数查看缓冲区中是否有数据可读。同样,这种方法也不好。因为该做法对系统造成的开销是很大的,并且应用程序至少要调用recv()函数两次,才能实际地读入数据。较好的做法是,使用套接字的“I/O模型”来判断非阻塞套接字是否可读可写。
非阻塞模式套接字与阻塞模式套接字相比,不容易使用。使用非阻塞模式套接字,需要编写更多的代码,以便在每个Windows Sockets API函数调用中,对收到的WSAEWOULDBLOCK错误进行处理。因此,非阻塞套接字便显得有些难于使用。
非阻塞套接字在控制建立的多个连接,在数据的收发量不均,时间不定时,明显具有优势。
这种套接字在使用上存在一定难度,但只要排除了这些困难,它在功能上还是非常强大的。通常情况下,可考虑使用套接字的“I/O模型”,它有助于应用程序通过异步方式,同时对一个或多个套接字的通信加以管理
相关推荐
本话题主要探讨的是在C++ Socket编程中的阻塞模式与非阻塞模式,以及它们在多线程环境下的应用和资源管理。 一、阻塞与非阻塞模式 1. **阻塞模式**:在阻塞模式下,当一个Socket调用(如recv或send)执行时,如果...
### Linux UDP Socket 非阻塞模式与阻塞模式的区别详解 #### 一、引言 在进行网络编程时,我们经常会遇到阻塞模式与非阻塞模式的选择问题。这两种模式直接影响程序的运行效率和资源利用率。本文将详细介绍在Linux...
在使用socket进行编程时,会遇到两种基本的操作模式:阻塞模式与非阻塞模式。这两种模式对于程序的性能和响应性有着重要的影响。 #### 二、阻塞模式 当一个socket处于阻塞模式时,所有的I/O操作都会阻塞当前线程,...
在通过一天学习,慢慢摸索中,研究出来了自己成果!
在这个"socket多线程例程非阻塞模式"的示例中,我们将深入探讨如何在Windows平台上实现多线程的socket通信,并了解非阻塞模式的工作原理。 首先,让我们来理解Socket的基本概念。Socket是进程间通信(IPC)的一种...
Socket编程中的阻塞与非阻塞、同步与异步是两个独立的概念,它们涉及的是不同层面的操作机制。这里我们将详细探讨这两个概念以及I/O模型。 首先,同步与异步是客户端(C端)调用服务端(S端)时的行为模式。同步...
通过本篇内容的学习,您将了解到设置socket函数为非阻塞模式的方法,并且能够深入了解阻塞与非阻塞模式在socket编程中的应用。此外,我们还将探讨SOCKET类的设计与实现。 #### 一、基本概念与环境搭建 **1.1 基本...
- **write**:`write`在阻塞和非阻塞模式下的行为与`send`类似,但需要注意的是,即使在非阻塞模式下,`write`也可能部分写入数据,然后返回已写入的字节数,而不是立即返回`EWOULDBLOCK`。这是因为`write`的语义...
非阻塞模式的Socket编程是网络编程中的一个重要概念,它与传统的阻塞模式Socket形成了鲜明对比。在阻塞模式下,Socket操作会一直等待直到有数据可读或可写,这可能导致程序在等待期间无法执行其他任务。而非阻塞模式...
在Windows中,可以使用WSAAsyncSelect()或WSAEventSelect()函数将Socket设置为非阻塞模式,并与Windows消息机制相结合,实现异步事件通知。这两种方法允许程序在等待Socket事件的同时处理其他任务,提高了系统的并发...
"Socket 通信(TCP)非阻塞模式-select 模型" 本资源是关于 Socket 通信的非阻塞模式下的 Select 模型的示例代码,基于 TCP 协议,分为服务器端和客户端。该示例代码展示了如何使用 Select 模型实现非阻塞 Socket ...
而非阻塞模式下,Socket调用不会使调用线程挂起,而是立即返回,即使没有数据可读或可写。这样,程序可以同时处理多个事件,提高系统效率和响应性。 MFC通过CAsyncSocket类提供对非阻塞Socket的支持。CAsyncSocket...
非阻塞模式是Socket的一种工作模式,与默认的阻塞模式相对。在阻塞模式下,如果尝试读取的数据尚未到达,或写入缓冲区已满,Socket会一直等待直到操作可以完成。而在非阻塞模式下,这些操作会立即返回一个错误状态,...
用一个最简单的例子说明异步非阻塞Socket的基本原理和工作机制
在非阻塞模式下,Socket调用不会阻塞,而是立即返回,告知调用者数据是否已经准备好。而在异步模式中,操作系统会在数据准备就绪时通知应用程序,这样可以确保程序在等待数据的同时执行其他任务。 然而,对于初学者...
Python的socket模块通过设置socket的选项,可以将socket转变为非阻塞模式。在非阻塞模式下,socket的send和recv等操作都会立即返回。如果操作不能立即完成,就会抛出异常或返回错误码。 多线程是实现非阻塞通讯的...
tcp socket同步 异步 阻塞 非阻塞 的解释.zip 基本概念:同步、异步、阻塞和非阻塞的区别 同步异步与阻塞非阻塞的区别 C++ 同步异步与阻塞非阻塞的区别
对于需要高效处理大量并发连接的场景,非阻塞模式与事件驱动编程是更好的选择。而对于简单且对实时性要求不高的应用,阻塞模式则相对易于实现。了解和掌握这两种模式及其转换方法是开发高质量网络应用的关键。