I can sent small data using java nio.
But If I want to send a very large data then my socket channel did not work fine.
message = "very large data"+"\n";
ByteBuffer buf = ByteBuffer.wrap(message.getBytes());
int nbytes = channel.write(buf);
all the data is sent.
I want to read data from server so i am using BufferedInputStreaReader.readLine();
In this case I am not getting any error also i cannot retrieve any of the data that i have sent
Thanks
Deepak
write()
Returns:
The number of bytes written, possibly zero
Write is not guaranteed to write your whole buf.
You need to check how much that was written, and do another write. (Probably also wait (select) until you can write again.)
You should probably also search for a good java.nio tutorial...
If you need a simpler api, use the blocking io in java.io instead...
Related
I want to implement a simple way to transfer Data from one client to another.
The implementation itself is not the question - it already works. I've a problem with the real transfer rate on sender side.
You all know the progress bars while you send files to another client using [put your desired chat/filetransfer program here]. You see the transferred bytes and the bytes left to transfer and maybe an estimated time until the transfer is complete. The same thing I try to implement too but it seems I've problems with the buffers in between.
While the send buffer is a nice feature - it affect the measured transfer rate to the other client enormously. Starting the transfer I get nearly infinite Bps and during the transfer the Bps reduce slowly but never get where the real transfer is.
The effect is that the sender visually finishes sending a file while the receiver still receiving bytes. This totally desync sender and receiver what I need to avoid (because of other reasons).
My first attempt sending a file was just like this (pseudo code):
while(still bytes left to read) {
Sender reading Byte-Array from InputStream (aka FileInputStream or something else)
Sender write and flushes this Byte-Array to the SocketOutputStream
}
This ends in the described situation where sender and receiver is totally desynced.
My next attempt was this:
while(still bytes left to read) {
Sender reading Byte-Array from InputStream (aka FileInputStream or something else)
Sender write and flushes this Byte-Array to the SocketOutputStream
Sender wait for ACK-Paket from Receiver
}
So the sender write the Byte-Array to the wire and wait for a small ACK-Paket from the receiver. After receiving the ACK the sender sends the next Byte-Array.
While this works as desired on slow connections (aka WAN connections to the internet) it is horrible slow on LAN connections.
I came to the conclusion that I don't like the ACK-Idea but I also don't like the desync situation.
How does other clients workaround such situations? Is there a way to disable the buffer so that outputStream.write(byte[]) just take as long as the wire need to transmit the data, or is there any other mechanism I can use to "see" how many bytes are transferred for real?
Thanks in advance
Martin
Instead of displaying what you have sent, display what the other end has told you it has received. i.e. the other end can send back the number of bytes it has received. This way your progress bar will be slightly pessimistic, rather than really optimistic.
Your problem is that you are trying to send the entire array you managed to read as a single object. On the sending side, you get a big array, call write and then flush which sends the entire array and waits for it to be flushed (with no control for you in between, so you sending app has no way to display progress). On the receiving end you get the same problem. You probably just call read which would read the entire ArrayList in a single operation.
Chances are, you are able to read a lot of data before you try to send it as a big array.
You can get some control if you break the array into reasonable "chunks" (maybe a simple max(1024, arraysize/100)). Then send the chunks one by one. The pseudo code would look like this:
chunkSize = max(1024, arraysize/100)
while(still bytes left to read) {
Sender reading chunkSize bytes into Byte-Array from InputStream
Sender write and flushes this Byte-Array to the SocketOutputStream
reportProgress()
}
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
I am using Java NIO's SocketChannel to write : int n = socketChannel.write(byteBuffer); Most of the times the data is sent in one or two parts; i.e. if the data could not be sent in one attemmpt, remaining data is retried.
The issue here is, sometimes, the data is not being sent completely in one attempt, rest of the data when tried to send multiple times, it occurs that even after trying several times, not a single character is being written to channel, finally after some time the remaning data is sent. This data may not be large, could be approx 2000 characters.
What could be the cause of such behaviour? Could external factors such as RAM, OS, etc cause the hindarance?
Please help me solve this issue. If any other information is required please let me know.
Thanks
EDIT:
Is there a way in NIO SocketChannel, to check, if the channel could be provided with data to write before actual writing. The intention here is, after attempting to write complete data, if some data hasn't been written on channel, before writing the remaining data can we check if the SocketChannel can take any more data; so instead of attempting multiple times fruitlessly, the thread responsible for writing this data could wait or do something else.
TCP/IP is a streaming protocol. There is no guarantee anywhere at any level that the data you send won't be broken up into single-byte segments, or anything in between that and a single segment as you wrote it.
Your expectations are misplaced.
Re your EDIT, write() will return zero when the socket send buffer fills. When you get that, register the channel for OP_WRITE and stop the write loop. When you get OP_WRITE, deregister it (very important) and continue writing. If write() returns zero again, repeat.
While using TCP, we can write over sender side socket channel only until the socket buffers are filled up and not after that. So, in case the receiver is slow in consuming the data, sender side socket buffers fill up and as you mentioned, write() might return zero.
In any case, when there is some data to be sent on the sender side, we should register the SocketChannel with the selector with OP_WRITE as the interested operation and when selector returns the SelectionKey, check key.isWritable() and try writing on that channel. As mentioned by Nilesh above, don't forget to unregister the OP_WRITE bit with the selector after writing the complete data.
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.
I've got this nasty problem where sending multiple, large messages in quick succession from a Java (NIO) server (running Linux) to a client will lead to truncated packets. The messages have to be large and sent very rapidly for the problem to occur. Here's basically what my code is doing (not actual code, but more-or-less what's happening):
//-- setup stuff: --
Charset charset = Charset.forName("UTF-8");
CharsetEncoder encoder = charset.newEncoder();
String msg = "A very long message (let's say 20KB)...";
//-- inside loop to handle incoming connections: --
ServerSocketChannel ssc = (ServerSocketChannel)key.channel();
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
sc.socket().setTcpNoDelay(true);
sc.socket().setSendBufferSize(1024*1024);
//-- later, actual sending of messages: --
for (int n=0; n<20; n++){
ByteBuffer bb = encoder.encode(CharBuffer.wrap(msg+'\0'));
sc.write(bb);
bb.rewind();
}
So, if the packets are long enough and sent as quickly as possible (i.e. in a loop like this with no delay), then on the other end it often comes out something like this:
[COMPLETE PACKET 1]
[COMPLETE PACKET 2]
[COMPLETE PACKET 3]
[START OF PACKET 4][SOME OR ALL OF PACKET 5]
There is data loss, and the packets start to run together, such that the start of packet 5 (in this example) arrives in the same message as the start of packet 4. It's not just truncating, its running the messages together.
I imagine that this is related to the TCP buffer or "window size", or that the server here is just providing data faster than the OS, or network adapter, or something, can handle it. But how do I check for, and prevent it from happening? If I reduce the length of message per use of sc.write(), but then increase the repetitions, I'll still run into the same problem. It seems to simply be an issue with the amount of data in a short amount of time. I don't see that sc.write() is throwing any exceptions either (I know that in my example above I'm not checking, but have in my tests).
I'd be happy if I could programmatically check if it is not ready for more data yet, and put in a delay, and wait until it is ready. I'm also not sure if "sc.socket().setSendBufferSize(1024*1024);" has any effect, or if I'd need to adjust this on the Linux side of things. Is there a way to really "flush" out a SocketChannel? As a lame workaround, I could try to explicitly force a complete send of anything that is buffered any time I'm trying to send a message of over 10KB, for example (which is not that often in my application). But I don't know of any way to force a send of the buffer (or wait until it has sent). Thanks for any help!
There are many reasons why sc.write() would not send some or all of the data. You have to check the return value and/or the number of bytes remaining in the buffer.
for (int n=0; n<20; n++){
ByteBuffer bb = encoder.encode(CharBuffer.wrap(msg+'\0'));
if(sc.write(bb) > 0 && bb.remaining() == 0) {
// all data sent
} else {
// could not send all data.
}
bb.rewind();
}
You are not checking the return value of:
sc.write(bb);
This returns the number of bytes written, which might be less than the data available in your buffer. Because of how nio works you can probably just call remaining() on your bytebuffer to see if there are any left.
I haven't done any NIO programming, but according to the Javadocs, sc.write() will not write the entire ByteBuffer if the SocketChannel is in non-blocking mode (as yours is) and the socket's output buffer is full.
Because you are writing so quickly, it is very likely that you are flooding your connection and your network or receiver cannot keep up.
I'd be happy if I could programmatically check if it is not ready for more data yet
You need to check the return value of sc.write() to find out whether your output buffer is full.
Don't assume you have any control over what data ends up in which packet.
More here: What's the best way to monitor a socket for new data and then process that data?
You are using the non-blocking mode: sc.configureBlocking(false);
Set blocking to true and your code should work as it is. Suggestions made by others here to check send count and loop will also work.