Question

Client Server programming

Asked by: pankajtiwary

Hello experts,

I am a newbie in Java and having problems with code.

I am working on an application where there is a server (which serves multiple connections using asynchronous I/O using select facility. It does nothing but accepts a connection and reply back with the same data as received (imitating an echo server). Code for the server is as follows:

// Server.java
import java.io.*;
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.util.*;

public class Server implements Runnable
{
  // The port we will listen on
  private int port;

  // A pre-allocated buffer for encrypting data
  private final ByteBuffer buffer = ByteBuffer.allocate( 100 );

  public Server( int port ) {
    this.port = port;
    new Thread( this ).start();
  }

  public void run() {
    try {
      // Instead of creating a ServerSocket,
      // create a ServerSocketChannel
      ServerSocketChannel ssc = ServerSocketChannel.open();

      // Set it to non-blocking, so we can use select
      ssc.configureBlocking( false );

      // Get the Socket connected to this channel, and bind it
      // to the listening port
      ServerSocket ss = ssc.socket();
      InetSocketAddress isa = new InetSocketAddress( port );
      ss.bind( isa );

      // Create a new Selector for selecting
      Selector selector = Selector.open();

      // Register the ServerSocketChannel, so we can
      // listen for incoming connections
      ssc.register( selector, SelectionKey.OP_ACCEPT );
      System.out.println( "Listening on port "+port );

      while (true) {
        // See if we've had any activity -- either
        // an incoming connection, or incoming data on an
        // existing connection
        int num = selector.select();

        // If we don't have any activity, loop around and wait
        // again
        if (num == 0) {
          continue;
        }

        // Get the keys corresponding to the activity
        // that has been detected, and process them
        // one by one
        Set keys = selector.selectedKeys();
        Iterator it = keys.iterator();
        while (it.hasNext()) {
          // Get a key representing one of bits of I/O
          // activity
          SelectionKey key = (SelectionKey)it.next();

          // What kind of activity is it?
          if ((key.readyOps() & SelectionKey.OP_ACCEPT) ==
            SelectionKey.OP_ACCEPT) {

            // It's an incoming connection.
            // Register this socket with the Selector
            // so we can listen for input on it

            Socket s = ss.accept();
            System.out.println( "Got connection from "+s );

            // Make sure to make it non-blocking, so we can
            // use a selector on it.
            SocketChannel sc = s.getChannel();
            sc.configureBlocking( false );

            // Register it with the selector, for reading
            sc.register( selector, SelectionKey.OP_READ );
          } else if ((key.readyOps() & SelectionKey.OP_READ) ==
            SelectionKey.OP_READ) {

            SocketChannel sc = null;

            try {

              // It's incoming data on a connection, so
              // process it
              sc = (SocketChannel)key.channel();
              boolean ok = processInput( sc );

              // If the connection is dead, then remove it
              // from the selector and close it
              if (!ok) {
                key.cancel();

                Socket s = null;
                try {
                  s = sc.socket();
                  s.close();
                } catch( IOException ie ) {
                  System.err.println( "Error closing socket "+s+": "+ie );
                }
              }

            } catch( IOException ie ) {

              // On exception, remove this channel from the selector
              key.cancel();

              try {
                sc.close();
              } catch( IOException ie2 ) { System.out.println( ie2 ); }

              System.out.println( "Closed "+sc );
            }
          }
        }

        // We remove the selected keys, because we've dealt
        // with them.
        keys.clear();
      }
    } catch( IOException ie ) {
      System.err.println( ie );
    }
  }

  // Do some cheesy encryption on the incoming data,
  // and send it back out
  private boolean processInput( SocketChannel sc ) throws IOException {
    buffer.clear();
    sc.read( buffer );
    buffer.flip();

    // If no data, close the connection
    if (buffer.limit()==0) {
      return false;
    }

    int i = 0;
    for (i=0; i<buffer.limit(); ++i) {
      byte b = buffer.get( i );

      if ( b == (char)13 ) {
        break;
      }

      buffer.put( i, b );
    }

    sc.write( buffer );

    System.out.println( "Processed "+buffer.limit()+" from "+sc );

    return true;
  }

  static public void main( String args[] ) throws Exception {
    int port = Integer.parseInt( args[0] );

    new Server( port );
  }
}

Client works in the following manner. It creates a sender thread which opens 10 connections to the server and starts sending some data (messages in our case). Client also creates a receiver thread which looks for incoming data on the same channel using the same select mechanism. When the data becomes available on one of the connections, it creates a worker thread and assigns the connection to it. The worker thread then reads the data from the connection (which is actually sent by the server) and prints it on the screen. Client code involves creation of  a ThreadPool and worker threads so its pretty big, but I have no option other than pasting the whole thing.

//Client.java
import java.net.*;
import java.io.*;
import java.nio.channels.*;
import java.nio.*;
import java.util.*;

class ThreadPool {
  /**
   * The threads in the pool.
   */
  protected Thread threads[] = null;
  /**
   * The backlog of assignments, which are waiting
   * for the thread pool.
   */
  Collection assignments = new ArrayList(3);
  /**
   * A Done object that is used to track when the
   * thread pool is done, that is has no more work
   * to perform.
   */
  protected Done done = new Done();

  /**
   * The constructor.
   *
   * @param size  How many threads in the thread pool.
   * @param s SocketChannel to read from.
   */
  public ThreadPool(int size)
  {
    threads = new WorkerThread[size];
    for (int i=0;i<threads.length;i++) {
      threads[i] = new WorkerThread(this);
      //System.out.println ("WorkerThread created");
    }
  }

  public void startWorking() {
    for (int i=0;i<threads.length;i++) {
      threads[i].start();
    }
  }


  /**
   * Add a task to the thread pool. Any class
   * which implements the Runnable interface
   * may be assienged. When this task runs, its
   * run method will be called.
   *
   * @param r   An object that implements the Runnable interface
   */
  public synchronized void assign(Runnable r)
  {
    //System.out.println ("assign");
    done.workerBegin();
    assignments.add(r);
    notify();
  }

  /**
   * Get a new work assignment.
   *
   * @return A new assignment
   */
  public synchronized Runnable getAssignment()
  {
    try {
      while ( !assignments.iterator().hasNext() )
        wait();

      Runnable r = (Runnable)assignments.iterator().next();
      assignments.remove(r);
      return r;
    } catch (InterruptedException e) {
      done.workerEnd();
      return null;
    }
  }

  /**
   * Called to block the current thread until
   * the thread pool has no more work.
   */
  public void complete()
  {
    done.waitBegin();
    done.waitDone();
  }

  protected void finalize()
  {
    done.reset();
    for (int i=0;i<threads.length;i++) {
      threads[i].interrupt();
      done.workerBegin();
      threads[i].destroy();
    }
    done.waitDone();
  }

}

/**
 * The worker threads that make up the thread pool.
 *
 */
class WorkerThread extends Thread {
  /**
   * True if this thread is currently processing.
   */
  public boolean busy;
  /**
   * The thread pool that this object belongs to.
   */
  public ThreadPool owner;

  /**
   * The constructor.
   *
   * @param o the thread pool
   */
  WorkerThread(ThreadPool o)
  {
    //System.out.println ("WorkerThread constructor");
    owner = o;
  }

  /**
   * Scan for and execute tasks.
   */
  public void run()
  {
    Runnable target = null;
    do {
      target = owner.getAssignment();
      if (target!=null) {
        target.run();
        owner.done.workerEnd();
      }
    } while (target!=null);
  }
}


/**
 *
 * This is a very simple object that
 * allows the TheadPool to determine when
 * it is done. This object implements
 * a simple lock that the ThreadPool class
 * can wait on to determine completion.
 * Done is defined as the ThreadPool having
 * no more work to complete.
 *
 */
class Done {

  /**
   * The number of Worker object
   * threads that are currently working
   * on something.
   */
  private int _activeThreads = 0;

  /**
   * This boolean keeps track of if
   * the very first thread has started
   * or not. This prevents this object
   * from falsely reporting that the ThreadPool
   * is done, just because the first thread
   * has not yet started.
   */
  private boolean _started = false;
  /**
   * This method can be called to block
   * the current thread until the ThreadPool
   * is done.
   */

  synchronized public void waitDone()
  {
    try {
      while ( _activeThreads>0 ) {
        wait();
      }
    } catch ( InterruptedException e ) {
    }
  }
  /**
   * Called to wait for the first thread to
   * start. Once this method returns the
   * process has begun.
   */

  synchronized public void waitBegin()
  {
    try {
    while ( !_started ) {
      wait();
    }
   } catch ( InterruptedException e ) {
   }
  }


 /**
   * Called by a Worker object
   * to indicate that it has begun
   * working on a workload.
   */
  synchronized public void workerBegin()
  {
    _activeThreads++;
    _started = true;
    notify();
  }

  /**
   * Called by a Worker object to
   * indicate that it has completed a
   * workload.
   */
  synchronized public void workerEnd()
  {
    _activeThreads--;
    notify();
  }

  /**
   * Called to reset this object to
   * its initial state.
   */
  synchronized public void reset()
  {
    _activeThreads = 0;
  }

}

/**
 * This class shows an example worker thread that can
 * be used with the thread pool. It demonstrates the main
 * points that should be included in any worker thread. Use
 * this as a starting point for your own threads.
 *
 */
class TestWorkerThread implements Runnable {
  static private int count = 0;
  private int taskNumber;
  protected Done done;

  /**
   * Buffer to read data from SocketChannel.
   */
  //private final ByteBuffer buffer = ByteBuffer.allocate( 1024 );

  /**
   * SocketChennel to read data from.
   */
  private SocketChannel sc;

  /**
   *
   * @param done
   */
  TestWorkerThread(SocketChannel s)
  {
    count++;
    taskNumber = count;
    sc = s;
  }

  public void run()
  {
    /*
    for (int i=0;i<100;i+=2) {
      System.out.println("Task number: " + taskNumber +
             ",percent complete = " + i );
      try {
        Thread.sleep((int)(Math.random()*500));
      } catch (InterruptedException e) {
      }
    }
    */
    try {
      final ByteBuffer buffer = ByteBuffer.allocate( 1024 );
      buffer.clear();
      sc.read( buffer );
      StringBuffer m = new StringBuffer();
      if (buffer.limit()==0) {
        //continue;
        return;
      }
      System.out.println ( "buffer.limit() = " + buffer.limit() );
      for (int i=0; i<buffer.limit(); ++i) {
        byte b = buffer.get( i );
        if ( b == (char)13 ) {
          break;
        } else {
          m.append((char)b);
        }
      }
      System.out.println("Read from server: " + m );
    } catch ( IOException g ) {
      System.out.println (g);
    }
  }
}

class SenderThread implements Runnable {
  Thread t;
  SocketChannel con[];
  SenderThread(SocketChannel sc[]) {
    t = new Thread(this, "Sender Thread");
    int i;
    con = new SocketChannel[10];
    for ( i = 0; i < 10; i++ ) {
      con[i] = sc[i];
    }
    System.out.println("Sender Thread initialized");
    t.start();
  }

  public void run() {
    String message[] = { "01message01" + (char)13, "02message02" + (char)13,
                         "03message03" + (char)13, "04message04" + (char)13,
                         "05message05" + (char)13, "06message06" + (char)13,
                         "07message07" + (char)13, "08message08" + (char)13,
                         "09message09" + (char)13, "10message10" + (char)13 };
    int i = 0;
    for (i=0; i<10; i++) {
      ByteBuffer buf = ByteBuffer.wrap ( message[i].getBytes() );
      try {
        System.out.println ( "Writing to socket channel:" + message[i] );
        int n = con[i].write(buf);
      }
      catch ( IOException e) {
        System.out.println (e);
      }
      if ( i == 9 ) {
        i = -1;
      }
    }
  }
}

class ReceiverThread implements Runnable {
  Thread t;
  ThreadPool pool;
  Selector s;
  SocketChannel con[];
  private final ByteBuffer buffer = ByteBuffer.allocate( 1024 );
  ReceiverThread (SocketChannel sc[]) {
    t = new Thread(this, "Receiver Thread");
    pool = new ThreadPool(10);
    System.out.println ("In ReceiverThread constructor: pool initialized");
    try {
      s = Selector.open();
      int i;
      con = new SocketChannel[10];
      for ( i = 0; i < 10; i++ ) {
        con[i] = sc[i];
        con[i].register(s, SelectionKey.OP_READ);
      }
    } catch ( IOException g ) {
      System.out.println (g);
    }
    System.out.println("Receiver Thread initialized");
    t.start();
  }
  public void run() {
    pool.startWorking();
    try {
      while ( true ) {
        int num = s.select();
        if ( num == 0 ) {
          System.out.println ( "num == 0");
          continue;
        }
        Set keys = s.selectedKeys();
        Iterator it = keys.iterator();
        while ( it.hasNext() ) {
          SelectionKey key = (SelectionKey)it.next();
          SocketChannel sc = null;
          if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {
            sc = (SocketChannel)key.channel();
            /*
            buffer.clear();
            sc.read( buffer );
            StringBuffer m = new StringBuffer();
            if (buffer.limit()==0) {
              continue;
            }
            System.out.println ( "buffer.limit() = " + buffer.limit() );
            for (int i=0; i<buffer.limit(); ++i) {
              byte b = buffer.get( i );
              if ( b == (char)13 ) {
                break;
              } else {
                m.append((char)b);
              }
            }
            System.out.println("Read from server: " + m );
            */
            pool.assign ( new TestWorkerThread ( sc ) );
          }
        }
        keys.clear();
      }
    } catch ( IOException g ) {
      System.out.println (g);
    }
  }
}

public class Client {
  public static void main(String[] args) {
    String addr = "localhost";
    int port = 19999;
    SocketChannel connection[];
    connection = new SocketChannel[10];
    int i;
    for (i = 0; i < 10; i++) {
      try {
        connection[i] = createSocketChannel(addr, port);

        // Before the socket is usable, the connection must be completed
        // by calling finishConnect(), which is non-blocking
        while (!connection[i].finishConnect()) {
          // Do something else
        }
        System.out.println("Connection[" + i + "] to server established");
      }
      catch (IOException g) {
        System.out.println("IOException: " + g);
      }
      catch (Exception g) {
        System.out.println("Exception: " + g);
      }
    }
    new SenderThread ( connection );
    new ReceiverThread ( connection );
  }

  // Creates a non-blocking socket channel for the specified host name and port.
  // connect() is called on the new channel before it is returned.
  private static SocketChannel createSocketChannel(String hostName, int port)
                                                   throws IOException {
    // Create a non-blocking socket channel
    SocketChannel sChannel = SocketChannel.open();
    sChannel.configureBlocking(false);

    // Send a connection request to the server; this method is non-blocking
    sChannel.connect(new InetSocketAddress(hostName, port));
    return sChannel;
  }
}
 Is there any obvious problems that you can see here in the code? If not, I ran Server and when I ran client I get the following output.

bash-2.05$ java Client
Connection[0] to server established
Connection[1] to server established
Connection[2] to server established
Connection[3] to server established
Connection[4] to server established
Connection[5] to server established
Connection[6] to server established
Connection[7] to server established
Connection[8] to server established
Connection[9] to server established
Sender Thread initialized
In ReceiverThread constructor: pool initialized
Receiver Thread initialized
Writing to socket channel:01message01
Writing to socket channel:02message02
Writing to socket channel:03message03
Writing to socket channel:04message04
Writing to socket channel:05message05
Writing to socket channel:06message06
Writing to socket channel:07message07
Writing to socket channel:08message08
Writing to socket channel:09message09
Writing to socket channel:10message10
Writing to socket channel:01message01
Writing to socket channel:02message02
Writing to socket channel:03message03
Writing to socket channel:04message04
Writing to socket channel:05message05
Writing to socket channel:06message06
Writing to socket channel:07message07
Writing to socket channel:08message08
Writing to socket channel:09message09
Writing to socket channel:10message10
...
...
buffer.limit() = 1024
Read from server: 07message07
buffer.limit() = 1024
Read from server: 07message07
buffer.limit() = 1024
Read from server: 04message04
buffer.limit() = 1024
Read from server: 03message03
buffer.limit() = 1024
Read from server: 10message10
buffer.limit() = 1024
Read from server: 02message02
buffer.limit() = 1024
Read from server: 08message08
buffer.limit() = 1024
Read from server: 05message05
buffer.limit() = 1024
Read from server: 01message01
buffer.limit() = 1024
Read from server: 09message09
buffer.limit() = 1024
Read from server: 06message06
buffer.limit() = 1024
Read from server:
buffer.limit() = 1024
Read from server:
...
...
Read from server:
buffer.limit() = 1024
Read from server:
buffer.limit() = 1024
Read from server: 06message06
buffer.limit() = 1024
Read from server: 06message06
buffer.limit() = 1024
Read from server:
buffer.limit() = 1024
...
...
Read from server:
buffer.limit() = 1024
Read from server:
buffer.limit() = 1024
Read from server: 09message09
buffer.limit() = 1024
Read from server:
buffer.limit() = 1024
...
...
Read from server:
buffer.limit() = 1024
Read from server:
buffer.limit() = 1024
buffer.limit() = 1024
Read from server: 03message03
buffer.limit() = 1024
Read from server: 10message10
buffer.limit() = 1024
Read from server: 02message02
buffer.limit() = 1024
Read from server:
buffer.limit() = 1024
...
...
Read from server:
buffer.limit() = 1024
Read from server:
Writing to socket channel:07message07
Writing to socket channel:08message08
Writing to socket channel:09message09
Writing to socket channel:10message10
Writing to socket channel:01message01
Writing to socket channel:02message02
Writing to socket channel:03message03
Writing to socket channel:04message04
Writing to socket channel:05message05
...
...
Writing to socket channel:06message06
Writing to socket channel:07message07
buffer.limit() = 1024
Read from server:
Read from server:
Read from server:
Read from server:
buffer.limit() = 1024
Read from server:
buffer.limit() = 1024
Read from server: 01message01
buffer.limit() = 1024
Read from server: 09message09
buffer.limit() = 1024
Read from server: 06message06
buffer.limit() = 1024
Read from server: 07message07
buffer.limit() = 1024
Read from server: 04message04
buffer.limit() = 1024
Read from server: 03message03
buffer.limit() = 1024
Read from server: 10message10
buffer.limit() = 1024
Read from server: 02message02
buffer.limit() = 1024
Read from server: 08message08
buffer.limit() = 1024
Read from server: 05message05
buffer.limit() = 1024
Read from server:
...
...
Read from server:
buffer.limit() = 1024
Read from server:
buffer.limit() = 1024
Read from server: ssage01
buffer.limit() = 1024
Read from server: ssage09
buffer.limit() = 1024
Read from server:
buffer.limit() = 1024
Read from server: ssage10
buffer.limit() = 1024
Read from server:
buffer.limit() = 1024
Read from server:
buffer.limit() = 1024
Read from server:
Writing to socket channel:08message08
Writing to socket channel:09message09
buffer.limit() = 1024
Read from server: ssage03
buffer.limit() = 1024
Read from server:
buffer.limit() = 1024

As you can see the lines starting with "Read from server" contains the message from the server, we see that the message is not coming properly and it gets truncated somehow. I have no idea as to why it is happening. Please help me.

Regards
Pankaj

This Question has been solved and asker verified All Experts Exchange premium technology solutions are available to subscription members.

Subscribe now for full access to Experts Exchange and get

Instant Access to this Solution

  • Plus...
  • 30 Day FREE access, no risk, no obligation
  • Collaborate with the world's top tech experts
  • Unlimited access to our exclusive solution database
  • Never be left without tech help again

Subscribe Now

Asked On
2005-10-09 at 22:46:59ID21589254
Tags

java

,

createsocketchannel

Topic

Java Programming Language

Participating Experts
1
Points
500
Comments
12

Trusted by hundreds of thousands everyday for fast, accurate and reliable tech support.

  • "The time we save is the biggest benefit of Experts Exchange to Warner Bros. What could take multiple guys 2 hours or more each to find is accessed in around 15 minutes on Experts Exchange." Mike Kapnisakis, Warner Bros.
  • "Our team likes having a resource that is more secure than just using Google and most experts using this service really know their stuff. It's nice to look here first versus using Google." Dayna Sellner, Lockheed Martin
  • "Anytime that I've been stumped with a problem, 9 out of 10 times Experts Exchange has either the accepted solution or an open discussion of the potential solution to the problem." Kenny Red, eBay Inc.

See what Experts Exchange can do for you.

Got a question?

We've got the answer.

Experts Exchange has been collecting answers to technology questions since 1996…3 million and counting! If you have a question, chances are we already have your answer.

Screenshot of Experts Exchange Knowledgebase

Need individual assistance?

Our experts are ready to help.

If you can't find the exact answer you're looking for, ask our exclusive community of 50,000 experts. You’ll get a personalized answer from a trusted professional.

Screenshot of Experts Exchange Knowledgebase

Want to learn from the best?

Read articles from industry experts.

Thousands of free tech tips, tricks, how-to’s and tutorials are available in our peer reviewed articles section. See for yourself how smart our experts are, no login required.

Screenshot of an Article

Working on a long term project?

Store your work and research.

Save solutions to your questions, answers you’ve discovered through searching plus helpful articles in your personal knowledgebase for easy future access.

Screenshot of Experts Exchange Knowledgebase

Access the answers to your technology questions today.

Subscribe Now

30-day free trial. Register in 60 seconds.

What Makes Experts Exchange Unique?

Members of the expert community talk about why the experience at Experts Exchange is different than what you will find anywhere else.

Trusted by the world's most respected brands.

image of each brand's logo

Faithfully serving IT professionals since 1996.

Experts Exchange Logo

Try it out and discover for yourself.

Subscribe Now

30-day free trial. Register in 60 seconds.

Related Solutions

  1. jni - passing args
    What's wrong with the following code? I try to pass a string (from C++ code) into a Java's main(..). However, I receive a "null" inside the Java class. JNIEnv *env; jstring jstr; jobjectArray args; char buff[100]; ........... printf(buff); // 'buff' is ...
  2. IOException problem
    I have made a client/server application where the server listens for clients messages and receives as well as sends messages to it. The snippet pasted below is that of the client's actionListener for the button b1 which is the "Enter" button which is clicked for s...
  3. URLConnection and IOException?
    Hi, In my application I am connecting to URL, and getting Input Stream. It works fine at local testing server. But it doesn't work at Client side server(Real-IP). The underlaying os is linux. It connects, but while getting input stream, it throws IOException. Is this a pro...

Free Tech Articles

  1. WARNING: 5 Reasons why you should NEVER fix a computer for free.
    It is in our nature to love the puzzle. We are obsessed. The lot of us. We love puzzles. We love the challenge. We thrive on finding the answer. We hate disarray. It bothers us deep in our soul. W...
  2. SCCM OSD Basic troubleshooting
    SCCM 2007 OSD is a fantastic way to deploy operating systems, however, like most things SCCM issues can sometimes be difficult to resolve due to the sheer volume of logs to sift through and the dispe...
  3. Migrate Small Business Server 2003 to Exchange 2010 and Windows 2008 R2
    This guide is intended to provide step by step instructions on how to migrate from Small Business Server 2003 to Windows 2008 R2 with Exchange 2010. For this migration to work you will need the fo...
  4. Create a Win7 Gadget
    This article shows you how to create a simple "Gadget" -- a sort of mini-application supported by Windows 7 and Vista. Gadgets can be dropped anywhere on the desktop to provide instant information, ...
  5. Outlook continually prompting for username and password
    There have been a lot of questions recently regarding Outlook prompting for a username and password whilst using Exchange 2007. There are a few reasons why this would happen and I will try to cover t...
  6. Backup Exchange 2010 Information Store using Windows Backup
    There seems to be quite a lot of confusion around the ability to backup Exchange 2010 using the built in Windows Backup feature. This stems from the omission of this feature prior to Exchange 2007 s...

Cloud Class Webinars

  1. Avoiding Bugs in Microsoft Access
    Alison Balter takes and in-depth look at avoiding bugs in Access. In this webinar you will learn about using the immediate window to debug your applications, invoking the debugger, using breakpoints to troubleshoot, stepping through code, setting the next statement to execute, ...
  2. Top 10 Best New Features in Visio 2010
    Scott Helmers gives live demonstrations of the top 10 new features in Visio 2010. This webinar will teach you how to create compelling diagrams by adding shapes to the page with a single click, linking the shapes in a diagram to data in Excel (or SQL Server, or SharePoint), ...
  3. IT Consultant Business Secrets Revealed
    Michael Munger, Experts Exchange tech pro and IT consultant, pulls back the curtain on his very successful businesses and answers question on every IT consultant and business owner should know about. He shares secrets on what he did to solve the 5 most common problems in IT, ...
  4. Disaster Recovery and Business Continuity
    Quest CTO, Mike Billon, gives an overview of the steps involved in building a dunamic disaster recovery plan. Through case studies and an examination of software/hardware tooles for monitoring and testing, you'll gain a better understandin of where you are, where you want ...
  5. Organize Your Visio Diagrams with Containers and Lists
    Scott Helmers uses cross functional flowcharts, wireframe diagrams, data graphic legends and seating charts to teach you: how to ustilize all three new structured diagram components in Visio 2010, the best practices for organizeing shapes in previous version of Visio, how to organize ...
  6. How to Us Objects, Properties, Events and Methods in Microsoft Access
    Alison Dalter gives an in-depbth look at objects, properties, events and methods in Microsoft Access. In this webinar you will learn about using the object browser, referring to objects, working with properties and methods, working with object variables, understanding the ...

Join the Community

Give a Little. Get a Lot.

Join the community of experts here and help other tech pros by answering question in your area of expertise. You can earn FREE access to all Experts Exchange's premium features and resources.

Join the Community

Answers

 

by: OnegaZhangPosted on 2005-10-10 at 02:24:16ID: 15050927

sc.write( buffer ); // You'd better check the return value.
You code works well on my PC.

 

by: pankajtiwaryPosted on 2005-10-10 at 02:33:35ID: 15050963

Thanks OnegaZhang for your time. Thanks that you tried to run it on your PC and I am glad to know that its working fine. But thats a surprize as I have tried to run the same code on RedHat 9 as well as Solaris 2.9 and both are giving similar problems.

Anyway, I am going to check for the return value for sc.write(buffer) and let you know.

Regards
Pankaj

 

by: pankajtiwaryPosted on 2005-10-10 at 03:35:32ID: 15051205

I checked the return value, but thats fine. Well OnegaZhang, are you sure you are getting all the messages successfully because I am always getting truncated messages after couple of cycle of successful messages. Also, this depend on the buffersize (1024) above. I mean to say the truncated messages start appearing very early if the buffer is small (say 50). I am getting something like this.

bash-2.05$ java Client | grep Read
Read from server: 07message07
Read from server: 04message04
Read from server: 03message03
Read from server: 10message10
Read from server: 02message02
Read from server: 08message08
Read from server: 05message05
Read from server: 01message01
Read from server: 08message08
Read from server: 03message03
Read from server: ssage01
Read from server: ssage02
Read from server: ssage05
Read from server: ssage03
Read from server: ssage06
Read from server: ssage07
Read from server: ssage08
Read from server: ssage09
Read from server: ssage10
Read from server: e01
Read from server: e02
Read from server: e03
Read from server: ssage04
Read from server: e05
Read from server: 06message06
Read from server: 07message07
Read from server: 08message08
Read from server: 09message09
Read from server: 05message05
Read from server: 08message08
Read from server: 03message03
Read from server: 01message01
Read from server: 06message06
Read from server: 07message07
Read from server: 04message04
Read from server: 03message03
Read from server: 10message10
Read from server: 02message02
Read from server: 08message08
Read from server: 05message05
Read from server: 01message01
Read from server: 09message09
Read from server: ssage08
Read from server: ssage09
Read from server: ssage10
Read from server: ssage01
Read from server: ssage02
Read from server: ssage03
Read from server: ssage04
Read from server: ssage05
Read from server: ssage06
Read from server: ssage07
Read from server: 08message08
Read from server: 09message09
Read from server: 10message10
^C

 

by: OnegaZhangPosted on 2005-10-10 at 05:14:12ID: 15051619

I modified your code a little bit, on windows XP sp2, Jbuilder 2006
  public void run()
  {
    /*
    for (int i=0;i<100;i+=2) {
      System.out.println("Task number: " + taskNumber +
             ",percent complete = " + i );
      try {
        Thread.sleep((int)(Math.random()*500));
      } catch (InterruptedException e) {
      }
    }
    */
    try {
      final ByteBuffer buffer = ByteBuffer.allocate( 1024 );
      buffer.clear();
      int n = sc.read( buffer );
      System.out.println("client read bytes:"+n);
      StringBuffer m = new StringBuffer();
      if (buffer.limit()==0) {
        //continue;
        System.out.println("buffer limit=0");
        return;
      }
      //System.out.println ( "buffer.limit() = " + buffer.limit() );
      for (int i=0; i<buffer.limit(); ++i) {
        byte b = buffer.get( i );
        if ( b == (char)13 ) {
          break;
        } else {
          m.append((char)b);
        }
      }
      System.out.println("Read from server: " + m );
    } catch ( IOException g ) {
      System.out.println (g);
    }
  }
The output is:
Connection[0] to server established
Connection[1] to server established
Connection[2] to server established
Connection[3] to server established
Connection[4] to server established
Connection[5] to server established
Connection[6] to server established
Connection[7] to server established
Connection[8] to server established
Connection[9] to server established
Sender Thread initialized
In ReceiverThread constructor: pool initialized
Writing to socket channel:01message01

Writing to socket channel:02message02

Writing to socket channel:03message03

Writing to socket channel:04message04

Writing to socket channel:05message05

Writing to socket channel:06message06

Writing to socket channel:07message07

Writing to socket channel:08message08

Writing to socket channel:09message09

Writing to socket channel:10message10

Writing to socket channel:01message01

Writing to socket channel:02message02

Writing to socket channel:03message03

Writing to socket channel:04message04

Writing to socket channel:05message05

Writing to socket channel:06message06

Writing to socket channel:07message07

Writing to socket channel:08message08

Writing to socket channel:09message09

Writing to socket channel:10message10

Writing to socket channel:01message01

Writing to socket channel:02message02

Writing to socket channel:03message03

Writing to socket channel:04message04

Writing to socket channel:05message05

Writing to socket channel:06message06

Writing to socket channel:07message07

Writing to socket channel:08message08

Receiver Thread initialized
Writing to socket channel:09message09

Writing to socket channel:10message10

Writing to socket channel:01message01

Writing to socket channel:02message02

Writing to socket channel:03message03

Writing to socket channel:04message04

Writing to socket channel:05message05

Writing to socket channel:06message06

Writing to socket channel:07message07

Writing to socket channel:08message08

Writing to socket channel:09message09

Writing to socket channel:10message10

Writing to socket channel:01message01

Writing to socket channel:02message02

Writing to socket channel:03message03

Writing to socket channel:04message04

Writing to socket channel:05message05

Writing to socket channel:06message06

Writing to socket channel:07message07

Writing to socket channel:08message08

Writing to socket channel:09message09

Writing to socket channel:10message10

Writing to socket channel:01message01

Writing to socket channel:02message02

Writing to socket channel:03message03

Writing to socket channel:04message04

client read bytes:48
client read bytes:48
client read bytes:48
client read bytes:48
client read bytes:48
client read bytes:60
client read bytes:0
client read bytes:0
client read bytes:0
client read bytes:0
Writing to socket channel:05message05

Read from server: 05message05
Read from server: 02message02
Read from server: 01message01
Read from server: 04message04
Read from server: 07message07
Read from server:
...

 

by: OnegaZhangPosted on 2005-10-10 at 05:23:32ID: 15051659

change your code to
final ByteBuffer buffer = ByteBuffer.allocate( 20 );
then I see
client read bytes:20
Read from server: ssage01

I think I understand the problem now:
For ith read operation, there are 12 * N bytes available, but sizeof your buffer is 12 * M + 4, and M<N,
so the next read would get a truncated message, because its head is read by previous call and abandoned.
      for (int i=0; i<buffer.limit(); ++i) {
        byte b = buffer.get( i );
        if ( b == (char)13 ) {
          break;  //when you stop here, there are undisplayed bytes in buffer in fact.
        } else {
          m.append((char)b);
        }
      }

 

by: pankajtiwaryPosted on 2005-10-10 at 05:32:16ID: 15051700

Hello OnegaZhang,

I have 2 things to say:

1. Well, I think I am creating a fresh new buffer for reading from the SocketChannel, so it should not have any bytes left from previous read. Am I missing something ?

2. What is the way to solve the situation. I mean you talked about the problem and not about the solution :-).

