Thrift第四课 连接中断异常处理
2018-02-17 14:47
399 查看
场景
Thrift框架采用了异常处理机制,当客户端异常断开连接,服务端这个时候尝试发送数据给客户端,Thrift库会抛出异常,导致进程中断。这种情况是非常正常的,服务器端应该捕获异常的发生,但是不应该异常退出。所以应该当前发送数据失败,直接返回
修改代码如下:
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) {
//修改的第一个地方,直接返回-1,不抛出异常
close();
return -1;
//throw TTransportException(TTransportException::NOT_OPEN, "write() send()", errno_copy);
}
//修改的第二个地方,直接返回-1,不抛出异常
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;
}
如下是新的尝试,尝试在最外层进行异常的捕获
void TSocket::write(const uint8_t* buf, uint32_t len) {
uint32_t sent = 0;
while (sent < len) {
//尝试通过try捕获write_partial函数抛出的异常,但是在测试结果中并没有什么用,异常还是中断程序
try
{
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;
}
catch (apache::thrift::transport::TTransportException* e)
{
return;
}
}
}
分析一下服务器发送数据的函数
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,是非常合理的值
Thrift框架采用了异常处理机制,当客户端异常断开连接,服务端这个时候尝试发送数据给客户端,Thrift库会抛出异常,导致进程中断。这种情况是非常正常的,服务器端应该捕获异常的发生,但是不应该异常退出。所以应该当前发送数据失败,直接返回
修改代码如下:
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) {
//修改的第一个地方,直接返回-1,不抛出异常
close();
return -1;
//throw TTransportException(TTransportException::NOT_OPEN, "write() send()", errno_copy);
}
//修改的第二个地方,直接返回-1,不抛出异常
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;
}
如下是新的尝试,尝试在最外层进行异常的捕获
void TSocket::write(const uint8_t* buf, uint32_t len) {
uint32_t sent = 0;
while (sent < len) {
//尝试通过try捕获write_partial函数抛出的异常,但是在测试结果中并没有什么用,异常还是中断程序
try
{
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;
}
catch (apache::thrift::transport::TTransportException* e)
{
return;
}
}
}
分析一下服务器发送数据的函数
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,是非常合理的值
相关文章推荐
- ARM异常---一个Uart中断的触发处理过程:
- Arm架构异常处理流程之中断
- 开发常见错误解决(6)WSE3.0未处理的WebException,未处理的Web异常,基础连接以及关闭
- 如果网络出现异常,TCP连接中断,那么计算机要多久才能够检测出来呢?
- 关于win7系统无线及本地连接图标异常的处理(可以连接无线)
- TCP连接中的异常断开情况处理
- 关于vfp调用连接服务器(linkServer)异常的处理方法
- 数据库连接时一个异常的处理:java.sql.SQLException: No suitable driver found for
- android 异常处理--java.io.IOException: 您的主机中的软件中止了一个已建立的连接
- android 异常处理--java.io.IOException: 您的主机中的软件中止了一个已建立的连接
- 6410之异常中断处理
- Oracle异常处理—ORA-12514:监听程序当前无法识别连接描述符中请求的服务
- MIPS 异常和中断处理(Exception and Interrupt handling)
- ARM:ARM中断异常的处理流程
- andorid 连接-心跳-异常中断流程图
- Oracle异常处理—ORA-12514:监听程序当前无法识别连接描述符中请求的服务
- 线程中断异常的处理 abort()
- 异常和中断处理 ARM系统开发者指南 Chapter9-1
- TCP连接中断的处理
- 关于s3c2410 中断异常处理