原文:
将一个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)
}

注意:这里主要是想强调当epoll或select监听到sockfd上有EPOLL_IN或EPOLL_OUT时,即读写事件时,并不能说明链接已经建立,如上面的代码。

/*

int error = 0;
socklen_t ilen = sizeof(error);
ret = getsockopt(fd,SOL_SOCKET,SO_ERROR,&error,&ilen);
if(ret < 0)
{
      //说明链接建立失败,close(fd);
}
else if(error != 0 )
{

//说明链接建立失败,close(fd);
}

else

{

//说明链接建立成功。即可以向fd上写数据。

}

*/

 recv 和 recvfrom

=0  当返回值为0时,表示对端已经关闭了这个链接,我们应该自己关闭这个链接,即close(sockfd)。另外因为异步操作会用select或epoll做事件触发,所以:

1、如果使用select,应该使用FD_CLR(sockfd,fd_set)将sockfd清除掉,不再监听。

2、如果使用epoll,系统会自己将sockfd清除掉,不再进行监听。

 >当返回值大于0 且 小于sizeof(buffer)时,表示数据肯定读完。(如果等于sizeof(buffer),可能有数据还没读,应该继续读,不可能有大于)

 <0 当返回值小于0,即等于-1时,分情况判断:

1、如果   errno   为  EAGAINE  或 EWOULDBLOCK

表示暂时无数据可读,可以继续读,或者等待epoll或select的后续通知。(EAGAINE,EWOULDBLOCK产生的

原因:可能是多进程读同一个sockfd,可能一个进程读到数据,其他进程就读取不到数据(类似惊群效应),当然

单个进程也可能出现这种情况。对于这种错误,不需用close(sockfd)。可以等待select或epoll的下一次触发,

继续读。)

2、如果   errno   为  EINTR

表示被中断了,可以继续读,或者等待epoll或select后续的通知。

否则,真的是读取数据失败。(此时应该close(sockfd))

send和sendto

返回值是实际发送的字符数,因为我们知道要发送的总长度,所以,如果没有发送完,我们可以继续发送。

<0 当返回值为 -1   时, 我们需要判断  errno:

1、如果errno为  EAGAINE   或 EWOULDBLOCK ,表示当前缓冲区写满,可以继续写,

或者等待epoll或select的后续通知,一旦有缓冲区,就会触发写操作,这个也是经常利用的一个特性。

2、如果errno为EINTR  ,表示被中断了,可以继续写,或者等待epoll或select的后续通知。

否则真的出错了,即errno不为EAGAINE或EWOULDBLOCK或EINTR,此时应该close(sockfd)

>=0 >=0且不等于要求发送的长度,应该继续send,如果等于要求发送的长度,发送完毕。

