”Connection reset by peer“引发的思考

  闲来无事,把之前写的一个游戏服务器框架(《一个java页游服务器框架》),部署到阿里云服务器上,测试运行了下,结果看到后台log中打印出了“Connection reset by peer”。出于好奇疑问就查了一下相关资料,网上说一般有这几种:

  ①:服务器的并发连接数超过了其承载量,服务器会将其中一些连接Down掉;

  ②:客户关掉了浏览器,而服务器还在给客户端发送数据;

  ③:浏览器端按了Stop

  但是这几种都可以排除,刚搭建的服务器,就我测试连接了下不可能超过负载,而且我这是tcp长连接与浏览器没半点关系。后来问了一些大神才知道,一个连接如果长时间不用防火墙或者路由器就会给你断开,于是就会打印如上异常。现实中的解决方法就是,客户端定时向服务器发送心跳包。才知道心跳包原来还有这个作用,说来甚是惭愧啊。

  说到了心跳包自然又想到了另一个功能。客户端断电等一些列强制连接断开的情况,可以通过心跳包机制,让服务器端及时知道链接断开,从而及时清除这些无法使用的链接尸体。反过来说,如果没有心跳包,那么客户端强制断开,服务器是无法及时捕获到链接断开的事件的。然而在我测试下,强制关闭客户端,服务器端是会抛出异常的(我的这个框架使用了mina,客户端强制断开后,会调用对应的exceptionCaught方法抛出异常,然后又调用sessionClosed关闭连接)。既然服务器会抛出异常,自然我们不用通过心跳包,服务器端也能及时知道客户端连接断开的情况。

  怀着强烈的好奇心就做了如下测试,由于java网络编程有bio和nio以及最新的aio,对于AIO,成产环境中我还没有接触到又用这个的,所以暂不做测试,就针对BIO和NIO做测试

(以下代码比较简单,就不做解释了。仅仅用于测试我的疑惑,某些不合理的地方也就不必在意了)

  BIO测试程序:

    服务器端测试代码:

public class BIOServer {

	public static void main(String[] args) throws UnsupportedEncodingException {
		byte[] datas="hello".getBytes("UTF-8");
		try {
			ServerSocket ss = new ServerSocket(810);
			while(true){
				Socket s = ss.accept();
				OutputStream os = s.getOutputStream();
				os.write(datas);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

}

    客户端程序:

public class Client {

	public static void main(String[] args) {
		try {
			Socket s = new Socket("localhost", 810);
			InputStream is = s.getInputStream();
			byte[] buf = new byte[1024];
			int len=0;
			while((len=is.read(buf))!=-1){
				System.out.println(new String(buf,0,len,"utf-8"));
			}

			System.in.read();
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

    先运行服务器端,然后运行客户端收到服务器端发来的hello,然后强制关闭客户端,服务器端没有任何反应,这说明BIO下强制关闭客户端,服务器端是没法及时捕获的。当然在连接断开的情况下,服务器端对此连接进行读写,就会抛出异常。

  NIO测试程序:

    服务器端:

public class NioServer {

	public static void main(String[] args)throws Exception {

		Selector selector = Selector.open();
		ServerSocketChannel serverChannel = ServerSocketChannel.open();
		serverChannel.configureBlocking(false);
		serverChannel.socket().bind(new InetSocketAddress(810));
		serverChannel.register(selector, SelectionKey.OP_ACCEPT);
		while(true){
			int l = selector.select();
			if(l==0){
				continue;
			}
			Set<SelectionKey> sets = selector.selectedKeys();
			for(SelectionKey key :sets){
				if(key.isAcceptable()){
					ServerSocketChannel tChannel = (ServerSocketChannel) key.channel();
					SocketChannel clientChannel = tChannel.accept();
					clientChannel.configureBlocking(false);
					clientChannel.register(selector, SelectionKey.OP_READ);
				}else if(key.isReadable()){
					SocketChannel clientChannel = (SocketChannel) key.channel();
					ByteBuffer buf = ByteBuffer.allocate(1024);
					int len = clientChannel.read(buf);
					if(len==-1){
						System.out.println("客户端断开了");
					}else{
						buf.flip();
						System.out.println(new String(buf.array(),0,len,"utf-8"));
					}
				}
				sets.remove(key);
			}
		}
	}

}

    客户端:

public class Client {

	public static void main(String[] args) {
		try {
			Socket s = new Socket("localhost", 810);
			OutputStream os = s.getOutputStream();
			byte[] datas="hello".getBytes("UTF-8");
			os.write(datas);
			System.in.read();
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

  运行服务器端,然后运行客户端,可以看到服务器端打印出客户端发来的“hello”,然后强制关闭客户端,服务器端就回抛出如下异常:

  

  通过以上测试,可以知道:BIO下,客户端强制断开,服务器端是没法及时知道的;NIO下,客户端强制断开,服务器端可以及时知道并抛出异常。有此差异肯定是因为BIO和nio使用了不同的网络模型。NIO有一个selector,我想也就是这个selector的底层对每一个连接会有检查,所以能及时知道客户端连接断开事件。我的有服务器框架就是基于mina,而mina使用的nio,所以对于强制关闭客户端,我的服务器能及时捕获到并抛出异常这个疑惑,也就算彻底明确了。

  

  

时间: 2024-10-18 21:19:20

”Connection reset by peer“引发的思考的相关文章

Connection reset by peer 的常见原因:

Connection reset by peer的常见原因: 1)服务器的并发连接数超过了其承载量,服务器会将其中一些连接关闭: 如果知道实际连接服务器的并发客户数没有超过服务器的承载量,则有可能是中了病毒或者木马,引起网络流量异常.可以使用netstat -an查看网络连接情况. 2)客户关掉了浏览器,而服务器还在给客户端发送数据: 3)浏览器端按了Stop: 这两种情况一般不会影响服务器.但是如果对异常信息没有特别处理,有可能在服务器的日志文件中,重复出现该异常,造成服务器日志文件过大,影响

Connection reset by peer问题分析

extremetable导出excel,弹出一个下载窗口,这时不点下载而点取消,则报下面的异常: ClientAbortException Caused by: java.net.SocketException: Connection reset by peer: socket write error 查了下TOMCAT的文档,解释如下: Wrap an IOException identifying it as being caused by an abort of a request by

ECS云主机SSH连接提示&ldquo;Connection reset by peer&rdquo;的解决办法和解决思路

三周前刚从上家公司换到新的公司,这家公司与上家公司相比对阿里云的云计算环境更加的依赖,使用的ECS实例和其他服务如SLB.RDS.OSS等更多了一个数量级.这篇文章的背景就是为了解决阿里云ECS云主机SSH连接的一个问题,从故障发现到故障排除到最后反思的一个详细过程.文章比较长,图片众多,建议有时间仔细阅读,没时间就阅读文末的"总结和反思"部分即可. 故障发现: 2017-05-23 下午17:00点前同事报告称GitLab所在的服务器访问出现异常.经查发现在公司内无法正常通过SSH连

Android通过Http协议POST请求异常(Connection reset by peer)

上周遇到了一个Connection reset by peer 网络连接问题,为此,我找遍了中英文的一些网站,搜遍了能找的每个角落,发现了出现这种状况的原理,该java异常在客户端和服务器端都有可能发生,引起该异常的原因有: Connection reset by peer的常见原因: 1)服务器的并发连接数超过了其承载量,服务器会将其中一些连接关闭: 如果知道实际连接服务器的并发客户数没有超过服务器的承载量,则有可能是中了病毒或者木马,引起网络流量异常.可以使用netstat -an查看网络连

Connection reset by peer的常见原因

1,如果一端的Socket被关闭(或主动关闭,或因为异常退出而 引起的关闭),另一端仍发送数据,发送的第一个数据包引发该异常(Connect reset by peer). Socket默认连接60秒,60秒之内没有进行心跳交互,即读写数据,就会自动关闭连接. 2,一端退出,但退出时并未关闭该连接,另一端如果在从连接中读数据则抛出该异常(Connection reset). 简单的说就是在连接断开后的读和写操作引起的. Connection reset by peer的常见原因: 1)服务器的并

ssh远程报错ssh_exchange_identification: read: Connection reset by peer

ssh远程登录报错: [[email protected] ~]$ ssh     198.44.241.34 ssh_exchange_identification: read: Connection reset by peer 初步原因锁定: 1-服务器防火墙限定, 2-是否达到ssh的最大连接数,超过之后会服务器端会拒绝新的连接,直到有新的连接释放出来 3-/etc/hosts.allow和/etc/hosts.deny配置文件限定ip登录 解决方案: 1 firewall-cmd --l

CentOS7 yum的一次报错&quot; 14: curl#56 - &quot;Recv failure: Connection reset by peer&quot; &quot;

1.故障现象 [[email protected] src]# yum update Loaded plugins: fastestmirror, langpacks Could not retrieve mirrorlist   7&arch=x86_64&repo=os&infra=stock error was 14: curl#56 - "Recv failure: Connection reset by peer" One of the configu

Netty 中 IOException: Connection reset by peer 与 java.nio.channels.ClosedChannelException: null

最近发现系统中出现了很多 IOException: Connection reset by peer 与 ClosedChannelException: null 深入看了看代码, 做了些测试, 发现 Connection reset 会在客户端不知道 channel 被关闭的情况下, 触发了 eventloop 的 unsafe.read() 操作抛出 而 ClosedChannelException 一般是由 Netty 主动抛出的, 在 AbstractChannel 以及 SSLHand

ssh_exchange_identification: read: Connection reset by peer

连接SSH报错:ssh_exchange_identification: read: Connection reset by peer 查看没有使用防火墙,怀疑是在hosts.deny中设置了拦截 果不其然 将这一行注释,默念三声“信春哥得永生”后,问题恢复了,so easy