Friday 31 March 2017

Scrabblet: The Server Code - Java Tutorials

These last two classes are not part of this applet. Rather, they must be installed and run separately on the web server that the applet classes are to be loaded from. This will require the security rights to install and run so-called daemon processes on the web site, which not many people have. Fortunately, most users of this game will not be setting up their own servers; more likely, they will just play games connected to existing ones.

Server.java
Server is the main class for the server side of Scrabblet. Once this is installed on the web server, you have to run it using the command-line Java interpreter for that system, as shown here:

  C:\java\Scrabblet> java Server

Once running, Server will respond with the following message:

Server listening on port 6564

The Server class starts out by declaring a few variables. The port has to be the same number, 6564, as we saw in ServerConnection. The idcon Hashtable is used to store all of the connections to all of the clients. We use a hash table rather than an array to manage frequent insertion and deletion, which require lots of array copying. The id is incremented for each new connection. This corresponds to the id instance variable we saw earlier in the client.

  import java.net.*;
  import java.io.*;
  import java.util.*;

  public class Server implements Runnable {
    private int port = 6564;
    private Hashtable idcon = new Hashtable();
    private int id = 0;
    static final String CRLF = "\r\n";

addConnection( )
The addConnection( ) method is called every time a new client connects to our applet. This method creates a new instance of ClientConnection, described next, to manage the client. It passes in a reference to this Server, the socket the client connected with, and the current value of id. Finally, it increments the id to have it ready for the next connection.

    synchronized void addConnection(Socket s) {
      ClientConnection con = new ClientConnection(this, s, id);
      // we will wait for the ClientConnection to do a clean
      // handshake setting up its "name" before calling
      // set() below, which makes this connection "live."
      id++;
    }

set( )
The set( ) method is called from ClientConnection in response to the client telling us its “name.” set( ) tracks all of the connections in the idcon hash table, and first it removes this id from the table so that it won’t get duplicates if the client sends its name twice. The method calls setBusy(false) to signify that this connection is available to play a game. Then it walks through all of the other connections by enumerating the keys of the idcon hash table. For all nonbusy connections (those players waiting for an opponent), set( ) sends an “add” protocol message so they will all know about this connection.

    synchronized void set(String the_id, ClientConnection con) {
      idcon.remove(the_id) ; // make sure we're not in there twice.
      con.setBusy(false);
      // tell this one about the other clients.
      Enumeration e = idcon.keys();
      while (e.hasMoreElements()) {
        String id = (String)e.nextElement();
        ClientConnection other = (ClientConnection) idcon.get(id);
        if (!other.isBusy())
          con.write("add " + other + CRLF);
      }
      idcon.put(the_id, con);
      broadcast(the_id, "add " + con);
    }

sendto( )
sendto( ) is called in response to a “to” protocol message. It writes whatever is in the body string directly to the connection identified by dest.

    synchronized void sendto(String dest, String body) {
      ClientConnection con = (ClientConnection)idcon.get(dest);
      if (con != null) {
        con.write(body + CRLF);
      }
    }

broadcast( )
The broadcast( ) method is used to send a single message, in body, to every single connection except the one identified in exclude (typically, the sender).

    synchronized void broadcast(String exclude, String body) {
      Enumeration e = idcon.keys();
      while (e.hasMoreElements()) {
        String id = (String)e.nextElement();
        if (!exclude.equals(id)) {
          ClientConnection con = (ClientConnection) idcon.get(id);
          con.write(body + CRLF);
        }
      }
    }

delete( )
The delete( ) method is used to tell all of the connected clients to forget they ever heard of the_id. This is used by clients that are engaged in a game to remove themselves from other players’ eligibility lists.

    synchronized void delete(String the_id) {
      broadcast(the_id, "delete " + the_id);
    }

kill( )
The kill( ) method is called whenever a client explicitly quits, sending the “quit” message, or when a client simply dies if the browser quits.

    synchronized void kill(ClientConnection c) {
      if (idcon.remove(c.getId()) == c) {
        delete(c.getId());
      }
    }

run( )
The run( ) method is the main loop of the server. It creates a new socket on port 6564
and goes into an infinite loop accepting socket connections from clients. It calls
addConnection( ) with each socket that it accepts.

    public void run() {
      try {
        ServerSocket acceptSocket = new ServerSocket(port);
        System.out.println("Server listening on port " + port);
        while (true) {
          Socket s = acceptSocket.accept();
          addConnection(s);
        }
      } catch (IOException e) {
        System.out.println("accept loop IOException: " + e);
      }
    }

main( )
main( ) is, of course, the method run by the Java command-line interpreter. It creates a new instance of Server and launches a new Thread to run it.

    public static void main(String args[]) {
      new Thread(new Server()).start();
      try {
        Thread.currentThread().join();
      } catch (InterruptedException e) { }
    }
  }


