Solved

block I/O and reliability

Posted on 2003-11-08
18
296 Views
Last Modified: 2010-05-18
Hi, I use nio (buffers and channels) to transfer data over the network and was wondering if it is a totally reliable transfer (i.e. can data that sent using a channel get lost on the way?).   In my chat program, which seem to work alright, sometimes when I send a long string message such as "I want to eat an ice cream" the server sends back a string "I want to eat an ice cream \n n ice cream".   The last substring of the original message is sent along and after the original.   This does not happen all the time though, for example if I send "Hello", it returns "Hello" and that hasn't failed yet.   So I just wanted to know if this is possibly due to the nature of nio stuff and that I need to come up with a way to improve this communication protocol or because I encoded and decoded using "US-ASCII" and need to use other character set or if this is some logic error I made in my program.   Any suggestions?
0
Comment
Question by:skyblue01
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 9
  • 8
18 Comments
 
LVL 15

Expert Comment

by:JakobA
ID: 9708499
sounds like you are not flushing the buffer after telling it to send. ie: purely a programming error, have another look at the interface to the bufferedwriter class or whatever you are using.
0
 
LVL 92

Expert Comment

by:objects
ID: 9718419
Post the code you are using to read and write the buffer.
I think I posted some code in one of your previous questions to avoid that problem.
0
 

Author Comment

by:skyblue01
ID: 9756078
Sorry for the late response.   I still can't figure out what's the problem.   I'll post what I'm doing when dealing with buffers and channel.   Let me know what I'm doing wrong here.   Thanks.  
----------------------------------------------------------------
    // The processMessage method gets called when the user types something in the GUI
    // Client sends the message to Server here
    private void processMessage(String message) {
        try {
            buffer.clear();

            buffer = encoder.encode(CharBuffer.wrap(message));

            int numWritten = sc.write(buffer); // sends it to the server
            System.out.println("numWritten: " + numWritten); // TEST

            tf.setText(""); // clears out text input field
        } catch(IOException ie) { System.out.println(ie); }
    }

    // upon receiving a message, for each incoming connection, Server starts ServerThread
    // run method runs in a separate thread and read the message from the channel
    public void run() {
        try {
            while (true) {
                buffer.clear();
                int r = socketChannel.read(buffer);

                if (r == -1)
                    break;

                buffer.flip();

                CharBuffer charBuffer = decoder.decode(buffer);
                String message = charBuffer.toString();
                charBuffer.clear(); // TEST

                System.out.println("Sending " + message); // tells the world

                server.sendToAll(message); // and have the server send it to all clients
            }
        } catch(EOFException ie) {
        } catch(IOException ie) { // this doesn't need an error message

        ie.printStackTrace(); // this does; tells the world
        } finally {
            server.removeConnection( socketChannel ); // the connection is closed for one reason or another, so have the server deal with it
        }
    }

    // Server then sends the received message to all the Client participating in the ongoing chat session
    // sendToAll method sends a message to all clients
    void sendToAll(String message) {

        synchronized(outputChannels) {

            for (ListIterator l = getOutputChannels(); l.hasNext();) { // for each client

                SocketChannel scBack = (SocketChannel) l.next(); // gets the output channel -- SocketChannel sc?

                try {
                    buffer.clear();
                    buffer = encoder.encode(CharBuffer.wrap(message));

                    scBack.write(buffer); // and sends the message
                } catch(IOException ie) { System.out.println(ie); }
            }
        }
    }

    // finally, each Client starts a background thread to receive all messages sent from Server
    // The run method is ran by background thread and shows messages from other window
    public void run() {
        try {
            System.out.println("Testing... Client.run()"); // TEST

            while (true) {
                buffer.clear();

                int r = sc.read(buffer); // there's nothing to read from!!

                if (r == -1)
                    break;

                buffer.flip();

                CharBuffer charBuffer = decoder.decode(buffer);
                String message = charBuffer.toString();
                charBuffer.clear(); // TEST
                System.out.println("received message: " + message); // TEST

                ta.append(message + "\n"); // prints it to our text window
            }
        } catch(IOException ie) { System.out.println(ie); }
    }
---------------------------------------------------------------
0
Salesforce Made Easy to Use

On-screen guidance at the moment of need enables you & your employees to focus on the core, you can now boost your adoption rates swiftly and simply with one easy tool.

 
LVL 92

Expert Comment

by:objects
ID: 9756674
Whats buffer defined as?
0
 
LVL 92

Accepted Solution

by:
objects earned 250 total points
ID: 9756691
Won't you get a problem if the client sends a message that is larger than the buffer size on the server.
Similarily for the client recieving the message.

You also assume that the call to read() will read the entire message.
0
 

Author Comment

by:skyblue01
ID: 9756694
I have:

ByteBuffer buffer = ByteBuffer.allocate(1024);
0
 

Author Comment

by:skyblue01
ID: 9756709
Buffer size doesn't seem to matter... no matter how much I increase the buffer size, Client still receives the original plus the cut-off message.  

