?? tokenring.java
字號:
// TokenRing.java
//
// Copyright (c) 2000-2001 Symbian Ltd. All rights reserved
package com.symbian.devnet.whist.tokenRing;
import java.io.*;
import javax.net.datagram.*;
import java.util.*;
/**
* A class implementing a token ring engine.
* Implements DatagramListener
* @see com.symbian.devnet.whist.tokenRing.DatagramListener
* @author Symbian Devnet
*/
public class TokenRing implements DatagramListener
{
/**
* The default port for receiving datagrams on. This is used when all engines
* are running on different machines.
*/
private static final int RECEIVE_PORT = 9999;
/** The variable used to determine when UDP datagrams are required. */
private static final int UDP = 0;
/** The variable used to determine when WDPSMS datagrams are required. */
private static final int WDPSMS = 1;
/** The number of Engines participating in the ring*/
private static final int NO_OF_ENGINES = 4;
/** A temporary UDP address used to determine the IP number of the machine. */
private final static String DUMMY_ADDRESS_UDP = "udp://+1234567890:9999";
/** A temporary WDPSMS address used to determine the IP number of the machine. */
private final static String DUMMY_ADDRESS_WDPSMS = "wdpsms://+123456789:9999";
/** The instance of a DatagramEvent. */
private DatagramEvent dgEvent;
/** A string representing the address for sending and receiving for the device. */
private String commsAddress;
/** A string representing the port number. */
private String port;
/** An instance of a Ring. */
private Ring rg;
/** An instance of a Receiver. */
private Receiver receive;
/** An instance of a DatagramService. */
private DatagramService senderService;
/** An instance of a DatagramCreator. */
private DatagramCreator dgCreator;
/** Indicates the address to which the message should be sent. */
private int nextAddress = 1;
/** The protocol to be used for sending datagrams, either UDP or WDPSMS. */
private int protocol;
/** An array of the names of the players */
private String names[];
/** An instance of a DatagramService. */
private DatagramService dummy;
/**
* An array of the addresses of the individual Token Ring Receivers
* represented as Strings.
* @see com.symbian.devnet.whist.tokenRing.Receiver Receiver
*/
private String adds[];
/**
* The address of the local machine (localhost). This will be used as the
* Address for the Sender and Receiver.
*/
private Address myAddress;
/** The identification number of the last datagram message sent. */
private int idNo;
/**
* The position of the player in the ring, for example playerNo = 3 indicates
* that this is the third player.
*/
private int playerNo;
/**
* The array of data received from the datagram. The maximum size for this is
* 160, which is the maximum size of an SMS message.
*/
private byte[] dataReceived = new byte[160];
/**
* Used to copy the data in {@link com.symbian.devnet.whist.tokenRing.TokenRing#dataReceived dataReceived}
* to ensure that data from a new datagram will not overwrite
* the data from the original datagram until it has been processed and discarded.
*/
private byte[] data = new byte[160];
/** Vector of listeners for GameEvents */
private Vector listeners = new Vector();
/**
* Constructor to initiate a token ring Engine which will wait until a datagram
* containing the information required to create the
* {@link com.symbian.devnet.whist.tokenRing.Ring#Ring(String[], String[]) Ring}
* is received.
* The {@link #createSender() createSender} method creates an instance of a
* an object through
* which datagrams can be sent. The {@link #setupEngine(String) setupEngine}
* method initialises the objects which are generic to both constructors.
* @param pProtocol the protocol to be used, either UDP or WDPSMS.
* @param rPort the port number for the Receiver.
* @param sport the port number for the Sender.
*/
public TokenRing()
{
protocol = UDP;
String[] ports = { "1010", "1011", "1012", "1013" };
port = ports[0];
int count = 0;
boolean b = setupEngine(port);
while (!b && (count < 3))
{
port = ports[++count];
b = setupEngine(port);
}
}
/**
* Configures the generic parts of the Engine. This is used by both
* constructors and initialises common variables.
* This method creates a String comprising of the protocol method (UDP or
* WDPSMS), the IP number of the device (Node), and the port number designated
* for receiving datagrams. If an Exception is not thrown, a new
* {@link com.symbian.devnet.whist.tokenRing.Receiver Receiver}, called
* receive, is created. The Receiver object is then added to the
* {@link com.symbian.devnet.whist.tokenRing.DatagramListener DatagramListener}
* vector and the {@link com.symbian.devnet.whist.tokenRing.Receiver#listen listen}
* method is called on receive.
* <P>
* The Engine now listens for incoming datagrams.
* @param port the port number for the Receiver.
*/
private boolean setupEngine(String port)
{
boolean b = true;
if (protocol == UDP)
commsAddress = "udp://" + getNodeIPNo() + ":" + port;
else
commsAddress = "wdpsms://" + getNodeIPNo() + ":" + port;
try
{
myAddress = DatagramService.parseAddress(commsAddress);
}
catch(Exception ex)
{
}
DatagramService dgService;
try
{
dgService = DatagramService.getServerService(myAddress);
receive = new Receiver(dgService, myAddress);
receive.addDatagramListener(this);
receive.listen();
}
catch(Exception e)
{
b = false;
}
return b;
}
/**
* This calls the
* {@link com.symbian.devnet.whist.tokenRing.TokenRing#getidNo() getidNo}
* method to extract the identification number from the received data
* and the performs different actions depending on the value of the current
* identification number and the identification number of the received message.
* <P>
* If the current identification number
* ({@link com.symbian.devnet.whist.tokenRing.TokenRing#idNo idNo}
* ) is zero, the
* {@link com.symbian.devnet.whist.tokenRing.Ring Ring}
* object has not been instantiated. The
* {@link com.symbian.devnet.whist.tokenRing.TokenRing#idNo idNo} is set to the
* identification number of the current message and the data from the datagram
* (without the identification number) is extracted into a char array. This is
* then passed to the Ring constructor to initialise a Ring.
* <P>
* Another comparison is made to determine if this is the last device in the
* token ring to be initialised. If this is not the last device, the character
* array is parsed as a String and the
* {@link com.symbian.devnet.whist.tokenRing.DatagramCreator#createAndSend(String, int, int) createAndSend}
* method is called
* to pass the setup details onto the next device in the ring. If this is the
* last device to be setup, a datagram is sent to the first machine in
* the ring (the initiator).
* <P>
* If the identification number from the datagram is less than or equal to the
* current identification number, the datagram is either a duplicate or old
* and can be ignored.
* <P>
* If the current identification is not equal to zero and the datagram is new,
* the data contained within it will be passed into the package above for
* processing
*/
private void processMessage()
{
int id = getidNo();
if (idNo == 0)
{
// A message containing the information required to set
// up the ring has been received.
idNo = id;
playerNo = idNo + 1;
char[] c = getData(data);
rg = new Ring(c);
createSender();
setNextAddress();
if (playerNo < NO_OF_ENGINES)
{
// Need to send setup message onto one or more other
// machines
String s = new String(c).trim();
dgCreator.createAndSend(s, nextAddress, ++idNo);
}
else
{
// This is the last player in the game (all others have
// received the setup datagram.
ReceivedTurnEvent ge = new ReceivedTurnEvent(this, c);
dgCreator.createAndSend("X", nextAddress, ++idNo);
}
}
else if (id <= idNo)
{
// An old message has been sent and should be ignored.
System.out.println("Received old message - id: " + id);
}
else
{
// The datagram contains data for the Game.
idNo = id;
char[] c = getData(data);
ReceivedTurnEvent ge = new ReceivedTurnEvent(this, c);
processReceivedTurn(ge);
}
}
/**
* Sets nextAddress, the variable which indicates which address in the array of
* addresses is to be used for the datagram which is about to be sent.
*/
private void setNextAddress()
{
if (playerNo == 4)
nextAddress = 0;
else
nextAddress = playerNo;
}
/**
* Extracts the data from the byte array and strips off the identification
* number.
* @return the data from the message as a character array.
*/
private char[] getData(byte[] buf)
{
char cha = '?';
int i = 0;
while ((char)data[i] != cha)
i++;
i++;
char[] c = new char[data.length - i];
for (int j = 0; j < c.length; j++)
c[j] = (char)data[j + i];
return c;
}
/**
* Extracts the identification number from the byte array obtained from a
* datagram.
* @return the identification number of the datagram.
*/
private int getidNo()
{
char cha = '?';
char[] ch = new char[6];
int i = 0;
while ((char)data[i] != cha)
ch[i] = (char)data[i++];
String num = new String(ch);
String n2 = new String(num.trim());
Integer inte = Integer.valueOf(n2);
int id = inte.intValue();
return id;
}
/**
* Creates a DatagramCreator object that can be used to send datagrams to the
* nodes in the ring
*/
private void createSender()
{
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -