Windows Sockets编程(三)操作模式2

本文详细解析了Winsock阻塞模式的概念、关键函数及其特性,包括阻塞函数、伪阻塞机制、阻塞情境的避免与撤销、自动与用户可设置的超时、以及TCP存活超时等概念。同时,文章还讨论了阻塞操作的滞后生效、限制和可能的失败情况,为开发者提供了全面的Winsock阻塞模式指导。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、阻塞模式

1、通过socket()函数调用得到一个socket描述符时,默认为该socket采取阻塞模式。这意味着引用这个socket句柄的某些WInsock函数调用将会阻塞,直到操作完成。

阻塞式函数:

accept():应用程序收到一个连接请求。

closesocket():关闭操作完成(只是流socket阻塞,并且只在setsockopt()的SO_LINGER设置了非0超时值时)

connect():连接操作完成(只对流socket)

recv() recvfrom():网络系统在这个socket上接收到数据

send() sendto():网络系统中有输出数据可用的缓存空间(只对流socket)


2、还有一些函数总是阻塞的,无论传递给它的是否是一个阻塞的socket。

select():检测socket集合的可读性、可写性和错误

gethostbyname():通过主机名查询主机信息

gethostbyaddr():通过主机地址查询主机信息

getprotobyname():通过协议名查询协议号

getprotobynumber():通过协议号查询协议名

getservbyname():通过服务名查询服务信息

getservbyport():通过端口号查询服务信息


3、伪阻塞:

虽然应用程序在等待网络操作完成,但是WINSock DLL却在等待时进行了避让,在等待操作完成时,由于WinSock DLL调用了阻塞钩子函数,因此使阻塞变成了伪阻塞。

通常,默认的阻塞钩子函数调用WinAPI函数PeekMessage()、DispatchMessage()和TranslateMessage(),方式与Windows应用程序的消息循环相似。

重入消息:

应用程序在阻塞操作尚未完成时所接收的消息。当应用程序在前门等待阻塞操作完成时,他们将从后门溜出来。


4、阻塞情境:

只要存在一个未完成的阻塞函数,任何WInsock函数(无论它是否发起另一个阻塞操作)都可能失败并产生WSAEINPROGRESS错误信息。

如何避免阻塞情境所带来的问题:

1)如果已提交了一个WinSock调用,则正确应对所返回的WSAEINPROGRESS错误信息。

2)使用WSAIsBlocking()检测阻塞情境,避免WInSock调用。

BOOL PASCSL FAR WSAIsBlocking( void);  //当前任务或线程即为输入参数

3)维持应用程序的状态信息,用以检测阻塞情境,避免WinSock调用。

可以维持一个代表应用程序当前状态的变量。例如,如果在状态变量中指明了connect()函数是成功的,你就会知道send()函数不会发生WSAENOTCONN错误。


5、撤销阻塞操作:

允许用户在应用程序的任何一点撤销阻塞操作是可能的,也可以使用一个Windows的定时器来实现自己的超时控制。函数WSACancelBlockingCall()允许通过强制其失败来强行结束一个等待的阻塞操作。

int PASCAL FAR WSACancelBlockingCall( void);  //0 on success

任务或线程即为参数。失败时,函数返回SOCKET_ERROR错误,WSAGetLastError返回WSAEINVAL错误。

1)撤销作用滞后生效:

此函数总是立即返回,并不等待处理中的阻塞函数撤销完成,所以阻塞操作在此函数返回时仍然处于待决状态。当被中断的函数以WSAEINTR错误(被中断的系统调用)返回时,阻塞操作的撤销才完成。

2)限制socket的继续使用:

对某些阻塞socket调用的撤销可能会导致一个socket处于中间状态,或损害一个数据流的完整性。只有函数accept和select是例外。

3)撤销操作可能失败:

设置一个状态变量记录撤销请求,即使撤销操作失败(即阻塞函数成功返回),仍可以让应用程序继续执行撤销操作。当撤销生效时,任何阻塞函数必须能够处理返回的WSAEINTR错误。


6、自动超时:

诸如connect、send和gethostbyname的函数将会自动超时。其超时与所采用协议的超时机制的实现有关。

7、用户可设置的超时:

诸如select、closesocket的函数允许应用程序来决定超时值。对于closesocket函数,默认情况下它不是阻塞模式的,即使对于阻塞socket也是如此。因此,只有对一个阻塞socket,并且调用setsockopt()设置非0的超时值来使能SO_LINGER选项时,它才是阻塞式的。一般来说,应用程序不该为closesocket设置非0的超时值。

8、应用程序超时:

诸如recv、recvfrom或accept的函数能够永远阻塞下去。所以,当没有数据可接收或者没有接收到连接请求时,它们将一直不返回。

9、TCP存活超时:

为流socket提供超时控制功能的另一种方法是设置setsockopt()选项SO_KEEPALIVE。这将使协议族周期性地发送TCP”存活“数据包,接收方必须将数据包反馈给发送方作为对接收的确认。若没有收到反馈,则之后的任何I/O操作或者待处理的I/O操作都将失败并返回WSAETIMEOUT错误。

10、无最少接收限制值:

函数recv或recvfrom的输入参数len定义了输入数据缓存区的长度(即上限值)。

注意:长度域的值不是WinSock从阻塞函数recv或recvfrom返回前必须复制的最小字节数。这是一个常见的错误,会导致应用程序丢失数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值