ClientConnection.java

This class is the mirror image of ServerConnection in the applet. One of these is created for each client. Its job is to manage all of the I/O to and from a client. The private instance variables hold all of the states about this client. The Socket is stored in sock. The buffered reader and output streams are stored in in and out. The host name of the client machine is kept in host. A reference to the Server instance that created this client is held in server. The name of the player on this client is stored in name, while the player’s automatically assigned ID number is held in id. The busy Boolean variable stores whether or not this client is actively engaged in a game.

  import java.net.*;
  import java.io.*;
  import java.util.*;

  class ClientConnection implements Runnable {
    private Socket sock;
    private BufferedReader in;
    private OutputStream out;
    private String host;
    private Server server;
    private static final String CRLF = "\r\n";
    private String name = null; // for humans
    private String id;
    private boolean busy = false;

ClientConnection( )
The constructor saves the reference to the server and socket and remembers the unique ID. We wrap an InputStreamReader and a BufferedReader around the input so that it can call readLine( ) on it. Then it writes the id back to the client to let it know what number it is. Finally, it creates and starts a new Thread to handle this connection.

    public ClientConnection(Server srv, Socket s, int i) {
      try {
        server = srv;
        sock = s;
        in = new BufferedReader(new
                            InputStreamReader(s.getInputStream()));
        out = s.getOutputStream();
        host = s.getInetAddress().getHostName();
        id = "" + i;

        // tell the new one who it is...
        write("id " + id + CRLF);

        new Thread(this).start();
      } catch (IOException e) {
        System.out.println("failed ClientConnection " + e);
      }
    }

toString( )
We override toString( ) so that we can have a clean representation of this connection for logging.

    public String toString() {
      return id + " " + host + " " + name;
    }

getHost( ), getId( ), isBusy( ), and setBusy( )
We wrap host, id, and busy in public methods to allow read-only access.

    public String getHost() {
      return host;
    }

    public String getId() {
      return id;
    }

    public boolean isBusy() {
      return busy;
    }

    public void setBusy(boolean b) {
      busy = b;
    }

close( )
The close( ) method is called if the client explicitly quits or if we get an exception reading from the socket. We call kill( ) in the server, which removes us from any lists. Then we close the socket, which also closes both the input and output streams.

    public void close() {
      server.kill(this);
      try {
        sock.close(); // closes in and out too.
      } catch (IOException e) { }
    }

write( )
To write a string to a stream, we have to convert it to an array of bytes, using getBytes( ).

    public void write(String s) {
      byte buf[];
      buf = s.getBytes();
      try {
        out.write(buf, 0, buf.length);
      } catch (IOException e) {
        close();
      }
    }

readline( )
The readline( ) method merely converts the IOException from readLine( ) into a null return value.

    private String readline() {
      try {
        return in.readLine();
      } catch (IOException e) {
        return null;
      }
    }

Keywords
This section is very similar to the same part of the ServerConnection class, which represents the other end of the wire. The static variables and static block shown here are used to initialize the keys Hashtable with a mapping between the strings in keystrings and their position in the array—for example, keys.get(“quit”) == QUIT The lookup( ) method takes care of unpacking the Integer objects into the right int, with –1 meaning the keyword was not found.

    static private final int NAME = 1;
    static private final int QUIT = 2;
    static private final int TO = 3;
    static private final int DELETE = 4;

    static private Hashtable keys = new Hashtable();
    static private String keystrings[] = {
      "", "name", "quit", "to", "delete"
    };
    static {
      for (int i = 0; i < keystrings.length; i++)
        keys.put(keystrings[i], new Integer(i));
    }

    private int lookup(String s) {
      Integer i = (Integer) keys.get(s);
      return i == null ? -1 : i.intValue();
    }

run( )
run( ) has the loop that manages all of the communication with this client. It uses a StringTokenizer to parse the input lines, keying off of the first word in each line. The lookup( ) method just shown is used to look up these first words in the keys hash table. We then switch, based on the integer value of the keyword. The NAME message comes from clients when they first gain a human identity. We call set( ) in the server to get this connection set up. The QUIT message is sent when the client wants to end its server session. The TO message contains a destination ID and a message body to be sent to that client. We call sendto( ) in the server to pass the message along. The last message is DELETE, which is sent by clients that want to continue being connected but no longer want to have their names listed as available to play. run( ) sets the busy flag and calls delete( ) in the server, which notifies the clients that we don’t want to be called.

    public void run() {
      String s;
      StringTokenizer st;
      while ((s = readline()) != null) {
        st = new StringTokenizer(s);
        String keyword = st.nextToken();
        switch (lookup(keyword)) {
        default:
          System.out.println("bogus keyword: " + keyword + "\r");
          break;
        case NAME:
          name = st.nextToken() +
            (st.hasMoreTokens() ? " " + st.nextToken(CRLF) : "");
          System.out.println("[" + new Date() + "] " + this + "\r");
          server.set(id, this);
          break;
        case QUIT:
          close();
          return;
        case TO:
          String dest = st.nextToken();
          String body = st.nextToken(CRLF);
          server.sendto(dest, body);
          break;
        case DELETE:
          busy = true;
          server.delete(id);
          break;
        }
      }
      close();
    }
  }


