EPOLL 非阻塞SOCKET READ 函数写法总结

【EPOLL 非阻塞SOCKET READ 函数写法】

使用EPOLL进行SOCKET通讯的代码,网上资料写的不明确,专门写了测试代码进行测试,对READ中注意事项进行了总结。

一、LT模式下的READ

READ()返回值:

大于0,正常接收的数据

等于0, SOCKET关闭

等于-1 ,ERRNO == EINTR  重新调用READ( 可以立即调用,也可以退出等下一个LT的触发);ERRNO == EAGAIN 稍后调用(退出等下一个LT的触发,立即调用有可能空转);ERRNO == EWOULDBLOCK(和EAGAIN多数系统是同一值,同EAGAIN处理)

由于非阻塞SOCKET LT模式,READ退出后,只要有数据在SOCKET BUFFER中,就一定会持续LT触发,所以READ退出的判断条件,要求不严格。

示例代码如下:

int Socket_Read(int socketfd,  char *buf, int buf_len )

{

        int ret;

        int num = 0;

        int savenum = 0;

      if ( NULL == buf )

      {

           printf("\n +++ [KLC_Socket_Read] pointer is null +++\n");

           return(0);

      }

          

      while(1)

      {

           if ( buf_len == num )

           {

                 printf("\n +++ [KLC_Socket_Read] buffer full +++\n");

                 return(num);

           }

          

           ret = read(socketfd, buf + num, buf_len-num); 

           if (ret == 0)

           {

                 /*  exit, then close socket */

                 return(-1);     

           }

          

           if (ret >0)

           {

                 num += ret;

                 continue;

           }

           if ( ret < 0)

           {

                 /* LT mode */

                 if ( errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)

                 {

                      /* 也可以直接退出,不CONTINUE , 两者都可以*/

                      if ( num != savenum)

                        {

                                savenum = num;

                                continue;

                        }

                        break;

                 }

               

                 printf("\n +++ Socket_Read error: %s\n", strerror(errno));

                  break;                        

           }

     

      }

      return(num);

}

二、ET模式下的READ

READ()返回值:

大于0,正常接收的数据,继续接收(READ BUFFER LEN和READ LEN值相等,退出READ,  新分配BUFFER后,在再次调用READ)

等于0, SOCKET关闭

等于-1 ,ERRNO == EINTR  退出READ ( 退出READ,  新分配BUFFER后,在再次调用READ );

ERRNO == EAGAIN 退出READ (退出READ,  新分配BUFFER后,在再次调用READ);

ERRNO == EWOULDBLOCK(和EAGAIN多数系统是同一值,同EAGAIN处理);

ERRNO == EBADF 退出READ, 马上调用CLOSE SOCKET( 在测试中发现有此种情况出现,几率不大)

由于非阻塞SOCKET ET模式,READ退出后,如果数据没有读完,此时不会ET触发,所以要继续读取,一直读到失败( 返回-1, num = 0),并且READ BUFFER 不等于 READ LEN.

示例代码如下:

int Socket_Read(int socketfd, char *buf, int buf_len)

{

      int ret;

      int num = 0;

          

      if ( NULL == buf )

      {

           printf("\n +++ [Socket_Read] pointer is null +++\n");

          return(0);

      }

          

      while(1)

      {

     

           if ( buf_len == num )

           {

                 printf("\n +++ [Socket_Read] buffer full +++\n");

                 return(num);

           }

          

           ret = read(socketfd, buf + num, buf_len-num);

           if (ret == 0)

           {

                 return(-1);             

           }

          

           if (ret >0)

           {

                 num += ret;

                 continue;     

           }

           if ( ret < 0)

           {

                 /* ET mode */

                 if ( errno == EINTR )

                 {

                      break;

                 }

                 /* same errno for most version */

                 if ( errno == EWOULDBLOCK || errno == EAGAIN)

                 {

                      break;

                 }

                

                 if ( errno == EBADF)

                 {

                      /* close socket */

                      return(-1);

                 }

                 printf("\n +++ [Socket_Read] error: %s\n", strerror(errno);   

                break;    

           }

      }

      return(num);

}

实际代码,需要在Socket_Read(int socketfd, char *buf, int buf_len) 外在加一层WHILE循环,当调用Socket_Read(socketfd, buffer_address, MAX_BUFFERSIZE)后 NUM = 0 的情况下,退出WHILE循环。

static void net_read(int socketfd, int socketindex, NETTASK_S *ptaskinfo)

{

      。。。

      while(1)

      {

           bufferindex  = Buffer_Alloc(bufferid, bufferlen);

           Buffer_GetAddress(bufferid,bufferindex, &buffer_address  );

           len = Socket_Read(socketfd, buffer_address, MAX_BUFFERSIZE);

           if ( len == 0)

           {

                 Buffer_Free( bufferid, bufferindex);        

                 break;       

           }

           if  ( len  == -1)

           {

                Buffer_Free( bufferid, bufferindex);

                 net_close( socketfd, socketindex, ptaskinfo);      

                 break;

           }

     

           。。。。。。

           BUFFER数据接收处理

           。。。。。。

          

            Buffer_Free( bufferid, bufferindex);

            continue;

      }

     

      return;

}

你可能感兴趣的:(系统设计,p2p,网络协议,网络)