I'll check out if the read() is not reading the entire message...
0
 
LVL 92

Expert Comment

by:objects
ID: 9756713
>   buffer.clear();
>   buffer = encoder.encode(CharBuffer.wrap(message));

On a side note, there is no point clear the buffer in the above case as you create a new buffer to send.
0
 

Author Comment

by:skyblue01
ID: 9756774
As in the java api, read() should read up to the end of what's in the buffer:

read()

An attempt is made to read up to r bytes from the channel, where r is the number of bytes remaining in the buffer, that is, dst.remaining(), at the moment this method is invoked.

so it's got to be something else...
0
 
LVL 92

Expert Comment

by:objects
ID: 9756823
"An attempt is made to read up to r bytes ..", this doesn't guarantee that the buffer will be filled.

Also from the javadoc:
"A read operation might not fill the buffer, and in fact it might not read any bytes at all...."

And your client and server buffer sizes are different so how do you know when one message ends and another begins.

Try printing out the number of bytes being written at one end, and the number being read by each read at the other to see whats going on.
0
 
LVL 92

Expert Comment

by:objects
ID: 9756833
> Buffer size doesn't seem to matter

Maybe not for this problem, but I think it will cause a different problem.
0
 

Author Comment

by:skyblue01
ID: 9756879
Yeah, I have two Client windows open and the one not sending message receives the right message.   The one that sends receives twice, one original, and the second one a cut-off so it's maybe a problem with something else.   I'll go back again and check.  
0
 

Author Comment

by:skyblue01
ID: 9757458
objects, if you're still around, I thought if you could take a look at my code.   I've tested and everything works fine until the last line, scBack.write(buffer);.   Then there's something else that this line is dependent on but I don't know why.   What I figured out from my tests are:

suppose two clients, c1 and c2 are connected to the server.   each channel is stored in a linked list called outputChannels.   for each incoming connection, the server starts a thread, and whenever a message is received from that channel, it invokes sendToAll(str) method.   it is this method that's causing the problem.   suppose "hello" is sent from c2.   then c1 and c2 successfully receives "hello".   then suppose c2 sends "dddddddddddd kkkkkkkkkkk".   then c1 receives "dddddddddddd kkkkkkkkkkk", but c2 receives two messages, "dddddddddddd kkkkkkkkkkk" and "dd kkkkkkkkkkk".   I can't figure out why this is happening because my linked list hold only two elements, namely socketchannel1 connected from c1 to server and socketchannel2 connected from c2 to server.   in the sendToAll(String message), message passed to this method is printed just as it is, and after encoding this to be written into the channel, I tested to see if this buffer is what i want it to be written to the channel so i decrypted, and it prints exactly what i want.   so i don't know why c2 received two messages because the background thread that runs in Clinet class to receive any incoming messages is only started once.   also, what i figured was that if i type in at c2 the messages "hello" and "dddddddddddd kkkkkkkkkkk" in that order, what i said above happens but if i type in "dddddddddddd kkkkkkkkkkk" first, then it is successfully sent to c1 and c2.   please let me know if you have any suggestion, or if you have time, i'd be greatly appreciated if you can take a look at what i have.   in that case, i'll increase the point value as well since that might take more time...
0
 
LVL 92

Expert Comment

by:objects
ID: 9757502
> but c2 receives two messages, "dddddddddddd kkkkkkkkkkk" and "dd kkkkkkkkkkk".

See my above comments.
There is no way for you client to know the size of the message.
It simply reads whatever bytes are avaible into the buffer and assumes that is the next message.
0
 

Author Comment

by:skyblue01
ID: 9757550
SocketChannel does not seem to provide a method for such issue (i.e. a way to know if all bytes are read into a buffer).   is there any way (or method) that can be used to counter this problem?
0
 
LVL 92

Expert Comment

by:objects
ID: 9757563
No it's just reading a stream of bytes, same as standard I/O. You needs to handle these kinds of issues yourself. By providing some means to first determine message seperation (eg. fixed size messages, or include message length), and then to ensure you have read the entire message.
0
 

Author Comment

by:skyblue01
ID: 9757571
k.   i'll try that.
0
 
LVL 92

Expert Comment

by:objects
ID: 9757583
0

Featured Post

Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
maven module vs maven project 3 109
Eclipse Java import and method not resolved 4 125
collection output issue 9 91
junit as external jar or library 7 56
This was posted to the Netbeans forum a Feb, 2010 and I also sent it to Verisign. Who didn't help much in my struggles to get my application signed. ------------------------- Start The idea here is to target your cell phones with the correct…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
Viewers learn about the scanner class in this video and are introduced to receiving user input for their programs. Additionally, objects, conditional statements, and loops are used to help reinforce the concepts. Introduce Scanner class: Importing…
Viewers will learn one way to get user input in Java. Introduce the Scanner object: Declare the variable that stores the user input: An example prompting the user for input: Methods you need to invoke in order to properly get  user input:
Suggested Courses

737 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question