您的位置:首页 > 编程语言

非阻塞socket编程

2014-08-06 12:49 281 查看
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则可以关闭套接字;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: