`
lvmlvy
  • 浏览: 44546 次
社区版块
存档分类
最新评论

[转]java 中的connection reset 异常处理分析

    博客分类:
  • java
 
阅读更多

在Java中常看见的几个connection rest exception, Broken pipe, Connection reset,Connection reset by peer

Socked reset case 
Linux中会有2个常见的sock reset 情况下的错误代码
ECONNRESET
          该错误被描述为“connection reset by peer”,即“对方复位连接”,这种情况一般发生在服务进程较客户进程提前终止。当服务进程终止时会向客户 TCP 发送 FIN 分节,客户 TCP 回应 ACK,服务 TCP 将转入 FIN_WAIT2 状态。此时如果客户进程没有处理该 FIN (如阻塞在其它调用上而没有关闭 Socket 时),则客户 TCP 将处于 CLOSE_WAIT 状态。当客户进程再次向 FIN_WAIT2 状态的服务 TCP 发送数据时,则服务 TCP 将立刻响应 RST。一般来说,这种情况还可以会引发另外的应用程序异常,客户进程在发送完数据后,往往会等待从网络IO接收数据,很典型的如 read 或 readline 调用,此时由于执行时序的原因,如果该调用发生在 RST 分节收到前执行的话,那么结果是客户进程会得到一个非预期的 EOF 错误。此时一般会输出“server terminated prematurely”-“服务器过早终止”错误。
EPIPE
          错误被描述为“broken pipe”,即“管道破裂”,这种情况一般发生在客户进程不理会(或未及时处理)Socket 错误,继续向服务 TCP 写入更多数据时,内核将向客户进程发送 SIGPIPE 信号,该信号默认会使进程终止(此时该前台进程未进行 core dump)。结合上边的 ECONNRESET 错误可知,向一个 FIN_WAIT2 状态的服务 TCP(已 ACK 响应 FIN 分节)写入数据不成问题,但是写一个已接收了 RST 的 Socket 则是一个错误。
 
Java 中的socket input stream/output stream 的处理
先看代码片段
SocketInputStream.c
[cpp] 
switch (errno) {  
case ECONNRESET:  
case EPIPE:  
    JNU_ThrowByName(env, "sun/net/ConnectionResetException",      
    "Connection reset");  
    break;  
                  ....  
 
SocketOutputStream.c
[cpp] 
if (errno == ECONNRESET) {  
                    JNU_ThrowByName(env, "sun/net/ConnectionResetException",  
                        "Connection reset");  
        } else {  
            NET_ThrowByNameWithLastError(env, "java/net/SocketException",   
            "Write failed");  
        }  
 
可以看到java 在读和写的情况关于EPIPE的情况是处理不一样的
在read 的情况中,Reset 是全部抛出 ConnectionResetException, 提示的错误信息是 Connection Reset
在write的情况下,Reset 对ECONNRESET的是抛出ConnectionResetException, 而对EPIPE 抛出的是SocketException ,错误信息是Broken pipe
如何打印出信息Broken pipe
SIGPIPE信号处理函数
当在收到reset包后,如果在读写socket,会出现错误EPIPE,同时经常收到SIGPIPE信号
在程序中可以看到java 并没有对write的情况下没有处理错误EPIPE,开始的时候错误的以抛出的异常是信号处理函数抛出的
先来看一下关于信号SIGPIPE的处理函数,在Linux::install_signal_handlers 里面调用函数
[cpp]  
set_signal_handler(SIGSEGV, true);  
set_signal_handler(SIGPIPE, true);  
set_signal_handler(SIGBUS, true);  
set_signal_handler(SIGILL, true);  
set_signal_handler(SIGFPE, true);  
set_signal_handler(SIGXFSZ, true);  
 
而函数set_signal_handler,中对对应的信号处理函数是signalHandler
[cpp]  
sigAct.sa_handler = SIG_DFL;  
  if (!set_installed) {  
    sigAct.sa_flags = SA_SIGINFO|SA_RESTART;  
  } else {  
    sigAct.sa_sigaction = signalHandler;  
    sigAct.sa_flags = SA_SIGINFO|SA_RESTART;  
  }  
最终还是调用了函数 JVM_handle_linux_signal
在X86架构下, 函数JVM_handle_linux_signal
[cpp]  
extern "C" int  
JVM_handle_linux_signal(int sig,  
                        siginfo_t* info,  
                        void* ucVoid,  
                        int abort_if_unrecognized) {  
  ucontext_t* uc = (ucontext_t*) ucVoid;  
  
  Thread* t = ThreadLocalStorage::get_thread_slow();  
  
  SignalHandlerMark shm(t);  
  
  // Note: it's not uncommon that JNI code uses signal/sigset to install  
  // then restore certain signal handler (e.g. to temporarily block SIGPIPE,  
  // or have a SIGILL handler when detecting CPU type). When that happens,  
  // JVM_handle_linux_signal() might be invoked with junk info/ucVoid. To  
  // avoid unnecessary crash when libjsig is not preloaded, try handle signals  
  // that do not require siginfo/ucontext first.  
  
  if (sig == SIGPIPE || sig == SIGXFSZ) {  
    // allow chained handler to go first  
    if (os::Linux::chained_handler(sig, info, ucVoid)) {  
      return true;  
    } else {  
      if (PrintMiscellaneous && (WizardMode || Verbose)) {  
        char buf[64];  
        warning("Ignoring %s - see bugs 4229104 or 646499219",  
                os::exception_name(sig, buf, sizeof(buf)));  
      }  
      return true;  
    }  
  }  
...  
}  
 
对信号SIGPIPE 使用了chained handler处理,也就是使用了系统的原来信号处理函数,也就证明了异常并不是信号处理函数抛出的
NET_ThrowByNameWithLastError函数
既然不是信号处理函数抛出的异常,继续查看原来的outputstream的程序
[cpp]  
if (errno == ECONNRESET) {  
                    JNU_ThrowByName(env, "sun/net/ConnectionResetException",  
                        "Connection reset");  
        } else {  
            NET_ThrowByNameWithLastError(env, "java/net/SocketException",   
            "Write failed");  
        }  
 
也就是else 的情况,那么针对EPIPE的错误,java抛出的socketexception, 错误信息是Write failed ,事实上我们可以看到的却是SockedException,异常对对上了, 但信息显示是Broken pipe,而不是Write failed.
关键点就在函数 NET_ThrowByNameWithLastError
[cpp] 
void  
NET_ThrowByNameWithLastError(JNIEnv *env, const char *name,  
                   const char *defaultDetail) {  
    char errmsg[255];  
    sprintf(errmsg, "errno: %d, error: %s\n", errno, defaultDetail);   
    JNU_ThrowByNameWithLastError(env, name, errmsg);   
}  
 
函数JNU_ThrowByNameWithLastError
[cpp]  
JNIEXPORT void JNICALL  
JNU_ThrowByNameWithLastError(JNIEnv *env, const char *name,  
                 const char *defaultDetail)  
{  
    char buf[256];  
    int n = JVM_GetLastErrorString(buf, sizeof(buf));  
  
    if (n > 0) {  
    jstring s = JNU_NewStringPlatform(env, buf);  
    if (s != NULL) {  
        jobject x = JNU_NewObjectByName(env, name,  
                        "(Ljava/lang/String;)V", s);  
        if (x != NULL) {  
        (*env)->Throw(env, x);  
        }  
    }  
    }  
    if (!(*env)->ExceptionOccurred(env)) {  
    JNU_ThrowByName(env, name, defaultDetail);  
    }  
}  
 
程序可以看到先显示 JVM_GetLastErrorString 的信息,如果信息是空的情况下才显示defaultDetail的异常信息,也就是开始对应的Write failed!
JVM_GetLastErrorString 使用hpi::lasterror ,也就是函数sysGetLastErrorString 在linux和solaris 是一样的
[cpp] 
int  
sysGetLastErrorString(char *buf, int len)  
{  
    if (errno == 0) {  
    return 0;  
    } else {  
    const char *s = strerror(errno);  
    int n = strlen(s);  
    if (n >= len) n = len - 1;  
    strncpy(buf, s, n);  
    buf[n] = '\0';  
    return n;  
    }  
}  
 
原来是strerror(errno) ,也就是直接显示linux kernel 对应这个error number 的错误内容
结论:Broken pipe 是内核对应的错误信息,并不是java自己提供的信息
 
分享到:
评论

相关推荐

    java中的connection reset 异常处理分析

    总的来说,处理Java中的"connection reset"异常需要对网络协议、操作系统错误代码以及Java的网络API有深入的理解。通过适当的错误处理和调试技术,开发者可以有效地定位和解决这类问题,保证应用程序的稳定性和可靠...

    java.net.SocketException Connection reset 解决方法

    "java.net.SocketException Connection reset 解决方法" 在 Java 编程中,SocketException 是一种常见的异常,特别是在网络编程中。Conexion reset by peer 是一种特殊的 SocketException,它发生在客户端和服务器...

    java.net.SocketException: Connection reset 解决方法

    Java中的`java.net.SocketException: Connection reset`是一个常见的网络编程错误,通常表示在TCP/IP通信过程中,连接突然中断。这个异常可能在客户端或服务器端发生,通常与数据传输的异常中断有关。 首先,我们来...

    connection reset by peer问题总结及解决方案

    connection reset by peer问题总结及解决方案 1.服务器的并发连接数超过了其承载量,服务器会将其中一些连接关闭 如果知道实际连接服务器的并发客户端数并没有超过服务器的承载量,则有可能是中了病毒或者木马,引起...

    Java Socket常见异常处理

    Java Socket编程中,异常处理是确保程序稳定性和健壮性的重要环节。以下是对常见的Java Socket异常的详细解析和处理建议: 1. **java.net.BindException: Address already in use: JVM_Bind** 这个异常表明尝试...

    Connection

    根据给定的文件信息,我们可以总结出以下关于SQL数据库连接(Connection)的相关知识点: ### SQL数据库连接...在实际开发中,通常还会使用异常处理机制来捕获并处理可能出现的运行时错误,确保程序的健壮性。

    javaerror处理资料

    ### Java网络编程错误处理详解 ...通过上述分析我们可以看出,在Java网络编程中,正确处理异常不仅能够提高程序的健壮性,还能增强用户体验。开发者应当充分理解每一种异常的成因,并采取适当的措施来预防和处理它们。

    Socket长连接异常处理

    java.net.SocketException: Connection reset by peer: Socket write error 该异常可能发生在客户端和服务器端,原因是因为一端的 Socket 被关闭,而另一端继续发送数据。解决方法是确保在关闭连接前完成所有的数据...

    java常见异常汇总

    `java.net.SocketException`: Connection reset **异常描述**:在使用 Socket 进行网络通信时,可能会遇到连接被远程主机关闭的情况。 **原因分析**:当远程主机突然关闭连接或者发生网络故障时,会抛出此类异常...

    Java实现文件下载并解决中文文件名乱码

    - 注意异常处理,确保文件读取过程中的错误能够被妥善处理。 - 对于不同浏览器的兼容性问题,可以通过检测User-Agent头来判断浏览器类型,并采取相应的编码转换策略。 - 使用`reset()`方法重置响应状态,确保之前的...

    java 监听本地文件自动上传服务器

    为了实现完全自动化,你可能还需要处理错误和异常,确保在上传过程中保持文件同步的可靠性。 在实际项目中,你可能还需要考虑线程安全、性能优化、文件重试策略以及服务器响应的处理。此外,对于大型文件,你可能...

    Google I/O 2013推荐Android 网络通信框架Volley

    5. **错误处理**:Volley提供了一套完整的错误处理机制,包括重试策略和错误回调,可以帮助开发者更好地理解和处理网络异常。 6. **强大的请求类型**:Volley支持GET、POST等多种HTTP方法,还可以处理HTTP头和POST...

    Nebula 异常情况记录1

    在处理Graph500数据集的K-hop neighbor(5/6度)查询时,TTransportException异常被触发,伴随有"java.net.SocketException: Connection reset"的错误信息。这通常意味着服务器主动关闭了连接,可能是由于资源耗尽、...

    java 将数据库中的数据导出到excel

    特别是在Web应用程序中,经常需要将数据库中的数据导出到Excel文件,以便用户可以方便地查看、分析或进一步处理这些数据。本文将详细介绍如何在Struts框架下实现这一功能,包括所需的技术栈、步骤以及代码示例。 ##...

    微信扫码支付和支付宝扫码支付代码

    - 异常处理:需要对可能出现的网络异常、支付失败等情况进行妥善处理,提供友好的用户反馈。 - 回调处理:正确实现支付回调接口,及时更新订单状态,防止重复支付。 7. **调试与测试** 在实际部署前,需在沙箱...

    java的常见问题及解决方法定义.pdf

    出现“java.net.SocketException: Connection reset”错误通常表示远程服务器关闭了连接。这可能在读取或写入数据时发生。检查服务器状态,确保网络连接稳定,同时在代码中处理异常,优雅地处理这种情况。 在开发...

    hadoop故障分析与技术方案揭秘

    例如,出现的java.io.IOException: Connection reset by peer异常,可能表明了网络通信中断或对方关闭了连接。而故障诊断中询问服务器时钟是否同步过,则暗示了时间同步问题可能导致集群中节点之间的通信异常。 ...

    com.microsoft.sqlserver.jdbc.SQLServerException: 只进结果集不支持请求的操作 解决方案

    在IT领域,尤其是在数据库操作与框架集成中,遇到异常错误是常见的挑战之一。本文将深入探讨标题和描述中提到的“com.microsoft.sqlserver.jdbc.SQLServerException: 只进结果集不支持请求的操作”这一异常,以及...

    jsp中增加数据的方法

    ### jsp中增加数据的方法 在Java Server Pages (JSP)技术中,处理...需要注意的是,在实际开发中还应考虑异常处理、SQL注入防护以及资源管理等方面的问题。希望本文能帮助您更好地理解和掌握JSP中的数据库操作技巧。

Global site tag (gtag.js) - Google Analytics