I have a Server that uses non blocking sockets, nio. Server works in a separate thread and there is another thread called Game. Game thread holds the server object and uses server.sendMessage, Server thread only reads the data. When I call sendMessage two times sequentially for 2 packets in a while loop, after a moment i get "java.io.StreamCorruptedException: invalid stream header: 6B6574B4" error in client.
part of server code:
public void write(SelectionKey channelKey, byte[] buffer) {
if (buffer != null) {
int bytesWritten;
try {
SocketChannel channel = (SocketChannel) channelKey.channel();
synchronized (channel) {
bytesWritten = channel.write(ByteBuffer.wrap(buffer));
}
if (bytesWritten == -1) {
resetKey(channelKey);
disconnected(channelKey);
}
} catch (Exception e) {
resetKey(channelKey);
disconnected(channelKey);
}
}
}
public void broadcast(byte[] buf, SelectionKey fr) {
synchronized (clientList) {
Iterator<SelectionKey> i = clientList.iterator();
while (i.hasNext()) {
SelectionKey key = i.next();
if (fr != key)
write(key, buf);
}
}
}
public synchronized void sendMessage(Packets pk) {
broadcast(pk.toByteArray(), null);
}
My guess (from the small amount of code you have included) is that you are not delineating your messages at all. even though you send 2 messages separately, the io layer may split/combine those in various ways such that the receiver gets part of one message attached to a previous message. you should use some sort of "message" protocol to indicate to the receiver exactly how many bytes to consume so that it can correctly parse each incoming message (e.g. write the message byte length first, then the message bytes).
as a side note, the write() method is not guaranteed to write all the bytes in one call, so you should be handling the return value and writing the remaining bytes as necessary.
You need to flip() before writing, and compact() afterwards, and you need to stop assuming that one write() writes the entire buffer. It returns a value for a reason. You need to loop, or if you're in non-blocking mode you need to proceeds as follows:
Write.
If the write didn't complete fully, register the channel for OP_WRITE and return to the select loop.
When the channel becomes writable, try the write again, and if it still doesn't complete just keep looping.
Otherwise deregister OP_WRITE.
Related
I'm using a 3rd party library, which has a method:
secureSend(int channel, byte[] data);
This method sends my binary data to the library, and if the data is larger than 64K, the method splits it to 64K chunks and sends them in order.
This method is marked as blocking, so it won't return immediately. Therefore is also advised to spawn a thread for each usage of this function:
new Thread(new Runnable() {
public void run() {
library.secureSend(channel, mydata);
}
}).start();
If I'm trying to send larger data (>1Mb), it will take about 30 seconds. This is fine.
However sometimes I need to interrupt the sending because there is a higher priority data to send.
Currently, If I spawn a new thread with calling secureSend it will have to wait, as library operates in FIFO-manner, ie.: it will finish first with previous sendings.
I decompiled the library's class files, and secureSend has the following pseudo algorithm:
public synchronized void secureSend(int c, byte[] data) {
try {
local_data = data;
HAS_MORE_DATA_TO_SEND = (local_data.length > 0)
while (HAS_MORE_DATA_TO_SEND) {
HAS_MORE_DATA_TO_SEND = sendChunk(...); //calculates offset, and length, and returns if still has more, operates with local_data!
}
} catch(IOException ex) {}
}
I've tried to interrupt the thread (I've stored it), but it didn't helped.
The library spends a lot of time in that while loop. However, it also fear of IOException.
My question: can I anyhow interrupt/kill/abort this function call? Maybe somehow throwing an IOException into the Thread? Is this somewhat possible?
In Java (or clojure) I would like to spin up an external process and consume its stdout as a stream. Ideally, I would like to consume the process' output stream every time that the external process flushes it, but am not sure how that can be accomplished, and how it can be accomplished without blocking.
Going around consuming a Java ProcessPipeInputStream for a shelled out process (for example a Unix ProcessPipeInputStream), I find the inherited InputStream methods a bit low-level to work with, and am not sure if there's a non-blocking way to consume from the stream every time the producer-side flushes or otherwise in a non-blocking fashion.
Many code examples block on the output stream in an infinite loop, thereby hogging a thread for the listening. My hope is this blocking behavior can be avoided altogether.
Bottom line:
Is there a non-blocking way to be notified on an input stream, every time that the producing side of it flushes?
You need to create a separate Thread that would consume from such a stream allowing the rest of your program to do whatever is meant to be do doing in parallel.
class ProcessOutputReader implements Runnable {
private InputStream processOutput;
public ProcessOutputReader(final InputStream processOutput) {
this.processOutput = processOutput;
}
#Override
public void run() {
int nextByte;
while ((nextByte = processOutput.read()) != -1) {
// do whatever you need to do byte-by-byte.
processByte(nextByte);
}
}
}
class Main {
public static void main(final String[] args) {
final Process proc = ...;
final ProcessOutputReader reader = new ProcessOutputReader(proc.getInputStream());
final Thread processOutputReaderThread = new Thread(reader);
processOutputReaderThread.setDaemon(true); // allow the VM to terminate if this is the only thread still active.
processOutputReaderThread.start();
...
// if you wanna wait for the whole process output to be processed at some point you can do this:
try {
processOutputReaderThread.join();
} catch (final InterruptedException ex) {
// you need to decide how to recover from if your wait was interrupted.
}
}
}
If instead of processing byte-by-byte you want to deal with each flush as a single piece... I'm not sure there is 100% guaranteed to be able tocapture each process flush. After all the process own's IO framework software (Java, C, Python, etc.) may process the "flush" operation differently and perhaps what you end up receiving is multiple blocks of bytes for any given flush in that external process.
In any case you can attempt to do that by using the InputStream's available method like so:
#Override
public void run() {
int nextByte;
while ((nextByte = processOutput.read()) != -1) {
final int available = processOutput.available();
byte[] block = new byte[available + 1];
block[0] = nextByte;
final int actuallyAvailable = processOutput.read(block, 1, available);
if (actuallyAvailable < available) {
if (actuallyAvailable == -1) {
block = new byte[] { nextByte };
} else {
block = Arrays.copyOf(block, actuallyAvailable + 1);
}
}
// do whatever you need to do on that block now.
processBlock(block);
}
}
I'm not 100% sure of this but I think that one cannot trust that available will return a guaranteed lower bound of the number of bytes that you can retrieve without being block nor that the next read operation is going to return that number of available bytes if so requested; that is why the code above checks on the actual number of bytes read (actuallyAvailable).
I am building a server that sends data via a single TCP socket for each user every 2 seconds and on a separate thread. There are also special events occasionally sent along side with the regular data. Sometimes, data in multiple packets would mix up so I created a queue to make sure it does not happen. However, the issue is still there, is my approach not correct or is there something wrong with my code?
protected void sendData (byte[] data) {
if (isSendingData) {
dataQueue.add(data);
return;
}
isSendingData = true;
Thread sendThread = new Thread() {
public void run () {
try {
BufferedOutputStream outStream = new BufferedOutputStream(connectionSocket.getOutputStream());
outStream.write(data);
outStream.flush();
// check queue, if there are data, send
byte[] moreData = null;
if (dataQueue.size() > 0) {
moreData = dataQueue.remove(0);
}
isSendingData = false;
if (moreData != null) {
sendData(moreData);
}
}
catch (Exception e) {
System.out.println ("Error sending data to peripheral: " + e);
isSendingData = false;
}
}
};
sendThread.start ();
}
The proper idiom to remove concurrency issues using a queue is to have a long-lived thread run an infinite loop which takes elements from the queue and processes them. Typically you'll use a blocking queue so that on each iteration the thread goes to sleep until there is an item to process.
Your solution deviates from the above in many aspects. For example:
if (isSendingData) {
dataQueue.add(data);
return;
}
isSendingData = true;
—if this method is called concurrently, this will result in a race condition: both threads can read isSendingData as false, then concurrently proceed to sending data over the network. If isSendingData isn't volatile, you've also got a data race on it (entirely separate from the race condition explained above).
if (dataQueue.size() > 0) {
moreData = dataQueue.remove(0);
}
—this is another race condition: after you read size as zero, the other thread can add an item to the queue. Now that item will possibly never be processed. It will linger in the queue until another such thread is started.
The more obvious way your solution is not correct is that the thread you start has no loops and is intended to just process one message, plus possibly one extra message in the queue. This should be reworked so that there are no special cases and sendData always, unconditionally, submits to a queue and never does any sending on its own.
I would do this completely differently. You don't want arbitrarily long queues in your application.
Have your hearbeat thread synchronize on the socket when sending the heartbeat.
Don't have it sending anything else.
Get rid of the queue, isSendingData, etc.
Have your main application synchronize on the socket when it wants to send, and just send whenever it needs to.
Use the same BufferedOutputStream or BufferedWriter for all sending, and flush it after each send.
I'm coding a simple Bank simulator where users would login from different locations at once, using sockets. In the Bank server I keep a bounded buffer to store every incoming request, ex: transfer funds, get account balance etc and there's a Background Thread running at Server end (Buffer Reader) to pull out each request from this Request Queue (assume it works as a Thread Scheduler in OS), in FCFS basis.
I have made buffer's put() and get() methods to have conditional synchronization.
ex:
// put method
while(total_buffer_size == current_total_requests) {
System.out.println("Buffer is full");
wait();
}
So my question is, do we have to synchronize methods like get-balance or transfer-funds to avoid corruption of data? I believe it is not necessary since the Buffer Reader takes each request one-by-one and relevant action. Have I avoided any deadlock situations through this? What do you think? Thanks
EDIT2:
public synchronized boolean put(Messenger msg, Thread t, Socket s) throws InterruptedException {
while(total_buffer_size == current_total_requests) {
System.out.println("Buffer is full");
wait();
}
current_total_requests++;
requests[cur_req_in] = new Request(msg, s); // insert into Queue
cur_req_in = (cur_req_in + 1) % total_buffer_size ;
notifyAll();
return true;
}
// take each incoming message in queue. FIFO rule followed
public synchronized Request get() throws InterruptedException {
while(current_total_requests==0) wait();
Request out = requests[cur_req_out];
requests[cur_req_out] = null;
cur_req_out = (cur_req_out + 1) % total_buffer_size ;
current_total_requests--;
notifyAll(); //wake all waiting threads to continue put()
return out;
}
If there is only one consumer (i.e. one thread that consumes the requests from the "buffer") , then you don't need to use any synchronization on the methods relating to the bank account. However, I don't believe that your current implementation of a "bounded buffer" is valid. To be more specific:
while(total_buffer_size == current_total_requests) {
System.out.println("Buffer is full");
wait();
}
There is absolutely no guarantee how many threads will get past the while loop, perform a context switch just before current_total_requests is incremented and queue more requests than what's allowed the buffer size. Unless your put method is synchronized, this approach will be extremely unreliable and prone to race conditions.
If you want a bounded buffer, then just use one of Java's already existing "bounded buffers" or more specifically: the BlockingQueue. The BlockingQueue blocks on put(...):
Inserts the specified element into this queue, waiting if necessary for space to become available.
It also blocks on take() if there is no data in the queue. I don't know if you can use one of the items in the concurrency library, but if you can't then you have to fix your BoundedBuffer.
My goal is to create (or use existing) an InputStream implementation (say, MergeInputStream) that will try to read from a multiple InputStreams and return the first result. After that it will release lock and stop reading from all InputStreams until next mergeInputStream.read() call. I was quite surprised that I didn't found any such tool. The thing is: all of the source InputStreams are not quite finite (not a file, for example, but a System.in, socket or such), so I cannot use SequenceInputReader. I understand that this will probably require some multi-thread mechanism, but I have absolutely no idea how to do it. I tried to google it but with no result.
The problem of reading input from multiple sources and serializing them into one stream is preferably solved using SelectableChannel and Selector. This however requires that all sources are able to provide a selectable channel. This may or may not be the case.
If selectable channels are not available, you could choose to solve it with a single thread by letting the read-implementation do the following: For each input stream is, check if is.available() > 0, and if so return is.read(). Repeat this procedure until some input stream has data available.
This method however, has two major draw-backs:
Not all implementations of InputStream implements available() in a way such that it returns 0 if and only if read() will block. The result is, naturally, that data may not be read from this stream, even though is.read() would return a value. Whether or not this is to be considered as a bug is questionable, as the documentation merely states that it should return an "estimate" of the number of bytes available.
It uses a so called "busy-loop", which basically means that you'll either need to put a sleep in the loop (which results in a reading latency) or hog the CPU unnecessarily.
Your third option is to deal with the blocking reads by spawning one thread for each input stream. This however will require careful synchronization and possibly some overhead if you have a very high number of input streams to read from. The code below is a first attempt to solve it. I'm by no means certain that it is sufficiently synchronized, or that it manages the threads in the best possible way.
import java.io.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
public class MergedInputStream extends InputStream {
AtomicInteger openStreamCount;
BlockingQueue<Integer> buf = new ArrayBlockingQueue<Integer>(1);
InputStream[] sources;
public MergedInputStream(InputStream... sources) {
this.sources = sources;
openStreamCount = new AtomicInteger(sources.length);
for (int i = 0; i < sources.length; i++)
new ReadThread(i).start();
}
public void close() throws IOException {
String ex = "";
for (InputStream is : sources) {
try {
is.close();
} catch (IOException e) {
ex += e.getMessage() + " ";
}
}
if (ex.length() > 0)
throw new IOException(ex.substring(0, ex.length() - 1));
}
public int read() throws IOException {
if (openStreamCount.get() == 0)
return -1;
try {
return buf.take();
} catch (InterruptedException e) {
throw new IOException(e);
}
}
private class ReadThread extends Thread {
private final int src;
public ReadThread(int src) {
this.src = src;
}
public void run() {
try {
int data;
while ((data = sources[src].read()) != -1)
buf.put(data);
} catch (IOException ioex) {
} catch (InterruptedException e) {
}
openStreamCount.decrementAndGet();
}
}
}
I can think of three ways to do this:
Use non-blocking I/O (API documentation). This is the cleanest solution.
Multiple threads, one for each merged input stream. The threads would block on the read() method of the associated input stream, then notify the MergeInputStream object when data becomes available. The read() method in MergedInputStream would wait for this notification, then read data from the corresponding stream.
Single thread with a busy loop. Your MergeInputStream.read() methods would need to loop checking the available() method of every merged input stream. If no data is available, sleep a few ms. Repeat until data becomes available in one of the merged input streams.