⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 732-735.html

📁 java game programming e-book
💻 HTML
字号:
<HTML>
<HEAD>
<META name=vsisbn content="1571690433"><META name=vstitle content="Black Art of Java Game Programming"><META name=vsauthor content="Joel Fan"><META name=vsimprint content="Sams"><META name=vspublisher content="Macmillan Computer Publishing"><META name=vspubdate content="11/01/96"><META name=vscategory content="Web and Software Development: Programming, Scripting, and Markup Languages: Java"><TITLE>Black Art of Java Game Programming:The Internet MahJong Server</TITLE>
<!-- HEADER --><STYLE type="text/css">  <!-- A:hover  { 	color : Red; } --></STYLE><META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW"><script><!--function displayWindow(url, width, height) {         var Win = window.open(url,"displayWindow",'width=' + width +',height=' + height + ',resizable=1,scrollbars=yes');	if (Win) {		Win.focus();	}}//--></script><SCRIPT><!--function popUp(url) {        var Win = window.open(url,"displayWindow",'width=400,height=300,resizable=1,scrollbars=yes');	if (Win) {		Win.focus();	}}//--></SCRIPT><script language="JavaScript1.2"><!--function checkForQuery(fm) {  /* get the query value */  var i = escape(fm.query.value);  if (i == "") {      alert('Please enter a search word or phrase');      return false;  }                  /* query is blank, dont run the .jsp file */  else return true;  /* execute the .jsp file */}//--></script></HEAD><BODY> 
<TABLE border=0 cellspacing=0 cellpadding=0>
<tr>
<td width=75 valign=top>
<img src="../1571690433.gif" width=60 height=73 alt="Black Art of Java Game Programming" border="1">
</td>
<td align="left">
    <font face="arial, helvetica" size="-1" color="#336633"><b>Black Art of Java Game Programming</b></font>
    <br>
    <font face="arial, helvetica" size="-1"><i>by Joel Fan</i>
    <br>
    Sams,&nbsp;Macmillan Computer Publishing
    <br>
    <b>ISBN:</b>&nbsp;1571690433<b>&nbsp;&nbsp;&nbsp;Pub Date:</b>&nbsp;11/01/96</font>&nbsp;&nbsp;
</td>
</tr>
</table>
<P>

<!--ISBN=1571690433//-->
<!--TITLE=Black Art of Java Game Programming//-->
<!--AUTHOR=Joel Fan//-->
<!--AUTHOR=Eric Ries//-->
<!--AUTHOR=Calin Tenitchi//-->
<!--PUBLISHER=Macmillan Computer Publishing//-->
<!--IMPRINT=Sams//-->
<!--CHAPTER=18//-->
<!--PAGES=732-735//-->
<!--UNASSIGNED1//-->
<!--UNASSIGNED2//-->

<CENTER>
<TABLE BORDER>
<TR>
<TD><A HREF="728-732.html">Previous</A></TD>
<TD><A HREF="../ewtoc.html">Table of Contents</A></TD>
<TD><A HREF="735-738.html">Next</A></TD>
</TR>
</TABLE>
</CENTER>
<P><BR></P>
<H4 ALIGN="LEFT"><A NAME="Heading17"></A><FONT COLOR="#000077">The Listener Thread</FONT></H4>
<P>As explained earlier, we need a listener thread for each player. This is why Player extends Thread. It is clear that its run() method should basically be a packet dispatcher:
</P>
<!-- CODE //-->
<PRE>
private Integer working = new Integer(0);
public void run () &#123;
loop:
  while (connected) &#123;
    try &#123;
      byte tag = in.readByte();
      // don&#146;t stop until we finish with this packet
      synchronized (working) &#123;
        switch (tag) &#123;
        case CP_QUIT:
          break loop;
        case CP_MESSAGE:
          hdMessage();
          break;
        // call other packet handlers
        &#125;
      &#125;
    &#125; catch (IOException e) &#123;
      break loop;
    &#125;
  &#125;
  connected = false;
  out_thread.stop();
  disconnect();
&#125;
public void stopOnWait () &#123;
  connected = false;         // so that run() won't loop again
  synchronized (working) &#123;   // stop only if blocked on input
    stop();
  &#125;
