I have the following infinite loop which listens for incoming messages:
public static void listenForMessages(){
while (true) {
dsocket.receive(receivepacket);
byte[] rcvMsg = receivepacket.getData();
MessageCreator tmc = new MessageCreator();
TrafficMessage message = tmc.constructMessageFromBinary(rcvMsg);
System.out.println("message: "+message);
}
}
This calls a method that reads the byte array into a string and populates a message object.
public Message constructMessageFromBinary(byte[] rcvMsg)
throws IOException {
ByteArrayInputStream bais = new ByteArrayInputStream(rcvMsg);
DataInputStream dis = new DataInputStream(bais);
StringBuffer inputLine = new StringBuffer();
String tmp;
while ((tmp = dis.readLine()) != null) {
inputLine.append(tmp);
}
dis.close();
Message message = new Message();
message.setDescriptions(tmp);
return message;
}
This simple process slowly leaks memory over a few hours and I receive an out of memory exception.
Is there anything wrong with this logic?
The problem was that I left a database connection open. I wanted to leave it open to pass data with out having to worry about stopping and starting connections. I now open and close connections each time and all is good.
The best bet here would be to move all possible object instantiations outside the loops. For example, in the first code snippet, every iteration creates a
MessageCreator tmc.
On your second snippet, each call to the method creates a
StringBuffer inputLine.
This instantiation process may be eating away your memory slowly.
Related
I am quite new to Java programming. For now I am studying source code of an android app called Evercam. However, I have a problem understanding a part of the code which involves while(true) loop.
Here is the snippet of the code:
while (true)
{
while (true)
{
byte[] responseMessageByteArray = new byte[4000];
DatagramPacket datagramPacketRecieve = new DatagramPacket(responseMessageByteArray, responseMessageByteArray.length);
datagramSocket.receive(datagramPacketRecieve);
String responseMessage = new String(datagramPacketRecieve.getData());
EvercamDiscover.printLogMessage("\nResponse Message:\n" + responseMessage);
StringReader stringReader = new StringReader(responseMessage);
InputNode localInputNode = NodeBuilder.read(stringReader);
EnvelopeProbeMatches localEnvelopeProbeMatches = (EnvelopeProbeMatches)(new Persister()).read(EnvelopeProbeMatches.class, localInputNode);
if (localEnvelopeProbeMatches.BodyProbeMatches.ProbeMatches.listProbeMatches.size() > 0)
{
ProbeMatch localProbeMatch = (ProbeMatch) localEnvelopeProbeMatches.BodyProbeMatches.ProbeMatches.listProbeMatches.get(0);
if (uuidArrayList.contains(localProbeMatch.EndpointReference.Address))
{
EvercamDiscover.printLogMessage("ONVIFDiscovery: Address " + localProbeMatch.EndpointReference.Address + " already added");
}
else
{
uuidArrayList.add(localProbeMatch.EndpointReference.Address);
DiscoveredCamera discoveredCamera = getCameraFromProbeMatch(localProbeMatch);
if (discoveredCamera.hasValidIpv4Address())
{
this.onActiveOnvifDevice(discoveredCamera);
cameraList.add(discoveredCamera);
}
}
}
}
}
Doesn't this create an infinite loop? My fundamentals in Java isn't strong, so I would be so grateful if anyone can tell in in what instances will a while(true){//codes} actually exits without any break or does it ever exit??
EDIT
My bad for actually extracting this snippet from decompiling directly from the android project files. I did not know that it would be different, and then again, I know very little. Here is the original code:
public ArrayList<DiscoveredCamera> probe() {
ArrayList<DiscoveredCamera> cameraList = new ArrayList<DiscoveredCamera>();
try {
DatagramSocket datagramSocket = new DatagramSocket();
datagramSocket.setSoTimeout(SOCKET_TIMEOUT);
InetAddress multicastAddress = InetAddress.getByName(PROBE_IP);
if (multicastAddress == null) {
// System.out.println("InetAddress.getByName() for multicast returns null");
return cameraList;
}
// Send the UDP probe message
String soapMessage = getProbeSoapMessage();
// System.out.println(soapMessage);
byte[] soapMessageByteArray = soapMessage.getBytes();
DatagramPacket datagramPacketSend = new DatagramPacket(
soapMessageByteArray, soapMessageByteArray.length,
multicastAddress, PROBE_PORT);
datagramSocket.send(datagramPacketSend);
ArrayList<String> uuidArrayList = new ArrayList<String>();
while (true) {
// System.out.println("Receiving...");
byte[] responseMessageByteArray = new byte[4000];
DatagramPacket datagramPacketRecieve = new DatagramPacket(
responseMessageByteArray,
responseMessageByteArray.length);
datagramSocket.receive(datagramPacketRecieve);
String responseMessage = new String(
datagramPacketRecieve.getData());
EvercamDiscover.printLogMessage("\nResponse Message:\n"
+ responseMessage);
StringReader stringReader = new StringReader(responseMessage);
InputNode localInputNode = NodeBuilder.read(stringReader);
EnvelopeProbeMatches localEnvelopeProbeMatches = new Persister()
.read(EnvelopeProbeMatches.class, localInputNode);
if (localEnvelopeProbeMatches.BodyProbeMatches.ProbeMatches.listProbeMatches
.size() <= 0) {
continue;
}
ProbeMatch localProbeMatch = localEnvelopeProbeMatches.BodyProbeMatches.ProbeMatches.listProbeMatches
.get(0);
// EvercamDiscover.printLogMessage("Probe matches with UUID:\n"
// +
// localProbeMatch.EndpointReference.Address + " URL: " +
// localProbeMatch.XAddrs);
if (uuidArrayList
.contains(localProbeMatch.EndpointReference.Address)) {
EvercamDiscover.printLogMessage("ONVIFDiscovery: Address "
+ localProbeMatch.EndpointReference.Address
+ " already added");
continue;
}
uuidArrayList.add(localProbeMatch.EndpointReference.Address);
DiscoveredCamera discoveredCamera = getCameraFromProbeMatch(localProbeMatch);
if (discoveredCamera.hasValidIpv4Address()) {
onActiveOnvifDevice(discoveredCamera);
cameraList.add(discoveredCamera);
}
}
} catch (Exception e) {
// ONVIF timeout. Don't print anything.
}
Turns out there is continue statement in the actual code. Thank you so much for the response, I will remember that de-compiled classes should not be depended on.
This looks like an infinite loop. To be absolutely sure, you would have to statically read every statement and follow invoked methods to see if any possible invocations like Activity#finish() or Service#stopSelf() exists which would finish the currently running activity, effectively breaking the loop.
Another possibility is that the code is intended to be running in an infinite loop as a background thread service, and some other component would have an option to kill that service when it reaches a certain condition. For example, it could be part of a Runnable class and executed in a thread pool, and when a timeout exists, the pool is shut down.
the only possible way to exit from while loop is if one of the methods being called in loop throws exception. check code of these methods for exception or share it here
Infinite loops without any breaks could be useful for a Service running in background.
You create a new Thread doing the service infinitely thanks to a while(true) and when you stop your application you simply kill the process corresponding to the service.
Saying my requirement is:
Either user type something in console (from system.in) or socket receive something, proceed to next step.
So I have a scanner
Scanner sc = new Scanner(System.in);
Have an Udp client. (a different input source)
DatagramSocket clientSocket = new DatagramSocket();
My code is
while (true) {
if (sc.hasNext()) {
String str = sc.next();
proceed(str)
} else {
clientSocket.receive(pack);
proceed(pack)
}
}
Obviously this code will not work. Because when checking sc.hasNext(), java is waiting user to type some input in console. Currently what I can do is open an thread for Udp client. If I change the order,
while (true) {
clientSocket.receive(pack);
if (not receive) read from system.in
}
It doesn't make sense, since receive() will keep waiting util receive something, it will never read from system.in concurrently.
So how can i achieve my requirement without using a thread?
Inspired by #Andriy Kryvtsun's answer, i did a quick test
As he said, this is somehow using non-blocking read, and keep letting socket timeout, to emulate
InputStream ins = System.in;
byte buffer[] = new byte[512];
BufferedReader reader = new BufferedReader(new InputStreamReader(ins));
DatagramSocket clientSocket = new DatagramSocket();
System.out.println("From buffer:" + clientSocket.getLocalPort());
while (true) {
try {
if (ins.available() > 0) {
String line = reader.readLine();
System.out.println("Read:" + line);
} else {
DatagramPacket pack = new DatagramPacket(buffer,buffer.length);
clientSocket.setSoTimeout(2000);
clientSocket.receive(pack);
System.out.println("Receive: " + new String(pack.getData()));
}
} catch (IOException e1) {
}
}
Use unblocking method call InputStream#available() to get info if something ready for reading before using blocking Scanner#hasNext() call.
Also you can call DatagramSocket#setSoTimeout(int timeout) before call blocking receive(DatagramPacket p) method. Thus you can break infinity waiting inside receive method after timeout period emulating unblocking reading.
First of all, this is a homework problem. That being said, I'm stuck. Googling for java Properties over Sockets results in a lot of irrelevant things.
I'm trying to transfer a Properties object over a socket. The API says it can be done with a Stream or a Writer/Reader, but I can't get it to work. I can do it manually, that is, if I read the file line by line and pass it through a PrintWriter.
On the client side I've got roughly:
socket = new Socket(host, port);
outStream = socket.getOutputStream();
out = new PrintWriter(outStream, true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
reader = new BufferedReader(new FileReader(file));
...
props.load(reader);
props.store(out, null);
On the server side the receiving bits look like:
out = new PrintWriter(sock.getOutputStream(), true);
inStream = sock.getInputStream();
in = new BufferedReader( new InputStreamReader(inStream));
...
props.load(in); // hangs
// doesn't get to code here...
In this case it hangs at the props.load(in). Instead of doing props.load(in), I read it in line by line to make sure props.store(out, null) was working, and the data looks like its being transferred.
Is there something about load/store I don't understand, or is it an issue with the Stream/Writer/Reader?
I think this will answer this question as well as How do I recognize EOF in Java Sockets? and What can I send to an InputStream to signify EOF has been reached?
I had a similar problem; my dilemma was that I had a client/server request-response protocol where one of the requests included a stream sent from the client side using clientProps.store(). The corresponding serverProps.load() on the server side never returns because it needs to see the "end-of-file" - which in Java means the client has to close it's stream; resulting in the socket connection closing. The unwanted result was that, not only could I not keep the socket open for indefinite request-response exchanges, I couldn't even keep it open for the server to send its reply.
I hated Java for making me do that, even more because the documentation for Properties.load() says:
The specified stream remains open after this method returns.
That could never happen if it's detecting end-of-file by seeing the stream close!! Anyway, now, I still love Java because it allowed me to use this solution (might not be useful if you have any special encoding or localization of the data you are streaming):
I used this on the client side:
PrintWriter toServer;
Properties clientProps = new Properties();
// ... code to populate the properties and to
// construct toServer from the socket ...
clientProps.store(toServer, null);
toServer.write('\u001A'); // this is an old-school ASCII end-of-file
toServer.flush();
On the server side I extended Reader to detect the 1A and return -1 (so that the serverProps.load() learns about the end-of-file in the normal way (by seeing -1 returned from a call to read()), but below that, the stream and the socket stay open.
BufferedReader fromClient;
Properties serverProps = new Properties();
// ... code to construct fromClient from the socket ...
serverProps.load (new PropReader (fromClient));
/////
private static class PropReader extends Reader {
BufferedReader src;
boolean eof=false;
private PropReader(BufferedReader fromClient) {
super();
src=fromClient;
}
#Override
public int read(char[] cbuf, int off, int len) throws IOException {
int inCount;
if (!eof) {
inCount = src.read(cbuf, off, len);
if (inCount > 0) {
// we read a buffer... look at the end for the EOF that the client used to mark the end of file
if (cbuf[off+inCount-1] == '\u001A') {
--inCount; // don't send eof with the data
eof = true; // next time... we'll return -1
}
}
} else {
inCount = -1;
}
return inCount;
}
#Override
public void close() throws IOException {
src.close();
}
I am working on a TFTP server application. I managed to process a successful file transfer from server to client however the other way around is bugged.
Client instead of transmitting the entire file simply terminated whit compiler returning no errors. Debugger shows IOBE exception on the marked code referring that the array is out of range.
The whole transfer process goes like so:
Client transmits a file name and requested operation WRQ - Write Request
Server received the packet and determines the operation if WRQ is gives the new file appropriate name.
Server now starts executing receiveData() until it gets a packet < 512 indicationg EOT
Client keeps transferring data it read from the file.
Key code:
Client:
private void sendWRQ() throws Exception
{
String rrq = "WRQ-" + data;
outgoingData = rrq.getBytes();
DatagramPacket output = new DatagramPacket(outgoingData, outgoingData.length, serverAddress, serverPort);
clientSocket.send(output);
//Thread.sleep(50);
sendData();
}
byte outgoingData = new byte[512];
private void sendData() throws Exception
{
DatagramPacket dataTransfer = new DatagramPacket(outgoingData, outgoingData.length, serverAddress, serverPort);
InputStream fis = new FileInputStream(new File(data));
int x;
while((x = fis.read(outgoingData,0,512)) != -1) // << Debugged gives IOBE
{
dataTransfer.setLength(x);
clientSocket.send(dataTransfer);
Thread.sleep(5);
}
fis.close();
}
Server:
private void listen() throws Exception
{
DatagramPacket incTransfer = new DatagramPacket(incomingData, incomingData.length);
serverSocket.receive(incTransfer);
clientAddress = incTransfer.getAddress();
clientPort = incTransfer.getPort();
String output = new String(incTransfer.getData());
if(output.substring(0, 3).equals("RRQ"))
{
File test = new File(output.substring(4));
responseData = output.substring(4);
if(test.exists())
{
sendResponse("Y");
} else {
sendResponse("N");
}
} else if (output.substring(0, 3).equals("WRQ"))
{
File test = new File(output.substring(4));
if(test.exists())
{
Calendar cal = Calendar.getInstance();
SimpleDateFormat prefix = new SimpleDateFormat(date_format);
String date = prefix.format(cal.getTime()).toString();
responseData = date + output.substring(4);
receiveData();
} else {
responseData = output.substring(4);
receiveData();
}
}
}
private void receiveData() throws Exception
{
DatagramPacket receiveData = new DatagramPacket(incomingData, incomingData.length);
OutputStream fos = new FileOutputStream(new File(responseData));
while(true)
{
serverSocket.receive(receiveData);
if(receiveData.getLength() == 512)
{
fos.write(receiveData.getData());
} else {
fos.write(receiveData.getData(), receiveData.getOffset(), receiveData.getLength());
break;
}
}
fos.close();
}
The only way that can happen is if the offset or length parameters violate the constraints specified for InputStream.read(byte[], int, int); in this case probably the buffer isn't 512 bytes long. There's no need to specify the 2nd nd third parameters in this case, just omit them, then it becomes read(buffer, 0, buffer.length) internally, which can't be wrong.
Okay, the way this is coded, the 'outgoingData' field is:
1) Initialized to a length of 512
2) Then, in sendWRQ(), 'outgoingData' is re-initialized to whatever rrq.getBytes() sends back.
3) Then, in sendData(), 'outgoingData' is used as the intermediate buffer to read data from file and put it in the dataTransfer object.
However, since 'outgoingData' is re-initialized in step #2, the assumption in step #3 that 'outgoingData' is still 512 bytes in length is false.
So while EJP was correct in saying that using read(outgoingData, 0, outgoingData.length()) will work, there are some architecture issues that if you address, you'll clean up a lot of potential errors.
For instance:
WIth the code provided, there is seemingly no reason to have outgoingData declared at the class level and shared among two functions. Depending on the rest of the app, this could end up being a Threading issue.
Perhaps byte[] buffer = rrq.getBytes(); in sendWRQ() and byte[] buffer = new byte[1024]; in sendData().
Also, the 'data' parameter is at the class level.... for what reason? Might be better able to be controlled if its a passed in parameter.
Lastly, I've had good luck using the do{} while() loop in network situations. Ensures that the send() gets at least one chance to send the data AND it keeps the code a bit more readable.
I'm reading messages from a socket (trough a TCP protocol), but I note that the CPU spend a lot of time to call the method available() of my BufferedInputStream. This is my code:
#Override
public void run()
{
Socket socket;
Scanner scanner;
BufferedInputStream buffer = null;
try
{
socket = new Socket(SERVER_HOST, SERVER_PORT);
System.out.println("Connection Completed");
InputStream inputStream = socket.getInputStream();
buffer = new BufferedInputStream(inputStream);
StringBuilder readCharacter;
while (true)
{
readCharacter = new StringBuilder();
try
{
while (buffer.available() > 0)
{
readCharacter.append((char) buffer.read());
}
}
catch (IOException e)
{
e.printStackTrace();
buffer.close();
}
String array[] = separe(new String(readCharacter));
... //parsing the message
I've also tried to use int read=buffer.read() and check if (read!=-1) instead of using the available function, but in this case I'm not able to recognize the end of the message...in my StringBuilder 'readCharacter' I have more than one message, one after the other..and it cause the fail of my parsing process...
Instead using the available() check, into the readCharacter I have only one message at a time..and the parsing works...
Can you help me to understand why, and how avoid the eating of CPU?
This loop:
while (buffer.available() > 0)
{
readCharacter.append((char) buffer.read());
}
can be replaced with simple:
readCharacter.append((char) buffer.read());
Instead of calling non-blocking available() over and over again (which consumes a lot of CPU) just call read() which will block not consuming CPU until something is available. Looks like this is what you want to achieve with less code and complexity.
The available() itself does not eat CPU. What does it is your loop:
while (buffer.available() > 0) {
readCharacter.append((char) buffer.read());
}
While bytes are unavailable you are actually calling available() multiple times (probably thousands of times). Since read() method of streams is blocking you do not have to call available() at all. The following code does the same but does not eat CPU.
String line = null;
while ((line = buffer.read()) != null) {
readCharacter.append(line);
}