Enhancing Scrabblet

This applet represents a complete client/server, multiplayer board game. In the future, the code in Server and ServerConnection could be extended in many ways. It could be used to support other turn-based games. It could track and maintain a high-score list for each game. It could be dynamically extensible to understand new protocol verbs. One such example for the game described in this chapter would be to have a lookup function that checked a series of submitted words against a dictionary stored on the server. The server could then be the arbiter for such disputes as whether xyzy is a valid word. You could also construct a word robot, which would reside on the server but act like another player and use the dictionary to generate the best word placement from its current set of seven letters. It could even use a list of pithy quotes to throw into the chat window after each move. You might want to try making some of these enhancements yourself. This applet is intended for entertainment and educational purposes. Any similarity to any and all commercial products is merely coincidental.

25 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. Have you been thinking about the power sources and the tiles whom use blocks I wanted to thank you for this great read!! I definitely enjoyed every little bit of it and I have you bookmarked to check out the new stuff you post

    Data Science Training in Chennai
    Data science training in bangalore
    Data science online training
    Data science training in pune
    Data Science training in kalyan nagar
    Data Science training in OMR
    selenium training in chennai

    ReplyDelete
  4. I found your blog while searching for the updates, I am happy to be here. Very useful content and also easily understandable providing.. Believe me I did wrote an post about tutorials for beginners with reference of your blog. 
    java training in electronic city

    java training in chennai | java training in USA

    selenium training in chennai

    ReplyDelete
  5. I would like to thank you for the efforts you have made in writing this article. I am hoping the same best work from you in the future as well. In fact your creative writing abilities has inspired me to start my own BlogEngine blog now. Really the blogging is spreading its wings rapidly. Your write up is a fine example of it.
    python online training
    python training in OMR
    python training in tambaram

    ReplyDelete
  6. Good Post! Thank you so much for sharing this pretty post, it was so good to read and useful to improve my knowledge as updated one, keep blogging.
    Devops Training in Chennai

    Devops training in sholinganallur

    ReplyDelete
  7. Its really an Excellent post. I just stumbled upon your blog and wanted to say that I have really enjoyed reading your blog. Thanks for sharing....
    Blueprism training in tambaram

    Blueprism training in annanagar

    Blueprism training in velachery

    ReplyDelete
  8. This comment has been removed by the author.

    ReplyDelete
  9. Really i found this article more informative, thanks for sharing this article! Also Check here
    Really i found this article more informative, thanks for sharing this article! Also Check here
    thnaska alot
    Ai & Artificial Intelligence Course in Chennai
    PHP Training in Chennai
    Ethical Hacking Course in Chennai Blue Prism Training in Chennai
    UiPath Training in Chennai

    ReplyDelete
  10. After reading this web site I am very satisfied simply because this site is providing comprehensive knowledge for you to audience.
    AWS training in chennai | AWS training in annanagar | AWS training in omr | AWS training in porur | AWS training in tambaram | AWS training in velachery

    ReplyDelete
  11. Digital marketing is the component of marketing that utilizes internet and online based digital technologies such as desktop computers, mobile phones and other digital media and platforms to promote products and servicesJava training in chennai

    python training in chennai

    web designing and development training in chennai

    selenium training in chennai

    digital-marketing training in chennai

    ReplyDelete
  12. I really appreciate your help with my The Suicide Squad 2 project!

    ReplyDelete
  13. Really an awesome blog and informative blog and useful for many people. Thanks for sharing this blog with us. If you want a data science course, then check out the following link.
    Best Online Data Science Courses

    ReplyDelete
  14. I have read your article, it is very informative and helpful for me.I admire the valuable information you offer in your articles. Thanks for posting it.. data science training in kanpur

    ReplyDelete