将一个socket 设置成阻塞模式和非阻塞模式,使用fcntl方法,即:设置成非阻塞模式:先用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)
}