1. 程式人生 > >Thrift發送中斷處理

Thrift發送中斷處理

lag clas def exc 斷開 sent tin 異常 套接字

場景

分析當客戶端異常斷開連接,但是這個時候服務器並不知道連接已經失效,服務端這個時候嘗試發送數據給客戶端,這個時候就會觸發中斷,拋出異常


先分析一下服務器發送數據的函數

void TSocket::write(const uint8_t* buf, uint32_t len) {

uint32_t sent = 0;


while (sent < len) {

uint32_t b = write_partial(buf + sent, len - sent);

if (b == 0) {

// This should only happen if the timeout set with SO_SNDTIMEO expired.

// Raise an exception.

throw TTransportException(TTransportException::TIMED_OUT,

"send timeout expired");

}

sent += b;

}

}

但b==0拋出異常,代表當前發送超時。while循環是為了循環發送,因為一次不一定發送完用戶數據,畢竟MTU的限制。註意sent是一個無符號整型,當b返回-1的時候,sent==0-1意味著將達到32位整數最大值,大於len,從而直接退出循環。因為套接字已經中斷,所以發送失敗,在調用write_partial函數的時候,返回b ==-1,導致退出循環,從而避免了拋出異常,因此返回-1,是非常合理的值


uint32_t TSocket::write_partial(const uint8_t* buf, uint32_t len) {

if (socket_ == -1) {

return -1;

throw TTransportException(TTransportException::NOT_OPEN, "Called write on non-open socket");

}


uint32_t sent = 0;


int flags = 0;

#ifdef MSG_NOSIGNAL

// Note the use of MSG_NOSIGNAL to suppress SIGPIPE errors, instead we

// check for the EPIPE return condition and close the socket in that case

flags |= MSG_NOSIGNAL;

#endif // ifdef MSG_NOSIGNAL


int b = send(socket_, const_cast_sockopt(buf + sent), len - sent, flags);

++g_socket_syscalls;


if (b < 0) {

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

return 0;

}

// Fail on a send error

int errno_copy = errno;

GlobalOutput.perror("TSocket::write_partial() send() " + getSocketInfo(), errno_copy);


if (errno_copy == EPIPE || errno_copy == ECONNRESET || errno_copy == ENOTCONN) {

close();

return -1;

//throw TTransportException(TTransportException::NOT_OPEN, "write() send()", errno_copy);

}

close();

return -1;

throw TTransportException(TTransportException::UNKNOWN, "write() send()", errno_copy);

}


// Fail on blocked send

if (b == 0) {

throw TTransportException(TTransportException::NOT_OPEN, "Socket send returned 0.");

}

return b;

}




Thrift發送中斷處理