`
aigo
  • 浏览: 2539832 次
  • 性别: Icon_minigender_1
  • 来自: 宜昌
社区版块
存档分类
最新评论

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

阅读更多
原文:
将一个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 当返回值大于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,如果等于要求发送的长度,发送完毕

分享到:
评论

相关推荐

    Linux系统调用-- recv/recvfrom 函数详解

    从套接字上接收一个消息。对于recvfrom ,可同时应用于面向连接的和无连接的套接字。recv一般只用在面向连接的套接...假如套接字上没有消息可以读取,除了套接字已被设置为非阻塞模式,否则接收调用会等待消息的到来。

    Socket通信(TCP)非阻塞模式-select模型

    这个范例是个基于TCP协议的非阻塞模式下的SOCKET通信,应该非常具有代表性了,分为服务器端和客户端。

    Socket-send-and-recv-.rar_c socket send recv_socket

    Socket下send和recv使用的说明及介绍

    Socket C++ TCP阻塞\非阻塞 服务器 客户端 开发

    一个很详细的文档,基于c++ winsocket的非阻塞服务器开发

    详解socket阻塞与非阻塞,同步与异步、I/O模型

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

    socket非阻塞超时设置

    socket非阻塞超时设置可编译。VC6

    关于socket阻塞与非阻塞情况下的recv、send、read、write返回值.zip

    关于socket阻塞与非阻塞情况下的recv、send、read、write返回值.zip

    socket_recv函数使用心得.

    这是一份关于 socket_recv的文档,相信对想学习 socket_recv的同学一定有很大的帮助!

    iterm2-recv-zmodem.sh

    iterm2-recv-zmodem.sh

    安全Socket(SSL)加密方法

    // C/C++, 利用OpenSSL库对Socket传输进行安全加密(RSA+AES) // 1. 利用RSA安全传输AES生成密钥所需的Seed(32字节) // 2. 利用AES_encrypt/AES_decrypt对Socket上面的业务数据进行AES加密/解密 // --- // * 理论上只...

    网络socket编程指南

    网络socket编程指南 -------------------------------------------------------------------------------- 介绍  Socket 编程让你沮丧吗?从man pages中很难得到有用的信息吗?你想跟上时代去编Internet相关的...

    安全SOCKET(SSL)实现方法

    // 在实际的Socket应用开发时,需要将这些步骤插入到Client/Server网络通信的特定阶段 // --- // 为能完成代码的编译和执行,需要先安装OpenSSL执行库及开发库 // 以Debian为例,需要安装openssl 和 libssl-dev // ...

    STM32H7 LWIP Rev非阻塞方式

    STM32H7 LWIP Rev非阻塞方式

    send-recv-init

    send recv nit linux 下recv send

    TCPsocket套接字.zip

    客户端和服务端操作流程 服务器端: socket() --&gt; bind() --&gt; listen() --&gt; accept() ...socket() --&gt; connect() --&gt; send() --&gt; close() 创建socket --&gt; 连接指定服务器的IP/端口号–&gt;向socket中写入信息–&gt;关闭socket

    python网络编程DAY02.txt

    socket() ---&gt; connect() ---&gt; send/recv ---&gt;close() ***************************************************** 套接字传输注意事项 1. 监听套接字存在客户端即可发起连接,但是最终连接的处理需要accept进行处理 ...

    基于客户/服务器模式的聊天应用程序

    一些基本的Socket系统调用,主要的系统调用包括:socket()-创建Socket;bind()-将创建的Socket与本地端口绑定;connect()与accept()-建立Socket连接;listen()-服务器监听是否有连接请求;send()-数据的可控缓冲发送...

    MFC网络编程之自制浏览器

     CAsyncSocket类在较低层次上封装了Windows Socket API,并且通过内建一个(隐藏的)窗口,实现了适合Windows应用的异步机制(Windows Socket API默认情况下工作在阻塞模式,不方便直接在消息驱动的Windows程序上使用)...

    yog2-plugin-recv-reload:yog2 上传和热重载插件

    yog2-plugin-recv-reload ======================== 通过yog2-plugin-recv-reload,可以实现在使用YOG2框架进行开发工作时,上传APP代码无需重启服务就可以调试最新代码 系统要求 yog2-kernel &gt;= 0.2.2 Usage 安装...

Global site tag (gtag.js) - Google Analytics