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

📄 735-738.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=735-738//-->
<!--UNASSIGNED1//-->
<!--UNASSIGNED2//-->

<CENTER>
<TABLE BORDER>
<TR>
<TD><A HREF="732-735.html">Previous</A></TD>
<TD><A HREF="../ewtoc.html">Table of Contents</A></TD>
<TD><A HREF="738-742.html">Next</A></TD>
</TR>
</TABLE>
</CENTER>
<P><BR></P>
<H4 ALIGN="LEFT"><A NAME="Heading19"></A><FONT COLOR="#000077">The Table Class: A Simple Version</FONT></H4>
<P>For the basic server, we only need to record which players are on a table, and provide methods for players to join and leave tables. As with players, we keep a list of all the tables on the server in an array. The following is a sketch of the Table class.
</P>
<!-- CODE //-->
<PRE>
package server;
class Table &#123;
  public static Table[] global = new Table[25];
  int id = -1;
  Player[] players = new Player[8];  // including 4 spectators

  public Table () throws FullServerException &#123;
    // assign a unique table id
    synchronized (global) &#123;          // critical section
      for (int i = 0; i &lt; global.length; i&#43;&#43;) &#123;
        if (global[i] == null) &#123;
          id = i;
          global[i] = this;
          break;
        &#125;
      &#125;
    &#125;
    if (id == -1) throw new FullServerException();
  &#125;
  public synchronized void outputTable (byte[] p) &#123;
    for (int i = 0; i &lt; players.length; i&#43;&#43;) &#123;
      if (players[i] != null)
        players[i].output(p);
    &#125;
  &#125;
  public synchronized void join (Player him, boolean play) &#123;
  join:
    &#123;
      // seats 0 - 3 are for players, the rest spectators
      int s0 = play ? 0 : 4;
      int s1 = play ? 4 : players.length;
      for (int i = s0; i &lt; s1; i&#43;&#43;) &#123;
        if (players[i] == null) &#123;
          players[i] = him;
          him.table = this;
          him.seat = i;
          Player.outputAll(Packet.SPTablePlayer(id, i, him.id));
          break join;
        &#125;
      &#125;
      him.output(Packet.SPMessage(Packet.MSG_GOD, 0,
                                  "Table is full."));
      return;
    &#125;
    // MahJong-related stuff here
  &#125;
  public void leave (Player him) &#123;
    synchronized (global) &#123;          // critical section
      synchronized (this) &#123;
        if (him.table != this) return;
        // announce to all;  player id of -1 means leaving table
        Player.outputAll(Packet.SPTablePlayer(id, him.seat, -1));
        players[him.seat] = null;
        him.table = null;
        him.seat = -1;
        for (int i = 0; i &lt; 4; i&#43;&#43;)
          if (players[i] != null)
            return;
        // now the table has only spectators, so we close it
        for (int i = 4; i &lt; players.length; i&#43;&#43;) &#123;
          if (players[i] != null) &#123;
            Player.outputAll(Packets.SPTablePlayer(id, i, -1));
            players[i].table = null;
            players[i].seat = -1;
            players[i] = null;
          &#125;
        &#125;
        global[id] = null;
      &#125;
    &#125;
  &#125;
  public synchronized void update (Player him) &#123;
    for (int i = 0; i &lt; players.length; i&#43;&#43;) &#123;
      if (players[i] != null)
        him.output(Packet.SPTablePlayer(id, i, t.players[i].id));
    &#125;
  &#125;
  // other methods...
&#125;
</PRE>
<!-- END CODE //-->
<P>I will say more about the leave() method later.
</P>
<H4 ALIGN="LEFT"><A NAME="Heading20"></A><FONT COLOR="#000077">Handling Login Requests</FONT></H4>
<P>There is one last loose end to tie up: login. For the basic server, we let a player log in whenever he isn&#146;t on the server already. Passwords can be added later.
</P>
<P>After a player logs in, we need to send him updates on all the players and tables currently on the server. This is done in the hdLogin() method that handles login requests:</P>
<!-- CODE //-->
<PRE>
void hdLogin () throws IOException &#123;
  String n = in.readUTF();                   // read in packet data
  synchronized (global) &#123;                    // critical section
    for (int i = 0; i &lt; global.length; i&#43;&#43;) &#123;
      if (global[i] != null &#38;&#38; n.equals(global[i].name)) &#123;
        output(Packet.SPLogin(Packet.LOGIN_TWICE));
        return;                              // reject his login
      &#125;
    &#125;
    name = n;                                // accept his login
  &#125;
  output(Packet.SPLogin(Packet.LOGIN_OK));
  // send updates on all the players
  synchronized (global) &#123;                    // critical section
    for (int i = 0; i &lt; global.length; i&#43;&#43;) &#123;
      if (global[i] != null &#38;&#38; global[i].name != null)
        output(Packet.SPJoin(i, global[i].name));
    &#125;
  &#125;
  // send updates on all the tables
  synchronized (Table.global) &#123;              // critical section
    for (int i = 0; i &lt; Table.global.length; i&#43;&#43;) &#123;
      if (Table.global[i] != null) &#123;
        output(Packet.SPTableOpt(i, null));  // update this table
        Table.global[i].update(this);        // update players
      &#125;
    &#125;
  &#125;
&#125;
</PRE>
<!-- END CODE //-->
<H4 ALIGN="LEFT"><A NAME="Heading21"></A><FONT COLOR="#000077">Synchronization and Deadlock Prevention</FONT></H4>
<P>As you&#146;ve seen in the code I&#146;ve given so far, in the Player and Table classes we often need to acquire monitors on certain objects&#151;four kinds of them, to be exact:
</P>
<DL>
<DD><B>&#149;</B>&nbsp;&nbsp;The Player.global array
<DD><B>&#149;</B>&nbsp;&nbsp;The Table.global array
<DD><B>&#149;</B>&nbsp;&nbsp;A particular Player instance
<DD><B>&#149;</B>&nbsp;&nbsp;A particular Table instance
</DL>
<P>Often, two or more monitors have to be acquired. For instance, in the process of updating all the tables to a certain player, we need to acquire the monitor of Table.global first and then of each individual Table instance. As the server code gets complicated, we face potential deadlock situations.
</P>
<P>A deadlock occurs when several threads are competing for monitors, yet each holds a monitor that another thread needs to acquire in order to proceed. As an example, suppose I defined Table.leave() like this (which is actually more &#147;natural&#148; than the first version):</P>
<!-- CODE SNIP //-->
<PRE>
// an alternative problematic Table.leave()
public synchronized leave (Player him) &#123;
  // get him off the table here, and check for empty table
  // suppose table is empty:
  synchronized (global) &#123;          // remove table
    global[id] = null;
  &#125;
&#125;
</PRE>
<!-- END CODE SNIP //-->
<P>Now imagine two players, A and B. A just logged in, so we are informing him about all the tables. We are about to reach table T, on which B just happens to be the only player, and he happens to decide to leave at this very moment. Say T.leave() is called first, then T.update() must wait for it to finish. In T.leave() we find out that the table should be removed because it is now empty. However, to do this we need to acquire the monitor on Table.global, which is currently held by player A. Thus, these two threads are now in a deadlock. Granted, the chance of this happening is rare, but it&#146;s likely to happen after an extended period of time, and we have to deal with it to get a robust server.
</P><P><BR></P>
<CENTER>
<TABLE BORDER>
<TR>
<TD><A HREF="732-735.html">Previous</A></TD>
<TD><A HREF="../ewtoc.html">Table of Contents</A></TD>
<TD><A HREF="738-742.html">Next</A></TD>
</TR>
</TABLE>
</CENTER>


</BODY>

⌨️ 快捷键说明

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