现在的位置: 首页 > 综合 > 正文

send函数返回值

2018年03月21日 ⁄ 综合 ⁄ 共 7084字 ⁄ 字号 评论关闭

1有关SIGPIPE信号

在Unix系统下,如果send  recv  write在等待协议传送数据时  socket  shutdown,调用send的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。 此种情况 应用就很难查  处理进程为什么退出。

 

SIGPIPE 信号:

对一个已经收到FIN包的socket调用read方法, 如果接收缓冲已空, 则返回0, 这就是常说的表示连接关闭. 但第一次对其调用write方法时, 如果发送缓冲没问题, 会返回正确写入(发送). 但发送的报文会导致对端发送RST报文, 因为对端的socket已经调用了close, 完全关闭, 既不发送, 也不接收数据. 所以, 第二次调用write方法(假设在收到RST之后), 会生成SIGPIPE信号, 导致进程退出 。如果对 SIGPIPE 进行忽略处理, 二次调用write方法时, 会返回-1, 同时errno置为SIGPIPE.

处理方法:

在初始化时调用 signal(SIGPIPE,SIG_IGN) 忽略该信号(只需一次)  SIGPIPE交给了系统处理。 此时send  recv  write 函数将返回-1,errno为EPIPE,可视情况关闭socket或其他处理    

SIGPIPE 被忽略的情况下,如果 服务器采用了fork的话,要收集垃圾进程,防止僵尸进程的产生,可以这样处理:  signal(SIGCHLD,SIG_IGN); 交给系统init去回收。 这样 子进程就不会产生僵尸进程了。

 

