我有一台运行Unity C#应用程序的PC,每隔几毫秒就通过网络向其他机器发送一个UDP数据包(嵌入Windows 7并运行相同JAVA程序的2台KUKA机器人,它有一个i5英特尔处理器,所以功能非常强大)。 Java程序应该接收这些数据包,解析它们的内容(机器人位置,编码为由'#'分隔的7个值的数组),再次移动和读取。问题是,当PC以每1 0.02秒的速率发送数据包时(这不会发生在0.03或更高,这是硬件限制?!),java程序会冻结大约1000个收到的数据包(有时是955或986等)8-10秒,然后再次恢复。它到达2000年和3000时也是如此 该程序冻结在:
serverSocket.receive(receivedPacket); // receives the array of Bytes
我怀疑网络切换,因此将PC直接连接到机器人,但没有任何改变。奇怪的是,它发生在两个机器人的同时,这让我怀疑PC。但是,当我的同事启动一个实时显示C#程序发送数据包的控制台时,它在java程序被冻结时没有冻结,看起来这些数据包丢失了。
我在SO上寻找类似的问题,很多可疑缓冲区,所以我正在考虑创建一个侦听UDP端口的线程并将数据包存储在内存中的队列中,然后我的主java程序从该线程读取。它看起来像一条可行的轨道吗?
欢迎任何建议。
P.S。这是代码:
package readers;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MyProgram {
// Network variables
public static DatagramSocket serverSocket;
private static DatagramPacket receivedPacket;
// Received data variables
private static byte[] aReceivedData = new byte[1024];
private static String sReceivedData;
private static String sAxesInformationReceived;
private static Double[] dAxesInformationReceived = new Double[7];
// ******** MAIN ***************************************
public static void main(String[] args) throws Exception {
int mFramecount =0;
int mPort = 30004; //default value
int mTimeout = 20*1000; //default value
int mFramelimit = (15 * 1000); //default value
// Create UDP server socket
try {
serverSocket = new DatagramSocket(mPort);
serverSocket.setReuseAddress(true);
serverSocket.setSoTimeout(mTimeout);
} catch (SocketException e)
{ System.err.println("socket bind fail"); closeSocket();e.printStackTrace(); return; }
// Receive the UDP packet
try {
receivedPacket = new DatagramPacket(aReceivedData, aReceivedData.length);
serverSocket.receive(receivedPacket); // receive the array of Bytes
} catch (Exception e) { closeSocket(); return; }
//Clear Buffer
for (int i = 0; i < 7; i++) {
if(dAxesInformationReceived[i] == null)
{
dAxesInformationReceived[i] = 0.0;
}
}
// <<<<<<<<<<<WHILE <<<<<<<<<<<<<<<<<<<<
while (true) {
//Clear Buffer
for(int i=0; i < aReceivedData.length; i++)
{
aReceivedData[i]=0;
}
// Decoding and Parsing received values
try {
receivedPacket = new DatagramPacket(aReceivedData, aReceivedData.length);
serverSocket.receive(receivedPacket); // receive the array of Bytes
byte[] byteData = new byte[receivedPacket.getLength()];
System.arraycopy(receivedPacket.getData(), receivedPacket.getOffset(), byteData, 0, receivedPacket.getLength());
sReceivedData = new String(byteData, "UTF-8");
Pattern pattern = Pattern.compile("@(.*?)@"); // RegEx
Matcher matcher = pattern.matcher(sReceivedData);
System.out.println("Data: '" + sReceivedData + "', || length: " + byteData.length + "|| Frame count="+ mFramecount ++);
/*
* mFramecount++;
if (mFramecount %100 == 0) {
System.out.println("Data: '" + sReceivedData + "', || length: " + byteData.length + "|| Frame count="+ mFramecount );
}
*/
if (matcher.find()) {
sAxesInformationReceived = matcher.group(1);
String[] sAxesValuesInStringArray = sAxesInformationReceived.split("#");
if (sAxesValuesInStringArray.length != 7) {
System.err.println("[UnityControl] invalide number of axis");
break;
}
for (int i = 0; i < 7; i++) {
dAxesInformationReceived[i] = Double.parseDouble(sAxesValuesInStringArray[i]);
}
} else {
System.err.println("[UnityControl] invalid format");
break;
}
} catch (Exception e) {
System.err.println("[UnityControl] socket exception");
e.printStackTrace();
break;
}
/* THIS PART IS USING THE ROBOT's API */
// Change destination according to the received position
JointPosition framePos = new JointPosition(
Math.toRadians(dAxesInformationReceived[0]),
Math.toRadians(dAxesInformationReceived[1]),
Math.toRadians(dAxesInformationReceived[2]),
Math.toRadians(dAxesInformationReceived[3]),
Math.toRadians(dAxesInformationReceived[4]),
Math.toRadians(dAxesInformationReceived[5]),
Math.toRadians(dAxesInformationReceived[6]));
try {
if(runtime.setDestination(framePos)<0)
break; // break when error planning robot motion
}
catch(Exception e)
{
System.err.println("Runtime exeption");
break;
}
if(mFramecount >= mFramelimit) break;
}
// LOOP BACK
}
//**********************************************************************
static void closeSocket() {
if (serverSocket != null) {
serverSocket.disconnect();
serverSocket.close();
System.out.println("[UnityControl] socket closed");
}
}
}
我做了@EJP在他的回答中提出的建议,为了更好地跟踪问题,我在最后添加了数据包的数量,看起来两台机器上的UDP数据包都丢失了(PC的日志)说它并没有停止发送)。这是来自运行相同代码的两台机器的日志:
答案 0 :(得分:0)
很有可能问题是你正在制作叫做停止世界的东西的GC(垃圾收集)。停止世界冻结应用程序并清除未使用对象的内存:)。您可以获取程序PID,然后连接jconsole以查看您的内存发生了什么。
设置更多内存也有可能有所帮助。 java -Xms1024m -Xmx1024m -Xms设置初始Java堆大小 -Xmx设置最大Java堆大小
如果您使用多个线程,那么创建线程可能会占用大量内存并且非常耗时 - 那么您可以使用线程池。
不幸的是,没有任何代码,我无法帮助你。
答案 1 :(得分:0)
你创造的垃圾多于必要的垃圾。您根本不需要byteArray
或System.arraycopy()
:
sReceivedData = new String(receivedPacket.getData(), 0, receivedPacket.getLength(), "UTF-8");
您也不需要将同一正则表达式重新编译为Pattern
。
在接收之前,您也不需要将字节数组归零。
NB 构建setReuseAddress()
之后调用DatagramSocket
(因此绑定它)完全是浪费时间。