OOP Lab Task 5

De la WikiLabs
Jump to navigationJump to search

Required Tutorials

Requirements

  1. Create a new project, named oop_lab5.
  2. For this task you need the previously designed class Message, from OOP Lab Task 1. Copy its source .java file inside this package (letting NetBeans to refactor it or manually changing its package statement to make the class part of this package).
  3. Create a class called ClientPeer with the following features:
    • The class constructor takes as arguments a string (the user/sender name) and a reference to a Socket object, that is supposed to be already instantiated and connected, and saves them in private fields.
    • The method void sendMessage(String message), that creates a Message object with the content taken from the method's argument and the sender's name read from the class' fields, and sends the newly created object through the available Socket.
      • In order to be able to send a Message object through a stream (to serialize that object), it must be serializable.
      • The object is sent through the output stream of the Socket. You get the reference to that stream using the Socket's method getOutputStream, but to be able to send objects through this stream, which is only a basic stream of bytes, you need to enclose it in a filter stream of type ObjectOutputStream (this object does the serialization for you, that is it converts the Message object into a stream of bytes).
    • A method named close, without arguments and return values, that symply closes the output stream.
      • The output stream is created at ClientPeer instantiation, used by sendMessage method which writes Message objects into, and closed by close method.
      • The constructor and both methods employ a socket and a stream, whose methods may throw various exceptions of type IOException when called. You do not catch them, but, because they are checked exceptions, you must declare them to be thrown by the constructor and the methods.
    • All fields must be private.
  4. Add to your project another class, named Client, which is executable (has a main method).
    • First, the main method instantiates a Socket object with the destination IP address 127.0.0.1 and port 9000 (that connects the client's socket to the destination's socket, the localhost (127.0.0.1) on port 9000).
    • Then, it instantiates a ClientPeer object with your name as an argument (you are the sender!) and the reference to the Socket object you have just instantiated as the other argument.
    • Third, open an input stream of characters to read from the keyboard. The input stream from the keyboard is already enclosed in the object System.in, which is opened and available by default. However, this stream is a byte stream, therefore you need to filter it properly, so that the bytes are transformed to characters. To do that, you enclose the System.in stream into an InputStreamReader object. The Reader object (InputStreamReader is derived from Reader) delivers the stream character by character. To read a whole line from the keyboard without calling the read method for each character, you enclose further the InputStreamReader into a BufferedReader object, whose readLine method fits this purpose. The readLine method returns (with a string) only after you type the Enter key (but the newline character will not be part of the returned string).
    • Then, read a string of characters from the keyboard (from the previously opened input stream) and call the sendMessage method of the ClientPeer object. Your typed messages will thus be sent to the destination.
    • You may send messages in a continuous loop (type a line, press Enter, type another line, press Enter a.s.o).
    • To break the loop, you test for a special typed line, QUIT (it will act like a command, not a message to be sent). Remember how to check that two strings are equal!
    • After you finish with sending messages don't forget to close the output stream of the ClientPeer object, the input stream and the socket! To be sure that they are closed in any circumstances, put the statements that closes them in a finally block, atached to a try block that encloses the other part of the main method. Be careful, the references used inside the finally block must be declared ouside the try block!
    • Because the main method operates with sockets and streams it may also run into checked exceptions of type IOException. You do not catch them; simply declare that the method main throws them out.
  5. You may run this file, to see that it compiles, builds and runs, but the execution will end abruptly with an exception because there is still no server running to which the client might connect (Connection refused). The following steps are devoted to the other part of the connection, the peer application, the server.
  6. Implement a class called ServerPeer with the following features:
    • The constructor has as its sole argument a reference to a pre-initialized Socket object, that it stores in a private field.
    • The method void run() opens an input stream for this socket, reads messages from it, and displays them on the screen, formatted as specified in OOP Lab Task 1.
      • You get the reference to that stream using the Socket's method getInputStream, but to be able to receive objects through this stream, which is only a basic stream of bytes, you need to enclose it in a filter stream of type ObjectInputStream (this object does the deserialization for you, that is it converts the stream of bytes into a Message object). However, you need to explicitly downcast the return type of ObjectInputStream, which is Object, to your expected Message type, if you want to call methods that are specific only to Message objects.
      • The formatted message is printed on the screen with the help of Message methods.
      • Both the constructor and the method run employ a socket and a stream, whose methods may throw various checked exceptions of type IOException when called. You do not catch them; simply declare that they throw them out.
      • In addition, the downcast may throw a ClassNotFoundException, that you also simply propagate out of the method (you do not expect other types than Message to receive from the stream, but this exception is checked, so it must be explicitly handled somehow).
      • Do these reads in a continuous loop (read a Message object from the stream, display the formatted message, read another object, display the new message, a.s.o.).
      • As long as the connection is open, the readObject method waits for a complete object to be received from the stream and then returns with a reference to it. If the connection is closed (by the other side for example) the method aborts and throws the EOFException. Use this exception to neatly end the read loop. For this purpose, enclose the continuous loop in a try block and attach a catch for this particular exception, whithout statements. This catch will simply serve to continue the program, instead of aborting it with an exception. If you want a more realistic output, you may print on the screen, after the EOFException was caught, the message The client has disconnected. or something like that.
      • Don't forget to close everything after the connection is closed (and you exited from the loop). You have just added a try block, so you need only to attach to it the finally block with statements to close the input stream and the socket. Be careful, the references used inside the finally block must be declared ouside the try block!
  7. The last to be added to your package is a class called Server, which is executable (has a main method).
    • The main method instantiates a ServerSocket object attached to port 9000.
    • The ServerSocket method accept is used to listen for clients. This method returns after a client request is accepted and a connection with that client is established. The method returns a reference to a Socket object created specially for this connection. You use this Socket reference to instantiate a ServerPeer object.
    • Call then the run method for this newly created ServerPeer object.
    • The method run returns after the connection is closed (remember, you just added the proper try-catch construction to handle the EOFException. The Socket is closed, but not the ServerSocket. You may call again the accept method to accept another client, a.s.o.
    • Don't forget to close the SeverSocket object after you decide to no longer accept clients and to exit your program.
    • If it still has compilation errors it's because you forget about that annoying exceptions. The main method uses various sockets and streams, that may throw exceptions ... already a classic story. Don't bother with them, simply append the necessary declaration to the main method signature. In addition to IOExceptions, a ClassNotFoundException may be thrown from run, so it needs to be declared too.
  8. Run the Server class (with the Server.java opened in the editor window right-click and select Run File, or click Run->Run File from the general Menu). If there are no errors the program runs, but nothing is output, and it appears to run without end. It's because there are no clients running around and it listens continuously waiting for some client to appear (the accept method returns only after it catches a client, or something bad happens).
  9. How to test your classes? Actually you have two separate applications, a server and a client. You have just started the server, but it runs without end waiting for a client to send messages. You need to start separately a client. To do that, switch the editor window to Client.java and run that file too (right-click and select Run File, or bla bla). A second output tab appears. You have now two programs running at the same time, with their outputs displayed on separate tabs in the output window at the bottom of the NetBeans environment.
  10. Type something in the output window of the Client and press Enter. Look to the other tab and see that the Sever outputs the message you have just typed. Try with other messages. To close the Client, type QUIT and press Enter. Depending on how you have written the main of the Server class, the server will end too, or it will continue, listening for other clients to connect (in case which you run again the Client.java, type something a.s.o)
  11. If you want more fun, and know the IP address of the computer of your colleague, ask him to open a server, change your Client class to open a Socket with that IP instead of the localhost IP 127.0.0.1, and run locally a client. Please, send only peacefull messages!

Submitting

  • The assignment will be evaluated automatically by the Web-CAT platform.
  • You could access the Web-CAT platform using the username and the password with which you acces the electronica.curs.pub.ro intranet.
  • Select the OOP Lab Task 5 assignment.
  • Submit your work as a single .zip archive (give it whatever name you choose) containing only the Java source code files.
  • Attention Any deviation from these instructions may lead to the loss of the entire amount of points.