Recently I was writing a http server and I transplanted some netty components to my project. When I read the source code of netty's ChannelHandlerContext, I found that actually it doesn't flush into socket. I knew that I have to invoke flush() to flush the internal buffer into socket.
So I wonder will netty automatically flush the internal buffer, I have read some source code, but I am not good at it. And I googled but none answered it, the only answer I got is do flushing.
What I have learned from source code is: write continue writing into outboundbuffer, and if outboundbuffer reaches highwatermark, it will fire writability changed event and the channel is unwritable.
You can call the writeAndFlush method if you want to do it in one line, but otherwise you need to flush or you data will not go through.
4.0 introduced a new operation called flush() which explicitly flushes the outbound buffer of a Channel, and write() operation does not flush automatically. You can think of this as a java.io.BufferedOutputStream, except that it works at message level.
Because of this change, you must be very careful not to forget to call ctx.flush() after writing something. Alternatively, you could use a shortcut method writeAndFlush().
I found it at https://netty.io/wiki/new-and-noteworthy-in-4.0.html#write-does-not-flush-automatically
In fact, I have the similar question at Why did not call ctx.flush() after ctx.write() is called at Netty user guide?
Please contact me if you got the answer.
No, it won't.
However, it could be implemented quite easily.
As you said:
What I have learned from source code is: write continue writing into
outboundbuffer, and if outboundbuffer reaches highwatermark, it will
fire writability changed event and the channel is unwritable.
It's right. and it in fact tells a way to automaticallly flush. Just override ChannelInboundHandler.channelWritabilityChanged to call flush().
Related
When I was using regular Sockets, I could call getInputStream() and use available() to see how many bytes were available. I switched to SSLSocket, but now available() always returns 0 for some reason. When I read instead, I can still get data. How can I tell if there is data available in an SSLSocket so that I can service it without blocking if there is no data?
Notes:
I cannot call read() on the InputStream or the thread will block. I would like non-blocking in my implementation.
available() returns 0 even though there is data for SSLSocket's InputStream.
There is no way to do this. Your streams cannot tell you the length of the data without first decrypting it. available() will always return 0 for SSLSocket.
As mentioned in this chat, the reason you wanted to check for data is to prevent read() from blocking when called, so you can handle multiple connections on a single thread, instead of a Thread per Client system.
Instead, use a non-blocking alternative. java.nio currently doesn't have it's own SSL implementation of SocketChannel, but you can find one online (like here) or create your own.
With this system, you can register a Selector to every channel, and manage them all using the "selector thread". I wrote an example of how to use a selector here (scroll down to Using a Selector).
With non-blocking IO, you to handle multiple clients per thread, allowing you to scale up. This method of managing channels was brought up due to the C10k Problem
I assume you fixed your problem, but for those like me, I found a much easier solution. If you perform a read, then the available() method fills up for what was decrypted. How to use and abuse this? Read a single byte with a very low SoTimeout on your socket, if you catch a SocketTimeoutException, then the connection is empty, if not, prepend that byte you read to your future interpretation of the message. Until in.available() == 0 again, just roll with it.
You can use available() with inputStream of underlying Socket. This works in my case.
In the following scenario
ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
output.flush();
// Do stuff with it
Why is it always necessary to flush the buffer after initial creation?
I see this all the time and I don't really understand what has to be flushed. I kind of expect newly created variables to be empty unless otherwise is specified.
Kind of like buying a trash-can and finding a tiny pile of trash inside that came with it.
In over 15 years of writing Java on a professional level I've never once encountered a need to flush a stream before writing to it.
The flush operation would do nothing at all, as there's nothing to flush.
You want to flush the stream before closing it, though the close operation should do that for you it is often considered best practice to do it explicitly (and I have encountered situations where that did make a difference, where apparently the close operation did not actually do a flush first.
Maybe you are confused with that?
When you write data out to a stream, some amount of buffering will occur, and you never know for sure exactly when the last of the data will actually be sent. You might perform many rite operations on a stream before closing it, and invoking the flush()method guarantees that the last of the data you thought you had already written actually gets out to the file. Whenever you're done using a file, either reading it or writing to it, you should invoke the close()method. When you are doing file I/O you're using expensive and limited operating system resources, and so when you're done, invoking close()will free up those resources.
This is needed when using either ObjectInputStream and ObjectOutputStream, because they send a header over the stream before the first write is called. The call to flush() will send that header to the remote side.
According to the spec, the header exists of the following contents:
magic version
If the header doesn't arrive at the moment a ObjectInputStream is build, this call will hang until it received the header bytes.
This means that if the protocol in question is written with ObjectStreams, it should flush after creating a ObjectOutputStream.
What happens if I close the channel right after writing the response? Is the response still delivered?
This http upload example seems to say that but I'm not sure if it's just a bug.
writeResponse(ctx.channel());
ctx.channel().close();
If you close a channel using .close() just after writing, then you create a race condition in with either all the data is written, half of the data, or even none, depending on the length of the message.
This happens because all written messages end up into a queue, and depending if the current thread is a Netty thread or not, it either processes the data directory, or just returns.
Since in most conditions you only want to close the channel after all writes as completed, you should use the following code when writing your response:
ctx.writeAndFlush(protocolSpecificPacket)
.addListener(ChannelFutureListener.CLOSE);
While this always works, you don't always have access to the last write, in these cases you can also send an empty ByteBuf, and then add the listener to that:
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
.addListener(ChannelFutureListener.CLOSE);
No it not a bug,but not the best way to close channel,I assume you writeResponse perform like this:
ctx.channel().write(msg)
It's sent asynchronisly,actuallay the message will offer to a writeBufferQueue,and the write IO thread will be wake up to do the actual write.
Check the ChannelFuture returned by ctx.channel().write(msg),you can wait on that object.
the best way to close a netty channel,I think,would be :
ctx.channel().write(a emptybuffer).addFutureListener(Channels.CloseFuture);
since you are using netty 4.0,you may neeed to search something similar with above.
It is possible to skip data from an InputStream
in.skip(in.available());
but if you want to do something similar with OutputStream I've found
socket.getOutputStream().flush();
But that's not the same, flush will transmit the buffered data instead of ignoring it.
Is there any possibility of deleting buffered data?
Thanks
EDIT
The situation is a client-server application, when a new command is send (from client)
it (try) to be sure that the answer read will correspond to the last command sent.
Some commands are sent by (human-fired) events, and others are sent by automatic threads.
If a command is on buffer and a new one is send then the answer will be for the first one, causing desynchronization.
Of course a synchronized method plus a flag called "waitingCommand" could be the safer approach but as the communication is not reliable, this approach is slow (depends on timeouts ). That's why I've asked for the skip method.
You can't remove data you could have sent. You can write the data into an in-memory OutputStream like ByteArrayOutputStream and copy only the portions you want.
I'm no sure if it makes sense, but you can try:
class MyBufferedOutputStream extends java.io.BufferedOutputStream {
public MyBufferedOutputStream(OutputStream out) {
super(out);
}
/** throw away everything in a buffer without writing it */
public synchronized void skip() {
count = 0;
}
}
What does it mean to "skip" outputting data?
Once the data is in the buffer, there's no way to get it back or remove it. I suggest checking if you want to skip the data before you write it to the OutputStream. Either that, or have your own secondary buffer that you can modify at will.
This question doesn't make any sense. Throwing away pending requests will just make your application protocol problem worse. What happens to the guy that is waiting for the response to the request that got deleted? What happened to the functionality that that request was supposed to implement? You need to rethink all this from another point of view. If you have a single connection to a server that is executing request/response transactions for this client, the protocol is already sequential. You will have to synchronize on e.g. the socket at the point of writing & flushing the request and reading the response, but you're not losing any performance by this as the processing at the other end is sequentialized anyway. You don't need a 'waitingCommand' flag as well, just synchronization.
Since you are controlling the data written to OutputStream, just don't write pieces that you don't need. OutputStream by contract, does not ensure when data is actually written, so it doesn't make much sense to have skip method.
The best you can do to "ignore" output data, is not to write it at first.
I have a question in my mind that, while writing into the file, before closing is done, should we include flush()??. If so what it will do exactly? dont streams auto flush??
EDIT:
So flush what it actually do?
Writers and streams usually buffer some of your output data in memory and try to write it in bigger blocks at a time. flushing will cause an immediate write to disk from the buffer, so if the program crashes that data won't be lost. Of course there's no guarantee, as the disk may not physically write the data immediately, so it could still be lost. But then it wouldn't be the Java program's fault :)
PrintWriters auto-flush (by default) when you write an end-of-line, and of course streams and buffers flush when you close them. Other than that, there's flushing only when the buffer is full.
I would highly recommend to call flush before close. Basically it writes remaining bufferized data into file.
If you call flush explicitly you may be sure that any IOException coming out of close is really catastrophic and related to releasing system resources.
When you flush yourself, you can handle its IOException in the same way as you handle your data write exceptions.
You don't need to do a flush because close() will do it for you.
From the javadoc:
"Close the stream, flushing it first. Once a stream has been closed, further write() or flush() invocations will cause an IOException to be thrown. Closing a previously-closed stream, however, has no effect."
To answer your question as to what flush actually does, it makes sure that anything you have written to the stream - a file in your case - does actually get written to the file there and then.
Java can perform buffering which means that it will hold onto data written in memory until it has a certain amount, and then write it all to the file in one go which is more efficient. The downside of this is that the file is not necessarily up-to-date at any given time. Flush is a way of saying "make the file up-to-date.
Close calls flush first to ensure that after closing the file has what you would expect to see in it, hence as others have pointed out, no need to flush before closing.
Close automatically flushes. You don't need to call it.
There's no point in calling flush() just before a close(), as others have said. The time to use flush() is if you are keeping the file open but want to ensure that previous writes have been fully completed.
As said, you don't usually need to flush.
It only makes sense if, for some reason, you want another process to see the complete contents of a file you're working with, without closing it. For example, it could be used for a file that is concurrently modified by multiple processes, although with a LOT of care :-)
FileWriter is an evil class as it picks up whatever character set happens to be there, rather than taking an explicit charset. Even if you do want the default, be explicit about it.
The usual solution is OutputStreamWriter and FileOutputStream. It is possible for the decorator to throw an exception. Therefore you need to be able to close the stream even if the writer was never constructed. If you are going to do that, you only need to flush the writer (in the happy case) and always close the stream. (Just to be confusing, some decorators, for instance for handling zips, have resources that do require closing.)
Another usecase for flushing in program is writing progress of longrunning job into file (so it can be stopped and restarted later. You want to be sure that data is safe on the drive.
while (true) {
computeStuff();
progresss += 1;
out.write(String.format("%d", progress));
out.flush();
}
out.close();