HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 

"Java and the MahJong Server"
Vol 1, Issue 1, P.36

	

Listing 1:  Packet Examples

// File Packet.java
import java.io.*;

public abstract class Packet {
  // client -> server packet tags
  public static final byte CP_LOGIN = 0;
  // server -> client packet tags
  public static final byte SP_LOGIN = 0;

  // abstract method to send the packet in binary form
  public abstract void output (DataOutputStream S) throws IOException;

  // write the packet into a byte-array buffer
  public byte[] format () throws IOException {
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
    DataOutputStream S = new DataOutputStream(buf);
    output(S);
    return buf.toByteArray();
  }
}

// File CPLogin.java
import java.io.*;

public class CPLogin extends Packet {
  public String name;

  public CPLogin (String n) {
    name = n;
  }

  public CPLogin (DataInputStream S) throws IOException {
    // we assume the tag is already read in
    name = S.readUTF();
  }
  public void output (DataOutputStream S) throws IOException {
    S.writeByte(CP_LOGIN);                 // always write the tag first
    S.writeUTF(name);
  }
}

// File SPLogin.java
import java.io.*;

public class SPLogin extends Packet {
  public static final byte OK = 0;
  public static final byte REJECTED = 1;
  public byte result;

  public SPLogin (byte r) {
    result = r;
  }
  public SPLogin (DataInputStream S) throws IOException {
    result = S.readByte();
  }
  public void output (DataOutputStream S) throws IOException {
    S.writeByte(SP_LOGIN);
    S.writeByte(result);
  }
}


Listing 2:  The Client

// File Greeting.java
import java.net.*;
import java.io.*;
import java.awt.*;

public class Greeting extends java.applet.Applet {
  Button main_button = new Button('Connect Now!');
  Client main = null;

  public void init () {
    add(main_button);
    show();
  }
  public void restart () {
    main = null;
    main_button.setLabel('Connect again');
    main_button.enable();
  }
  public boolean action (Event evt, Object what) {
    if (evt.target == main_button) {
      main_button.disable();
      main_button.setLabel('Connecting...');
      String server_host = getParameter('ServerHost');
      int server_port = 5555;  // default port number
      try {
        server_port = Integer.parseInt(getParameter('ServerPort'));
      } catch (NumberFormatException e) {
      }
      try {
        Socket sock = new Socket(server_host, server_port);
        DataInputStream in = new DataInputStream(sock.getInputStream());
        DataOutputStream out = new DataOutputStream(sock.getOutputStream());
        main_button.setLabel('Connected!');
        main = new Client(this, sock, in, out);
      } catch (Exception e) {
        restart();
      }
    }
    return true;
  }
}

// File Client.java
import java.awt.*;
import java.io.*;
import java.net.*;

class Client extends Frame implements Runnable {
  Socket sock;
  DataInputStream in;
  DataOutputStream out;
  Greeting greeter;
  Thread listener;
  TextField name_field;
  // other variables

  public Client (Greeting g, Socket s, DataInputStream i, DataOutputStream o) {
    sock = s;
    in = i;
    out = o;
    greeter = g;
    (listener = new Thread(this)).start();
    setTitle('Login');
    name_field = new TextField(20);
    setLayout(new FlowLayout());
    add(name_field);
    pack();
    show();
  }
  void output (Packet p) {
    try {
      p.output(out);
    } catch (IOException e) {
      disconnect();
      listener.stop();
      listener = null;
      dispose();
      greeter.restart();
    }
  }
  void disconnect () {
    try {
      in.close();
      out.close();
      sock.close();
    } catch (IOException e) {
    }
  }
  public boolean action (Event evt, Object what) {
    if (evt.target == name_field) {
      output(new CPLogin(name_field.getText()));
    }
    // handle other user interactions and send client->server packets
    return true;
  }
  public void run () {
    for (;;) {
      try {
        byte type = in.readByte();
        switch (type) {
        case Packet.SP_LOGIN:
          hdLogin(new SPLogin(in));
          break;
        // other packets
        }
      } catch (IOException e) {
        disconnect();
        listener = null;
        dispose();
        greeter.restart();
        return;
      }
    }
  }
  void hdLogin (SPLogin pkt) {
    if (pkt.result == SPLogin.OK) {
      System.out.println('We are logged in!');
      // we can proceed to start games now
    } else {
      System.out.println('Login rejected!');
    }
  }
  // other packet handlers
}

// File applet.html

<html>
<applet	CODE='Greeting.class'
 WIDTH=150
 HEIGHT=40>
<param	NAME='ServerHost'
 VALUE='localhost'>
<param	NAME='ServerPort'
 VALUE='5555'>
</applet>
</html>


Listing 3:  A Queue Class

// File Queue.java

class QueueLink {
  QueueLink next;
  Object obj;

  public QueueLink (Object o) {
    obj = o;
    next = null;
  }
}

public class Queue {
  private QueueLink head = null, tail = null;

  public synchronized Object pop () {
    while (head == null) {
      try {
 wait();
      } catch (InterruptedException e) {
      }
    }
    Object o = head.obj;
    head = head.next;
    if (head == null) {
      tail = null;
    }
    return o;
  }

