非阻塞socket编程

本文详细介绍了socket编程中可能出现的阻塞调用,包括write、send、read、recv等,并阐述了如何在select中观察描述符变化以避免阻塞,以及如何处理非阻塞connect调用,包括创建套接字、设置非阻塞属性、开始建立连接、检查连接状态等关键步骤。

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

socket编程中可能出现阻塞的调用有4个:

1. write、send、sendto、sendmsg、sendv等,如果某个进程调用一个阻塞的TCP套接字(默认设置),如果发送缓冲区没有空间,调用进程将会睡眠,直到有空间为止。 如果TCP套接字是非阻塞的,且没有空间可写,则会返回一个EWOULEBLOCK的错误。

2.read、recv、recvfrom、recvmsg、recvv等,如果某个进程调用一个阻塞的TCP套接字(默认设置),如果接收缓冲区没有数据可读,调用进程将会睡眠,直到有数据可读为止。 如果TCP套接字是非阻塞的,且没有数据可读,则会返回一个EWOULEBLOCK的错误。

3. accept调用,如果一个阻塞的套接字调用accept且没有新连接到达,则调用进程将睡眠。如果一个非阻塞的套接字调用accept且没有新连接到达,调用进程返回EWOULEBLOCK。

4. connect 调用,connect至少会阻塞其调用进程一个RTT(RTT从微秒到几秒不等),如果一个非阻塞的套接字调用connect,且不能立即建立连接,则会返回一个EINPROCESS,正在进行3路握手连接。如果connect非阻塞,如果检查其成功建立连接是一个比较麻烦的过程。

对应1、2、3,可以在select观察到描述符发生变化后再调用它们,则可防止阻塞发生。但是对于4只能先设置套接字为非阻塞(通过fnctl)。

处理非阻塞connect的步骤:
第一步:创建socket,返回套接口描述符;
第二步:调用fcntl把套接口描述符设置成非阻塞;
第三步:调用connect开始建立连接;
第四步:判断连接是否成功建立;
A:如果connect返回0,表示连接简称成功(服务器可客户端在同一台机器上时就有可能发生这种情况);
B:调用select来等待连接建立成功完成;
      如果select返回0,则表示建立连接超时;我们返回超时错误给用户,同时关闭连接,以防止三路握手操作继续进行下去;
      如果select返回大于0的值,则需要检查套接口描述符是否可读或可写;如果套接口描述符可读或可写,则我们可以通过调用getsockopt来得到套接口上待处理的错误(SO_ERROR),        如果连接建立成功,这个错误值将是0,如果建立连接时遇到错误,则这个值是连接错误所对应的errno值(比如:ECONNREFUSED,ETIMEDOUT等).
"读取套接口上的错误"是遇到一个可移植性问题;如果出现问题,getsockopt源自Berkeley的实现是返回0,等待处理的错误在变量errno中返回;但是Solaris会让getsockopt返回-1,errno置为待处理的错误;我们对这两种情况都要处理;

Plus:socket在接收数据(读)的时候,可以先用ioctl(sockfd, FIONREAD, &nread); 查询缓冲区中有多少数据,查询的字节数放在nread中。如果为0则可以关闭套接字;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值