Closing the channel right after writing the response - java

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.

Related

Will netty automatically flush writed data?

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().

Writing to a non-blocking NIO UDP (DatagramChannel) socket after processing request on a separate thread

I'm experimenting with some network code, and I'm trying to figure out a good way to trigger writes to my DatagramChannel after having processed an event on a separate thread. This is quite simple for TCP, since you have a separate socket on which you can register your write interest (see reactor pattern, etc). For UDP, however, registering and deregistering interest with the datagram channel doesn't work so well, since I'm basically just modifying the same selection key.
I feel like you either block on the send in the event handler thread (wrong because then we're using blocking sends), or you block on a queue or something to take the responses and write them (also wrong because then we're blocking the selector thread).
I'd like to do something like switch the interest to write once I have something to write, and then back again to read, but then I run the risk of a race where I set it back to read after a write has been queued up, and then that write waits until I get the next read, which is also bad.
Yes, I know that there are other, potentially better suited threading models for these sorts of things, but I'm experimenting, so I'm curious. =)
You don't have to set the interest-ops to write when you want to write. Just write, from whatever thread you happen to be in. Only if that write returns zero do you need to worry about write interest-ops, as per many answers here.

Make sure Java will not close OutputStream before PrinWriter.print() finishes

I'm developing a distributed system that receives requests via Socket and writes the results back using OutputStream.
I'm facing problems because I have to return a very large string, but Java just keeps the execution of the code after I call the method print() without it finished printing:
public void attendRequisition(Socket clientSocket) {
PrintWriter pw = new PrintWriter(clientSocket.getOutputStream());
pw.print(getResults());
pw.close()
}
Some information:
I need to close the connection after sending the results.
Without the close() instruction, the whole printing process takes about 3~5 seconds to finishes
I'm using telnet to test this method, and I can see the message coming and being cut becase of Java running the close() instruction
I can't count with receiving client's feedback
I believe this is happening because Java thinks the method print() finished executing, but what might be happening is that Java sends the message to the JVM, and JVM send it to the network adapter, and since the message is very large, close() method is called before the network adapter is able to send the entire message.
What I need is a way to make sure Java will only run the instruction close() after the printing process finished and the client received the entire message.
UPDATE: I was able to get it working properly by adding a Thread.sleep(). By doing this, the SO has enough time to send the message before Java closes the connection. But I don't want to use this solution, it implicates on too many problems.
I was able to solve the problem using DataOutputStream.writeBytes(). This way, the execution only continues when the method finishes sending the data. It is slower, but works.
I'll bet that if you use another constructor (i.e., the one whose 2nd argument is a boolean to indicate your desire to flush) then your example will work. The way you're constructing the object, autoflush is disabled.
If your real code is more complex, then you can call pw.flush() at the appropriate moments.
I can see the message coming and being cut becase of Java running the close() instruction
No you can't. You can see the message being cut, unless you're wrong about how long it is, but you're jumping to conclusions about the reason. Java does not close the PrintWriter before it has finished sending. It flushes the writer to the socket send buffer, blocking if necessary, and then closes the underlying socket, which buffers a FIN behind the data. All the data gets sent, and all the data gets received, before the FIN arrives, which signals end of stream to the receiver.
Possibly you are unaware that PrintWriter swallows exceptions and therefore should really not be used over a network.

Interrupt blocking network IO without closing the socket

I read from a stream created by Socket.getInputStream(). When I use it, it blocks until it gets new data(exactly what it should). Now I need the stream to read something (see below). But when I start a new read it will give me unspecified output(or not?). My question is:
How can I interrupt the actual read, so I can use the read method?
Details: I connect to a server and send commands to it. From time to time the server sends messages to my client (event notifications), which I need to register. I want to be able to send commands while I'm waiting for this messages. When I send a command the answer to this command is read from the stream. And here is the problem: I'm still listening to the messages while I try to read my answer. So I need something that interrupts the current read.
The problem with stopping the event processor from reading is that you introduce a race condition: What happens if the server sends an event right after you terminated the read? The "response" that you read would wind up being an event.
The proper way to do this is to do all your reading, both events and responses, in one place and handle the responses like an event also. Right before you send a command, register a listener for the response, then send the command. When the reading thread sees a response, have it find the proper listener and notify it that the response has been received.
Easiest, best way to handle this IMO is to use an asynchronous listener with event callbacks. DataFetcher is an implementation (Also see Timeout and PartialReadException, dependencies in the same project/package, and IOUtils, which has capabilities to directly connect a FetcherListener with an InputStream)

Is there a way to read the inputstream for a specific amount of time?

I've a situation where a thread opens a telnet connection to a target m/c and reads the data from a program which spits out the all the data in its buffer. After all the data is flushed out, the target program prints a marker. My thread keeps looking for this marker to close the connection (successful read).
Some times, the target program does not print any marker, it keeps on dumping the data and my thread keeps on reading it (no marker is printed by the target program).
So i want to read the data only for a specific period of time (say 15 mins/configurable). Is there any way to do this at the java API level?
Use another thread to close the connection after 15 mins. Alternatively, you could check after each read if 15mins have passed and then simply stop reading and cleanup the connection, but this would only work if you're sure the remote server will continue to send data (if it doesn't the read will block indefinitely).
Generally, no. Input streams don't provide timeout functinality.
However, in your specific case, that is, reading data from a socket, yes. What you need to do is set the SO_TIMEOUT on your socket to a non-zero value (the timeout you need in millisecs). Any read operations that block for the amount of time specified will throw a SocketTimeoutException.
Watch out though, as even though your socket connection is still valid after this, continuing to read from it may bring unexpected result, as you've already half consumed your data. The easiest way to handle this is to close the connection but if you keep track of how much you've read already, you can choose to recover and continue reading.
If you're using a Java Socket for your communication, you should have a look at the setSoTimeout(int) method.
The read() operation on the socket will block only for the specified time. After that, if no information is received, a java.net.SocketTimeoutException will be raised and if treated correctly, the execution will continue.
If the server really dumps data forever, the client will never be blocked in a read operation. You might thus regularly check (between reads) if the current time minus the start time has exceeded your configurable delay, and stop reading if it has.
If the client can be blocked in a synchronous read, waiting for the server to output something, then you might use a SocketChannel, and start a timer thread that interrupts the main reading thread, or shuts down its input, or closes the channel.

Categories