Subversion Repositories programming

Rev

Rev 217 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
213 ira 1
/*******************************************************************************
2
 * File: P2_Client.java
3
 * Author: Ira W. Snyder (devel@irasnyder.com)
4
 * License: GNU General Public License v2
5
 * Class: CS380 - Computer Networking
6
 *
7
 * Assignment: Project #2
218 ira 8
 * Date Last Modified: 2006-02-08
213 ira 9
 *
10
 * Purpose: Implement a simple client allowing the user to send datagrams
11
 * to P2_Server, which will decode them from 4B to 5B encoding. The client
12
 * will retransmit any packets that do not recieve a reply.
13
 ******************************************************************************/
211 ira 14
 
15
import java.io.*;
16
import java.net.*;
17
import java.util.*;
18
 
19
public class P2_Client
20
{
21
    private static int soTimeout = 3000; // 3000 ms timeout = 3 sec
22
    private static DatagramSocket socket;
23
    private static DatagramPacket packet;
24
    private static int portNumber = 1337;
216 ira 25
    private static int packetNum = 0;
211 ira 26
 
218 ira 27
    /**
28
     * Method: verifyInput()
29
     * Purpose: Verify the user's input before it is sent out to the
30
     * server for translation.
31
     */
217 ira 32
    public static boolean verifyInput (String s)
33
    {
34
        int i;
35
 
36
        // Check for QUIT message
37
        if (s.equals("QUIT"))
38
            return true;
39
 
40
        // If it's not a QUIT, it must be 0's and 1's only
218 ira 41
        for (i=0; i<s.length(); i++)
217 ira 42
            if (!(s.charAt(i) == '0' || s.charAt(i) == '1'))
43
                return false;
44
 
45
        // Everything was a 0 or 1, good!
46
        return true;
47
    }
48
 
213 ira 49
    /**
50
     * Method: readPacket()
51
     * Purpose: Read a packet on the currently opened DatagramSocket,
218 ira 52
     * and return it as a P2_Packet.
213 ira 53
     */
215 ira 54
    public static P2_Packet readPacket ()
211 ira 55
    {
215 ira 56
        byte[] buf = new byte[256];
211 ira 57
        packet = new DatagramPacket (buf, buf.length);
58
 
218 ira 59
        // Try to recieve a packet from the server, and catch all possible
60
        // exceptions that can happen.
211 ira 61
        try {
62
            socket.receive (packet);
63
        } catch (SocketTimeoutException e) {
64
            System.out.println ("Read timed out, requesting retransmit");
65
            return null;
66
        } catch (PortUnreachableException e) {
67
            System.out.println ("Caught PortUnreachableException, are you" +
68
                                " sure the server is running?");
69
            System.exit(1);
70
        } catch (IOException e) {
71
            System.out.println ("Caught exception in readPacket()");
72
            e.printStackTrace();
73
            return null;
74
        }
75
 
218 ira 76
        // Convert the bytes to a P2_Packet, then return them.
215 ira 77
        return new P2_Packet (packet.getData());
211 ira 78
    }
213 ira 79
 
80
    /**
81
     * Method: writePacket()
82
     * Purpose: Send a packet to localhost:portNumber.
83
     */
216 ira 84
    public static boolean writePacket (byte type, byte[] data, int packetNum)
211 ira 85
    {
215 ira 86
        InetAddress address = null;
211 ira 87
        int port = portNumber;
88
 
218 ira 89
        // Try to get the localhost address. If this fail's, we've got major
90
        // problems going on, so just exit.
215 ira 91
        try {
92
            address = InetAddress.getLocalHost();
93
        } catch (UnknownHostException e) {
94
            System.err.println ("Caught UnknownHostException in writePacket(), " +
95
                                "are you sure the system is working?");
96
            System.exit(1);
97
        }
98
 
218 ira 99
        // Create the new packet
216 ira 100
        byte[] buf = P2_Packet.createPacket (type, data, packetNum);
211 ira 101
        packet = new DatagramPacket (buf, buf.length, address, port);
102
 
218 ira 103
        // Try to send the packet, and catch all of the possible errors.
211 ira 104
        try {
105
            socket.send (packet);
106
        } catch (PortUnreachableException e) {
107
            System.out.println ("Caught PortUnreachableException, are " +
108
                                "you sure the server is running?");
109
            System.exit(1);
110
        } catch (IOException e) {
111
            System.out.println ("Caught exception in writePacket()");
112
            e.printStackTrace();
113
            return false;
114
        }
115
 
218 ira 116
        // We sent successfully, so return true.
211 ira 117
        return true;
118
    }
119
 
213 ira 120
    /**
121
     * Method: guaranteedTransmit()
122
     * Purpose: A wrapper around readPacket() and writePacket() that implements
217 ira 123
     * a reliable transmit mechanism.
213 ira 124
     */
215 ira 125
    public static P2_Packet guaranteedTransmit (byte type, byte[] data)
213 ira 126
    {
215 ira 127
        P2_Packet reply;
213 ira 128
        int retries = 0;
129
 
218 ira 130
        // Send a packet, and wait for a reply
216 ira 131
        writePacket (type, data, packetNum);
215 ira 132
        reply = readPacket ();
213 ira 133
 
218 ira 134
        // If the read timed out, keep trying to send until it gets through
215 ira 135
        while (reply == null)
213 ira 136
        {
137
            System.err.println ("Packet lost, retransmitting...");
216 ira 138
            writePacket (type, data, packetNum);
215 ira 139
            reply = readPacket ();
213 ira 140
            retries++;
141
        }
142
 
218 ira 143
        // Reset the packetNum if we had to retry sending a packet.
144
        // The packetNum is used to control the server's dropping
145
        // of packets.
216 ira 146
        if (retries > 0)
218 ira 147
            packetNum = 0;
216 ira 148
 
149
        packetNum++;
213 ira 150
        return reply;
151
    }
152
 
217 ira 153
    /**
154
     * Method: guaranteedTransmit()
155
     * Purpose: A simplified version of the guaranteedTransmit() above.
156
     */
215 ira 157
    public static P2_Packet guaranteedTransmit (byte type)
158
    {
159
        byte[] pData = { 0 };
160
 
161
        return guaranteedTransmit (type, pData);
162
    }
163
 
213 ira 164
    /**
165
     * Method: main()
166
     * Purpose: This will accept input from the user, and attempt to send it
167
     * to the corresponding server, which will convert the messages from 4B
168
     * to 5B encoding.
169
     */
211 ira 170
    public static void main (String[] args) throws Exception
171
    {
212 ira 172
        int dropHowMany = 0;
211 ira 173
        socket = new DatagramSocket();
174
        socket.connect (InetAddress.getLocalHost(), portNumber);
218 ira 175
 
176
        // Set the socket's timeout to 3 seconds
211 ira 177
        socket.setSoTimeout (soTimeout);
178
 
179
        BufferedReader kbd = new BufferedReader (
180
                                 new InputStreamReader (
181
                                     System.in));
182
 
218 ira 183
        // Parse the first command-line argument into an int, and use that
184
        // to inform the server how often to drop packets.
212 ira 185
        try {
186
            dropHowMany = Integer.parseInt(args[0]);
187
        } catch (ArrayIndexOutOfBoundsException e) {
188
            System.err.println ("You need to call the program with \'java P2_Client <num>\'");
189
            System.exit(1);
190
        }
211 ira 191
 
215 ira 192
        String msg;
193
        byte[] pData = { (byte)dropHowMany };
194
        P2_Packet reply = guaranteedTransmit (P2_Packet.DROP, pData);
212 ira 195
 
218 ira 196
        // Check to make sure our packet informing the server how often to drop
197
        // packets was recieved successfully.
215 ira 198
        if (reply.getPacketType() != P2_Packet.DROP)
213 ira 199
        {
200
            System.err.println ("Unable to inform the server how often to drop packets");
201
            System.exit(1);
202
        }
203
 
211 ira 204
        boolean done = false;
205
 
218 ira 206
        // Keep running until the user decides that they don't want to
207
        // decode any more 4B numbers.
211 ira 208
        while (!done)
209
        {
218 ira 210
            System.out.print ("% decode: ");
211
            msg = kbd.readLine ();
212
 
213
            // Check user input
214
            if (!verifyInput(msg))
215
            {
216
                System.out.println ("Bad input, try again...");
217
                continue;
218
            }
219
 
220
            // Check for a QUIT message
215 ira 221
            if (msg.equals("QUIT"))
211 ira 222
            {
215 ira 223
                reply = guaranteedTransmit (P2_Packet.QUIT);
211 ira 224
                done = true;
225
                continue;
226
            }
215 ira 227
 
228
            reply = guaranteedTransmit (P2_Packet.TRANSREQ, P2_EncDec.convertToByteArray(msg));
211 ira 229
 
218 ira 230
            // Check for a bad packet from the server
231
            if (reply.getPacketType() == P2_Packet.BADPACKET)
232
                System.out.println ("-> reply: BAD REQUEST");
233
            else
234
                System.out.println ("-> reply: " + 
235
                        P2_EncDec.convertToString(reply.getPacketData()));
211 ira 236
        }
213 ira 237
 
238
        // Close the socket
239
        socket.close();
211 ira 240
    }
241
}
242