Sending objects through Java NIO non-blocking sockets - java

I am getting an exception when trying to use:
oos = new ObjectOutputStream(socketChannel.socket().getOutputStream());
oos.writeObject(o);
And this raises the exception:
java.nio.channels.IllegalBlockingModeException
Is it impossible to pass objects in non-blocking sockets?
If it is, how should I proceed on passing message objects through the socket channels?
I've looked other places for this answer but couldn't find one...

You'll probably want to write your own ObjectOutputStream implementation that constructs a ByteBuffer and write()s it to the channel.
With non-blocking sockets, you cannot directly use the channel's socket; you need to use the channel's read() and write() methods.
When you write your own ObjectOutputStream, you'll mainly need to override the write() methods to buffer output and use the flush() method to write the buffer to the channel. Then, override the writeObject() method to look like this:
public void writeObject(Object o) throws IOException {
super.writeObject(o);
flush();
}
to make sure the data gets written after each object write.

It's been a while since I worked in this area but it seemed to be more complex than simply wrapping writeObject. java.nio typically expects fixed size buffers (though you can dynamically allocate them I believe) and your remote endpoints need to know how much to read for an arbitrary Object coming down the wire. What I ended up doing was to send an initial int header telling the other end how much data to expect, and then serializing the object to a byte array and sending that down the wire.
I've got an example of this that may still have some bugs, so use at your own risk. The PendingDataBufferS are needed to deal with objects that are larger than the initially allocated fixed size buffer.

Related

ObjectOutputStream objects sometimes flush automatically. How can I know exactly when to rely on this behavior and when to flush manually?

I've noticed that sometimes, a thread calling a write method on an ObjectOutputStream object, like writeUTF(), to send a value via a socket will flush the data automatically, so that there is no need for me to call flush() on the object. The thread at the other end of the communication line receives the data just fine. This has worked even when the sender thread writes on the stream object many hundreds of times under a loop.
Other times, my threads are deadlocked because the sender threads are not sending the data. This problem is fixed when I manually call a flush() method immediately after invoking, for example, writeUTF().
I doubt that this is random. I think there must be some specific circumstance under which threads writing to a stream flush the data automatically. I would like to know what those circumstances are, if any.
This is implementation dependent and may change depending on platform, version, and build of Java. Your best bet is to call flush() whenever you might need to. If there is no data to be flushed, a call to flush() is extremely fast, so this will not significantly slow down your program.

Do Java sockets support full duplex?

Is it possible to have one thread write to the OutputStream of a Java Socket, while another reads from the socket's InputStream, without the threads having to synchronize on the socket?
Sure. The exact situation you're describing shouldn't be a problem (reading and writing simultaneously).
Generally, the reading thread will block if there's nothing to read, and might timeout on the read operation if you've got a timeout specified.
Since the input stream and the output stream are separate objects within the Socket, the only thing you might concern yourself with is, what happens if you had 2 threads trying to read or write (two threads, same input/output stream) at the same time? The read/write methods of the InputStream/OutputStream classes are not synchronized. It is possible, however, that if you're using a sub-class of InputStream/OutputStream, that the reading/writing methods you're calling are synchronized. You can check the javadoc for whatever class/methods you're calling, and find that out pretty quick.
Yes, that's safe.
If you wanted more than one thread reading from the InputStream you would have to be more careful (assuming you are reading more than one byte at a time).

Sending buffered data through a socket from Android

