Pipe Broken问题

最近在生产上总是遇到pipe broken的问题,包括使用java客户端向ES同步数据,java向kafka发送数据等,都出现了类似的问题,为弄清楚Pipe broken问题产生的根因,参考网上其他的教程(详见参考链接)。设计了服务端和客户端的报错的情况,并进行分析。

 

 

 一、情况模拟

1.1 服务端报错

Server

 1 import java.io.DataInputStream;
 2 import java.io.DataOutputStream;
 3 import java.io.IOException;
 4 import java.io.InputStream;
 5 import java.net.ServerSocket;
 6 import java.net.Socket;
 7  8 public class Server {
 9 10     public static void main(String[] args) {
11             try {
12                 ServerSocket ss = new ServerSocket(3113);
13                 Socket s = ss.accept();
14                 //client->server
15                 DataInputStream is = new DataInputStream(s.getInputStream());
16                 byte[] buf =new byte[1024];
17                 int len = is.read(buf);
18                 System.out.println("recv:"+new String(buf,0,len));
19     
20                 Thread.sleep(10000);
21 22                 //server->client
23                 s.getOutputStream().write("1111 server".getBytes());
24     
25 26 27                 //client->server
28                 DataInputStream in = new DataInputStream(s.getInputStream());
29                 byte[] bytes = new byte[1024];
30                 int length = in.read(bytes);
31 32                 try {
33                     System.out.println("recv2:"+new String(bytes,0,length));
34                 } catch (Exception e) {
35                     e.printStackTrace();
36 37                     System.out.println("--------------");
38 39                     DataOutputStream out = new DataOutputStream(s.getOutputStream());
40                     try {
41                         out.write("error write ".getBytes());
42                     } catch (IOException e1) {
43                         System.out.println("==============================");
44                         e1.printStackTrace();
45                     }
46                 }
47 48             }catch (Exception e){
49                 System.out.println(e.getStackTrace());
50                 e.printStackTrace();
51             }
52         }
53 }

Client

 1 import java.io.DataInputStream;
 2 import java.io.DataOutputStream;
 3 import java.io.IOException;
 4 import java.io.OutputStream;
 5 import java.net.Socket;
 6  7 public class Client {
 8     public static void main(String[] args) {
 9         Socket s = null;
10         try {
11             s = new Socket("127.0.0.1", 3113);
12             s.setSoTimeout(5000);
13 14             DataOutputStream out = new DataOutputStream(
15                     s.getOutputStream());
16 17             //client->server
18             out.write("1111 from client".getBytes());
19 20             // server->client
21             DataInputStream in = new DataInputStream(s.getInputStream());
22             byte[] bytes = new byte[1024];
23             int len = in.read(bytes);
24 25             System.out.println("client:" + new String(bytes, 0, len));
26 27             out.write("2222 from client".getBytes());
28 29 30         } catch (Exception e) {
31             e.printStackTrace();
32         } finally {
33             if (s != null) {
34                 try {
35                     s.close();
36                 } catch (IOException e) {
37                     e.printStackTrace();
38                 }
39             }
40         }
41     }
42 }

服务端报错情况

 

 使用tcpdump抓包

tcpdump -i lo

 

 倒数第二步,服务端请求发送12字节。最后一步,客户端发送RST报文.然后服务端就报Broken PIPE错误了。

1.2 客户端报错

Server

 1 import java.io.DataInputStream;
 2 import java.io.DataOutputStream;
 3 import java.io.IOException;
 4 import java.io.InputStream;
 5 import java.net.ServerSocket;
 6 import java.net.Socket;
 7  8 public class Server {
 9 10     public static void main(String[] args) {
11             try {
12                 ServerSocket ss = new ServerSocket(3113);
13                 Socket s = ss.accept();
14 15                 s.setSoTimeout(5000);
16 17                 DataInputStream is = new DataInputStream(s.getInputStream());
18                 byte[] buf =new byte[1024];
19                 int len = is.read(buf);
20                 System.out.println("recv:"+new String(buf,0,len));
21 22               //  Thread.sleep(10000);
23 24                 s.getOutputStream().write("1111 server".getBytes());
25                 
26                 DataInputStream in = new DataInputStream(s.getInputStream());
27                 byte[] bytes = new byte[1024];
28                 int length = in.read(bytes);
29 30                 try {
31                     System.out.println("recv2:"+new String(bytes,0,length));
32                 } catch (Exception e) {
33                     e.printStackTrace();
34 35                     System.out.println("--------------");
36 37                     DataOutputStream out = new DataOutputStream(s.getOutputStream());
38                     try {
39                         out.write("error write ".getBytes());
40                     } catch (IOException e1) {
41                         System.out.println("==============================");
42                         e1.printStackTrace();
43                     }
44                 }
45 46             }catch (Exception e){
47                 System.out.println(e.getStackTrace());
48                 e.printStackTrace();
49             }
50         }
51 }
52

