设置成非阻塞模式:
先用fcntl的F_GETFL获取flags,用F_SETFL设置flags|O_NONBLOCK;
即:
flags = fcntl(sockfd, F_GETFL, 0); //获取文件的flags值。
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); //设置成非阻塞模式;
同时在接收和发送数据时,需要使用MSG_DONTWAIT标志
即:
在recv,recvfrom和send,sendto数据时,将flag设置为MSG_DONTWAIT。
设置成阻塞模式:
先用fcntl的F_GETFL获取flags,用F_SETFL设置flags&~O_NONBLOCK;
即:
flags = fcntl(sockfd,F_GETFL,0); //获取文件的flags值。
fcntl(sockfd,F_SETFL,flags&~O_NONBLOCK); //设置成阻塞模式;
同时在接收和发送数据时,需要使用阻塞标志
即:
在recv,recvfrom和send,sendto数据时,将flag设置为0,默认是阻塞。
在将socket设置成非阻塞模式后,每次的对于sockfd 的操作都是非阻塞的;
非阻塞模式下:
connect
=0 当返回0时,表示立即创建了socket链接,
<0 当返回-1时,需要判断errno是否是EINPROGRESS(表示当前进程正在处理),否则失败。
例如:下面会有select或epoll监听fd是否建立链接,
select监听connect是否成功的例子,注意getsockopt验证,因为三次握手的第三个ACK有可能会丢失,但是客户端认为链接已经建立:
int ret = ::connect(_socket_fd, add.addr(), add.length()); if(ret == 0) { //建立链接成功 } else if(ret < 0 && errno == EINPROGRESS) //errno == EINPROGRESS表示正在建立链接 { // 等待连接完成,errno == EINPROGRESS表示正在建立链接 fd_set set; FD_ZERO(&set); FD_SET(_socket_fd,&set); //相反的是FD_CLR(_sock_fd,&set) time_t = 10; //(超时时间设置为10毫秒) struct timeval timeo; timeo.tv_sec = timeout / 1000; timeo.tv_usec = (timeout % 1000) * 1000; int retval = select(_socket_fd + 1, NULL, &set, NULL, &timeo); //事件监听 if(retval < 0) { //建立链接错误close(_socket_fd) } else if(retval == 0) // 超时 { //超时链接没有建立close(_socket_fd) } //将检测到_socket_fd读事件或写时间,并不能说明connect成功 if(FD_ISSET(_socket_fd,&set)) { int error = 0; socklen_t len = sizeof(error); if(getsockopt(_socket_fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { //建立简介失败close(_socket_fd) } if(error != 0) // 失败 { //建立链接失败close(_socket_fd) } else { //建立链接成功 } } } else { //出现错误 close(_sock_fd) }