3 * Time-stamp: "2007-10-30 20:39:05 anton"
6 // import necessary input/output classes
7 import java
.io
.BufferedWriter
;
8 import java
.io
.DataOutputStream
;
9 import java
.io
.FileWriter
;
10 import java
.io
.IOException
;
11 import java
.io
.InputStream
;
13 // import necessary network classes
14 import java
.net
.ConnectException
;
15 import java
.net
.DatagramPacket
;
16 import java
.net
.InetAddress
;
17 import java
.net
.ServerSocket
;
18 import java
.net
.Socket
;
19 import java
.net
.UnknownHostException
;
22 * TCPNode – a node in a TCP packet ring.
24 * @author "Anton Johansson" <anton.johansson@gmail.com>
25 * @author "Victor Zamanian" <victor.zamanian@gmail.com>
27 public class TCPNode
extends Node
{
29 private ServerSocket welcomeSocket
;
31 private Socket nextNode
;
32 private Socket prevNode
;
34 private DataOutputStream nextNodeOutput
;
35 private InputStream prevNodeInput
;
37 public TCPNode(int localPort
,
42 super(localPort
, nextHost
, nextPort
, logger
);
45 final int MAXTRIES
= 120;
47 // create a server socket so a node can connect to this one
49 welcomeSocket
= new ServerSocket(localPort
);
51 catch (IOException e
) {
55 // first try to make contact with
56 // the next and previous node in the ring
58 nextNode
= new Socket(nextHost
, nextPort
);
59 prevNode
= welcomeSocket
.accept();
61 catch (IOException e
) {
62 System
.out
.println(e
);
65 // if connecting to the next node failed
66 if (nextNode
== null) {
67 // try to let the previous node connect to this node
69 prevNode
= welcomeSocket
.accept();
71 catch (IOException e
) {
75 // then try to connect to the next node a number of times
76 while (nextNode
== null && tries
< MAXTRIES
) {
78 nextNode
= new Socket(nextHost
, nextPort
);
80 catch (IOException e
) {
81 System
.out
.println(e
);
83 // increase the number of tries made by 1
88 catch (InterruptedException e
) {
94 // if we after all of these efforts have been unsuccessful
95 // in connecting to the next and previous node, exit
96 // with a status code of 1, indicating failure.
97 if (nextNode
== null || prevNode
== null) {
98 System
.out
.println("Unable to connect; quitting...");
103 nextNodeOutput
= new DataOutputStream(
104 nextNode
.getOutputStream());
105 prevNodeInput
= prevNode
.getInputStream();
107 catch (IOException e
) {
112 // if this node is a logger, set the file name
113 // and open a file with that name for writing.
115 logFileName
= "lap-times-tcp.log";
117 file
= new FileWriter(logFileName
);
118 out
= new BufferedWriter(file
);
120 catch (IOException e
) {
126 // the method in which everything happens
127 public void runTCPNode() {
128 // the byte-array to store received data in
129 byte[] receivedData
= new byte[DATAGRAMSIZE
];
130 // the current phase the ring is in
133 //send the first packet
135 nextNodeOutput
.write(constructByteArray(
136 FINDMASTER
, new Integer(ID
).toString()));
138 catch (IOException e
) {
144 while (phase
== FINDMASTER
) {
147 prevNodeInput
.read(receivedData
);
149 catch (IOException e
) {
153 // acquire the message's message type
154 // also set the phase to the message type, because
155 // if it changes (to RUNMODE), that means another
156 // node was chosen as the master node.
157 int messageType
= phase
= receivedData
[0];
159 // if the message received was a message of type RUNMODE
160 if (phase
== RUNMODE
) {
161 // send a message to the following node(s),
162 // telling it to break out of phase one.
164 nextNodeOutput
.write(receivedData
);
167 catch (IOException e
) {
170 // if the start time hasn't been set
171 if (isLogger
&& startTime
== 0) {
172 // set the starting time -- the time
173 // when phase two was initiated
174 startTime
= System
.nanoTime();
176 // break out of phase one
180 // acquire the message's length
181 int messageLength
= receivedData
[1];
183 // acquire the message...
185 new String(receivedData
).substring(2, messageLength
+ 2);
187 // the largest ID that this packet has seen so far, i.e. the
188 // ID of the node with the largest ID so far in the ring.
189 int receivedID
= Integer
.parseInt(message
);
191 // if this node will surely not be the master node because
192 // there exists a node with an ID larger than this one's
193 if (receivedID
> ID
) {
194 // just forward the data to the next node
196 nextNodeOutput
.write(receivedData
);
198 catch (IOException e
) {
203 // if this node should be the master node
204 else if (receivedID
== ID
) {
205 // set this node to be the master node
207 // set the phase to RUNMODE
212 // if this node turned out to be the master node,
213 // send the first message of phase two.
215 // send first packet in phase two
217 nextNodeOutput
.write(constructByteArray(
218 RUNMODE
, new Integer(ID
).toString()));
219 // set the start time if it hasn't been set
220 if (isLogger
&& startTime
== 0) {
221 startTime
= System
.nanoTime();
224 catch (IOException e
) {
228 // increase the amount of sent packets by 1
233 while (phase
== RUNMODE
) {
234 // receive data from previous node
236 prevNodeInput
.read(receivedData
);
238 catch (IOException e
) {
242 // if this node is a logging node,
244 // write the current average lap time of the data
245 writeToLog(new String(receivedData
).substring(2, receivedData
[1] + 2));
248 // send data to the next node
250 nextNodeOutput
.write(receivedData
);
252 catch (IOException e
) {
257 // if it is time to end phase two
258 if (sentPackets
== PACKETSTOSEND
) {
259 // set the phase to phase three
260 // and send a terminating packet
264 // send terminate packet
265 nextNodeOutput
.write(
266 constructByteArray(TERMINATE
, null));
267 // receive terminate packet before
268 // exiting the ring by closing socket
269 prevNodeInput
.read(receivedData
);
271 catch (IOException e
) {
278 // close sockets (and log file if this node is a logger)
283 System
.out
.println("Closing log file...");
285 System
.out
.println("Finished.");
288 catch (IOException e
) {
293 public boolean receivePacket(DatagramPacket receivePacket
) {
294 return false; // not used, but interfaces can be demanding...
297 public boolean sendPacket(DatagramPacket receivePacket
) {
298 return false; // not used, but interfaces can be demanding...
301 public static void main(String
[] args
) throws IOException
,
302 InterruptedException
{
304 // determine if this node should be a logger
305 boolean logger
= false;
306 if (args
.length
== 4 && args
[3].charAt(0) == 'L') {
311 node
= new TCPNode(Integer
.parseInt(args
[0]),
312 InetAddress
.getByName(args
[1]),
313 Integer
.parseInt(args
[2]),