Regards
Pankaj

 

by: pankajtiwaryPosted on 2005-10-10 at 05:34:52ID: 15051711

Sorry, I am a little more eager, did not read your full post before posting.

Apologies.

 

by: pankajtiwaryPosted on 2005-10-10 at 05:45:36ID: 15051771

I don't see anything except the println statements in my code that you changed. Changing the buffer size to 20 gives truncated messages earlier.

Please help.

 

by: OnegaZhangPosted on 2005-10-10 at 07:37:55ID: 15052543

solution: use a nontempory buffer for each socketchannel.
after each read operation, process all complete messages and remove them,
eg if there are 12*N+4 useful bytes in the buffer, copy the last 4 byte to start of the buffer and reset current position of the buffer.
for the sending part, you also need a buffer to store all data to be sent, don't assume a message could be sent out by a single send call.

 

by: OnegaZhangPosted on 2005-10-10 at 22:24:33ID: 15057819

try the following changes, it does not truncate message

class TestWorkerThread implements Runnable {
  static private int count = 0;
  private int taskNumber;
  protected Done done;

  /**
   * Buffer to read data from SocketChannel.
   */
  //private final ByteBuffer buffer = ByteBuffer.allocate( 1024 );

  /**
   * SocketChennel to read data from.
   */
  private SocketChannel sc;
  private ByteBuffer buffer;