socket异步通信-如何设置成非阻塞模式、非阻塞模式下判断connect成功(失败)、判断recv/recvfrom成功(失败)、判断send/sendto的更多相关文章

  1. IO模式设置网络编程常见问题总结—IO模式设置,阻塞与非阻塞的比较,recv参数对性能的影响—O_NONBLOCK(open使用)、IPC_NOWAIT(msgrcv)、MSG_DONTWAIT(re

    非阻塞IO 和阻塞IO: 在网络编程中对于一个网络句柄会遇到阻塞IO 和非阻塞IO 的概念, 这里对于这两种socket 先做一下说明:       基本概念: 阻塞IO:: socket 的阻塞模式 ...

  2. linux socket设置阻塞与非阻塞

    非阻塞IO 和阻塞IO: 在网络编程中对于一个网络句柄会遇到阻塞IO 和非阻塞IO 的概念, 这里对于这两种socket 先做一下说明:       基本概念: 阻塞IO:: socket 的阻塞模式 ...

  3. socket阻塞与非阻塞,同步与异步、I/O模型,select与poll、epoll比较

    1. 概念理解 在进行网络编程时,我们常常见到同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式: 同步/异步主要针对C端: 同步:      所谓同步,就 ...

  4. socket阻塞与非阻塞,同步与异步

    socket阻塞与非阻塞,同步与异步 作者:huangguisu 转自:http://blog.csdn.net/hguisu/article/details/7453390 1. 概念理解 在进行网 ...

  5. socket编程-阻塞和非阻塞

    转自:https://www.cnblogs.com/sunziying/p/6501045.html 建立连接 阻塞方式下,connect首先发送SYN请求道服务器,当客户端收到服务器返回的SYN的 ...

  6. linux-socket connect阻塞和非阻塞模式 示例

    ~/cpp$ ./connect 192.168.1.234 1234 kkkk block mode:  ubuntu 14.04 : time used:21.0.001053s connect ...

  7. Socket调用方式(同步,异步,阻塞,非阻塞)

    同步: 我调用一个功能,该功能没有结束前,我死等结果. 异步: 当一个异步过程调用发出后,调用者不能立刻得到结果.该功能在完成后,通过状态.通知和回调来通知调用者. 同步和非同步关注的是调用者是否等待 ...

  8. 网络编程中阻塞和非阻塞socket的区别

    阻塞socket和非阻塞socket 建立连接阻塞方式下,connect首先发送SYN请求道服务器,当客户端收到服务器返回的SYN的确认时,则connect返回.否则的话一直阻塞.非阻塞方式,conn ...

  9. 怎样通过MSG_WAITALL设置阻塞时间,IO模式精细讲解: MSG_DONTWAIT 、 MSG_WAITALL

    首先给出MSDN上一段设置阻塞超时的代码:(网址为http://social.msdn.microsoft.com/Forums/zh-SG/visualcpluszhchs/thread/3d9da ...

随机推荐

  1. Python学习教程(learning Python)--2.1 Python下自定义函数

    在Python里可以自定义函数,实现某特定功能,这里首先要区分一下函数的定义和函数的调用两个基本概念,初学者往往容易混淆. 函数的定义是指将一堆能实现特定功能的语句用一个函数名标识起来,而函数的调用则 ...

  2. C#模糊查询绑定datagridview

    private CollectionViewSource wgdData = new CollectionViewSource(); private DataTable Ds_wgd { get { ...

  3. C,C++容易被忽略的问题

    1.字符串数组,字符串指针可以直接输出 ]="I am a student"; cout<<s2<<endl; char *p="I am a s ...

  4. VBA赋值给指定单元格

    这是一个Range对象基本操作实例,对指定单元格赋值,然后使用弹窗获取值. 代码如下: Sub test1() Worksheets( MsgBox "工作表Sheet1内单元格A5中的值为 ...

  5. 透过数据看现实,漫谈实况FIFA的这些年

    虽然,只是个普通玩家,虽然带了一点青春,一点爱.虽然,有那么些怀念 ~ 好吧,不浪费篇幅伪伪的煽情,直插主题.(很长且多图,更多讲述的是实况FIFA间的你来我往,互相赶超的故事.本想全面展开描述细节, ...

  6. hdu 1873 看病要排队

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=1873 看病要排队 Description 看病要排队这个是地球人都知道的常识.不过经过细心的0068的 ...

  7. java 切换

    Android L之后推荐使用JDK7编译程序,这是自然发展规律,就像是4年前编译Android 1.6需要使用JDK5一样. 多版本JDK是可以共存的,只需要使用update-alternative ...

  8. django-pagination的使用

    1.安装django-pagination 2.将文件夹pagination复制到项目的根目录下 3.修改settings: 1.将 'pagination.middleware.Pagination ...

  9. wordpress nginx 开启链接为静态

    使用固定连接里的自定义 /%postname%/ 日志标题的缩略版本(日志/页面编辑界面上的日志别名).因此“This Is A Great Post!”在URI中会变成this-is-a-great ...

  10. VC++编程中获取系统时间

    <span style="white-space:pre"> </span>总结了在程序中如何获得系统时间的方法 void CGetSystenTimeDl ...