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.
Related
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().
I am trying to understand some things about threads in java, which I am very unfamiliar with. Unfortunately my example is too big for running code, but I'll try to specify my problem as well as possible.
One of two similar code segments (taken from a little example which features a simple ChatClient/Server class), which are the center of my question:
public void run(){
String message;
try{
while((message = reader.readLine()) != null){
tellEveryone(message);
}
}catch(Exception ex){...}
}
(Taken from an inner class of the Server class.)
The server is waiting in a while(true) loop for clients via its serversockets accept() method and whenever a client connects, a new Thread is started with the above run method as "entry point".
What I don't understand is why this works. My understanding until now was that Thread which is supposed to constantly listen to something has to contain a while(true) construct because otherwise it would just finish it's run method and it would be finished with no return ("dead" call stack).
So for my example when reader gave us all lines he had to give in the beginning, I supposed it would leave the run()-method and nothing would happen when the specific client would send a new message but it seems it stays listening for client input. How does that work?
(I probably should say that "reader" is a BufferedReader within the inner class which is instantiated once for every connected client.)
I hope that was sufficiently explained. If more Information is needed I will gladly provide it.
readLine() blocks while there is no data. It only returns null at end of stream, which in the case of a socket means that the peer has disconnected.
If the client does not send anything, the server socket does not have anything to read. When the client writes to the socket and the contents are sent the reader can read the contents
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.
I am writing a socket-based server in java. A client connects to it(a web-browser) and the server sends back a simple html code and sets cookie to recognize next time client connects to it again. I am using PrintStream to write to the socket , but flush is not working. The only way i can flush is to use shutdownoutput or close and both close the socket stream. But i do not want that because i am readin/writing to it several times in several places in the code. What can do? Could't get any help from the tags.
I also tried other buffered writer classes, same problem.
Ah yeah , sillyproblem , you just have to use pstream.writeln(""); since breader.readLine() reads until it finds '\n' character.
so write() won't work.
I would try calling this method instead of flush:
public boolean checkError()
Returns:
True if and only if this stream has encountered an IOException other than InterruptedIOException, or the setError method has been invoked
See if it is failing for some reason to do the flush (checkError calls flush internally and remembers error state).
Also worth trying is connecting to the server using telnet and seeing if the data is being returning immediately, or writing a simple java client socket program to check (cut/paste one off the net).
It might be that the browser has decided to deliberately wait for more input before displaying your html (especially if the html is not perfectly formed). I seem to remember having this issue myself in the past.