SocketChannel.write()

I've written a non-blocking server and am trying to test it with a client that uses the traditional (blocking) I/O. The problem I'm running into is when the server tries to write data to the client, it seems to take an inordinate amount of time.
Often times the SocketChannel.write() method will return zero and write nothing to the socket when it has a perfectly good ByteBuffer available to be written. The Javadoc for the SocketChannel.write() states this is normal:
Some types of channels, depending upon their state, may write only some of the bytes or possibly none at all. A socket channel in non-blocking mode, for example, cannot write any more bytes than are free in the socket's output buffer.
So I put the following statement in the code:
while ((retVal = socketChannel.write(outputBuffer)) == 0);However, this is proving to be quite slow, sometimes taking over half a second to complete a write of around 1000 bytes.
While this solution delivers all of the data, it is slow. Has anybody run into this, and if so, found a better solution?
Thanks,
Ken

I feel compelled to reply to myself to keep this alive, so to add:
It seems like the delays being experience here would not happen with blocking sockets and that this is a function of NIO. What I don't understand is why socket channel takes so long to know when it can write again. Waiting over half a second for one write of a 1000 byte message is not acceptable.
Is it because I am not using a Selector? Would that tell me the channel is ready any faster? I wouldn't see why. Or is it because the client application is reading the data too slowly?
Any help would be appreciated.
Ken

