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)。