【问题标题】:Server: Socket hangs within unpredictable period time at read stream function服务器:套接字在读取流功能时在不可预测的时间段内挂起
【发布时间】:2016-07-12 13:14:25
【问题描述】:

我编写了一个 Java 套接字服务器,它将保持连接直到客户端断开连接。我的客户端代码会不断向这个服务器应用推送消息。

但是当我运行这些程序一段时间时,我似乎也出现了一种不寻常的情况,即服务器在不可预知的时间内从客户端读取输入流时会挂起。它总是挂在inData.read(b),因为我看到它在发生此问题时在日志上打印了“正在接收...”;即使我杀死了我的客户端,服务器应用程序仍然挂在那里。

但是当我在发生此问题后在运行服务器应用程序的控制台上按Ctrl+C 时,它将继续工作。这真的很烦人。

有没有办法很好地解决这个 Unusual 问题?

服务器代码:

    static ServerSocket server;

    try {
        server = new ServerSocket("1234");
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    Socket socket = null;
    String inIp = null;
    BufferedInputStream inData;
    BufferedOutputStream outData;

    while (true) {
        try {
            synchronized (server) {
                socket = server.accept();
            }
            inIp = String.valueOf(socket.getInetAddress());
            if (Log4j.log.isEnabledFor(Level.INFO)) {
                Log4j.log.info("Incoming connection " + inIp);
            }
            while (true) {
                inData = new BufferedInputStream(socket.getInputStream());
                outData = new BufferedOutputStream(socket.getOutputStream());
                String reply = "Hey";

                byte[] b = new byte[10240];
                String data = "";
                int length;

                if (Log4j.log.isEnabledFor(Level.INFO)) {
                    Log4j.log.info("InetAddr = " + inIp + ", receiving...");
                }


                // read input stream
                length = inData.read(b);
                data += new String(b, 0, length);
                if (Log4j.log.isEnabledFor(Level.INFO)) {
                    Log4j.log.info("Data Length: " + length + ", Received data:  " + data);
                }


                // output result
                outData.write(reply.getBytes());
                outData.flush();
            }
        } catch (Exception e) {
            String tempStr = e.toString();
            Log4j.log.error("Service error during executing: " + tempStr);
        }
    }

客户代码:

    Socket client = new Socket();
    InetSocketAddress isa = new InetSocketAddress("127.0.0.1", "1234");
    String data = "Hi";

    while(true) {
        try {
            if(!client.isConnected())
                client.connect(isa, 30000);

            BufferedOutputStream out = new BufferedOutputStream(client.getOutputStream());
            BufferedInputStream in = new BufferedInputStream(client.getInputStream());

            // send msg
            out.write(data.getBytes());
            out.flush();


            System.out.println("Message sent, receiving return message...");


            // get return msg
            int length;
            byte[] b = new byte[10240];

            // read input stream
            length = in.read(b);
            retMsg = new String(b, 0, length);

            System.out.println("Return Msg: " + retMsg);

            Thread.sleep(60000); 

        } catch (java.io.IOException | InterruptedException e) {
            System.out.println("Socket Error!");
            System.out.println("IOException :" + e.toString());
        }
    }

【问题讨论】:

    标签: java sockets tcp serversocket


    【解决方案1】:
    try {
        server = new ServerSocket("1234");
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    

    不要写这样的代码。 catch 块应该在最后,所有依赖new ServerSocket 成功的代码都应该在try 块内。

    synchronized (server) {
        socket = server.accept();
    }
    

    这里不需要同步。

    while (true) {
        inData = new BufferedInputStream(socket.getInputStream());
        outData = new BufferedOutputStream(socket.getOutputStream());
    

    问题的很大一部分,如果不是全部的话,都在这里。每次围绕此循环时,您都会不断创建新的缓冲流,这意味着以前的流缓冲的任何内容都将被丢弃。所以你正在失去输入。您应该在循环之前创建这两个流。

    while(true) {
        try {
            if(!client.isConnected())
                client.connect(isa, 30000);
    

    这是没有意义的。消除。您还没有展示client 套接字是如何创建的,但如果您在未连接的情况下创建它,您应该在进入此循环之前连接它。

            BufferedOutputStream out = new BufferedOutputStream(client.getOutputStream());
            BufferedInputStream in = new BufferedInputStream(client.getInputStream());
    

    这里你必须在循环之前创建这些流。

    【讨论】:

    • @Fildor 我不同意。
    • 我不同意你的说法。您的陈述是普遍适用还是仅在这种情况下适用?这种讨论值得吗?你的评论和我的回答有关系吗?
    猜你喜欢
    • 1970-01-01
    • 2018-10-26
    • 2014-04-12
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 2015-09-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多