Similar Messages

  • Exceptions not thrown on interrupted SocketChannel.write()

    I just noticed a behaviour of java.nio.channels.SocketChannel.write() that makes me wonder. If write() blocks(), and the channel is closed during this blocking by another thread, AsynchronousCloseException should be thrown.
    However, in most cases this does not happen in my little test app. If any part of the data passed to write() has already been written to TCP before the socket was closed, write() returns without exception.
    Similar behaviour is observed with intterupting. If the thread blocked in write() is interrupted by another thread, it returns immediately and has the interrupted Flag set, but in most cases no Exception is thrown.
    ClosedByInterruptException is only thrown if not any part of the data passed to write() has been passed to TCP.
    Is this a bug or a feature ?

    Yes, i'm pretty sure that it blocks. In my test, the server just accepts the connection and then goes to sleep for a looooong time. The client just connects, and sends 10Meg of fata in one write() call. If i do not interrupt the client, it blocks as long as the server sleeps. In this case, this is the client's stack while blocking:
    Thread [main] (Suspended)     
         FileDispatcher.write0(FileDescriptor, long, int) line: not available [native method]     
         SocketDispatcher.write(FileDescriptor, long, int) line: 29     
         IOUtil.writeFromNativeBuffer(FileDescriptor, ByteBuffer, long, NativeDispatcher, Object) line: 104     
         IOUtil.write(FileDescriptor, ByteBuffer, long, NativeDispatcher, Object) line: 75     
         SocketChannelImpl.write(ByteBuffer) line: 334     
         Channels.write(WritableByteChannel, ByteBuffer) line: 60     
         Channels.access$000(WritableByteChannel, ByteBuffer) line: 47     
         Channels$1.write(byte[], int, int) line: 134     
         Channels$1(OutputStream).write(byte[]) line: 58     
         SocketClient.main(String[]) line: 75     If i start another thread before calling write(), that closes the socket after 3 seconds, the following happens: The call of IOUtil.write() returns ( with a value n that i cannot see in the debugger ), This value n is tested inside SocketChannelImpl.write() via (n > 0 || (n == IOStatus.UNAVAILABLE), what return true. For that reason, AbstractInterruptibleChannel.end(boolean), does not throw an exception.
    Once the server wakes up later, it is able to read about 200K from the socket...
    I tried this on a linux system (kernel 2.6.17, glibc 2.4) with jdk 1.6.0_03. I'm now gonna try it under windows, hold on..
    Of course, if anybody is interested, i'll post the test proggy...

  • SocketChannel.write() on J2SDK1.4.2_04/Windows 2000

    Hello,
    I have a question regarding SocketChannel.write() (as I mentioned before, I am using J2SDK 1.4.2_04 on Win 2000 pro).
    I prepared a ByteBuffer with some binary data. When I invoke SocketChannel.write(), the other application receives the data only until the first null (byte = 0) character is found??? What am I doing wrong??
    Thanks.

    On the other side, I get the message
    Read: ZYKT
    (only the first 4 bytes of the message)
    I experimented adding more non-null characters and the
    result was
    Read: ZYKT08@AYes, but (again) what does the CODE look like? Maybe it's written incorrectly to stop when it gets a null byte. Or maybe it stuffs it into a C-style char array (which is null-terminated by convention) and just happens to print up to the null (as C-style char array functions are designed to do). Or, who knows? You're not showing what that client process looks like.

  • SocketChannel.write() throws IOException instead of returning 0

    I would like your opinion.
    When a send buffer is full in the OS, should a channel's write()
    return 0, or throw an exception? If an exception, should it be the
    same exception (IOException) thrown when truly exceptional events
    happen (e.g, a connection drop)?
    On Win32, SocketChannel.write() internally calls WSASend(). When
    WSASend() returns WSAEWOULDBLOCK, write() throws IOException. I
    think it should return zero instead, or at least throw an exception
    that can be distinguished easily (by other than parsing the
    IOException.getMessage())
    Should I submit a bug?
    Thanks,
    Juan

    The java doc for write() says it should return zero. If you have a simple test case that demonstrates the behavior you describe and it is not already in the bug database, then yes. You should file the bug report.

  • SelectionKey.OP_WRITE versus SocketChannel.write(ByteBuffer)

    I'm writing a small Socket server using Non blocking approach based on the ractor design pattern.
    Many samples use the OP_WRITE on the selection keys to know when the channel is ready to accept writes.
    I use the SocketChannel.write(ByteBuffer) whenever I need to write instead.
    Is there a reason why SelectionKey.OP_WRITE is prefered in the samples??????
    Thanks
    Stéphane

    Rainman4500 wrote:
    I'm writing a small Socket server using Non blocking approach based on the ractor design pattern.
    Many samples use the OP_WRITE on the selection keys to know when the channel is ready to accept writes.
    I use the SocketChannel.write(ByteBuffer) whenever I need to write instead.
    Is there a reason why SelectionKey.OP_WRITE is prefered in the samples??????
    So that you don't attempt a write unless the channel can accept some data from you. In your example, suppose you actually transfer 0 bytes because the output buffer is still full. What do you do then?

  • Does SocketChannel.write() block

    I have a server communicating with it's clients using NIO and therefore SocketChannel's. When data are send to clients, the method SocketChannel.write(ByteBuffer) are used. The question is then, does the execution time depend of SocketChannel.write() depend on the speed of the client to receive data? Does the the method block in any way, or does it just send what is possible and then returns?

    If you have the channel in blocking mode, it also depends on how fast the client is reading. If the client isn't reading at all, ultimately its receive buffer will fill up, then the sender's sending buffer will fill, and then the write will block waiting for space in the send buffer; once the client starts reading again, space will become available and the write can complete. That's not to say that every write waits for the completion of every prior read, it's a matter of buffering and windowing, and the effect is rather decoupled because of the presence of two intermediate buffers. However it certainly can occur.

  • Socketchannel  write(bytebuffer)

    I use nio socketchannel write(bytebuffer [])method.
    In my program,as following...
    buff.clear();
    sc.read(buff);
    buff.flip();
    sc.write();
    sc.close();//Ok,when this line is not been marked.
    In another program,
    msg(String s)
    buff.get(s.getBytes());
    buff.flip();
    sc.write(buff);//No close(),and problems come,in design,
    sc can not close()
    How to solve the problem?

    You didn't show any client-side code, did you? Are you using a selector? If so, it could be that your select logic is wrong, causing you to miss when the socket first becomes readable (happened to me, for instance).
    When you ctrl-c the server, a TCP FIN packet gets sent to the client - if you were blocked in a select on the client side, it'd break out - and since the data in the TCP receive queue would still be there to read, your application would be able to read it out before getting an EOF on the socket.
    --bruce                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       

  • SocketChannel.write() blocking application

    Greets,
    I'm developping a huge application and got a latency/block problem using the write(ByteBuffer) method on a Socket from a socketchannel connection.
    Running java 1.5 (diablo) on Freebsd 6 servers, 4Gb ram (2.2 allocated to jvm), with dual xeon dual-core (total 4 cores)
    Here is the application schema :
    - A thread accepting connexion on the socketchannel
    - A thread selecting keys with data to process, enqueuing it after some basic checks on a command FIFO
    - A thread getting commands from the FIFO and processing 'em, generating answers on 4 answer FIFOs
    - 4 threads (1 per FIFO) to get answers and send 'em back to the socket.
    The application usually runs with 4500-5000 simultaneous clients.
    My problem is that the only write() method sometimes takes over 20ms to write a message, with a length smaller than 50 bytes.
    As I got about 25000 answers to process each second, when some of 'em decide to be slow, the 4 threads runs slowly, and all the connected clients are suffering of that latency, for the few minutes needed to empty the FIFOs.
    Every client socket get about 5 answers per second.
    On about 1 hour running, there are about 3 'peaks' of slowness, that I cannot explain yet. That's why I'm in need of advices !
    I monitored the application when such case happens. TOP indicates 40% cpu idle, JVM memory got >500Mb free, network runs @ about 1.2Mbps, where maximal transfer rate is >20Mbps. netstat -m told me no erros, and a large amount of free buffers available.
    As the only slow process is the write() method that usually runs faster than 1ms each call, but in those case I got delays over 20ms.
    freebsd tcp default sendbuffer size is 64k, receive buffer is 32k
    Commands average received size is below 1k, Answers average sending size below 8k.
    This application is running live, and as I cannot emulate 5000+ connections with a similar beahviour to test withour being sure that won't crash all.
    What points could be responsible of such slow write() calls ? Seems it's not CPU, not RAM, not network itself...
    I suppose it's the network buffers that are causing problems. But I don't really know if I have to fit 'em to a lower size, fitting my requirements, or to a larger size, to be sure there won't be full buffers blocking all ?
    I need advices. Thanks for your ideas !
    Bill

    Hmm. So you're happy to lose data?
    A few comments:
    (a) SocketChannels are thread-safe. I don't think you need the synchronization at all, unless maybe multiple writing threads are possible. I would eliminate that possibility and the sync myself.
    (b) If you're getting write delays of 30ms occasionally, the sync must also take 30ms at the same points if it is doing anything at all, i.e. if the possibility of multiple writing threads does exist. So maybe it doesn't?
    (c) I would have a good look at this:
    http://forum.java.sun.com/thread.jspa?threadID=459338
    and specifically the part on how to manage a channel that presents write blocks, using OP_WRITE when it happens and turning it off when it doesn't.
    (d) You seem to be using one output buffer for all channels. You might be better off using a small one per channel. Then that way you don't clear, you just do put/flip/write/compact, and if the write returned 0 just post OP_WRITE for next time around the select loop. Then you won't lose any data at all, except to a client who really isn't reading: you can detect that situation by keeping track of the last successful write time to a channel, and when there is pending data and the last write is too long ago have a think about what the block means in terms of the application. Maybe you should just disconnect the client?
    (e) It would be interesting to know how many times the write loop looped when you get these large delays, and also what the data size was, and also to know that for the other cases to see if there is a difference.
    (f) Generally from a fairness point of view I prefer not to have write loops, just one attempt and if it returns even a short read I post OP_WRITE as above. Otherwise you're spending too long servicing one channel.
    You can contact me offline via http://www.telekinesis.com.au if you like.

  • NIO Echo Server SocketChannel.write() multiple times?

    Hello,
    I have found and experimented with two simple nio echo socket servers,
    one from hutchinson's book. The other has similar code:
         if (key.isWritable())
         SocketChannel client = (SocketChannel) key.channel();
         ByteBuffer output = (ByteBuffer) key.attachment();
         output.flip();
         client.write(output);
                         output.compact();
         }but in my client, I noticed that when I send something to the server,
    apart from echoing it back it also sends back about 90 empty
    strings, which fire in my client's onData() event.
    Is this normal or am I missing something?
    Message was edited by:
    Robse

    This code is correct, and it can't send empty strings. The error is elsewhere.

  • Problems with SocketChannel.write(ByteBuffer buff).

    I am using the following version of JDK on Red Hat Linux
    java version "1.4.2_01"
    Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_01-b06)
    Java HotSpot(TM) Client VM (build 1.4.2_01-b06, mixed mode)
    I am using SocketChannel's write method mentioned above to write data to the SocketChannel. When data is being written on the SocketChannel via this write method and the underlying socket is closed by the receiving endpoint, I expect this method to throw an exception. This method does not throw any exception and returns me 0 as the value of number of bytes written out.
    The way my code is written out, it ends up going in an infinite loop. Now, I can very well fix my code to not run in an infinite loop, but is anybody else seeing this? Is this a valid behavior? Am I doing something wrong?
    Following is the code snippet that writes data to the SocketChannel. Note that writeBuffer is an instance of ByteBuffer and sc is an instance of SocketChannel. Both these variables are member variables in my class:
    public void write(byte[] buff, int offset, int length)
        throws IOException
        int toBeWritten = 0;
        while (length > 0)
            int writeOffset = offset;
            toBeWritten = writeBuffer.remaining();
            if (toBeWritten >= length)
                // All the bytes that are scheduled to be written will be
                // written.
                toBeWritten = length;
                length = 0;
            else
                // Only some of the bytes that are scheduled to be written will
                // be written.
                length -= toBeWritten;
                offset += toBeWritten;
            writeBuffer.put(buff, writeOffset, toBeWritten);
            // toBeWritten is the number of bytes that need to be written out.
            while (writeBuffer.position() != 0)
                // position = toBeWritten.
                writeBuffer.flip();
                // position = 0, limit = toBeWritten.
                int wrote = sc.write(writeBuffer);
                // position = wrote, limit = toBeWritten.
                // Compact the write buffer. It is very much possible that all
                // the bytes have not yet been written out.
                writeBuffer.compact();
                // The data that was written out, is now removed from the write
                // buffer. position = toBeWritten - wrote, limit = capacit
    }Thanks in advance!!

    When ByteBuffer.write(...) return 0, it means this
    socket is closed gracefully by another peer. the
    socket is need to re-connect again.Oh.. I forgot to mention, I am using non blocking SocketChannel. As per the Java docs for write(ByteBuffer src) method in WritableByteChannel:
    "Some types of channels, depending upon their state, may write only some of the bytes or possibly none at all. A socket channel in non-blocking mode, for example, cannot write any more bytes than are free in the socket's output buffer."
    So, I cannot assume that if the write method returns 0, the socket is closed by another peer.

  • Can SocketChannel.write return -1 ?

    Hi,
    In the SSLEngine documentation sample code it mentions handling a -1 returned by Channel.write() if the channel is closed.
    This is the only place I've ever seen it mentioned, there's nothing in the javadoc, and I've never come across it in practice.
    Can anybody confirm that this is just a mistake - or is it something my code needs to handle ?
    regards
    Tony Seebregts

    I've just submitted this as a bug. It occurs twice in the sample: once in the I/O section and once in the shutdown section. The tests for num == -1 and the associated empty code block and comment should be deleted. The code seems to have been copied & pasted from the read() block, where a -1 return is indeed valid.
    Also in the shutdown section it incorrectly has
    while (myNetData().hasRemaining())which should be
    while (myNetData.hasRemaining())Also surely myNetData needs to be flipped before the write and compacted afterwards, which means that the test should really be not hasRemaining() but position() > 0. hasRemaining() would only work if the buffer was already flipped.

  • SocketChannelImpl write data corruption issue

    Hi,
    I am new in working with the SocketChannelImpl class.. In fact java is not my forte.. I come from the C++ world. Recently we ported a socket based communication library originally written in C++ (this lib allows various processes in our App to communicate via sockets) to java to allow integration with an existing java application. We chose to use the same communication library in java to allow seamless application level integration.
    Things works fine mostly except few quirky-ness with data payload integraity when passed between the java based process to C++ based process. This app is running on solaris 10 with mostly latest patchset.
    Here is the typical action doen while communicating:
    - An object at the java process end is encoded in to an ASCII (UTF8/ISO-8859-1) char stream with delimeters like "\t", 0x07, etc. This results in a contiguous char stream.
    - The data is then pushed over the socket to the peer process.
    - The C++ process end then receives the payload and decode the data to recontruct the object with known delimeter, data markers, etc.
    We have not seen any issues with communication between C++ processes, however we have seen that between the java process and any other C++ processes, the payload contents changes for certain locations in the char stream. I have debugged from both the java end and c++ end simulataneously and see that when the char stream raw data (byteBuffer) is pushed out from java side in SocketChannelImpl.write() method, the char stream buffer looks perfectly OK in the byteBuffer, however when the read is done in the C++ process side and when I look at the raw data received, I see that some char sequences have changed!! This obviously causes problems in the C++ side decoding of the raw data.
    Here is the java code that sends the encoded dat (The method receives the raw char stream in the byte array buffer )
    final byte[] tmpBuffer = new byte[size];
    System.arraycopy(buffer, 0, tmpBuffer, 0, size);
    final ByteBuffer socketBufferWrite = ByteBuffer.wrap(tmpBuffer);
    int ErrorLoop = 0;
    final int MAX_LOOP = 100;
    int TotalWritten = 0;
    do {
    result = -1;
    try {
    result = socketCh.write(socketBufferWrite);
    } catch (final IOException ex) {
    trcStalker.logException(ex);
    if (result != -1) {
    TotalWritten += result;
    if (TotalWritten < size) {
    result = -1;
    if (result == -1) {
    ErrorLoop++;
    try {
    Thread.sleep(100 * ((ErrorLoop / (MAX_LOOP)) + 1)); //
    m to catch up
    } catch (final InterruptedException ex) {
    trcStalker.logException(ex);
    } // Wait a bit for the system to catch up
    } while ((result == -1) && (ErrorLoop < MAX_LOOP));
    My question to you would be what can cause the payload to get corrupted on the wire in socketchannelImpl.write() method invocation? I have tried using directAllocated Vs allocated Vs wrapped byteBuffers.. but the result has been same.
    I have not been able to find any pattern of corruption either, i.e. not seeing that the corrupted charactes are increased or decreased by certain number in the charset. However I have seen that certain locations in the buffer always gets changed.
    Any idea in debugging/fixing this issue? This thing is driving me nuts!
    thansk in advance.

    final byte[] tmpBuffer = new byte[size];
    System.arraycopy(buffer, 0, tmpBuffer, 0, size);
    final ByteBuffer socketBufferWrite = ByteBuffer.wrap(tmpBuffer);You can collapse all that to:
    final ByteBuffer socketBufferWrite = ByteBuffer.wrap(buffer, 0, size);
    result = socketCh.write(socketBufferWrite);
    } catch (final IOException ex) {
    trcStalker.logException(ex);
    if (result != -1) {SocketChannel.write() never returns -1. It can return zero if you are in non-blocking mode. Are you? Otherwise it can only return a positive integer. If you get any kind of IOException while writing to the socket the connection has been dropped and you should close the socket and start all over again. Retrying a write after an IOException is just a waste of time.
    if (TotalWritten < size) {
    result = -1;TotalWritten can be anything between 0 or 1 depending on your blocking mode, and 'size'. This is not an error.
    Thread.sleep(100 * ((ErrorLoop / (MAX_LOOP)) + 1));    //What is the purpose of this sleep?
    My question to you would be what can cause the payload to get corrupted on the wire in socketchannelImpl.write() method invocation?Nothing except bad coding at one end or the other.
    I have tried using directAllocated Vs allocated Vs wrapped byteBuffers.. but the result has been same.Have you tried using java.net.Socket? Much simpler.
    I have not been able to find any pattern of corruption either, i.e. not seeing that the corrupted charactes are increased or decreased by certain number in the charset. However I have seen that certain locations in the buffer always gets changed.It could be a disagreement about charsets between the sender and the receiver.

  • NIO problem: multiple write

    Hello.
    I am using a NIO server for my application with a pool of WorkingThreads to handle client requests.
    The read part seems to work fine (I am deregistering the OP_READ interest when I begin to read from the socketchannel and I register it back when I finish processing the data). This way I am able to process data coming in chunks down the stream.
    Now, the problem I have is with writing data back to the client. If I send the data with only 1 socketChannel.write(ByteBuffer) method the client gets it correctly. But if I try to write in a while() loop more messages it happens that the client receives the first chunk correctly but SOMETIMES it receives rubbish as the next chunks. My guess is that after the first write(), the server may send some zeros to the client just before the next chunk so the client interprets that as valid data.
    I have tried to unregister the key from writing (key.interestOps(key.interestOps() & (~SelectionKey.OP_WRITE))) immediatelly after I've done a write() and reregister it for writing just before I want to send the data but this didn't help. I'm sure this is solvable but I haven't met anywhere code that deals with writing more than 1 buffer (like writing a big file for example).
    Any help would be very much appreciated.
    Thank you.
    Bogdan

    Thank you for replying, ejp, but it seems that what you said is not quite true. Here is my send method:
    public void send(SelectionKey key) {
         try {
              if (sendMessages.size() != 0) {
                   String message = null;
                   while (sendMessages.size() > 0) {
                        synchronized (sendMessages) {
                             message = (String) sendMessages.removeFirst();
                        ByteBuffer theBuffer = ByteBuffer.wrap(message.getBytes());
                        theBuffer.put(message.getBytes());
                        theBuffer.flip();
                        ((SocketChannel) key.channel()).write(theBuffer);
                        theBuffer.flip();
                        log.debug("Sent message:" + decoder.decode(theBuffer));
              key.interestOps(key.interestOps() | SelectionKey.OP_READ);
              key.interestOps(key.interestOps() & (~SelectionKey.OP_WRITE));
         } catch (IOException e) {
              key.cancel();
    }I verify what I send by outputting with the line log.debug("Sent message:" + decoder.decode(theBuffer));The messages are strings which are being taken from a LinkedList. The chunks I'm sending are of size 4096 bytes.
    I forgot to mention that the client uses simple IO (blocking mode). In between the sendings from the server it receives zeros and considers them as part of the message.
    I am using Windows 2000 + JDK 1.4.2_01

  • NIO write flush problem?

    Hello there,
    I've got a odd problem here, and it's going to be hard to explain so please excuse me if I haven't explained correctly. I'm writing a Java application, which uses nio, with non blocking sockets, to handle its networking. I presumably have a problem with writing data. Quick recap of the problem is that for some reason, data gets concatenated to each other and then sent. So for example, let's say I'd want to send 'hello' and 'there'. What my application sometimes does, is sending 'hellothere' instead of sending 'hello', and then, in a new packet, 'there'.
    What now happens on the server side is that it receives 'hellothere' and doesn't know what do with it, while it would have worked fine if they were separated.
    This is a snippet coming from the server. This is always running on background (in a thread), in a loop.
    synchronized (m_ChangeRequests)
                        Iterator changes = m_ChangeRequests.iterator();
                        while (changes.hasNext())
                            ChangeRequest change = (ChangeRequest)changes.next();
                            switch (change.getType())
                                case ChangeRequest.CHANGEOPS:
                                    SelectionKey key = change.getSocket().keyFor(m_Selector);
                                    try
                                        key.interestOps(change.getOps());
                                    catch (NullPointerException e)
                                        disconnectClient(getClientWithChannel(change.getSocket()));
                        m_ChangeRequests.clear();
    // Waiting for events
                    m_Selector.select(1000);
                    // Get keys
                    Set keys = m_Selector.selectedKeys();
                    Iterator i = keys.iterator();
                    // For each keys...
                    while(i.hasNext())
                        SelectionKey key = (SelectionKey) i.next();
                        // Remove the current key
                        i.remove();
                        // if isAccetable = true
                        // then a client required a connection
                        if (!key.isValid())
                            continue;
                        if (key.isAcceptable())
                            accept(key);
                        else if (key.isReadable())
                            read(key);
                        else if (key.isWritable())
                            write(key);
                    }Now, I suppose the important method here is write().
    private void write(SelectionKey key)
            SocketChannel socketChannel = (SocketChannel)key.channel();
            synchronized (m_PendingData)
                List queue = (List)m_PendingData.get(socketChannel);
                while (!queue.isEmpty())
                    try
                        ByteBuffer buf = (ByteBuffer)queue.get(0);
                        System.out.println(socketChannel.write(buf));
                        if (buf.hasRemaining())
                            continue;
                        queue.remove(0);
                    catch (IOException ioe)
                        ioe.printStackTrace();
                if (queue.isEmpty())
                    key.interestOps(SelectionKey.OP_READ);
                  As you can see I'm using a variable m_PendingData there, which is simply a HashMap. There is another important method, which is the send method.
    public void send(SocketChannel socket, byte[] data)
            synchronized (m_ChangeRequests)
                m_ChangeRequests.add(new ChangeRequest(socket, ChangeRequest.CHANGEOPS, SelectionKey.OP_WRITE));
                synchronized (m_PendingData)
                    List queue = (List)m_PendingData.get(socket);
                    if (queue == null)
                        queue = new ArrayList();
                        m_PendingData.put(socket, queue);
                    queue.add(ByteBuffer.wrap(data));
            m_Selector.wakeup();
        }You might have noticed the m_ChangeRequests variable. Please see the first code snippet for what it does. It's a LinkedList.
    Sorry if I have not explained it clear enough. I suppose this problem could also be in the read method, I assume it is in the write method though.
    Thanks,
    Lars

    Basically you can't think of reading and writing to/from sockets in terms of packets - you write some bytes to the socket at one end, and read some bytes at the other. This is true for both blocking and non blocking sockets.
    If you want your bytes to be split into meaningful packets, then you have to encode the packet format yourself. A really simple way to do that is to start each message with a fixed number of bytes that contain the number of data bytes in the packet - from your example this would give:
    5 hello 5 there
    On the reading end, your server will then be able to read the initial byte count of each packet and know how much data is expected.

  • Nio write problem: server data sent isn't fully read by client

    Hi everyone,
    still writing away with my nio server and once again have run into
    some problems. Essentially my main problem is that when the server
    writes to the client, the write appears to output all the bytes in the
    write operation, but the client never accepts them all, even if a
    buffer has been manually allocated to the correct size of the data.
    As background my server will accept connections. When a connection
    is established I register OP_READ on the key. When a OP_READ trigger
    occurs the server accepts the clients request, processes it, then
    attaches the output to the SelectionKey as a ByteBuffer that has
    already been encoded. At this point I then register OP_WRITE on that
    SelectionKey (as a side note i'm running this server on XP and had
    read that registering OP_READ and OP_WRITE on the same selector was
    bad, but then it looked like there was a work around to this) and wait
    for an OP_WRITE trigger.
    When an OP_WRITE occurs on that key I run a new method (with heavy
    influences from the thread: http://forum.java.sun.com/thread.jsp?forum=11&thread=530825 and the taming the nio circus thread) which will grab the attachment and attempt to send it. The code has been written that IF the send cannot complete it should re-attach the remaining bytebuffer to the key and wait for another OP_WRITE to occur so it can send the remainder.
    The problem is that whenever I write (and for this test the amount im writing is approx 10100 bytes) the server appears to send it all (by checking the int returned from socketchannel.write()), but at the client end it never reads all the data that is sent.
    If i'm using a blocking socket client, then I get a java.net.SocketException: Connection Reset exception, whilst if i'm using a non-blocking client, I get no exception, just not the whole amount of data, even when i've statically allocated a receiving bytebuffer that is big enough.
    The following code is a class that is used to do the writing from the server:
       /* code for nio write model referenced from:
         * http://forum.java.sun.com/thread.jsp?forum=11&thread=530825
        class NIOWriteHandler {
            private ByteBuffer sendBuffer;
            private SelectionKey localSelectionKey;
            NIOWriteHandler(SelectionKey currentKey) {
                localSelectionKey = currentKey;
            public void doWrite() {
                localSelectionKey.interestOps(SelectionKey.OP_READ);  //deselect write,
                sendBuffer = (ByteBuffer)localSelectionKey.attachment();
                // perform the writing
                SocketChannel writingChannel = (SocketChannel)localSelectionKey.channel();
                if (writingChannel.isOpen()) {
                    int len = 0;
                    if (sendBuffer.hasRemaining()) {
                        try {
                            System.out.println("Sending chunks o data");
                            len = writingChannel.write(sendBuffer);
                            System.out.println("value of len: " + len);
                        } catch (IOException ioe) {
                            ioe.printStackTrace();
                            // call close method
                            System.out.println("CLOSE INVOKED at POINT 8");
                            closeComplete(localSelectionKey);
                    System.out.println("Second IF coming...");
                    if (sendBuffer.hasRemaining()) {
                        // if we get here then the previous write did not fully
                        // complete, so need to save data etc
                        System.out.println("Couldn't send all data this time...");
                        localSelectionKey.interestOps(SelectionKey.OP_WRITE|SelectionKey.OP_READ);
                        localSelectionKey.attach(sendBuffer);
                    } else {
                        sendBuffer = null;
                        closeComplete(localSelectionKey);
                // write complete at this stage
        }This is the basic block client that is incredibly dumb:
    import java.net.*;
    import java.util.*;
    import java.io.*;
    import java.nio.charset.*;
    import java.nio.channels.*;
    import java.nio.*;
    import java.nio.ByteBuffer;
    public class ServerTest {
        /* args 0 - the IP of the machine to connect to
           args 1 - the port number
           Simple client that connects to a specified IP & port, takes a line
           of input via stdin, sends that to the connected machine and prints
           out the response.
           Error handling and such isn't accounted for.
       public static void main (String args[]) throws Exception{
            Socket socket = new Socket(args[0], Integer.parseInt(args[1]));
            BufferedReader buffRead = new
                BufferedReader(new InputStreamReader((socket.getInputStream())));
            PrintStream ps =
                new PrintStream(socket.getOutputStream());
            Charset charset = Charset.forName("ISO-8859-1");
            BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("[CLIENT]Data to send: ");
            String data = stdin.readLine();
            ps.println(data);
            String returned = buffRead.readLine();
            while (returned != null) {
                System.out.println(returned);
                returned = buffRead.readLine();
            System.out.println("[CLIENT]End server response");
            buffRead.close();
            ps.close();
            socket.close();
    }And here is the non-blocking basic client (which dosn't actually close at the moment):
    import java.net.*;
    import java.util.*;
    import java.io.*;
    import java.nio.charset.*;
    import java.nio.channels.*;
    import java.nio.*;
    public class ServerTestNonBlock {
        /* args 0 - the IP of the machine to connect to
           args 1 - the port number
           Simple client that connects to a specified IP & port, takes a line
           of input via stdin, sends that to the connected machine and prints
           out the response.
           Error handling and such isn't accounted for.
       public static void main (String args[]) throws Exception{
            InetSocketAddress addr = new InetSocketAddress
                (args[0], Integer.parseInt(args[1]));
            SocketChannel sc = SocketChannel.open();
            sc.configureBlocking(false);
            Selector selector = Selector.open();
            System.out.println("Starting connection...");
            sc.connect(addr);
            while(!sc.finishConnect()) {
               System.out.println("1,2,3,4 I will keep on counting...");
            System.out.println("Connection established..");       
            Charset charset = Charset.forName("ISO-8859-1");
            CharsetEncoder encoder = charset.newEncoder();
            sc.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
            while (true) {
               int n = selector.select();
               if (n==0) {
                  continue;
               Set keys = selector.selectedKeys();
               Iterator it = keys.iterator();
               while (it.hasNext()) {
                  SelectionKey selKey = (SelectionKey)it.next();
                  if (selKey.isReadable()) {
                     // time to setup read
                     ByteBuffer incomingData =
                        ByteBuffer.allocateDirect(102000);
                     incomingData.clear();
                     int count;
                     while ((count = sc.read(incomingData)) > 0) {
                        System.out.println("Value of count: " + count);
                        // reading the data
                     System.out.println("Count value: " + count);       
                     int pos = incomingData.position();
                     incomingData.flip();
                     CharBuffer content = charset.decode(incomingData);
                     String inData = content.toString();
                     System.out.println(inData.trim());
                     System.out.println("[CLIENT]End server response");
                     System.out.println("Count value: " + count);       
                     System.out.println("Position value: " + pos);       
                     //sc.close();
                     //break;
                  if (selKey.isWritable()) {
                     BufferedReader stdin = new BufferedReader
                       (new InputStreamReader(System.in));
                     System.out.println("[CLIENT]Data to send: ");
                     String data = stdin.readLine();
                     ByteBuffer byteBufferOut = encoder.encode
                        (CharBuffer.wrap(data));
                     int length = sc.write(byteBufferOut);
                     System.out.println("Wrote: " + length + " bytes.");
                     selKey.interestOps(SelectionKey.OP_READ);
    }I'm kinda stuck at the moment and am making change for the sake of change without getting a good grasp of what is going on. If anyone can provide any help that'd be fantastic. If in the mean time I figgure something out i'll post a response.
    If you've gotten this far thanks a bunch for reading :)
    Cheers,
    Pete

    Hi Meesum,
    thanks for the reply :)
    I'm not convinced this is the error - as i've got two clients listed there, and the odd behaviour from both is that neither is getting through to the last of the data that is sent.
    If the null were the problem (which is only checked for in the basic dumb blocking client) i'd be expecting some sort of infinite loop or wait for more data from the server, not an abnormal termination (ala connection reset) from the server. I'll give it a shot anyhow, but I know that under a blocking write operation that that code worked fine.
    Thanks again though for the post, has got some of my cogs slowly turning :)
    Cheers,
    Pete

Maybe you are looking for