java - Java TCP Socket While循环和计数器接收数据X次
问题描述
我是一名业余程序员,正在编写从服务器(plc)接收整数和字符串类型消息的 Java TCP 套接字客户端程序。目前,如果使用没有任何循环的基本 try catch 来保持程序运行,它可以正常工作并返回正确的值。
但是...我一直在尝试添加带有 5 个接收时间的计数器的 while 循环,在此之后结束程序,但它在 ONE 读取时返回:
Int: 705 //correct value that it should receive every time
String: testi3 //correct value that it should receive every time
Int: 0 // prints also this duplicate value
String: // prints also this duplicate value
在这种情况下我应该如何使用 while 循环,以便它返回正确的值 5 次,然后正确结束程序?
我的程序如下所示:
import java.io.*;
import java.net.Socket;
import java.util.Arrays;
public class GetData2 {
private static int counter =0;
private Socket clientSocket;
//private PrintWriter out;
private String host = "192.168.0.1";
private int port2 = 2000;
private DataInputStream inFromServer;
public void start() throws IOException{
System.out.println("Client started");
clientSocket = new Socket(host, port2);
}
public void run() throws IOException {
while (counter <= 5) {
inFromServer = new DataInputStream(clientSocket.getInputStream());
//BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
int length = 100; // read length of incoming message
byte[] messageFromServer = new byte[length];
for (int i = 0; i < messageFromServer.length; i++) {
messageFromServer[i] = (byte) inFromServer.read(); //read message from the server
}
System.out.println("\n");
//System.out.println(Arrays.toString(messageFromServer));
byte[] copyOfData = Arrays.copyOf(messageFromServer, messageFromServer.length); //copies byte array from messageFromServer[] to copyOfData[]
System.out.println("\n");
//Integer
short value = 0;
// reads bytes 0-1
value = (short) (copyOfData[0] * 256 + (short) copyOfData[1]); // moves received bytes
// shows the order of received byes
System.out.println("Int: " + value); // return bytes as an Integer
//String
System.out.print("String: ");
for (int i = 4; i < copyOfData.length && i < 10; i++) { // reads bytes 4-10 from array
System.out.printf("%c", copyOfData[i]); // returns String testi2 from pythondemo 2 plc application
}
counter++;
System.out.println(counter);
}
}
public void stop() throws IOException{
//out.close();
System.out.println("Application stopped");
clientSocket.close();
inFromServer.close();
}
public static void main(String[] args) throws IOException {
GetData2 getData2 =new GetData2();
getData2.start();
getData2.run();
if(counter == 5){
getData2.stop();
}
}
}
编辑:
好像如果我将接收到的字节数组长度从 [100] 更改为 [10],程序就会执行并打印它;
Client started
Int: 705
String: testi3
counter: 1
Int: 0
String:
counter: 2
Int: 0
String:
counter: 3
Int: 0
String:
counter: 4
Int: 0
String:
counter: 5
Application stopped
编辑#2
因此,我制作了在 localhost 中运行并发送 byte[100] 的服务器程序,它可以正常工作。似乎问题最有可能在我的 PLC 程序中,而不是在 Java 中。
服务器类:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class GetData2_Server {
public static void main(String[] args) throws IOException {
System.out.println("server started");
Scanner scan = new Scanner(System.in);
ServerSocket server = new ServerSocket(8080);
Socket socket = server.accept();
System.out.println("server accepted");
System.out.println("1 == out n flush, 0 == close program");
int value = scan.nextInt();
byte[] bytesOut = new byte[100];
bytesOut[0]=0;
bytesOut[1]=3;
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
while (value == 1)
{
out.write(bytesOut);
out.flush();
value = scan.nextInt();
if(value == 0){
out.close();
socket.close();
}
}
}
}
解决方案
您没有考虑到发送数据的设备(我将其简称为“服务器”)可能会在其末端关闭流。发生这种情况时,inFromServer.read()
将返回 -1。你没有检查这个值,所以你最终会messageFromServer
用 -1 值填充数组。
如果您知道消息应该是 100 字节,则可以通过单个DataInputStream
方法调用读取消息,而无需 for 循环。将您
的替换for (int i = 0; i < messageFromServer.length; i++)
为:
byte[] messageFromServer = new byte[length];
inFromServer.readFully(messageFromServer);
如果在读取完整消息之前关闭服务器流,此方法将抛出异常(EOFException)。
推荐阅读
- kubernetes - 无法使用 Istio 网关访问 Kubernetes 集群
- python - STAN RuntimeError:初始化失败
- python - 代替 。在 json 文件中使用 _ 并使用 python 将其写入表
- c# - 如何在 C# 中解密 EncryptedXml?
- java - 想在eclipse上使用我自己的控制台,但是遇到一些unkown error for package not found
- angular - 为什么我在间隔内更改对象引用并且更改检测为onPush时UI不更新?
- select - 数据绑定点击事件不起作用
- gnuplot - gnuplot:事件直方图:timecolumn() 问题
- linux - 在 fzf 预览中使用 bat 突出显示行号
- laravel - 使用 Laravel 配置 Omnipay-stripe 以与 PCI SCA 一起使用