Java nio Only Reading 8192/433000 bytes - java

I have a project that I'm working on to better understand Java NIO and network programming stuff. I'm trying to send a 400,000+ byte file through netcat to my server where it will be found and written to a file.
The Problem:
The program works perfectly when the file is below 10,000 bytes, or when I place a Thread.sleep(timeout) before the Select(). The file sends over but only reads 8192 bytes and then cancels out of the loop and goes back to the select() to capture the rest of the data. However the file captures what comes after. I need the complete data for further expansion to the project.
Things I've Tried:
I've tried to load the data onto another byte array which evidently works, but skips over the 8192 bytes (since the select() has been called again). Reads the rest of the 391000 bytes. When comparing the files the first 8192 bytes is missing.
I've tried various other things but I'm not adequate in NIO to understand what I'm messing up on.
My Code
This is just where I feel the code is messing bout (after debugging)
private void startServer() {
File temp = new File("Filepath");
Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.socket().bind(listenAddress);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
log.info("Server Socket Channel Started");
while(!stopRequested){
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
for(SelectionKey key : keys){
if(key.isAcceptable()){
try {
serverSocketChannel = (ServerSocketChannel) key.channel();
SocketChannel socket = serverSocketChannel.accept();
socket.configureBlocking(false);
socket.register(selector, SelectionKey.OP_READ);
}catch (IOException e) {
log.error("IOException caught: ", e);
}
}
if(key.isReadable(){ read(key); }
keys.remove(key);
}
}
} catch (IOException e) {
log.error("Error: ", e);
}
}
private void read(SelectionKey key) {
int count = 0;
File tmp = new File("Path");
try {
SocketChannel channel = (SocketChannel) key.channel();
byteBuffer.clear();
while((count = channel.read(byteBuffer)) > 0) {
byteBuffer.flip();
//in bytearrayoutputstream to append to data byte array
byteArrayOutputStream.write(byteBuffer.array(), byteBuffer.arrayOffset(), count);
byteBuffer.compact();
}
}
data = byteArrayOutputStream.toByteArray();
FileUtils.writeByteArrayToFile(tmp, data);
}
}
The above code is what I'm working with. I have more stuff in this class but I believe the main two functions having the problem are these two. I'm not too sure what steps I should take. The file I have to test my program contains many TCPs about 400,000 bytes. The select() collects the initial 8192 bytes and then runs read (which shouldn't happen until it captures all of the data in the stream), comes back and gathers the rest. I've allocated the byteBuffer to be 30720 bytes.
If not clear, I can post the rest of the code, let me know what your suggestions are.
Question
Why does this code only grab 8192 bytes when the allocated space is 30720? Why does it work in debug mode or with Thread.sleep()?
Previous person advised me to place my byteBuffer.clear() outside of loop, even after doing so, the problem persists.

The non-blocking API merely promises that the 'readable' state is raised if there are more than 0 bytes. It makes no guarantee that it'll wait until all the bytes you're interested in have arrived; there isn't even a way to say 'dont mark this channel as isReadable until at least X bytes are in'. There is no way to fix that directly; your code must instead be capable of dealing with a half filled buffer. For example, by either reading this data away so that the 'isReadable' state gets cleared until MORE bytes arrive.
Using the raw non-blocking APIs is rocket science (as in, it is very tricky to write your code correctly, it is easy to get a CPU core to spin to 100% because you're mismanaging your flags, and it is easy to have all threads frozen and the app reduced to being able to handle only a percent or two of what a normal threaded variant could have done due to accidental invocation of blocking methods.
I strongly suggest you first reconsider whether you need non-blocking at all (it always almost slower, and orders of magnitude harder to develop for. After all, you cannot make a single potentially blocking call anywhere in any handler code or your app will be dog slow under load, and java is not great at await/yield stuff – the only real benefit is that you get more finegrained control over buffer sizes, which is irrelevant unless you are very RAM constrained and can get away with tiny buffers for per-connection state). And if you then conclude that truly this is the only way, use a library that makes this API easier to use, such as netty.

Related

Proper way to read (write) through a SocketChannel

My questions is more generic than the following scenario, though this covers everything needed.
It is for Java and the correct practices of socket programming.
Scenario:
One server with many clients. Usage of non-blocking I/O
The server is a client to another server. Usage of blocking I/O
Two cases for each: in one case all data fit inside the allocated bytebuffer, in the second case they do not fit (for one iteration only, not for the lifespan of the program).
All examples that I have found for a non-blocking I/O go something like this:
InetAddress host = InetAddress.getByName("localhost");
Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress(host, 1234));
serverSocketChannel.register(selector, SelectionKey. OP_ACCEPT);
while (true) {
if (selector.select() <= 0)
continue;
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectedKeys.iterator();
while (iterator.hasNext()) {
key = (SelectionKey) iterator.next();
iterator.remove();
if (key.isAcceptable()) {
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
// Do something or do nothing
}
if (key.isReadable()) {
SocketChannel socketChannel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
socketChannel.read(buffer);
// Something something dark side
if (result.length() <= 0) {
sc.close();
// Something else
}
}
}
Does the read here reads all incoming data from that particular client and that particular request, if the buffer is large enough, or do I need to have it inside a while loop? If the buffer is not large enough?
In case of a write, do I also just do socketChannel.write(buffer) and I am good to go (at least from the programs point of view)?
The doc here does not specify the case when all incoming data fit in the buffer. It also makes it a bit confusing when I have a blocking I/O:
It is guaranteed, however, that if a channel is in blocking mode and there is at least one byte remaining in the buffer then this method will block until at least one byte is read.
Does this mean that here (blocking I/O) I need to read through a while loop either way (most examples that I found does this)? What about a write operation?
So, to sum it up, my question is, what is the proper way to read and write the data in my scenario, from the point of view of the middle server (client to the second server)?
If you had not called configureBlocking(false), then yes, you would use a loop to fill the buffer.
However… the point of a non-blocking socket is not to get hung up waiting on any one socket, since that would delay the reading from all the remaining sockets whose selected keys haven’t yet been processed by your Iterator. Effectively, if ten clients connect, and one of them happens to have a slow connection, some or all of the others might experience the same slowness.
(The exact order of the selected key set is not specified. It would be unwise to look at the source of the Selector implementation class, since the lack of any guarantee of order means future versions of Java SE are permitted to change the order.)
To avoid waiting for any one socket, you don’t try to fill up the buffer all in one go; rather, you read whatever the socket can give you without blocking, by reading only once per select() call.
Since each ByteBuffer might hold a partial data sequence, you’ll need to remember each ByteBuffer’s progress for each Socket. Luckily, SelectionKey has a convenient way to do that: the attachment.
You also want to remember how many bytes you’ve read from each socket. So, now you have two things you need to remember for each socket: the byte count, and the ByteBuffer.
class ReadState {
final ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
long count;
}
while (true) {
// ...
if (key.isAcceptable()) {
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
// Attach the read state for this socket
// to its corresponding key.
socketChannel.register(selector, SelectionKey.OP_READ,
new ReadState());
}
if (key.isReadable()) {
SocketChannel socketChannel = (SocketChannel) key.channel();
ReadState state = (ReadState) key.attachment();
ByteBuffer buffer = state.buffer;
state.count += socketChannel.read(buffer);
if (state.count >= DATA_LENGTH) {
socketChannel.close();
}
buffer.flip();
// Caution: The speed of this connection will limit your ability
// to process the remaining selected keys!
anotherServerChannel.write(buffer);
}
For a blocking channel, you can just use one write(buffer) call, but as you can see, the use of a blocking channel may limit the advantages of the primary server’s use of non-blocking channels. It may be worth making the connection to the other server a non-blocking channel as well. That will make things more complicated, so I won’t address it here unless you want me to.

Is it necessary to register interest to write to a NIO socket to send data?

Is it necessary to register interest to write to a NIO client socket channel to send data? Do I have to always call socketChannel.register(selector, SelectionKey.OP_WRITE), or some equivalent, before writing to the client SocketChannel to be able to write there?
Would not be enough simply to write data to client SocketChannel with channel.write(outputBuffer) and awake potentially blocked Selector, all in a client thread? The main selector loop would then look like this:
Selector selector = SelectorProvider.provider().openSelector();
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
while (selector.select() > 0) {
Set<SelectionKey> readyKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = readyKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = (SelectionKey)keyIterator.next();
keyIterator.remove();
while (keyIterator.hasNext()) {
...
if (key.isAcceptable()) {
...
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
// client socket channel would be permanently in the read mode
...
} else if (key.isReadable()) {
...
} else if (key.isWritable()) {
// the key should know here that the underlying channel
// has something to be send to the wire, so it should get
// here if there are still data to be sent
socketChannel.write(outputBuffer)
}
It would only get to the if (key.isWritable()) branch when there is something remaining to be send, the remainder of data from the initial channel.write(outputBuffer) call; like when the message is too long and needs to be send out into chunks and I want no blocking. The loop would spin until outputBuffer.hasRemaining() is finally false.
I am even thinking, does have to be writing to Channel, that is sending data out, done through Selector at all? Leave only incoming traffic to be handled with Selector, as only incoming traffic need wait states?
UPDATE
From further reading of valuable user207421 posts, which I partly inspired me to post this question, NIO Javadoc, in the push to join the dots, I summarized this:
SocketChannel and SelectionKey are thread safe.
Reading and writing from/to channel socket outside the selector loop is indeed possible; it's independent of it. Reading outside does not make much sense, writing to socket definitively does and it's in fact how most of writing is done.
Writing of data is typically initiated outside the selector loop, in a different thread. write(buffer) will not necessary send all data - if the message is too huge for the socket buffer, remote client is very slow or even went unresponsive. In that case write() has to be called repeatedly. Buffer updates the current position with every call, depending how much was sent, which can be anything between 0 and buffer.remaining().
If write() returns 0 then, and user207421 cannot stress this more, it's the case, possibly the only one, when OP_WRITE needs to be registered and writing is then handled within selector loop.
When all data are written the OP_READ must be immediately restored
Having OP_WRITE set without any data to write would cause selector loop to endlessly spin; waste of CPU time.
It is unclear what to do if write() returns >0 but still not all remaining message data were sent, that is buffer.remaining() > 0. Should I also set OP_WRITE and pass it to selector loop, or loop write(buffer) inside writing thread until there is no remainder or 0 is returned?
Can actually such situation happen? Official SocketChannel Javadoc says initially Unless otherwise specified, a write operation will return only after writing all of the r requested bytes ..meaning, no, it cannot happen! But then they add: Some types of channels, depending upon their state, may write only some of the bytes ..so does it mean write() can return before sending all? Or does that mean that returns '0' if it sent, say, just half of the buffer?
In the write returned 0 scenario, when writing is passed to the selector loop, ie different thread; is the writing thread blocked to write a completely new message, ie new buffer, to the same socket channel? Or I have to ensure it does not happen by other means? The Javadoc says: This method may be invoked at any time. If another thread has already initiated a write operation upon this channel, however, then an invocation of this method will block until the first operation is complete. Does that cover my scenario?
Official Javadoc does not mention any special meaning for 0 as a return value for write() method. It just says: The number of bytes written, possibly zero. Hmm.
I'm also not sure how unresponsive or slow client is handled during the write. I'm guessing that returning 0 from write() and passing it to selector loop is exactly the reason it's done like that. Selector then can, and I'm only guessing here, manage writing in an optimal way: speeding it, slowing it, increasing intervals, sending smaller chunks, whatever; whatever the underlying TCP/IP stack reports back.

Can Java NIO.2 read the ByteBuffer out of order?

For anyone interested, the answer to this questions is no, the socket wont read the buffer out of order.
Is it possible for the AsynchronousSocketChannel to read bytes out of order? Im strugling to debug where my issue starts, my protocol serializes objects up to 32k and writes them to the socket like this:
AsynchronousSocketChannel socket; ...
// serialize packet
ByteBuffer base; // serialized buffer (unknown size, size growns as needed with limit of 32k)
for (int j1 = 0; j1 < 6 && base.remaining() > 0; j1++) { // limit to 6 tries
socket.write(base).get(15, TimeUnit.SECONDS);
if (base.remaining() > 0) {
// aparently, if the write operation could write everything at once, we wouldnt have an issue
}
}
This write operation is not concurrent it is synchronized with locks. I use the standard read operation like this:
AsynchronousSocketChannel socket; ...
Future<Integer> reading = socket.read(getReadBuffer()); // the read buffer is 8k big
// consume the buffer also not concurrently
I can write up to 1000 packets per second with up to 1000 bytes each without issues, but eventually one or other client will break. If the packet is bigger, the frequency that it can handle without breaking will be lower, packets with 40.000 bytes will break if I write around 8 per second.
Example: I write 5 bytes (1,2,3,4,5), the buffer is big enough the write everything at once but the operation decides to stop with remaining bytes in the buffer (this should be the normal TCP behavior), so lets say the operation wrote 1,2,3, stopped and wrote the remain 4,5 (while buf.remain > 0 { write }), while reading, is most likely that I will read 4,5 first and 1,2,3 later, this should not happen.
While on localhost everything works fine, but just outside the same machine (still same network/routers) it wont work.
I do not flip the buffers to write/read. I can ensure its not an issue with the serialization and both the server and client are single-threaded. I'm forgetting to do something? Any suggestions on how to fix this?
It isn't clear why you're using asynchronous I/O if all you really want is synchronous I/O, which is what you are getting from that code. You'd be better off with an ordinary SocketChannel.
I do not flip the buffers to write/read.
You must. You must flip() before write(), and compact() afterwards, where 'afterwards' in this case means the same as above.

Make InputStream non-blocking

Currently I have a server that listens for connections (it is a basic highscore server for a mobile game I have), loops through the connections every 1000ms and listens for any incoming data.
public void readData(Connection c) throws IOException {
PacketBuffer readBuffer = new PacketBuffer(Server.PACKET_CAPACITY);
int packetSize = c.getIn().read();
c.getIn().mark(packetSize);
byte[] buffer = new byte[packetSize];
c.getIn().read(buffer, 0, buffer.length);
readBuffer.setBuffer(buffer);
packetHandler.addProcess(c, readBuffer);
}
I use my own PacketBuffer and I need to find a way so that c.getIn().read() (That is my connections InputStream) doesn't block. Currently the socket is set to 500ms timeout, and my server would run fine that way. My problem is if someone tries to make their own program to connect to try and hack their own highscores or ddos the server it will become convoluted with a bunch of useless connections that block the thread for 500ms a piece when the connection isn't writing.
You could try something like this. Every time readData gets called it will check to see if bytes are available to read. I used a while loop here because you want it to process all the data it can before the thread sleeps again. This will ensure messages dont get backed up, if it were to only read one every x milliseconds.
public void readData(Connection c) throws IOException {
while (c.getIn().available() > 0) {
int packetSize = c.getIn().read();
c.getIn().mark(packetSize);
byte[] buffer = new byte[packetSize];
c.getIn().read(buffer, 0, buffer.length);
PacketBuffer readBuffer = new PacketBuffer(Server.PACKET_CAPACITY);
readBuffer.setBuffer(buffer);
packetHandler.addProcess(c, readBuffer);
}
I dont know why you are using the mark method. Looks problematic to me.
You also really need to use a readFully() style method (see DataInputStream) which won't return until it's definitely read the full byte array. Regular reads can always "return short", even when the sender has sent the full data block (due to network packet sizing etc).
There are two classic ways to implement servers in java.
The first and oldest way is to use a read/write thread pair for each connected client. This is okay for smaller servers without a lot of connected clients as each client requires two threads to manage it. It doesn't scale very well to a lot of concurrent clients.
The second and newer way is to use java.nio.ServerSocketChannel, java.nio.SocketChannel, and java.nio.Selector. These three classes allow you to manage all IO operations for every client you have connected in a single thread. Here is an example for how to implement a very basic server using the java.nio package.
A much better way to implement a server would be to use a third-party framework. A great library that I have used in the past is Netty. It handles all the nitty-gritty details of sockets and provides a fairly clean and simple api that scales well.
You can't. InputStreams are blocking. Period. It's hard to see how non-blocking mode would actually solve the problem you mention. I suggest a redesign is in order.

Measuring actual bytes written through Java sockets

I have written a small program which send/receives files from one client to another. I've set up progressbars for both the receiver and the client, but the problem is that the sender seems to have his progressbar finish much quicker than the actual transfer. The problem lies with the how it calculates how many bytes that have been written. I'm assuming it's counting how many bytes I've read into buffer, rather than bytes that were sent through the network, so how can I find a solution to this problem? The receiver is calculating his received bytes at a correct rate, but the sender is not doing his part correctly.
Setting a lower buffersize offsets the difference a bit, but it's still not correct. I've tried wrapping the outputstream with a CountingOutputStream, but it returns the same result as the code snippet below. The transfer eventually completes correctly, but I need the proper "sent" values to update my progressbar, as in what was actually received and written to disc at the receiver side. I've included a very stripped down code snippet which represents my way of calculating transferred bytes. Any examples of a solution would be very helpful.
try
{
int sent = 0;
Socket sk = new Socket(ip, port);
OutputStream output = sk.getOutputStream();
FileInputStream file = new FileInputStream(filepath);
byte[] buffer = new byte[8092];
while ((bytesRead = file.read(buffer)) > 0)
{
output.write(buffer, 0, bytesRead);
sent += bytesRead;
System.out.println(sent); // Shows incorrect values for the actual speed.
}
}
In short, I don't think you can get the sort of accurate visibility you're looking for solely from the "sender" side, given the number of buffers between you and the "wire" itself. But also, I don't think that matters. Here's why:
Bytes count as "sent" when they are handed to the network stack. When you are sending a small number of bytes (such as your 8K example) those bytes are going to be buffered & the write() calls will return quickly.
Once you're reached network saturation, your write() calls will start to block as the various network buffers become full - and thus then you'll get a real sense of the timings.
If you really must have some sort of "how many bytes have you received?" you'll have to have the receiving end send that data back periodically via an out-of-band mechanism (such as suggested by glowcoder)
Get the input stream from the socket, and on the other side, when you've written a selection of bytes to disk, write the result to the output stream. Spawn a second thread to handle the reading of this information, and link it to your counter.
Your variable is sent - it is accurate. What you need is a received or processed variable, and for that you will need two-way communication.

Categories