java中的connection reset 异常处理分析
发布时间 - 2026-01-11 00:29:44 点击率:次在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
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信号处理函数
当在收到reset包后,如果在读写socket,会出现错误EPIPE,同时经常收到SIGPIPE信号
在程序中可以看到java 并没有对write的情况下没有处理错误EPIPE,开始的时候错误的以抛出的异常是信号处理函数抛出的
先来看一下关于信号SIGPIPE的处理函数,在Linux::install_signal_handlers 里面调用函数
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
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
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的程序
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
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
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 是一样的
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自己提供的信息
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!
# connection
# reset
# 详解Java异常处理中throw与throws关键字的用法区别
# Java程序常见异常及处理汇总
# Java中异常处理之try和catch代码块的使用
# 深入探讨JAVA中的异常与错误处理
# java异常处理机制示例(java抛出异常、捕获、断言)
# Java异常分类及统一处理详解
# java异常与错误处理基本知识
# Java一些常见的出错异常处理方法总结
# Java异常(Exception)处理以及常见异常总结
# 抛出
# 信号处理
# 错误信息
# 可以看到
# 这种情况
# 的是
# 情况下
# 发生在
# 几个
# 使用了
# 会有
# 就在
# 还可以
# 却是
# 也就
# 上了
# 则是
# 我们可以
# 会使
# 看一下
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
如何在阿里云域名上完成建站全流程?
Laravel怎么多语言本地化设置_Laravel语言包翻译与Locale动态切换【手册】
通义万相免费版怎么用_通义万相免费版使用方法详细指南【教程】
如何用好域名打造高点击率的自主建站?
百度浏览器ai对话怎么关 百度浏览器ai聊天窗口隐藏
Laravel如何实现全文搜索_Laravel Scout集成Algolia或Meilisearch教程
Laravel如何使用缓存系统提升性能_Laravel缓存驱动和应用优化方案
jQuery 常见小例汇总
JavaScript如何操作视频_媒体API怎么控制播放
Laravel怎么写单元测试_PHPUnit在Laravel项目中的基础测试入门
如何在新浪SAE免费搭建个人博客?
Laravel如何使用Facades(门面)及其工作原理_Laravel门面模式与底层机制
如何在阿里云完成域名注册与建站?
javascript基于原型链的继承及call和apply函数用法分析
如何解决hover在ie6中的兼容性问题
如何在宝塔面板中修改默认建站目录?
Python进程池调度策略_任务分发说明【指导】
Laravel如何使用软删除(Soft Deletes)功能_Eloquent软删除与数据恢复方法
如何挑选高效建站主机与优质域名?
Laravel中DTO是什么概念_在Laravel项目中使用数据传输对象(DTO)
JavaScript如何实现类型判断_typeof和instanceof有什么区别
js实现点击每个li节点,都弹出其文本值及修改
iOS UIView常见属性方法小结
Laravel如何实现多级无限分类_Laravel递归模型关联与树状数据输出【方法】
Laravel怎么配置不同环境的数据库_Laravel本地测试与生产环境动态切换【方法】
宙斯浏览器视频悬浮窗怎么开启 边看视频边操作其他应用教程
个人摄影网站制作流程,摄影爱好者都去什么网站?
如何快速打造个性化非模板自助建站?
浅述节点的创建及常见功能的实现
详解免费开源的DotNet二维码操作组件ThoughtWorks.QRCode(.NET组件介绍之四)
如何在VPS电脑上快速搭建网站?
如何在阿里云ECS服务器部署织梦CMS网站?
佛山网站制作系统,佛山企业变更地址网上办理步骤?
如何在IIS中配置站点IP、端口及主机头?
详解vue.js组件化开发实践
百度浏览器如何管理插件 百度浏览器插件管理方法
如何用虚拟主机快速搭建网站?详细步骤解析
原生JS获取元素集合的子元素宽度实例
百度浏览器网页无法复制文字怎么办 百度浏览器复制修复
如何为不同团队 ID 动态生成多个“认领值班”按钮
中山网站推广排名,中山信息港登录入口?
Laravel如何实现多语言支持_Laravel本地化与国际化(i18n)配置教程
如何为不同团队 ID 动态生成多个非值班状态按钮
网站制作公司哪里好做,成都网站制作公司哪家做得比较好,更正规?
python中快速进行多个字符替换的方法小结
Claude怎样写约束型提示词_Claude约束提示词写法【教程】
Laravel如何使用Eloquent ORM进行数据库操作?(CRUD示例)
Laravel如何处理JSON字段的查询和更新_Laravel JSON列操作与查询技巧
Laravel怎么生成URL_Laravel路由命名与URL生成函数详解
Android Socket接口实现即时通讯实例代码

