最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java中的connection reset 異常處理分析

 更新時(shí)間:2017年04月02日 18:14:42   作者:raintungli  
本文主要介紹了java中的connection reset 異常處理分析的相關(guān)資料,具有很好的參考價(jià)值。下面跟著小編一起來看下吧

在Java中??匆姷膸讉€(gè)connection rest exception, Broken pipe, Connection reset,Connection reset by peer

Socked reset case

Linux中會(huì)有2個(gè)常見的sock reset 情況下的錯(cuò)誤代碼

ECONNRESET

該錯(cuò)誤被描述為“connection reset by peer”,即“對(duì)方復(fù)位連接”,這種情況一般發(fā)生在服務(wù)進(jìn)程較客戶進(jìn)程提前終止。當(dāng)服務(wù)進(jìn)程終止時(shí)會(huì)向客戶 TCP 發(fā)送 FIN 分節(jié),客戶 TCP 回應(yīng) ACK,服務(wù) TCP 將轉(zhuǎn)入 FIN_WAIT2 狀態(tài)。此時(shí)如果客戶進(jìn)程沒有處理該 FIN (如阻塞在其它調(diào)用上而沒有關(guān)閉 Socket 時(shí)),則客戶 TCP 將處于 CLOSE_WAIT 狀態(tài)。當(dāng)客戶進(jìn)程再次向 FIN_WAIT2 狀態(tài)的服務(wù) TCP 發(fā)送數(shù)據(jù)時(shí),則服務(wù) TCP 將立刻響應(yīng) RST。一般來說,這種情況還可以會(huì)引發(fā)另外的應(yīng)用程序異常,客戶進(jìn)程在發(fā)送完數(shù)據(jù)后,往往會(huì)等待從網(wǎng)絡(luò)IO接收數(shù)據(jù),很典型的如 read 或 readline 調(diào)用,此時(shí)由于執(zhí)行時(shí)序的原因,如果該調(diào)用發(fā)生在 RST 分節(jié)收到前執(zhí)行的話,那么結(jié)果是客戶進(jìn)程會(huì)得到一個(gè)非預(yù)期的 EOF 錯(cuò)誤。此時(shí)一般會(huì)輸出“server terminated prematurely”-“服務(wù)器過早終止”錯(cuò)誤。

EPIPE

錯(cuò)誤被描述為“broken pipe”,即“管道破裂”,這種情況一般發(fā)生在客戶進(jìn)程不理會(huì)(或未及時(shí)處理)Socket 錯(cuò)誤,繼續(xù)向服務(wù) TCP 寫入更多數(shù)據(jù)時(shí),內(nèi)核將向客戶進(jìn)程發(fā)送 SIGPIPE 信號(hào),該信號(hào)默認(rèn)會(huì)使進(jìn)程終止(此時(shí)該前臺(tái)進(jìn)程未進(jìn)行 core dump)。結(jié)合上邊的 ECONNRESET 錯(cuò)誤可知,向一個(gè) FIN_WAIT2 狀態(tài)的服務(wù) TCP(已 ACK 響應(yīng) FIN 分節(jié))寫入數(shù)據(jù)不成問題,但是寫一個(gè)已接收了 RST 的 Socket 則是一個(gè)錯(cuò)誤。

Java 中的socket input stream/output stream 的處理

先看代碼片段

SocketInputStream.c

switch (errno) { 
case ECONNRESET: 
case EPIPE: 
  JNU_ThrowByName(env, "sun/net/ConnectionResetException",   
  "Connection reset"); 
  break; 
         .... 

SocketOutputStream.c

if (errno == ECONNRESET) { 
          JNU_ThrowByName(env, "sun/net/ConnectionResetException", 
            "Connection reset"); 
    } else { 
      NET_ThrowByNameWithLastError(env, "java/net/SocketException",  
      "Write failed"); 
    } 

可以看到j(luò)ava 在讀和寫的情況關(guān)于EPIPE的情況是處理不一樣的

在read 的情況中,Reset 是全部拋出 ConnectionResetException, 提示的錯(cuò)誤信息是 Connection Reset

在write的情況下,Reset 對(duì)ECONNRESET的是拋出ConnectionResetException, 而對(duì)EPIPE 拋出的是SocketException ,錯(cuò)誤信息是Broken pipe

如何打印出信息Broken pipe

SIGPIPE信號(hào)處理函數(shù)

當(dāng)在收到reset包后,如果在讀寫socket,會(huì)出現(xiàn)錯(cuò)誤EPIPE,同時(shí)經(jīng)常收到SIGPIPE信號(hào)

在程序中可以看到j(luò)ava 并沒有對(duì)write的情況下沒有處理錯(cuò)誤EPIPE,開始的時(shí)候錯(cuò)誤的以拋出的異常是信號(hào)處理函數(shù)拋出的

先來看一下關(guān)于信號(hào)SIGPIPE的處理函數(shù),在Linux::install_signal_handlers 里面調(diào)用函數(shù)

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); 

而函數(shù)set_signal_handler,中對(duì)對(duì)應(yīng)的信號(hào)處理函數(shù)是signalHandler

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; 
 } 

最終還是調(diào)用了函數(shù) JVM_handle_linux_signal

在X86架構(gòu)下, 函數(shù)JVM_handle_linux_signal

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; 
  } 
 } 
... 
} 

對(duì)信號(hào)SIGPIPE 使用了chained handler處理,也就是使用了系統(tǒng)的原來信號(hào)處理函數(shù),也就證明了異常并不是信號(hào)處理函數(shù)拋出的