Client

 1 import java.io.DataInputStream;
 2 import java.io.DataOutputStream;
 3 import java.io.IOException;
 4 import java.io.OutputStream;
 5  6 import java.net.Socket;
 7  8  9 public class Client {
10     public static void main(String[] args) {
11         Socket s = null;
12 13         try {
14             s = new Socket("127.0.0.1", 3113);
15             // s.setSoTimeout(5000);
16             Thread.sleep(10000);
17 18             DataOutputStream out = new DataOutputStream(s.getOutputStream());
19 20             try {
21                 out.write("1111 from client".getBytes());
22             } catch (Exception e) {
23                 e.printStackTrace();
24             }
25 26             System.out.println("11111111");
27 28             DataInputStream in = new DataInputStream(s.getInputStream());
29             byte[] bytes = new byte[1024];
30             int len = in.read(bytes);
31 32             try {
33                 System.out.println("client:" + new String(bytes, 0, len));
34             } catch (Exception e) {
35                 e.printStackTrace();
36             }
37 38             try {
39                 out.write("2222 from client".getBytes());
40             } catch (Exception e) {
41                 e.printStackTrace();
42             }
43         } catch (Exception e) {
44             e.printStackTrace();
45         } finally {
46             if (s != null) {
47                 try {
48                     s.close();
49                 } catch (IOException e) {
50                     e.printStackTrace();
51                 }
52             }
53         }
54     }
55 }

客户端报错情况

 

tcpdump情况

 

 倒数第二步,客户端请求发送17字节,服务端返回RST报名,客户端报错。

二、分析

如下划线部分所说:向某个已收到RST的连接执行写操作时,将会返回EPIPE错误。EPIPE!PIPE!

  • 知识准备之RST报文

终止一个TCP连接的正常方式是发送FIN。在发送缓冲区中所有排队数据都已发送之后才发送FIN,正常情况下没有任何数据丢失。但我们有时也可能发送一个RST报文段而不是FIN来中途关闭一个连接。这称为异常关闭。 现在知道RST报文的作用了,那就在大致列一下出现RST报文的场景吧:

  1. connect一个不存在的端口;
  2. 向一个已经关掉的连接send数据;
  3. 向一个已经崩溃的对端发送数据(连接之前已经被建立);
  4. close(sockfd)时,直接丢弃接收缓冲区未读取的数据,并给对方发一个RST。这个是由SO_LINGER选项来控制的;
  5. a重启,收到b的保活探针,a发rst,通知b。

 

 

通俗的讲

服务端和客户端是建立的两个相应的通道

当向一个写关闭的通道,读数据时。这个操作是允许的(管道里可能还有数据)

但是,向一个读关闭的关闭,写数据时,是不允许的。因为就没有人读了(这也就是报错的原因)

三、产生问题的可能原因

一方向通道写数据时,对方(读方)因为各种原因使连接关闭了,导致写方报错。

那么这个各种原因可能包括:读方

资源不够用,意外关闭了连接

读方设置了读取超时时间,写方操作时间太长

 

四、参考

https://www.cnblogs.com/cthon/p/9139553.html

https://www.cnblogs.com/liangzs/p/9448575.html

https://www.cnblogs.com/yaowen/p/9726357.html

https://blog.csdn.net/qq_23013625/article/details/52816757 setSotimeout方法

posted @ 2020-02-09 09:48  yanyouqiang  阅读(1352)  评论(0编辑  收藏  举报