I develop the first part of an Android application that allows to broadcast video stream through the network. Currently, I'm sending the video in a very direct way, like this:
Socket socket = new Socket(InetAddress.getByName(hostname), port);
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
recorder.setOutputFile(pfd.getFileDescriptor());
But unfortunately, it is not very fluid. I want to buffered the data stream before sending it through the socket. One of the way I tried is to write the stream in a file using the Android API for recording media, and to use another thread to stream the file to the server on a conputer.
So my problem is: how can I send by a socket a file which is still under writing?
As BufferedInputStream has not a blocking method for reading, I tried to do things like this one, but without any success
while (inputStream.available() >= BUFFER_SIZE) {
inputStream.read(buffer);
outputStream.write(buffer);
}
outputStream.flush();
But when i'm doing that, if the network is faster than the datastream, I get quickly out of the loop.
Is there a 'good' way to do that? I though about doing active waiting but it is not a good solution, especially for mobiles. Another way is to do something like this :
while (true) {
while (inputStream.available() < BUFFER_SIZE) {
wait(TIME);
}
inputStream.read(buffer);
outputStream.write(buffer);
}
outputStream.flush();
But it sound quite dirty for me... Is there sleeker solution?
What I do in these situations if simply fill up a byte array (my buffer) until either I've hit the end of the data I'm about to transmit, or the buffer is full. In which case the buffer is ready to be passed to my Socket transmission logic. Admittedly, I do not do this on video or audio though … only on “regular” data.
Something worth noting is this will give a "janky" user experience to the recipient of that data (it might look like the network is stopping for short periods then running normally again ... the time the buffer is using to fill up). So if you have to use a buffered approach on either video or audio be careful on what buffer size you decide to work with.
For things like video it's been my experence to use streaming based logic versus buffered, but you apparently have some different and interesting requirements.
I can't think of a pretty way of doing this, but one option might be to create a local socket pair, use the 'client' end of the pair as the MediaRecorder output fd, and buffer between the local-server socket and the remote-server. This way, you can block on the local-server until there is data.
Another possibility is to use a file-based pipe/fifo (so the disk doesn't fill up), but I can't remember if the Java layer exposes mkfifo functionality.
In any event, you probably want to look at FileReader, since reads on that should block.
Hope this helps,
Phil Lello

How can I serialize an object to a non-blocking socket in java

I have been reading about java nio and non-blocking sockets and I want to write serialized objects into the socket. I was reading this article here http://www.owlmountain.com/tutorials/NonBlockingIo.htm#_Toc524339525, and it says if you wrap your non-blocking socket around a PrintWriter, it will be blocking. I wonder if it's the same if I wrap my socket.getOutputStream around an ObjectOutputStream? Any easy way to test if a wrapper will be blocking or not? I couldn't find any mentions of this in the PrintWriter or ObjectOutputStream documentation.
Here' a code snippet from the article above:
else if ( key.isWritable() ) {
Socket socket = (Socket) key.attachment();
PrintWriter out = new PrintWriter( socket.getOutputStream(), true );
out.println( "What is your name? " );
}
Not sure if you missed it or not, but the article clearly says than any conventional I/O utilities used won't cut in and goes out to present the sample code for reading and writing text from asynchronous channels. Here is the relevant extract:
The problem with this code is that the
PrintWriter blocks I/O and does not
support the underlying asynchronous
I/O mechanisms. To deal with this
problem, we cannot use any of the
standard I/O utilities, but instead
must wrap our message in a ByteBuffer
object and send it through the
SocketChannel object
Is that code not working in your case?
You said:
I am trying to figure out how to
convert an object into a byte[].
Strings have the getBytes() method. I
am not sure what to use for a general
serializable Object. I have been using
ObjectOutput/InputStream classes but
according to the article, if I use
them, it will be blocking again. Am I
understanding this correctly?
You are correct; wrapping the I/O streams with ObjectInputStream/ObjectOutputStream would again end up blocking things. The solution here might be to wrap a ByteArrayOutputStream in an ObjectOutputStream and write your objects to the underlying byte array. This underlying byte stream/array now has the byte representation (which follows the Java serialization specification obviously) of your object. From there on, it's the normal stuff with NIO. In case you are interested, there are some nice discussions here and here related to the thing I'm talking about.
EDIT: Also, I agree with the article's author that NIO is tricky to get right. The author recommends Apache Mina but I'll like to add another recommendation, "Jboss Netty". The author of Netty frequents SO so you can get your queries answered.
I'd also like to point out that if your motivation is to send across Java objects, use a framework which is tuned to those needs i.e. Java RMI or JBoss remoting. Much easier than mucking around with object streams etc.

Java: ignoring an input stream - will buffers overflow and bad things happen?

I have a client connecting to my server. The client sends some messages to the server which I do not care about and do not want to waste time parsing its messages if I'm not going to be using them. All the i/o I'm using is simple java i/o, not nio.
If I create the input stream and just never read from it, can that buffer fill up and cause problems? If so, is there something I can do or a property I can set to have it just throw away data that it sees?
Now what if the server doesn't create the input stream at all? Will that cause any problems on the client/sending side?
Please let me know.
Thanks,
jbu
When you accept a connection from a client, you get an InputStream. If you don't read from that stream, the client's data will buffer up. Eventually, the buffer will fill up and the client will block when it tries to write more data. If the client writes all of its data before reading a response from the server, you will end up with a pretty classic deadlock situation. If you really don't care about the data from the client, just read (or call skip) until EOF and drop the data. Alternatively, if it's not a standard request/response (like HTTP) protocol, fire up a new thread that continually reads the stream to keep it from getting backed up.
If you get no useful data from the client, what's the point of allowing it to connect?
I'm not sure of the implications of never reading from a buffer in Java -- I'd guess that eventually the OS would stop accepting data on that socket, but I'm not sure there.
Why don't you just call the skip method of your InputStream occasionally with a large number, to ensure that you discard the data?
InputStream in = ....
byte[] buffer = new byte[4096] // or whatever
while(true)
in.read(buffer);
if you accept the connection, you should read the data. to tell you the truth i have never seen (or could forsee) a situation where this (a server that ignores all data) could be useful.
I think you get the InputStream once you accept the request, so if you don't acknowledge that request the underlying framework (i.e. tomcat) will drop that request (after some lapsed time).
Regards.

Categories

Resources