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

📄 724-728.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=724-728//-->
<!--UNASSIGNED1//-->
<!--UNASSIGNED2//-->

<CENTER>
<TABLE BORDER>
<TR>
<TD><A HREF="719-724.html">Previous</A></TD>
<TD><A HREF="../ewtoc.html">Table of Contents</A></TD>
<TD><A HREF="728-732.html">Next</A></TD>
</TR>
</TABLE>
</CENTER>
<P><BR></P>
<P>The client and the server talk to each other in a language that&#146;s usually called a <I>protocol</I>. Individual sentences of this language are called <I>packets</I>. When a player wants to log in, his client sends the server a login packet, which contains his user name. The server decides if he can log in, and sends back a reply packet. Thus, we need many types of packets, each type carrying a certain piece of information. Java provides several classes for networking. I use ServerSocket and Socket, because they provide reliable point-to-point communication and don&#146;t impose a particular data format. I choose to send packets in binary, because it is the most bandwidth-efficient.</P>
<H4 ALIGN="LEFT"><A NAME="Heading7"></A><FONT COLOR="#000077">Threads</FONT></H4>
<P>The server keeps two threads for each player. One is a &#147;listener&#148; that receives packets from the player&#146;s client and processes them. The other is a &#147;replier&#148; that sends packets back to the client. I will explain later why I chose to use two threads instead of one. MahJong is not an action game, so the threads will be blocked most of the time and not cause load problems. The client only needs one listener thread. Its job is to receive and process packets from the server. Client to server packets are only sent in response to user actions.
</P>
<H4 ALIGN="LEFT"><A NAME="Heading8"></A><FONT COLOR="#000077">Source Code Tree Structure</FONT></H4>
<P>For such a big project there are inevitably a huge number of classes. I chose to group them into four packages: a server package for all server-specific classes (e.g., Player and Table), a client package for the Client and GUI-related classes, a common package for classes that are used by both the server and the client (e.g., Tile and Hand), and finally, a types package for auxiliary classes that are useful for other programming projects. This arrangement makes the source tree much easier to maintain.
</P>
<P>This is pretty much all the designing we can do at this stage. The client-server structure is summarized in Figure 18-3. From now on, we will keep this &#147;grand picture&#148; in mind, and work our way up from the bottom.</P>
<P><A NAME="Fig3"></A><A HREF="javascript:displayWindow('images/18-03.jpg',640,797 )"><IMG SRC="images/18-03t.jpg"></A>
<BR><A HREF="javascript:displayWindow('images/18-03.jpg',640,797)"><FONT COLOR="#000077"><B>Figure 18-3</B></FONT></A>&nbsp;&nbsp;The client-server structure</P>
<H3><A NAME="Heading9"></A><FONT COLOR="#000077">Protocols and Packets</FONT></H3>
<P>Since we are writing a network game, it&#146;s a good idea to first get the networking part right. I&#146;ve taken a quick-and-dirty approach to this.
</P>
<H4 ALIGN="LEFT"><A NAME="Heading10"></A><FONT COLOR="#000077">The Packet Class</FONT></H4>
<P>To think abstractly, we have a socket connected to a remote site, and several types of packets that we would like to send and receive through this socket. As far as the socket is concerned, each packet is simply a byte stream. We can make the first byte a special tag that tells us which type of packet it is. For the rest of the packet, we use the DataInput-Stream and DataOutputStream classes for binary I/O. The Packet class is simply a ByteArrayOutputStream buffer wrapped with a DataOutputStream:
</P>
<!-- CODE //-->
<PRE>
import java.io.*;
public class Packet extends DataOutputStream &#123;
  ByteArrayOutputStream b_out;            // holds binary data

  private Packet (ByteArrayOutputStream buf) &#123;
    super(buf);
    b_out = buf;
  &#125;
  private byte[] buf () &#123;
    return b_out.toByteArray();
  &#125;
  private static Packet New (int size) &#123;  // make a new packet
    ByteArrayOutputStream buf = new ByteArrayOutputStream(size);
    return new Packet(buf);
  &#125;
  // constants and methods here
