繁体   English   中英

多线程环境中与Java服务器和C#客户端通信的管道错误

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

我希望对我的旧烦恼问题有所帮助。

我有一个带有Java的TCP服务器程序和一个带有C#的客户端程序

两者之间的分组协议仅由4字节长度和主体ASCII数据组成。

问题是C#客户端遇到FormatException,这是由于解析长度字节失败而引起的。 如果我从客户端查看错误,则客户端正在尝试解析正文中某个不是长度标头的地方。 但是显然,服务器不会发送损坏的数据包。

同时,在服务器上,每当发生此类问题时,我都可以发现管道损坏的错误。

不幸的是,此错误并非总是会发生,并且无法重现问题情况。 这使我很难找到此问题的确切原因

请参阅以下服务器端代码

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();
        }
    }
}

}

这是客户端代码

 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);

    }
}

考虑到不可能重现问题,我猜这个问题是由于多线程问题引起的。 但我找不到解决此问题的任何其他线索。

如果您需要更多信息来解决此问题,请告诉我。

任何帮助将不胜感激,在此先感谢。

断开管道的另一端导致管道破裂。 C#客户端很可能有一个错误,导致格式异常,这导致其关闭连接,并因此断开了服务器端的管道。 看看Broken pipe Exception是什么意思?

检查此读取的返回值:

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

根据Microsoft BinaryReader文档。阅读https://msdn.microsoft.com/zh-cn/library/ms143295%28v=vs.110%29.aspx

[返回值为]读入缓冲区的字节数。 如果有许多字节不可用,则该数目可能小于所请求的字节数;如果到达流的末尾,则该数目可能为零。

如果读取的数据少于长度字节,则下一次它将使用最后一条消息中间某处的数据来解析长度。

当客户端(浏览器)关闭连接,但服务器(您的标记)继续尝试写入流时,会发生这些管道中断异常。

当有人在浏览器中单击“上一步”,“停止”等,并且在请求完成之前与服务器断开连接时,通常会发生这种情况。 有时可能会发生,因为例如Content-Length标头不正确(浏览器将其值设为true)。

通常,这是非事件,无需担心。 但是,如果您知道自己没有中断浏览器就在自己的开发环境中看到它们,那么您可能需要进一步研究以找出原因。

WLS服务器将尝试从Web容器中将这些异常从日志中筛选出来,因为这是由于客户端(浏览器)操作引起的,我们无法对此进行任何处理。 但是服务器无法捕获所有这些。

请参考:: https://community.oracle.com/thread/806884

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM