非阻塞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则可以关闭套接字;
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则可以关闭套接字;
相关文章推荐
- UNIX环境高级编程学习之第十六章网络IPC:套接字 - 非阻塞的Socket通信Poll模型(多路复用), 实用Socket通信模板
- 非阻塞socket编程问题小结
- 非阻塞socket编程问题小结
- linux网络编程中阻塞和非阻塞socket的区别
- SOCKET编程c/s模式(阻塞模式下的)
- Socket编程之非阻塞connect
- Socket编程中,阻塞与非阻塞的区别
- 一步一步android(16):关于socket编程(2)【以非阻塞I/O服务器及Service为例】
- win无阻塞多线程socket编程模型
- 非阻塞socket编程问题小结
- socket编程之阻塞模式
- socket编程 ------ 建立 TCP 服务器和客户端流程(阻塞方式)
- linux网络编程中阻塞和非阻塞socket的区别
- socket编程的同步、异步与阻塞、非阻塞示例详解之一
- socket编程之connect非阻塞模型-初探
- linux 客户端 Socket 非阻塞connect编程
- Socket编程中,阻塞与非阻塞的区别
- [python&php 网络编程]把socket改成阻塞或非阻塞模式
- Socket编程中,阻塞与非阻塞的区别
- socket-select函数来实现非阻塞的网络编程