&#125;
</PRE>
<!-- END CODE //-->
<P>Say we have a type of packet sent from the server to the client (let&#146;s call it SP_SOME_PACKET), carrying the information of a byte <I>b</I>, an int <I>i</I>, and a String <I>s</I>. We would define in the Packet class a unique tag (among all server-to-client packets; client-to-server packets are tagged separately) and a static method to construct it:</P>
<!-- CODE //-->
<PRE>
public static final byte SP_SOME_PACKET = 0;  // unique tag
public static byte[] SPSomePacket (byte b, int i, String s) &#123;
  try &#123;
    Packet p = New(10);                       // estimated size
    p.writeByte(SP_SOME_PACKET);              // write tag first
    p.writeByte(b);                           // write fields
    p.writeInt(i);
    p.writeUTF(s);
    return p.buf();                           // return the buffer
  &#125; catch (IOException e) &#123; return null; &#125;    // shouldn't happen
&#125;
</PRE>
<!-- END CODE //-->
<H4 ALIGN="LEFT"><A NAME="Heading11"></A><FONT COLOR="#000077">Sending Packets</FONT></H4>
<P>Suppose we are given a DataOutputStream out; then sending SP_SOME_PACKET to it involves only two steps:
</P>
<!-- CODE SNIP //-->
<PRE>
// construct it first
byte[] buf = Packet.SPSomePacket(0, 1, "Hi");
// send it out
out.write(buf, 0, buf.length);     // send it out
</PRE>
<!-- END CODE SNIP //-->
<H4 ALIGN="LEFT"><A NAME="Heading12"></A><FONT COLOR="#000077">Receiving Packets</FONT></H4>
<P>Receiving and processing packets is slightly trickier. I use a <I>packet dispatcher</I> plus multiple handlers for this purpose. Suppose we are given a DataInputStream in. The packet dispatcher is just a loop that reads in a byte that is the tag of the packet that follows, and calls the appropriate handlers. The handlers are methods that actually read in packet data and act upon them.</P>
<!-- CODE //-->
<PRE>
public void run () &#123;
  // ...
  // A typical packet handler for server-&gt;client packets.
  // Here we assume given a DataInputStream in.
  // This code resides in a run() method of the Client class.
loop:
  while (true) &#123;
  try &#123;
    byte tag = in.readByte();  // read in the packet tag
    switch (tag) &#123;
    case SP_SOME_PACKET:
      hdSomePacket();
      break;
      // handle other packets here
    default:                   // invalid tag
      break loop;
    &#125;
  &#125; catch (IOException e) &#123;    // bad connection?
    break loop;
  &#125;
  // handle bad connection here
  // ...
&#125;
</PRE>
<!-- END CODE //-->
<P>In the handler method hdSomePacket(), we read in data in the order our SPSomePacket() method encodes it, minus the first tag byte, which has been read in the <I>while</I> loop already:</P>
<!-- CODE SNIP //-->
<PRE>
private void hdSomeThing () throws IOException &#123;
  // read in the data fields
  byte b = in.readByte();
  int i = in.readInt();
  String s = in.readUTF();
  // do something with the data...
&#125;
</PRE>
<!-- END CODE SNIP //-->
<H4 ALIGN="LEFT"><A NAME="Heading13"></A><FONT COLOR="#000077">Other Possible Approaches</FONT></H4>
<P>You may have noticed that my approach isn&#146;t very object-oriented. This is true; a &#147;better&#148; way to do networking is to define a separate class for each packet type, and embed methods in those classes to convert the packet to and from binary data. In fact, I did exactly this in the first version of my game. However, as I added more features, I had to add more packet types and hence define more classes. At some point, Netscape started to crash, because I had too many classes! That is why I use the current method. It&#146;s not very elegant, but cuts down the number of classes to one.
</P>
<P>I&#146;d also like to point out that when Java gets more mature, for example, when Sun finalizes its RMI (Remote Method Invocation) library, the networking task will become much easier. But at this moment, we are on our own.</P><P><BR></P>
<CENTER>
<TABLE BORDER>
<TR>
<TD><A HREF="719-724.html">Previous</A></TD>
<TD><A HREF="../ewtoc.html">Table of Contents</A></TD>
<TD><A HREF="728-732.html">Next</A></TD>
</TR>
</TABLE>
</CENTER>


</BODY>

⌨️ 快捷键说明

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