  /**
   *
   * @param done
   */
  TestWorkerThread(SocketChannel s, ByteBuffer buff)
  {
    count++;
    taskNumber = count;
    sc = s;
    buffer = buff;
  }
  void println(StringBuffer s)
  {
      System.out.println(s);
  }
  public void run()
  {

    try {
//store output in StringBuffer first to avoid interference of other thread
        StringBuffer sb = new StringBuffer();
        String newline = " ";//I don't use line feed in order to save screen space
      int n = sc.read( buffer );
      sb.append("read bytes:"+n + newline);
      StringBuffer m = new StringBuffer();
      if (buffer.limit()==0) {
        sb.append("buffer limit=0");
        println(sb);
        return;
      }
      int end_of_last_msg = 0;
      for (int i=0; i<buffer.limit(); i++) {
        byte b = buffer.get( i );
        if ( b == (char)13 ) {
            end_of_last_msg = i;
            //print one message, but the buffer may hold more than one message
            sb.append(" Read from server: " + m );
            sb.append( " i:" +i + " limit:" + buffer.limit() );    
            //we have decoded a full message, clear m to decode next message.
            m = new StringBuffer();
        } else {
          m.append((char)b);
        }
      }
      if(end_of_last_msg<buffer.limit())
      {
          //there is an incomplete message in buffer, move it to the begin of buffer
          byte tmp[] = new byte[buffer.limit()-end_of_last_msg-1];
          buffer.position(end_of_last_msg+1);
          for(int j=0;j<tmp.length;j++)
          {
              tmp[j] = buffer.get();
          }
          buffer.clear();
          buffer.put(tmp);
      }
      else
      {//there is no partial message in the buffer, and all full messages are processed,
          //so the buffer can be cleared.
          buffer.clear();
      }
      sb.append(" position:" + buffer.position());
      println(sb);
    } catch ( IOException g ) {
        g.printStackTrace();
    }
  }
}

