select 函数
- int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval*timeout);
- fd_set * readfds
需要监视变化的文件描述符
只要有一个文件可读就返回 > 0
没有文件可读
超出 timeout 时间, 返回 = 0
发生错误返回负值
传入 NULL 表示不关心任何文件
fd_set * readfds
需要监视变化的文件描述符
只要有一个文件可写就返回 > 0
没有文件可读
超出 timeout 时间, 返回 = 0
发生错误返回负值
传入 NULL 表示不关心任何文件
fd_set * errorfds
同上: 监视异常文件
struct timeval* timeout
select 的超时时间
为 NULL 时: select 置于阻塞状态
直到监视文件发生变化位置
为 0s0ms 时: select 变为纯非阻塞函数
不管文件描述符是否变化都立刻返回
有变化返回正数
无变化返回 0
大于 0 时为等待的超时时间
select 在 timeout 内阻塞
返回值
有可读文件: 表示可读文件的数量 返回值 > 0
没有可读文件: 判断 timeout 参数超时
超出 timeout 时间后 返回值 = 0
FD_ZERO
清空文件描述符集
FD_SET
在文件描述符集合中增加一个新的
FD_CLR
删除一个文件描述符
FD_ISSET
测试指定的文件描述符是否在集合中
SOCKET 函数
- int socket(int domain, int type, int protocol);
- int sockfd=socket(AP_INET, SOCK_STREAM | SOCK_NOBLOCK, IPPROTO_TCP);
ACCEPT 函数
- int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
- int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);
- flags: SOCK_NOBLOCK
- SOCK_CLOEXEC
FCNTL 函数
fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK);
IOCTL 函数
- ioctl(sockfd, FIONBIO, 1);//1: 非阻塞 0: 阻塞
- accept,connect,recv(recvfrom),send(sendto),closesocket,select(poll 或 epoll)
1)accept 在阻塞模式下, 没有新连接时, 线程会进入睡眠状态; 非阻塞模式下, 没有新连接时, 立即返回 WOULDBLOCK 错误
2)connect 在阻塞模式下, 仅 TCP 连接建立成功或出错时才返回, 分几种具体的情况, 这里不再叙述; 非阻塞模式下, 该函数会立即返回 INPROCESS 错误 (需用 select 检测该连接是否建立成功)
3)recv/recvfrom/send/sendto 很好理解, 因为这两类函数读写 socket 文件描述符的接收 / 发送缓冲区
4) select/poll/epoll 并不是真正意义上的阻塞, 它们的阻塞是由于它们最后一个 timeout 参数决定的, timeout 大于 0 时, 它们会一直等待直到超时才退出 (相等于阻塞了吧,^_^), 而 timeout=-1 即永远等待
5)closesocket 也不是真正意义上的阻塞, 它其实是指是否等待关闭它受套接字选项 SO_LINGER 和 SO_DONTLINGER 的影响
若 SO_DONTLINGER 或 SO_LINGER 的间隔 = 0 时, closesocket 就是非等待关闭的, 但是当 SO_LINGER 的间隔 > 0 时, closesoket 就是等待关闭的, 直到剩余数据都发送完毕或直到超时才退出
(但是这个地方只有对于阻塞的套接口才有用, 如果是非阻塞的套接口, 它会立即返回并且指示错误 WOULDBLOCK)
来源: http://www.bubuko.com/infodetail-2514646.html