NET_ThrowByNameWithLastError函數(shù)

既然不是信號(hào)處理函數(shù)拋出的異常,繼續(xù)查看原來的outputstream的程序

if (errno == ECONNRESET) { 
          JNU_ThrowByName(env, "sun/net/ConnectionResetException", 
            "Connection reset"); 
    } else { 
      NET_ThrowByNameWithLastError(env, "java/net/SocketException",  
      "Write failed"); 
    } 

也就是else 的情況,那么針對(duì)EPIPE的錯(cuò)誤,java拋出的socketexception, 錯(cuò)誤信息是Write failed ,事實(shí)上我們可以看到的卻是SockedException,異常對(duì)對(duì)上了, 但信息顯示是Broken pipe,而不是Write failed.

關(guān)鍵點(diǎn)就在函數(shù) NET_ThrowByNameWithLastError

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);  
} 

函數(shù)JNU_ThrowByNameWithLastError

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的異常信息,也就是開始對(duì)應(yīng)的Write failed!

JVM_GetLastErrorString 使用hpi::lasterror ,也就是函數(shù)sysGetLastErrorString 在linux和solaris 是一樣的

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 對(duì)應(yīng)這個(gè)error number 的錯(cuò)誤內(nèi)容

結(jié)論:Broken pipe 是內(nèi)核對(duì)應(yīng)的錯(cuò)誤信息,并不是java自己提供的信息

以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時(shí)也希望多多支持腳本之家!

相關(guān)文章

  • springboot?vue接口測(cè)試前后端實(shí)現(xiàn)模塊樹列表功能

    springboot?vue接口測(cè)試前后端實(shí)現(xiàn)模塊樹列表功能

    這篇文章主要為大家介紹了springboot?vue接口測(cè)試前后端實(shí)現(xiàn)模塊樹列表功能,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • Java中IdentityHashMap與HashMap區(qū)別詳解

    Java中IdentityHashMap與HashMap區(qū)別詳解

    這篇文章主要介紹了Java中IdentityHashMap與HashMap區(qū)別詳解,很多人不曉得IdentityHashMap的存在,其中不乏工作很多年的Java開發(fā)者,他們看到就說是第三方j(luò)ar包,實(shí)際上它是Jdk源碼自帶的集合類,需要的朋友可以參考下
    2023-11-11
  • Java循環(huán)隊(duì)列與非循環(huán)隊(duì)列的區(qū)別總結(jié)

    Java循環(huán)隊(duì)列與非循環(huán)隊(duì)列的區(qū)別總結(jié)

    今天給大家?guī)淼氖顷P(guān)于Java的相關(guān)知識(shí)總結(jié),文章圍繞著Java循環(huán)隊(duì)列與非循環(huán)隊(duì)列的區(qū)別展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(28)

    Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(28)

    下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧,希望可以幫到你
    2021-07-07
  • java中ArrayList和LinkedList的區(qū)別詳解

    java中ArrayList和LinkedList的區(qū)別詳解

    這篇文章主要介紹了java中ArrayList和LinkedList的區(qū)別詳解,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下
    2021-01-01
  • 使用javassist動(dòng)態(tài)生成類的配置代碼

    使用javassist動(dòng)態(tài)生成類的配置代碼

    Javassist它是一個(gè)用 Java 編輯字節(jié)碼的類庫,它使 Java 程序能夠在運(yùn)行時(shí)定義新類,并在 JVM 加載時(shí)修改類文件,本文給大家介紹使用javassist動(dòng)態(tài)生成類的實(shí)例代碼,感興趣的朋友一起看看吧
    2022-09-09
  • 使用Files.walkFileTree遍歷目錄文件

    使用Files.walkFileTree遍歷目錄文件

    這篇文章主要介紹了使用Files.walkFileTree遍歷目錄文件,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • SpringBoot配置shiro安全框架的實(shí)現(xiàn)

    SpringBoot配置shiro安全框架的實(shí)現(xiàn)

    這篇文章主要介紹了SpringBoot配置shiro安全框架的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • 詳解MyBatis多數(shù)據(jù)源配置(讀寫分離)

    詳解MyBatis多數(shù)據(jù)源配置(讀寫分離)

    這篇文章主要介紹了詳解MyBatis多數(shù)據(jù)源配置(讀寫分離),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-01-01
  • SpringCloud Feign傳遞HttpServletRequest對(duì)象流程

    SpringCloud Feign傳遞HttpServletRequest對(duì)象流程

    HttpServletRequest接口的對(duì)象代表客戶端的請(qǐng)求,當(dāng)客戶端通過HTTP協(xié)議訪問Tomcat服務(wù)器時(shí),HTTP請(qǐng)求中的所有信息都封裝在HttpServletRequest接口的對(duì)象中,這篇文章介紹了Feign傳遞HttpServletRequest對(duì)象的流程,感興趣的同學(xué)可以參考下文
    2023-05-05

最新評(píng)論

凤庆县| 宁远县| 长沙市| 大宁县| 资溪县| 东乌珠穆沁旗| 鞍山市| 新晃| 固原市| 且末县| 陆河县| 黑河市| 纳雍县| 巴马| 沛县| 新干县| 葵青区| 桐柏县| 莎车县| 开原市| 万安县| 寿光市| 滁州市| 周口市| 旺苍县| 浦县| 宣武区| 汝阳县| 金塔县| 清河县| 乌拉特中旗| 拜泉县| 外汇| 德化县| 满洲里市| 临城县| 呼图壁县| 阿瓦提县| 麻阳| 南昌县| 天水市|