prrroff
[packetlaptime.git] / TCPNode.java
blobe2f7b98afb81f75becad3a7e74e4f81d5202baf9
1 /*
2 * @(#)TCPNode.java
3 * Time-stamp: "2007-10-30 20:39:05 anton"
4 */
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;
21 /**
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,
38 InetAddress nextHost,
39 int nextPort,
40 boolean logger) {
42 super(localPort, nextHost, nextPort, logger);
44 int tries = 0;
45 final int MAXTRIES = 120;
47 // create a server socket so a node can connect to this one
48 try {
49 welcomeSocket = new ServerSocket(localPort);
51 catch (IOException e) {
52 e.printStackTrace();
55 // first try to make contact with
56 // the next and previous node in the ring
57 try {
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
68 try {
69 prevNode = welcomeSocket.accept();
71 catch (IOException e) {
72 e.printStackTrace();
75 // then try to connect to the next node a number of times
76 while (nextNode == null && tries < MAXTRIES) {
77 try {
78 nextNode = new Socket(nextHost, nextPort);
80 catch (IOException e) {
81 System.out.println(e);
83 // increase the number of tries made by 1
84 tries++;
85 try {
86 Thread.sleep(250);
88 catch (InterruptedException e) {
89 e.printStackTrace();
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...");
99 System.exit(1);
101 else {
102 try {
103 nextNodeOutput = new DataOutputStream(
104 nextNode.getOutputStream());
105 prevNodeInput = prevNode.getInputStream();
107 catch (IOException e) {
108 e.printStackTrace();
112 // if this node is a logger, set the file name
113 // and open a file with that name for writing.
114 if (isLogger) {
115 logFileName = "lap-times-tcp.log";
116 try {
117 file = new FileWriter(logFileName);
118 out = new BufferedWriter(file);
120 catch (IOException e) {
121 e.printStackTrace();
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
131 int phase;
133 //send the first packet
134 try {
135 nextNodeOutput.write(constructByteArray(
136 FINDMASTER, new Integer(ID).toString()));
138 catch (IOException e) {
139 e.printStackTrace();
142 // PHASE ONE
143 phase = FINDMASTER;
144 while (phase == FINDMASTER) {
145 // receive packet
146 try {
147 prevNodeInput.read(receivedData);
149 catch (IOException e) {
150 e.printStackTrace();
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.
163 try {
164 nextNodeOutput.write(receivedData);
165 sentPackets++;
167 catch (IOException e) {
168 e.printStackTrace();
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
177 break;
180 // acquire the message's length
181 int messageLength = receivedData[1];
183 // acquire the message...
184 String 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
195 try {
196 nextNodeOutput.write(receivedData);
198 catch (IOException e) {
199 e.printStackTrace();
203 // if this node should be the master node
204 else if (receivedID == ID) {
205 // set this node to be the master node
206 isMasterNode = true;
207 // set the phase to RUNMODE
208 phase = RUNMODE;
210 } // end while
212 // if this node turned out to be the master node,
213 // send the first message of phase two.
214 if (isMasterNode) {
215 // send first packet in phase two
216 try {
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) {
225 e.printStackTrace();
228 // increase the amount of sent packets by 1
229 sentPackets++;
232 // PHASE TWO
233 while (phase == RUNMODE) {
234 // receive data from previous node
235 try {
236 prevNodeInput.read(receivedData);
238 catch (IOException e) {
239 e.printStackTrace();
242 // if this node is a logging node,
243 if (isLogger) {
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
249 try {
250 nextNodeOutput.write(receivedData);
252 catch (IOException e) {
253 e.printStackTrace();
255 sentPackets++;
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
261 phase = TERMINATE;
262 if (isMasterNode) {
263 try {
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) {
272 e.printStackTrace();
276 } // end while
278 // close sockets (and log file if this node is a logger)
279 try {
280 nextNode.close();
281 prevNode.close();
282 if (isLogger) {
283 System.out.println("Closing log file...");
284 closeLogFile();
285 System.out.println("Finished.");
288 catch (IOException e) {
289 e.printStackTrace();
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 {
303 TCPNode node = null;
304 // determine if this node should be a logger
305 boolean logger = false;
306 if (args.length == 4 && args[3].charAt(0) == 'L') {
307 logger = true;
310 // create a new node
311 node = new TCPNode(Integer.parseInt(args[0]),
312 InetAddress.getByName(args[1]),
313 Integer.parseInt(args[2]),
314 logger);
315 node.runTCPNode();