中文字幕日韩精品一区二区免费_精品一区二区三区国产精品无卡在_国精品无码专区一区二区三区_国产αv三级中文在线

深入淺析java中connectionreset的異常處理

今天就跟大家聊聊有關深入淺析java中connection reset 的異常處理,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據(jù)這篇文章可以有所收獲。

為堯都等地區(qū)用戶提供了全套網頁設計制作服務,及堯都網站建設行業(yè)解決方案。主營業(yè)務為網站設計、成都網站建設、堯都網站設計,以傳統(tǒng)方式定制建設網站,并提供域名空間備案等一條龍服務,秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務。我們深信只要達到每一位用戶的要求,就會得到認可,從而選擇與我們長期合作。這樣,我們也可以走得更遠!

在Java中常看見的幾個connection rest exception, Broken pipe, Connection reset,Connection reset by peer

Socked reset case

Linux中會有2個常見的sock reset 情況下的錯誤代碼

ECONNRESET

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

EPIPE

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

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

可以看到java 在讀和寫的情況關于EPIPE的情況是處理不一樣的

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

在write的情況下,Reset 對ECONNRESET的是拋出ConnectionResetException, 而對EPIPE 拋出的是SocketException ,錯誤信息是Broken pipe

如何打印出信息Broken pipe

SIGPIPE信號處理函數(shù)

當在收到reset包后,如果在讀寫socket,會出現(xiàn)錯誤EPIPE,同時經常收到SIGPIPE信號

在程序中可以看到java 并沒有對write的情況下沒有處理錯誤EPIPE,開始的時候錯誤的以拋出的異常是信號處理函數(shù)拋出的

先來看一下關于信號SIGPIPE的處理函數(shù),在Linux::install_signal_handlers 里面調用函數(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,中對對應的信號處理函數(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; 
 } 

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

在X86架構下, 函數(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; 
  } 
 } 
... 
} 

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

NET_ThrowByNameWithLastError函數(shù)

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

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.

關鍵點就在函數(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的異常信息,也就是開始對應的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 對應這個error number 的錯誤內容

結論:Broken pipe 是內核對應的錯誤信息,并不是java自己提供的信息

看完上述內容,你們對深入淺析java中connection reset 的異常處理有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。

分享名稱:深入淺析java中connectionreset的異常處理
文章來源:http://m.rwnh.cn/article2/pcdoic.html

成都網站建設公司_創(chuàng)新互聯(lián),為您提供網站導航、云服務器、企業(yè)建站、小程序開發(fā)關鍵詞優(yōu)化、響應式網站

廣告

聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

網站托管運營
贵溪市| 来宾市| 丰原市| 瑞昌市| 泽库县| 景洪市| 明溪县| 武平县| 怀安县| 水城县| 信宜市| 武冈市| 柘荣县| 鄯善县| 敦煌市| 资阳市| 聂拉木县| 固原市| 桓仁| 陆河县| 汉源县| 漠河县| 正镶白旗| 乌拉特后旗| 囊谦县| 丰台区| 广东省| 庐江县| 萍乡市| 孙吴县| 高唐县| 乌恰县| 集安市| 汶川县| 东台市| 易门县| 左权县| 荣昌县| 奉新县| 长岛县| 南乐县|