&#125;
</PRE>
<!-- END CODE //-->
<P>The stopOnWait() method is called when an abnormal event happens to a player, for example, when the server decides his network connection is dead and wants to clear his slot. The run() method may be in the middle of handling a packet, so we don&#146;t want to stop it immediately and potentially leave the server in an inconsistent state. However, we do make sure that the thread dies before it reads in the next packet.
</P>
<P>I only present here a handler method for CP_MESSAGE. It first determines whether a message is directed to all players on the server or only to those on the player&#146;s table (I chose not to allow personal messages as a countermeasure against cheating), then constructs a corresponding SP_MESSAGE packet and sends it to targeted players. Other packet handlers are similar in nature, so I will skip them.</P>
<!-- CODE //-->
<PRE>
void hdMessage throws IOException &#123;
  // CP_MESSAGE contains a target type (MSG_SERVER,
  // MSG_TABLE, or MSG_ALL), and a text message.
  byte type = in.readByte();
  String text = in.readUTF();
  if (type == Packet.MSG_SERVER)
    System.out.println("Msg from " &#43; id &#43; ": " &#43; text);
  else if (type == Packet.MSG_TABLE &#38;&#38; table != null)
    table.outputTable(Packet.SPMessage(Packet.MSG_TABLE, id, text));
  else
    outputAll(Packet.SPMessage(Packet.MSG_ALL, id, text));
&#125;
</PRE>
<!-- END CODE //-->
<H4 ALIGN="LEFT"><A NAME="Heading18"></A><FONT COLOR="#000077">The Replier Thread</FONT></H4>
<P>It remains to explain the use of PlayerOutput <I>out_thread</I>. This is the replier thread for our player. Let me first convince you that there is a need for two threads per player. Sending packets is done via the output() method. Its naive implementation is to just do an out.write() call. However, this may cause problems. Player A&#146;s listener thread may need to send another player B&#146;s client a packet (this happens, for example, when A sends everyone a message); thus, somewhere inside A.run() we have a call to B.output(). But as we know, network connections are far from perfect, so such a call, implemented the naive way, might take an arbitrarily long time to finish. This would prevent A.run() from handling more packets in a timely manner. Indeed, a general rule of thumb is that all packet handlers must do their job quickly.</P>
<P>To solve this problem, I let the output() method simply add the packet to a queue. The replier thread of the player pops them off the queue and sends them out. First, let me give a version of the Queue class:</P>
<!-- CODE //-->
<PRE>
package types;
class QueueLink &#123;            // a linked list node for our Queue
  public QueueLink next;
  public Object obj;
  public QueueLink (Object o) &#123;
    obj = o;
    next = null;
  &#125;
&#125;
public class Queue &#123;         // first-in, first-out
  private QueueLink head = null, tail = null;
  public synchronized Object pop () &#123;
    while (head == null) &#123;
      try &#123;
        wait();              // block until we get an item
      &#125; catch (InterruptedException e) &#123;
      &#125;
    &#125;
    Object o = head.obj;     // pop the first item
    head = head.next;
    if (head == null) &#123;
      tail = null;
    &#125;
    return o;
  &#125;
  public synchronized void push (Object o) &#123;
    if (head == null) &#123;
      head = tail = new QueueLink(o);
    &#125; else &#123;
      tail.next = new QueueLink(o);
      tail = tail.next;
    &#125;
    notify();                // wake up blocked threads
  &#125;
&#125;
</PRE>
<!-- END CODE //-->
<P>The actual class for the replier thread is PlayerOutput:
</P>
<!-- CODE //-->
<PRE>
package server;
import java.io.*;
class PlayerOutput extends Thread &#123;
  private static Player the_player;
  private DataOutputStream out;
  private Queue pkt_queue = new Queue();

  public PlayerOutput (Player p, DataOutputStream o) &#123;
    the_player = p;
    out = o;
  &#125;
  public void output (byte p[]) &#123;
    pkt_queue.push(p);
  &#125;
  public void run () &#123;
  loop:
    while (true) &#123;                 // keep sending packets out
      byte p[] = (byte[])pkt_queue.pop();
      if (p != null &#38;&#38; p.length &gt; 0) &#123;
        try &#123;
          out.write(p, 0, p.length);
        &#125; catch (IOException e) &#123;  // bad connection
          break loop;
        &#125;
      &#125;
    &#125;
    the_player.stopOnWait();       // stop the listener thread
    the_player.disconnect();       // make the player leave
  &#125;
&#125;
</PRE>
<!-- END CODE //-->
<P>Note that since we keep two threads for each player, abnormal conditions like a dead network connection could occur in either thread. Some care needs to be taken to stop both threads (when they can be safely stopped) on such occasions.
</P><P><BR></P>
<CENTER>
<TABLE BORDER>
<TR>
<TD><A HREF="728-732.html">Previous</A></TD>
<TD><A HREF="../ewtoc.html">Table of Contents</A></TD>
<TD><A HREF="735-738.html">Next</A></TD>
</TR>
</TABLE>
</CENTER>


</BODY>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -