Broken pipe vs Connection reset Exception

目录

Broken pipe 和 Connection reset 什么情况下会发生?

 

Broken pipe 和 Connection reset 什么情况下会发生?

下面通过两个不同的客户端demo,以及一个服务端 demo 的验证结果来说明

服务端demo

package com.study.hsyang.problems.brokenPipe;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
	public static void main(String[] args){
		ServerSocket ss = null;
		try {
			System.out.println("Server start...");
			ss = new ServerSocket(7342);
			Socket s = ss.accept();
			InputStream is = s.getInputStream();
			byte[] buf = new byte[1024];
			int len = is.read(buf);
			System.out.println("recv:" + new String(buf, 0, len));
			Thread.sleep(5000);//等待 5 秒,确保客户端连接已经关闭了
			try{
				System.out.println("send hello1 start");
				s.getOutputStream().write("hello1".getBytes());
				System.out.println("send hello1 end");
			}catch(IOException e) {
				e.printStackTrace();
			}
			try{
				System.out.println("send hello2 start");
				s.getOutputStream().write("hello2".getBytes());
				System.out.println("send hello2 end");
			}catch(IOException e){
				e.printStackTrace();
			}try{
				System.out.println("send hello3 start");
				s.getOutputStream().write("hello3".getBytes());
				System.out.println("send hello3 end");
			}catch(IOException e){
				e.printStackTrace();
			}
			System.in.read();// block program
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

大致逻辑:服务端在接收到客户端发送的 “hello” 之后休眠 5 秒,然后连续发送三个字符串至客户端。

客户端 Demo1:

package com.study.hsyang.problems.brokenPipe;

import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;

public class Client {
	public static void main(String[] args) {
		try {
			System.out.println("Client start...");
			Socket s = new Socket();
			s.setSoLinger(true, 0);// 设置调用 close 就发送 RST 报文
			s.connect(new InetSocketAddress("172.31.6.41", 7342));
			OutputStream os = s.getOutputStream();
			os.write("hello".getBytes());
            Thread.sleep(2000);//休眠2秒,确保服务端读操作已经完成
			s.close();
			System.in.read();// block program
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

 大致逻辑: 在发送完 “hello” 之后,会休眠两秒,然后立刻异常关闭(直接向服务端发送 rst 报文)。

先启动服务端,然后启动客户端,至运行结束后服务端会抛出如下异常

分析

通过 wireShark 捕获的报文信息

图片每一行简单说明:

1:客户端向服务端发送 【SYN】 报文,请求建立连接

2:服务端向客户端发送 【SYN,ACK】报文,同意建立连接,并再次向客户端确认

3:客户端向服务端再次发送【ACK】报文,再次进行连接确认,至此。三次握手完成,tcp 连接正式建立成功

4:客户端向服务端发送 hello 报文

5:服务端发送收到 hello 报文的响应

6:异常关闭 Close 连接(由于SO_LINGER设置为0的缘故),向服务端发送 【RST,ACK】报文。

由于客户端异常关闭,且已经向服务端发送了【RST,ACK】报文。在关闭后,服务端首次向客户端发送消息,服务端会抛出 Connection reset 异常,之后再次发送消息就会抛出 Broken pipe 异常了。

客户端Demo2

package com.study.hsyang.problems.brokenPipe;

import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;

public class Client {
	public static void main(String[] args) {
		try {
			System.out.println("Client start...");
			Socket s = new Socket();
			s.connect(new InetSocketAddress("172.31.6.41", 7342));
			OutputStream os = s.getOutputStream();
			os.write("hello".getBytes());
            Thread.sleep(2000);//休眠2秒,确保服务端读操作已经完成
			s.close();
			System.in.read();// block program
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

demo2与demo1的唯一区别就是少了 SO_LINGER的设置,使得客户端可以正常close缺省close()的行为是,如果有数据残留在socket发送缓冲区中则系统将继续发送这些数据给对方,等待被确认,然后返回

服务端打印结果

分析

由服务端打印结果可知,在客户端正常关闭之后,服务端向客户端多次发送消息,也不会抛出任何异常了

wireShark捕获的报文

图片中红框位置为客户端向服务端发送的断开连接请求。

总结

当第一次向已经异常关闭的通道写入数据时,会抛出 Connection reset Exception,再次写入时会抛出 Broken pipe Exception。

当向已经正常关闭的通道写入数据时,不会抛出任何异常

Thanks:

【你假笨@JVM】:http://lovestblog.cn/blog/2014/05/20/tcp-broken-pipe/

永志●哥德https://www.cnblogs.com/metoy/p/6565486.html

猜你喜欢

转载自blog.csdn.net/yhs1296997148/article/details/83347492