ACE中发送和接收超时都是基于select的

 

  1. ssize_t  
  2. ACE::send_n_i (ACE_HANDLE handle,  
  3.                const void *buf,  
  4.                size_t len,  
  5.                int flags,  
  6.                const ACE_Time_Value *timeout,  
  7.                size_t *bt)  
  8. {  
  9.   size_t temp;  
  10.   size_t &bytes_transferred = bt == 0 ? temp : *bt;  
  11.   ssize_t n;  
  12.   ssize_t result = 0;  
  13.   int error = 0;  
  14.   int val = 0;  
  15.   ACE::record_and_set_non_blocking_mode (handle, val);  
  16.   for (bytes_transferred = 0;  
  17.        bytes_transferred < len;  
  18.        bytes_transferred += n)  
  19.     {  
  20.       // Try to transfer as much of the remaining data as possible.  
  21.       // Since the socket is in non-blocking mode, this call will not  
  22.       // block.  
  23.       n = ACE_OS::send (handle,  
  24.                         (char *) buf + bytes_transferred,  
  25.                         len - bytes_transferred,  
  26.                         flags);  
  27.       // Check for errors.  
  28.       if (n == 0 ||  
  29.           n == -1)  
  30.         {  
  31.           // Check for possible blocking.  
  32.           if (n == -1 &&  
  33.               (errno == EWOULDBLOCK || errno == ENOBUFS))  
  34.             {  
  35.               // Wait upto <timeout> for the blocking to subside.  
  36.               int rtn = ACE::handle_write_ready (handle,  
  37.                                                  timeout);  
  38.               // Did select() succeed?  
  39.               if (rtn != -1)  
  40.                 {  
  41.                   // Blocking subsided in <timeout> period.  Continue  
  42.                   // data transfer.  
  43.                   n = 0;  
  44.                   continue;  
  45.                 }  
  46.             }  
  47.           // Wait in select() timed out or other data transfer or  
  48.           // select() failures.  
  49.           error = 1;  
  50.           result = n;  
  51.           break;  
  52.         }  
  53.     }  
  54.   ACE::restore_non_blocking_mode (handle, val);  
  55.   if (error)  
  56.     {  
  57.       return result;  
  58.     }  
  59.   else  
  60.     {  
  61.       return ACE_Utils::truncate_cast<ssize_t> (bytes_transferred);  
  62.     }  
  63. }  
  64. int  
  65. ACE::handle_ready (ACE_HANDLE handle,  
  66.                    const ACE_Time_Value *timeout,  
  67.                    int read_ready,  
  68.                    int write_ready,  
  69.                    int exception_ready)  
  70. {  
  71. #if defined (ACE_HAS_POLL) && defined (ACE_HAS_LIMITED_SELECT)  
  72.   ACE_UNUSED_ARG (write_ready);  
  73.   ACE_UNUSED_ARG (exception_ready);  
  74.   struct pollfd fds;  
  75.   fds.fd = handle;  
  76.   fds.events = read_ready ? POLLIN : POLLOUT;  
  77.   fds.revents = 0;  
  78.   int result = ACE_OS::poll (&fds, 1, timeout);  
  79. #else  
  80.   ACE_Handle_Set handle_set;  
  81.   handle_set.set_bit (handle);  
  82.   // Wait for data or for the timeout to elapse.  
  83.   int select_width;  
  84. #  if defined (ACE_WIN32)  
  85.   // This arg is ignored on Windows and causes pointer truncation  
  86.   // warnings on 64-bit compiles.  
  87.   select_width = 0;  
  88. #  else  
  89.   select_width = int (handle) + 1;  
  90. #  endif /* ACE_WIN64 */  
  91.   int result = ACE_OS::select (select_width,  
  92.                                read_ready ? handle_set.fdset () : 0, // read_fds.  
  93.                                write_ready ? handle_set.fdset () : 0, // write_fds.  
  94.                                exception_ready ? handle_set.fdset () : 0, // exception_fds.  
  95.                                timeout);  
  96. #endif /* ACE_HAS_POLL && ACE_HAS_LIMITED_SELECT */  
  97.   switch (result)  
  98.     {  
  99.     case 0:  // Timer expired.  
  100.       errno = ETIME;  
  101.       /* FALLTHRU */  
  102.     case -1: // we got here directly - select() returned -1.  
  103.       return -1;  
  104.     case 1: // Handle has data.  
  105.       /* FALLTHRU */  
  106.     default// default is case result > 0; return a  
  107.       // ACE_ASSERT (result == 1);  
  108.       return result;  
  109.     }  

其它lighttpd:

[c-sharp] view
plain
copy

  1. // if  (len == 0 || (len < 0 && errno != EAGAIN && errno != EINTR) ) {  
  2. case -1:  
  3.             if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINPROGRESS)  
  4.             {  
  5.                 return 0;  
  6.             }  
  7. if (-1 == (cnt = accept(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {  
  8.         switch (errno) {  
  9.         case EAGAIN:  
  10. #if EWOULDBLOCK != EAGAIN  
  11.         case EWOULDBLOCK:  
  12. #endif  
  13.         case EINTR:  
  14.             /* we were stopped _before_ we had a connection */  
  15.         case ECONNABORTED: /* this is a FreeBSD thingy */  
  16.             /* we were stopped _after_ we had a connection */  
  17.             break;  
  18.         case EMFILE:  
  19.             /* out of fds */  
  20.             break;  
  21.         default:  
  22.             log_error_write(srv, __FILE__, __LINE__, "ssd""accept failed:", strerror(errno), errno);  
  23.         }  
  24.         return NULL;  
  25.     }  
  26. fcgi  
  27. if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {  
  28.         if (errno == EINPROGRESS ||  
  29.             errno == EALREADY ||  
  30.             errno == EINTR) {  
  31.             if (hctx->conf.debug > 2) {  
  32.                 log_error_write(srv, __FILE__, __LINE__, "sb",  
  33.                     "connect delayed; will continue later:", proc->connection_name);  
  34.             }  
  35.             return CONNECTION_DELAYED;  
  36.         } else if (errno == EAGAIN) {  
  37.             if (hctx->conf.debug) {  
  38.                 log_error_write(srv, __FILE__, __LINE__, "sbsd",  
  39.                     "This means that you have more incoming requests than your FastCGI backend can handle in parallel."  
  40.                     "It might help to spawn more FastCGI backends or PHP children; if not, decrease server.max-connections."  
  41.                     "The load for this FastCGI backend", proc->connection_name, "is", proc->load);  
  42.             }  
  43.             return CONNECTION_OVERLOADED;  
  44.         } else {  
  45.             log_error_write(srv, __FILE__, __LINE__, "sssb",  
  46.                     "connect failed:",  
  47.                     strerror(errno), "on",  
  48.                     proc->connection_name);  
  49.             return CONNECTION_DEAD;  
  50.         }  
  51.     }  

 2有关SEND,RECV函数的返回值及错误码

2.1EINTR

指操作被中断唤醒,需要重新读/写
2.2EAGAIN
在Linux环境下开发经常会碰到很多错误(设置errno),其中EAGAIN是其中比较常见的一个错误(比如用在非阻塞操作中)。从字面上来看,是提示再试一次。这个错误经常出现在当应用程序进行一些非阻塞(non-blocking)操作(对文件或socket)的时候。例如,以 O_NONBLOCK的标志打开文件/socket/FIFO,如果你连续做read操作而没有数据可读。此时程序不会阻塞起来等待数据准备就绪返 回,read函数会返回一个错误EAGAIN,提示你的应用程序现在没有数据可读请稍后再试。又例如,当一个系统调用(比如fork)因为没有足够的资源(比如虚拟内存)而执行失败,返回EAGAIN提示其再调用一次(也许下次就能成功)。

2.3EAGIN处理
当客户通过Socket提供的send函数发送大的数据包时,就可能返回一个EGGAIN的错误。该错误产生的原因是由于send 

函数 中的size变量大小超过了tcp_sendspace的值。tcp_sendspace定义了应用在调用send之前能够在kernel中缓存的数据 量。当应用程序在socket中设置了O_NDELAY或者O_NONBLOCK属性后,如果发送缓存被占满,send就会返回EAGAIN的错误。 
为了消除该错误,有三种方法可以选择: 
1.调大tcp_sendspace,使之大于send中的size参数 
---no -p -o tcp_sendspace=65536 

2.在调用send前,在setsockopt函数中为SNDBUF设置更大的值 

 

抱歉!评论已关闭.