BinaryProbe
BinaryProbe

Reputation: 273

Broken pipe error communicating with Java server & C# client in multi thread env

I hope to find any help on my old annoying problem.

I have a TCP sever program with java and client program with c#

packet protocol between those two is simply consist of 4byte length & body ASCII data.

The Problem is that C# client faces FormatException which is from parsing fail on length byte. If I look into an error from client side, then client is trying to parse somewhere in the body which is not length header. But apparently, Server does not send broken packet.

meanwhile, at the server, I could find an Broken pipe error whenever this kind of problem happens.

Unfortunately this error does not always happen and was not able to recreate the problem situation. it makes me difficult to find exact cause of this problem

Please see below codes for server side

public class SimplifiedServer {

private Map<InetAddress, DataOutputStream> outMap;
private Map<InetAddress,DataInputStream> inMap;

protected void onAcceptNewClient(Socket client) {
    DataOutputStream out = null;
    DataInputStream in = null;
    try {
        out = new DataOutputStream(client.getOutputStream());
        in = new DataInputStream(client.getInputStream());
    } catch (IOException e) {
        e.printStackTrace();
    }
    outMap.put(client.getInetAddress(), out);
    inMap.put(client.getInetAddress(), in);

}

    public void writeToAll(String packet) {
    outMap.forEach((key, out) -> {

        try {
            byte[] body = packet.getBytes("UTF-8");
            int len = body.length;
            if (len > 9999) {
                throw new IllegalArgumentException("packet length is longer than 10000, this try will be neglected");
            }

            String lenStr = String.format("%04d%s", len, packet);
            byte[] obuf = lenStr.getBytes();

            synchronized (out) {
                out.write(obuf);
                out.flush();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    });

}


public void listenClient(Socket client) {
    try {
        DataOutputStream out = outMap.get(client.getInetAddress());
        DataInputStream in = inMap.get(client.getInetAddress());

        while (true) {

            byte[] received = SimplePacketHandler.receiveLpControlerData(in);

            byte[] lenBytes = new byte[4];

            for( int i = 0 ; i < 4 ; i ++){
                lenBytes[i] = in.readByte();
            }

            String lenString = new String(lenBytes);
            int length = Integer.parseInt(lenString);
            byte[] data = new byte[length];

            for ( int i = 0 ; i < length ; i ++){
                data[i] = in.readByte();
            }

            if ( data == null ){
                System.out.println("NetWork error, closing socket :" + client.getInetAddress());
                in.close();
                out.close();
                outMap.remove(client.getInetAddress());
                inMap.remove(client.getInetAddress());
                return;
            }

            doSomethingWithData(out, data);

        }

    } catch (NumberFormatException e) {
        e.printStackTrace();
    } catch ( Exception e ) {
        e.printStackTrace();
    } finally {
        try {
            System.out.println(client.getRemoteSocketAddress().toString() + " closing !!! ");
            // remove stream handler from map
            outMap.remove(client.getInetAddress());
            inMap.remove(client.getInetAddress());

            //close socket.
            client.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

}

And here is client side code

 public class ClientSide
{
    public TcpClient client;


    public String ip;
    public int port;
    public NetworkStream ns;
    public BinaryWriter writer;
    public BinaryReader reader;

    public Boolean isConnected = false;
    public System.Timers.Timer t;
    public String lastPacketSucceeded = String.Empty;


    public ClientSide(String ip, int port)
    {
        this.ip = ip;
        this.port = port;
        client = new TcpClient();

    }

    public bool connect()
    {
        try
        {
            client.Connect(ip, port);
        }
        catch (SocketException e)
        {
            Console.WriteLine(e.ToString());
            return false;
        }


        Console.WriteLine("Connection Established");

        reader = new BinaryReader(client.GetStream());
        writer = new BinaryWriter(client.GetStream());
        isConnected = true;


        return true;
    }

    public void startListen()
    {
        Thread t = new Thread(new ThreadStart(listen));
        t.Start();
    }

    public void listen()
    {

        byte[] buffer = new byte[4];
        while (true)
        {               

            try
            {
                reader.Read(buffer, 0, 4);
                String len = Encoding.UTF8.GetString(buffer);
                int length = Int32.Parse(len);
                byte[] bodyBuf = new byte[length];
                reader.Read(bodyBuf, 0, length);

                String body = Encoding.UTF8.GetString(bodyBuf);
                doSomethingWithBody(body);
            }
            catch (FormatException e)
            {
                 Console.WriteLine(e.Message);

            }

        }

    }

    public void writeToServer(String bodyStr)
    {
        byte[] body = Encoding.UTF8.GetBytes(bodyStr);
        int len = body.Length;
        if (len > 10000)
        {
            Console.WriteLine("Send Abort:" + bodyStr);
        }
        len = len + 10000;
        String lenStr = Convert.ToString(len);

        lenStr = lenStr.Substring(1);

        byte[] lengthHeader = Encoding.UTF8.GetBytes(lenStr);


        String fullPacket = lenStr + bodyStr;
        byte[] full = Encoding.UTF8.GetBytes(fullPacket);

        try
        {
            writer.Write(full);
        }
        catch (Exception)
        {
            reader.Close();
            writer.Close();
            client.Close();

            reader = null;
            writer = null;
            client = null;
            Console.WriteLine("Send Fail" + fullPacket);

        }
        Console.WriteLine("Send complete " + fullPacket);

    }
}

Considering it is impossible to recreate problem, I would guess this problem is from multithread issue. but I could not find any further clue to fix this problem.

Please let me know if you guys need any more information to solve this out.

Any help will be great appreciated, thanks in advance.

Upvotes: 0

Views: 3217

Answers (2)

Mihir Patel
Mihir Patel

Reputation: 412

These broke pipe exceptions happen when the client (browser) has closed the connection, but the server (your tag) continues to try to write to the stream.

This usually happens when someone clicks Back, Stop, etc. in the browser and it disconnects from the server before the request is finished. Sometimes, it can happen because, for example, the Content-Length header is incorrect (and the browser takes its value as true).

Usually, this is a non-event, and nothing to worry about. But if you are seeing them in your dev environment when you know you have not interrupted your browser, you might dig a bit more to find out why.

WLS server will try to filter these exceptions from the web container out of the log, since it is due to client (browser) action and we can't do anything about it. But the server doesn't catch all of them.

refer from :: https://community.oracle.com/thread/806884

Upvotes: 0

WillShackleford
WillShackleford

Reputation: 7018

A broken pipe exception is caused by closing the connection on the other side. Most likely the C# client has a bug, causing the format exception which causes it to close the connection and therefore the broken pipe on the server side. See what is the meaning of Broken pipe Exception?.

Check the return value of this read:

            byte[] bodyBuf = new byte[length];
            reader.Read(bodyBuf, 0, length);

According to Microsoft documentation for BinaryReader.Read https://msdn.microsoft.com/en-us/library/ms143295%28v=vs.110%29.aspx

[The return value is ] The number of bytes read into buffer. This might be less than the number of bytes requested if that many bytes are not available, or it might be zero if the end of the stream is reached.

If it reads less than the length bytes then next time it will be parsing the length using data somewhere in the middle of the last message.

Upvotes: 1

Related Questions