  public synchronized void push (Object o) {
    if (head == null) {
      head = tail = new QueueLink(o);
      notify();
    } else {
      tail.next = new QueueLink(o);
      tail = tail.next;
    }
  }
}


Listing 4: The Server

// File Server.java
import java.io.*;
import java.net.*;

class Server {
  public static void main (String argv[]) {
    ServerSocket main_sock = null;
    try {
      main_sock = new ServerSocket(5555);  // default port to listen on
    } catch (IOException e) {
      System.out.println(e.toString());
      System.exit(1);
    }
    // other initializations
    for (;;) {
      try {
        Socket s = main_sock.accept();
        DataInputStream in = new DataInputStream(sock.getInputStream());
        DataOutputStream out = new DataOutputStream(sock.getOutputStream());
        new Player(s, in, out).start();
      } catch (IOException e) {
        System.out.println(e.toString());
      }
    }
  }
}

// File Player.java
import java.io.*;
import java.net.*;
import java.util.Hashtable;

class Player extends Thread {
  static Hashtable list = new Hashtable();
  static RWMonitor rw_mon = new RWMonitor();
  Socket sock;
  DataInputStream in;
  DataOutputStream out;
  PlayerOutput out_thread;
  String name = null;
  // other variables

  public Player (Socket s, DataInputStream i, DataOutputStream o) {
    sock = s;
    in = i;
    out = o;
    (out_thread = new PlayerOutput(this, out)).start();
    // other initialization stuff
  }
  public void output (Packet p) {
    try {
      out_thread.output(p.format());
    } catch (IOException e) {
    }
  }
  public void disconnect () {
    try {
      in.close();
      out.close();
      sock.close();
    } catch (IOException e) {
    }
    if (name != null) {
      rw_mon.inWrite();  // enter critical region
        list.remove(this);
      rw_mon.outWrite();  // leave critical region
    }
    // other clean up stuff
  }
  public void run () {
    for (;;) {
      try {
        byte type = in.readByte();
        switch (type) {
        case Packet.CP_LOGIN:
          hdLogin(new CPLogin(in));
          break;
        // other packets
        default:  // unrecognized packet
          disconnect();
          out_thread.stop();
          return;
        }
      } catch (IOException e) {
        disconnect();
        out_thread.stop();
        return;
      }
    }
  }
  void hdLogin (CPLogin pkt) {
    if (name != null) {  // can't login twice
      output(new SPLogin(SPLogin.REJECTED));
      return;
    }
    rw_mon.inWrite();  // enter critical region    
    if (list.get(pkt.name) == null) {  // check if he's already on the server
      name = pkt.name;
      list.put(name, this);
      output(new SPLogin(SPLogin.OK));
    } else {
      output(new SPLogin(SPLogin.REJECTED));
    }
    rw_mon.outWrite();  // leave critical region
    // other stuff to do after successful login
  }
  // other packet handlers
}

// File PlayerOutput.java
import java.io.*;

class PlayerOutput extends Thread {
  private static Player the_player;
  private DataOutputStream out;
  private Queue pkt_queue = new Queue();

  public PlayerOutput (Player p, DataOutputStream S) {
    the_player = p;
    out = S;
  }
  public void output (byte p[]) {
    pkt_queue.push(p);
  }
  public void run () {
 loop:
    while (true) {
      byte p[] = (byte[])pkt_queue.pop();
      try {
 if (p.length != 0) {
   out.write(p, 0, p.length);
 }
      } catch (IOException e) {
 break loop;
      }
    }
    the_player.disconnect();
    the_player.stop();
  }
}


Listing 5:  Reader-Writer Problem

// File RWMonitor.java

class Mutex {
  public synchronized void mywait () throws InterruptedException {
    wait();
  }
  public synchronized void mynotify () {
    notify();
  }
  public synchronized void mynotifyAll () {
    notifyAll();
  }
}

public class RWMonitor {
  private int n_readers = 0;
  private int n_writers = 0;
  private int n_queued = 0;
  private Mutex reader_mon = new Mutex();
  private Mutex writer_mon = new Mutex();

  private synchronized boolean readable () {
    if (n_writers > 0) {
      return false;
    }
    n_readers++;
    return true;
  }
  private synchronized boolean writable () {
    n_writers++;
    if (n_writers > 1) {
      return false;
    }
    if (n_readers > 0) {
      return false;
    }
    return true;
  }
  public void inRead () {
    while (!readable()) {
      try {
 reader_mon.mywait();
      } catch (InterruptedException e) {
      }
    }
  }
  public synchronized void outRead () {
    if (n_readers == 0) {
      if (n_writers > 0) {
 writer_mon.mynotify();
      }
    }
  }
  public void inWrite () {
    if (!writable()) {
      try {
 writer_mon.mywait();
      } catch (InterruptedException e) {
      }
    }
  }
  public synchronized void outWrite () {
    if (n_writers > 0) {
      writer_mon.mynotify();
    } else {
      reader_mon.mynotifyAll();
    }
  }
}

 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: info@sys-con.com

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.