class ReceiverThread implements Runnable {
  Thread t;
  ThreadPool pool;
  Selector s;
  SocketChannel con[];
  private final ByteBuffer buffer = ByteBuffer.allocate( 1024 );
  ByteBuffer socketbuffer[];
  ByteBuffer getBuffer(SocketChannel sc)
  {//you can use better algorithm to associate ByteBuffer with SocketChannel
      for( int i=0; i< con.length;i++)
      {
          if(con[i].equals(sc))
              return socketbuffer[i];
      }
      return null;
  }
  ReceiverThread (SocketChannel sc[]) {
      socketbuffer = new ByteBuffer[sc.length];
      for(int i=0;i<sc.length;i++)
      {//test to create buffer of different size, the code shall still works
          //the only limitation is that: it must be longer than maximum lenght of a full message
          socketbuffer[i] = ByteBuffer.allocate(20+i);
      }
    t = new Thread(this, "Receiver Thread");
    pool = new ThreadPool(10);
    System.out.println ("In ReceiverThread constructor: pool initialized");
    try {
      s = Selector.open();
      int i;
      con = new SocketChannel[10];
      for ( i = 0; i < 10; i++ ) {
        con[i] = sc[i];
        con[i].register(s, SelectionKey.OP_READ);
      }
    } catch ( IOException g ) {
      System.out.println (g);
    }
    System.out.println("Receiver Thread initialized");
    t.start();
  }
  public void run() {
    pool.startWorking();
    try {
      while ( true ) {
        int num = s.select();
        if ( num == 0 ) {
          System.out.println ( "num == 0");
          continue;
        }
        Set keys = s.selectedKeys();
        Iterator it = keys.iterator();
        while ( it.hasNext() ) {
          SelectionKey key = (SelectionKey)it.next();
          SocketChannel sc = null;
          if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {
            sc = (SocketChannel)key.channel();
            pool.assign ( new TestWorkerThread ( sc, getBuffer(sc) ) );
          }
        }
        keys.clear();
      }
    } catch ( IOException g ) {
      System.out.println (g);
    }
  }
}

20120131-EE-VQP-002

3 Ways to Join

30-Day Free Trial

The Experts

98% positive feedback on 31,087 answers since March 2000. angeliii is a Microsoft Most Valuable Professional for his work with MS SQL Server & Develoment.

He has also proven his knowledge of Visual Basic Programming, PHP Scripting and Oracle Databases.

The Experts

97% positive feedback on 10,752 answers since July 2000. lrmoore has more than 18 years experience in the networking industry.

The six-time Mircosoft MVPs specialties include firewalls, virtual private networking, and network management.

Testimonials

"...and excellent source for support... Kind of like having your very own IT dept." Electriciansnet

Testimonials

"I was apprehensive at signing up at first. However... it has already made my life as an IT administrator much easier." JaCrews

Testimonials

"WOW! You guys have great, active, and knowledgeable people on here." moore50

Business Clients

Business Clients

In the Press

"If you’ve got a question... Experts Exchange can supply an answer.”

In the Press

"...an invaluable aid for both IT professionals and those who require tech support."

In the Press

"where IT professionals provide quick answers on just about any topic"

Business Account Plans

Loading Advertisement...