Android上的java.net.SocketException: sendto失败:EPIPE(断开管道)

6
我正在尝试在Android客户端从服务器套接字读取数据。
以下是我使用的代码片段:
客户端(使用JAVA在Android上)
    DataOutputStream dataOutputStream = null;
    DataInputStream dataInputStream = null;
    try {

        if (client.socket == null || !client.socket.isConnected())
            client.createSocket();

        // Get Input/Output stream for socket
        dataOutputStream = new DataOutputStream(client.socket.getOutputStream());
        dataInputStream = new DataInputStream(client.socket.getInputStream());

       // Here RS is simple JAVA class that stores information about payload and response length
        Log.d("Send", "Sending payload for pair " + RS.getc_s_pair() + " " + RS.getResponse_len());

        dataOutputStream.write(UtilsManager.serialize(RS.getPayload()));

        // Notify waiting Queue thread to start processing next packet
        if (RS.getResponse_len() > 0) {
            Log.d("Response", "Waiting for response for pair " + RS.getc_s_pair() + " of " + RS.getResponse_len() + " bytes");

            int totalRead = 0;

            byte[] buffer = new byte[RS.getResponse_len()];
            while (totalRead < RS.getResponse_len()) {
                int bytesRead = dataInputStream.read(buffer, totalRead, RS.getResponse_len() - totalRead);

                if (bytesRead < 0) {
                    throw new IOException("Data stream ended prematurely");
                }
                totalRead += bytesRead;
            }
    }

服务器(Python)
        # Here request_len is the expected request size
        while buffer_len < response_set.request_len:
            new_data = connection.recv( min(self.buff_size, response_set.request_len-buffer_len) )
            if not new_data:
                return False
            buffer_len += len(new_data)

        # Send required response
        for response in response_set.response_list:
            try:
                connection.sendall(str(response.payload))
            except:
                return False

有时候,当我从客户端发送有效载荷时,会出现错误。
       dataOutputStream.write(UtilsManager.serialize(RS.getPayload()));

我收到的错误是:
java.net.SocketException: sendto failed: EPIPE (Broken pipe)
    at libcore.io.IoBridge.maybeThrowAfterSendto(IoBridge.java:506)
    at libcore.io.IoBridge.sendto(IoBridge.java:475)
    at java.net.PlainSocketImpl.write(PlainSocketImpl.java:507)
    at java.net.PlainSocketImpl.access$100(PlainSocketImpl.java:46)
    at java.net.PlainSocketImpl$PlainSocketOutputStream.write(PlainSocketImpl.java:269)
    at java.io.DataOutputStream.write(DataOutputStream.java:98)
    at java.io.OutputStream.write(OutputStream.java:82)
    at com.rgolani.replay.tcp.TCPClientThread.run(TCPClientThread.java:56)
    at java.lang.Thread.run(Thread.java:856)
Caused by: libcore.io.ErrnoException: sendto failed: EPIPE (Broken pipe)
    at libcore.io.Posix.sendtoBytes(Native Method)
    at libcore.io.Posix.sendto(Posix.java:151)
    at libcore.io.BlockGuardOs.sendto(BlockGuardOs.java:177)
    at libcore.io.IoBridge.sendto(IoBridge.java:473)
    ... 7 more

我知道这有点令人困惑。Python代码不是我编写的,存在一个Python客户端,可以正常运行而没有任何错误。我只在我的JAVA代码中遇到了这个错误。 正常运行的Python客户端
    if self.sock is None:
        self._connect_socket()

    self.sock.sendall(tcp.payload)

    buffer_len = 0
    while tcp.response_len > buffer_len:
        data = self.sock.recv( min(self.buff_size, tcp.response_len-buffer_len) )
        buffer_len += len(data)

请告诉我您是否需要更多信息。
谢谢。

https://stackoverflow.com/questions/36386141/retrofit-retrofiterror-sendto-failed-epipe-broken-pipe/54861233#54861233 - sajjad Yosefi
4个回答

1
如果您正在使用setChunkedStreamingMode,请将其删除,然后再查看。我认为我太晚了,但这解决了我的问题。您可以使用固定长度流模式。

我使用 setChunkedStreamingMode 是因为 链接。并且遇到过一次这种情况。这是由于服务器的 PHP 不允许非固定长度。应该在服务器端解决,而不需要在客户端删除代码。 - Yeung

1
当客户端尝试向后端已经关闭的连接写入数据时,会出现该错误。默认情况下,Android 将 "保持活动" 属性设置为 true,并且将重用旧的套接字连接,因为在移动环境中建立连接是一项资源消耗操作(您可以使用 fiddler 等工具进行测试)。尝试将 "Connection" 头设置为 "close" 或调用 System.setProperty("http.keepAlive", "false"); 以禁用 Keep Alive,从而强制系统创建新连接。

0
也许我对你的问题有所疏漏,但我认为使用这个Java片段会更好:
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;

ObjectOutputStream dataOutputStream = null;
ObjectInputStream dataInputStream = null;
try {

    if (client.socket == null || !client.socket.isConnected())
        client.createSocket();

    // Get Input/Output stream for socket
    dataOutputStream = new ObjectOutputStream (client.socket.getOutputStream());
    dataInputStream = new ObjectInputStream (client.socket.getInputStream());

    // Here RS is simple JAVA class that stores information about payload and response length
    Log.d("Send", "Sending payload for pair " + RS.getc_s_pair() + " " + RS.getResponse_len());

    // You might consider using java.io.Serializable interface with the argument object
    dataOutputStream.writeObject(UtilsManager.serialize(RS.getPayload()));

    // Notify waiting Queue thread to start processing next packet
    if (RS.getResponse_len() > 0) {
        Log.d("Response", "Waiting for response for pair " + RS.getc_s_pair() + " of " + RS.getResponse_len() + " bytes");

        // Read a java.io.Serializable object from the stream. So you have to write a java.io.Serializable object into the stream.
        Object o = dataInputStream.readObject();
    }
}

希望这能有所帮助...

0
在我的情况下:client.createSocket(); 不会连接到任何服务器 - 只是创建一个套接字。所以稍后我必须 client.connect(_sock_sddr_here_);
此外 isConnected() - 愚蠢的测试,因为它永远为真。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接