In my application, I have used two while loops for reading the sockets. while loop-1 takes 1% of CPU and while loop-2 takes 100% CPU. I am confused. Please share your valuable thoughts. For more information, I have added two while loops below:
While loop-1:
while(true) {
String message = onReadFinal(in);
if (message != null) {
synchronized (message) {
System.out.println("Message size:" + message);
}
}
}
private String onReadFinal(DataInputStream in) {
String mess = null;
try{
StringBuilder builder = new StringBuilder();
do {
builder.append(in.readInt());
} while(in.available() > 0);
mess = builder.toString();
} catch(IOException e){ e.printStackTrace(); }
return mess;
}
While loop-2:
while(true) {
String message = onRead(in);
if (message != null) {
synchronized (message) {
System.out.println("Message size:" + message);
}
}
}
public String onRead(DataInputStream input) {
String socketmessage = null;
int length;
try {
if(input != null) {
length = input.available();
if(length>0) {
byte[] message = new byte[length];
input.readFully(message, 0, message.length);
socketmessage = new String(message);
}
}
} catch (IOException ioException) {
ioException.printStackTrace();
}
return socketmessage;
}
Also, if I execute infinite while loop with no statements, it takes 100% of CPU. Someone can you please explain.
if a loop does not contain blocking operations, it always would take 100% CPU.
Your first loop contains blocking operation in.readInt(). Your second loop also contains potentially blocking operation input.readFully(), but calls it only when the stream buffer has enough bytes to read, and so in fact this operation does not block. When there is not enough bytes, the loop immediately repeats non-blocking operation input.available(), without much sense.
You better tell us what you want.
Related
I've a class which is responsible for listening two other machines which have exactly the same classes, so it's a network of three computers having the same code. The connection is there and I can see them passing data to each other. Everything until there works OK.
Things get tricky when I take out one of the machines and observe how the other two behave. Expectedly, when one of the machines stops working for some reason, other two should continue. And if two of them stop, the remaining should go on.
I tried to implement this mechanism below. However, when I take out one of the machines, the program keeps waiting, so it does not switch to "two-way comparison mode".
public void listen() {
try {
logger.info("Creating listener sockets");
while (isRunning) {
final byte[] buf = new byte[bufferSize];
final DatagramPacket packetOne = new DatagramPacket(buf, buf.length);
final DatagramPacket packetTwo = new DatagramPacket(buf, buf.length);
MediatorMessageMsg mediatorMessageOne = null;
MediatorMessageMsg mediatorMessageTwo = null;
try {
socketReceiverOne.receive(packetOne);
ByteArrayInputStream firstInput = new ByteArrayInputStream(buf);
mediatorMessageOne = MediatorMessageMsg.parseDelimitedFrom(firstInput);
socketReceiverTwo.receive(packetTwo);
ByteArrayInputStream secondInput = new ByteArrayInputStream(buf);
mediatorMessageTwo = MediatorMessageMsg.parseDelimitedFrom(secondInput);
logger.trace("Received packets");
} catch (final SocketTimeoutException e) {
logger.trace(e.getMessage());
continue;
} catch (final SocketException e) {
logger.warn(e);
logger.warn("Ignore the error and go on.");
continue;
} catch (final IOException e) {
logger.error("Incoming communication stopped!");
logger.error(e);
stop();
}
// if two mediators sent the data, it's OK
if (packetOne.getLength() > 0 && packetTwo.getLength() > 0) {
handlePackets(mediatorMessageOne, mediatorMessageTwo);
logger.info("Number of active mediators: 2. Comparison style: 1v1v1");
}
// if only one sent the data, compare it with our own
else if (packetOne.getLength() > 0 || packetTwo.getLength() > 0) {
// whicehever sent the data, compare its data with our own
logger.info("Number of active mediators: 1. Comparison style: 1v1");
if (packetOne.getLength() > 0) {
handlePackets(mediatorMessageOne);
} else {
handlePackets(mediatorMessageTwo);
}
}
// if no data is sent, then pass our own directly
else {
logger.info("Number of active mediators: 0. Comparison style: No Comparison");
// our datamodel to retrieve data on our own
DataModel modelOwn = DataModel.getInstance();
MediatorMessageMsg newMessage = MediatorMessageMsg.newBuilder().setHeading(modelOwn.getHeading()).setSpeed(modelOwn.getSpeed()).setSender(getId()).build();
// publish(topicName, newMessage);
}
Thread.sleep(1);
}
socketReceiverOne.close();
socketReceiverTwo.close();
logger.info("stopped");
} catch (final IllegalArgumentException e) {
logger.error("Illegal argument received: " + e);
} catch (final Exception e) {
logger.error("Unexpected error occured: " + e);
} finally {
if (socketReceiverOne instanceof DatagramSocket && socketReceiverTwo instanceof DatagramSocket) {
if (!socketReceiverOne.isClosed() || !socketReceiverTwo.isClosed()) {
socketReceiverOne.close();
socketReceiverTwo.close();
}
}
}
}
To save your time, let me share my opinion on the matter. I suspect the problem to be in this part:
socketReceiverOne.receive(packetOne);
ByteArrayInputStream firstInput = new ByteArrayInputStream(buf);
mediatorMessageOne = MediatorMessageMsg.parseDelimitedFrom(firstInput);
socketReceiverTwo.receive(packetTwo);
ByteArrayInputStream secondInput = new ByteArrayInputStream(buf);
mediatorMessageTwo = MediatorMessageMsg.parseDelimitedFrom(secondInput);
To me it seems like the program expects a package and when it cannot receive it, it keeps waiting. Although I have time out exception condition, I cannot get this done.
private int socketTimeout = 1000 * 2;// 2sec
socketReceiverOne.setSoTimeout(socketTimeout);
socketReceiverTwo.setSoTimeout(socketTimeout);
Any thoughts?
Okay I found where I was mistaken. I needed more ports (for in and out). Once I incorporated those ports, the problem did not occur again.
So I am writing my own piece of stuff using jzmq GIT master branch and ZeroMQ 3.2.3.
After installation I tried to test the following simple PUB/SUB program, where a publisher and a subscriber talk in a single process. Since the test is under Windows, I used TCP.
public class ZMQReadynessTest {
private ZMQ.Context context;
#Before
public void setUp() {
context = ZMQ.context(1);
}
#Test
public void testSimpleMessage() {
String topic = "tcp://127.0.0.1:31216";
final AtomicInteger counter = new AtomicInteger();
// _____________________________________ create a simple subscriber
final ZMQ.Socket subscribeSocket = context.socket(ZMQ.SUB);
subscribeSocket.connect(topic);
subscribeSocket.subscribe("TestTopic".getBytes());
Thread subThread = new Thread() {
#Override
public void run() {
while (true) {
String value = null;
// This would result in trouble /\/\/\/\/\/\/\/\/\
{
ByteBuffer buffer = ByteBuffer.allocateDirect(100);
if (subscribeSocket.recvZeroCopy( buffer,
buffer.remaining(),
ZMQ.DONTWAIT
) > 0 ) {
buffer.flip();
value = buffer.asCharBuffer().toString();
System.out.println(buffer.asCharBuffer().toString());
}
}
// This works perfectly + + + + + + + + + + + + +
/*
{
byte[] bytes = subscribeSocket.recv(ZMQ.DONTWAIT);
if (bytes == null || bytes.length == 0) {
continue;
}
value = new String(bytes);
}
*/
if (value != null && value.length() > 0) {
counter.incrementAndGet();
System.out.println(value);
break;
}
}
}
};
subThread.start();
// _____________________________ create a simple publisher
ZMQ.Socket publishSocket = context.socket(ZMQ.PUB);
publishSocket.bind("tcp://*:31216");
try {
Thread.sleep(3000); // + wait 3 sec to make sure its ready
} catch (InterruptedException e) {
e.printStackTrace();
fail();
}
// publish a sample message
try {
publishSocket.send("TestTopic".getBytes(), ZMQ.SNDMORE);
publishSocket.send("This is test string".getBytes(), 0);
subThread.join(100);
} catch (InterruptedException e) {
e.printStackTrace();
fail();
}
assertTrue(counter.get() > 0);
System.out.println(counter.get());
}
}
Now as you can see, in the subscriber if I use a simple .recv(ZMQ.DONTWAIT) method, it works perfectly. However, if I am using the direct byte buffer I got nothing returned - and I got the following exception, seems like on program exit:
Exception in thread "Thread-0" org.zeromq.ZMQException: Resource temporarily unavailable(0xb)
at org.zeromq.ZMQ$Socket.recvZeroCopy(Native Method)
at ZMQReadynessTest$1.run(ZMQReadynessTest.java:48)
I also tried to use a simple ByteBuffer (not a direct buffer), which doesn't throw the exception above; but also return me nothing.
Does anybody know how to resolve the above?
I don't want to create byte[] objects all around, as I am doing some high performance system. If this cannot be resolved, I might simply use Unsafe instead. But I really want to work in the "supposed way".
Thanks in advance.
Alex
I have an ObjectOutputStream and an ObjectInputStream. I try to send ints and objects through them. Now I manage to send through and read up to a point and I don't know why it stops there.
Here is the point:
Reader:
while (true) {
start = in.readInt();
System.out.println("PART 1");
int temp1 = in.readInt();
int temp2 = in.readInt();
int temp3 = in.readInt();
System.out.println("PART12");
Chunk temp = new Chunk(temp1,temp2, temp3);
while (true) {
It doesn't get to part12 (doesn't pass the first int...)
Writer:
if (chunkList != null) {
for (Chunk c: chunkList) {
out.writeInt(-1);
out.writeInt(c.getLocation().getX());
out.writeInt(c.getLocation().getY());
out.writeInt(c.getLocation().getZ());
if (c.getTileList() != null) {
it passes all of it successfully.
I am every 2ms out.flushing in a separate thread.
Thread:
while (true)
{
while (c.sendPacket()) {
try
{
if (c.getOut() != null)
{
c.getOut().flush();
}
}
catch (IOException ioexception)
{
ioexception.printStackTrace();
}
try
{
sleep(2L);
}
catch (InterruptedException interruptedexception) { }
}
}
Why does it stop reading at the part with the 3 ints?
I have a feeling that this is a thread-safety issue. As a general rule, streams are not designed to be thread-safe. So, unless the you are synchronizing the two threads at a higher level, one thread writing to a stream and a second thread calling flush is unsafe.
I am working on a program for Android, which connects to a server via SSH to get some data.
The problem is, in the event a command is sent to the server, that doesn't return anything (such as cat on an empty file), my program hangs, seemingly being blocked by in.read().
I have a breakpoint on the the line
if ((read = in.read(buffer)) != -1){
and on the then/else lines below it. If I debug it, the program breaks normally on the if-statement, but when I hit continue, the program just hangs again, and never makes it to the next breakpoint.
The program works normally if it actually gets a response from the server, but I'd like to protect my program from a hang if the server isn't cooperating properly.
I am using the J2SSH library.
public String command(String command) {
command = command + "\n";
if (session.getSessionType().equals("Uninitialized") || session.isClosed()) {
openShell();
}
OutputStream out = session.getOutputStream();
InputStream in = session.getInputStream();
byte buffer[] = new byte[255];
int read;
String in1 = null;
String fullOutput = "";
try {
try {
out.write(command.getBytes());
} catch (IOException e){
Log.e(TAG,"Error writing IO stream");
e.printStackTrace();
}
boolean retrivingdata = true;
while (retrivingdata){
String iStreamAvail = "Input Stream Available "+ in.available();
if ((read = in.read(buffer)) != -1){
retrivingdata = true;
} else {
retrivingdata = false;
return null;
}
in1 = new String(buffer, 0, read);
fullOutput = fullOutput + in1;
if (read < 255){
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
return fullOutput;
}
Reading and writing should be done in separate threads. read() is a blocking method that waits until data is available from the server.
This is my code:
private String receiveData(String sjson) {
Log.i(TAG,"send request: " + sjson);
String jstr="";
try {
OutputStream out = s.getOutputStream();
out.write(sjson.getBytes());
out.flush();
//out.close();
Log.v(TAG,"sended data");
BufferedReader input = new BufferedReader(new InputStreamReader(s.getInputStream()));
char[] cbuf = new char[1];
input.read(cbuf);
String size = new String(cbuf);
while (input.read(cbuf) != 0) {
if((new String(cbuf)).equals("{") == true)
break;
size = size + new String(cbuf);
}
char[] jbuf = new char[Integer.valueOf(size)];
input.read(jbuf);
jstr = "{" + new String(jbuf);
}catch (Exception e) {
Log.e(TAG,e.toString());
}
Log.d(TAG,"responce: " + jstr);
return jstr;
}
public void connectSocket() {
Log.v(TAG,"connecting Socket: "+URL+":"+PORT);
try {
s = new Socket(URL, PORT);
Log.v(TAG,"connect Socket!");
ERROR_CODE = 0;
}catch (Exception e) {
Log.e(TAG,e.toString());
ERROR_CODE = ERROR_SOCKET_CONNECT_SUCCESSFULL;
}
Log.e(TAG,getErrorMsg(ERROR_CODE));
}
public void closeSocket() {
Log.v(TAG,"closeSocket");
try {
s.close();
}catch (Exception e) {
Log.e(TAG,e.toString());
}
}
At server the answer is less than a second. At the client it passes 1 minute before reading data.
Apps stoped at input.read(cbuf); waiting for answer.
Logs:
05-23 06:35:17.540: VERBOSE/Utilits(358): Auth: 77.221.129.100:10598
05-23 06:35:17.660: INFO/Utilits(358): send request: 0119{"data":{"password":"12345","imei":"000000000000001"},"method":"login"}
05-23 06:36:17.909: DEBUG/Utilits(358): responce: {"response":{"success":true,"user":{"id":"6","properties":{"auto":"model":"audi","color":"ffff","number":"td123r"}},"is_driver":"1"}}}
Why does it take so long to read an answer?
What on earth do you expect that method to do? There are bugs in it, and it does things that it should do.
You should specify encoding/charset when you create the InputStreamReader
Why do you read character by character from start to "{"
Why do you create a string for each character that you read before you hit "{"
Why do you append strings in a loop? Use a StringBuilder if you must append.
input.read returns an integer that says how many bytes/character that you have received
It's never guaranteed that it will fill the buffer. So you might not get all data.
Why aren't you closing resources?
.. and now to why it might be slow. Is the server flushing the data? If not, make sure that the server is flushing the data.