通过套接字通信读取数据时出错

时间:2018-03-24 06:19:20

标签: java sockets

以下方案解释了我的问题 我是一个充当服务器套接字程序的PLC。我编写了一个客户端Java程序,通过与PLC的套接字通信进行通信。

此过程中发生的步骤是:
1)对于每一秒,我的客户端程序碰巧与PLC通信,读取流中的数据,临时将数据存储在 ByteArrayOutputStream 中并关闭输入流和套接字。以下片段给出了想法

    try {
        socket = new Socket(host, port);
        is = socket.getInputStream();
        outputBuffer = new ByteArrayOutputStream();

        byte[] buffer = new byte[1024];
        int read;
        if((read = is.read(buffer)) != -1) {
            outputBuffer.write(buffer, 0, read);
        }
    } catch (UnknownHostException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            System.out.println("Before closing the socket");
            try {
                is.close();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println("After closing the socket");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

2)根据我的要求处理存储的数据是我想要做的。因此,每1秒,客户端程序连接到服务器,读取数据(如果存在数据),存储数据,关闭套接字并处理它。它必须在很长一段时间内发生,可能直到服务器程序打开。这可能发生在每隔几周。

3)我遇到的问题是,我能够运行上述节目1-2小时,但从那时起,客户端程序无法从服务器程序中获取数据(PLC in这种情况),虽然两者都通过套接字连接。即,存在128字节的数据,但客户端程序无法读取该数据。这项计划在成功运行近2小时后开始发生

4)请找到可能有助于您了解的简要代码。

public class LoggingApplication {
    public static void main(String[] args) throws NumberFormatException {
        if (args.length > 0 && args.length == 2) {
            String ipAddress = mappingService.getIpAddress();
            int portNo = (int) mappingService.getPortNo();
            ScheduledExecutorService execService = Executors.newScheduledThreadPool(1);
            execService.schedule(new MyTask(execService, ipAddress, portNo, mappingService), 1000, TimeUnit.MILLISECONDS);
        } else {
            throw new IllegalArgumentException("Please pass IPAddress and port no as arguments");
        }
    }
}

可运行代码:

public class MyTask implements Runnable {

    public ScheduledExecutorService execService;
    private String ipAddress;
    private int portNo;
    private ConfigurationMappingService mappingService;
    private MySocketSocketUtil mySocketSocketUtil;

    public MyTask(ScheduledExecutorService execService, String ipAddress, int portNo, ConfigurationMappingService mappingService) {
        this.execService = execService;
        this.ipAddress = ipAddress;
        this.portNo = portNo;
        this.mappingService = mappingService;
    }

    public void run() {
        MySocketSocketUtil mySocketSocketUtil = new MySocketSocketUtil(ipAddress, portNo);
        execService.schedule(new MyTask(execService, ipAddress, portNo, mappingService), 1000, TimeUnit.MILLISECONDS);

        mySocketSocketUtil.getData();  //It's able to fetch the data for almost 2 hours but from then, it's just getting empty data and it's keep on giving empty data from then. and so on.


        /*
         *
         *Some code
         */
    }
}

在这里,我遇到了问题 mySocketSocketUtil.getData(); 能够获取数据近2个小时,但从那时起,它只是获取空数据并且从那时起继续提供空数据。等等。这是一个我知道的大问题,而且我想了解可能出现的问题。

编辑:我忽略了检查流结束并根据它关闭套接字的条件是因为,我知道我要读取前1024个字节的数据总是如此。所以,我在finally块

中关闭套接字

3 个答案:

答案 0 :(得分:3)

socket = new Socket(host, port);
if(socket != null && socket.isConnected())

此时socket无法为空或socket.isConnected()为假。不要写无意义的代码。

        if((read = is.read(buffer)) != -1) {
            outputBuffer.write(buffer, 0, read);
        };

在这里,您忽略了可能的流结束。如果read()返回-1,则必须关闭套接字。它永远不会再次返回-1。这完全解释了您的空数据':

  从那时起,它只是获取空数据,并且从那时起继续提供空数据,等等

你应该创建一个 new Socket ,除非你在前一个套接字上收到-1或异常。

    } else {
        System.err.println("Socket couldn't be connected");
    }

无法访问:见上文。不要写无意义的代码。

答案 1 :(得分:2)

永远不要断开已建立的连接。在LoggingApplication中连接一次。连接插座后,请将其打开。在下次阅读时重新使用套接字。

答案 2 :(得分:1)

我认为在解决您的问题之前,您需要解决几点问题。请先尝试遵循以下建议:

  1. 因为@EJP说不需要这个代码块。

    if(socket != null && socket.isConnected()) {
    
  2. 您还使用长度为1024的字节数组,而不使用while或for循环来读取数据流。您是否只期望一个永远不会超过1024字节的数据块?

        byte[] buffer = new byte[1024];
        int read;
        if((read = is.read(buffer)) != -1) {
    
  3. 由于无法访问,因此也不需要。

    } else {
        System.err.println("Socket couldn't be connected");
    }
    
  4. 您能解释一下您期望的数据流行为吗?

  5. 最后但并非最不重要is.read(buffer)是一个阻塞调用,所以如果还没有要读取的数据,它将在那时保持线程执行。
  6. 请尝试回答我提出的问题。

      

    @KishoreKumarKorada来自您在评论部分的描述,看起来您正在监视服务器端的数据更改。套接字流以一次性读取方式工作。所以,

         

    首先,您需要每次都从服务器请求服务器需要在每个请求上重新发送数据。

         

    其次,你提出的方式更像是你在字节级别上运行,除非你有任何合理的理由,否则这不是很好的方法。好的方法是以JSON或XML格式包装数据并通过流发送它。但是为了减少带宽消耗,有时可能需要对字节流进行操作。你需要做出决定。

         

    第三,为了监控数据变化,更好的方法是使用一些时间戳来比较服务器端数据何时发生变化以及客户端存储的时间戳是什么,如果匹配,数据没有改变。否则从服务器端获取数据并更新客户端。

         

    第四,当有可用的数据无法读取时,是否可以调试ins.read(...)语句以查看它是否已执行并且执行是否在if块内部或if语句被评估是假的?如果是,那么检查读取值并让我知道你找到了什么?

    感谢。