Creating Intercom 1


The first thing to do in Intercom 1 is to create the window and controls you see in Figure 9.1. This works by creating a new object of the Intercom1 class in the main method:

 import java.awt.*; import java.awt.event.*; public class Intercom1 extends Frame implements Runnable, ActionListener {     public static void main(String[] args)     {         new Intercom1();     }     .     .     . } 

Next, the code adds the Send button, connects it to an ActionListener, and adds the top text area control (note that the text area controls in this project have only vertical scrollbars so that the user doesn't have to stop to scroll horizontally with the mouse each time long text appears or he's typing something longer than the text area can display on one line):

 import java.awt.*;  import java.awt.event.*; public class Intercom1 extends Frame implements Runnable, ActionListener {     private Button button1;     private TextArea textarea1;     public static void main(String[] args)     {         new Intercom1();     }     public Intercom1()     {         setLayout(null);         button1 = new Button("Send");         button1.setBounds(160, 360, 60, 20);         add(button1);         button1.addActionListener(this);         textarea1 = new TextArea("", 7, 45,             TextArea.SCROLLBARS_VERTICAL_ONLY);         textarea1.setBounds(20, 80, 340, 120);         add(textarea1);      .     .     . } 

You can find the significant methods of the Java AWT TextArea class in Table 9.1.

Table 9.1. Significant Methods of the java.awt.TextArea Class

Method

Does This

void append(String str)

Appends the specified text to the current text in the text area control

int getColumns()

Returns the number of columns in this text area as currently configured

Dimension getMinimumSize()

Returns the minimum size of this text area control

Dimension getMinimumSize (int rows, int columns)

Returns the minimum size needed for this text area control given the specified number of rows and columns

Dimension getPreferredSize()

Returns the preferred size of this text area control

Dimension getPreferredSize (int rows, int columns)

Returns the preferred size of the text area control given the specified number of rows and columns

int getRows()

Returns the number of rows currently in the text area control

void insert(String str, int pos)

Inserts the given text at a particular position in this text area control

void setColumns(int columns)

Sets the number of columns in this text area control

void setRows(int rows)

Sets the number of rows in this text area control


Next comes the bottom text area control, where you enter text to send to Intercom 2. To make it clear that this text area is for that purpose, the code also adds a label with the text "Type here:" above the second text area control:

 import java.awt.*;  import java.awt.event.*; public class Intercom1 extends Frame implements Runnable, ActionListener {     private Button button1;     private TextArea textarea1, textarea2;     private Label label1;     public static void main(String[] args)     {         new Intercom1();     }     public Intercom1()     {         setLayout(null);         button1 = new Button("Send");         button1.setBounds(160, 360, 60, 20);         add(button1);         button1.addActionListener(this);         .         .         .         label1 = new Label();         label1.setBounds(20, 210, 100, 20);         label1.setText("Type here:");         add(label1);          textarea2 = new TextArea("", 7, 45,             TextArea.SCROLLBARS_VERTICAL_ONLY);         textarea2.setBounds(20, 230, 340, 120);         add(textarea2);         .         .         . } 

All that's left to create the Intercom 1 display is to add the label "Intercom 1" you see in Figure 9.1, to set the window title, and to handle window-closing events, as you see here:

 import java.awt.*; import java.awt.event.*; public class Intercom1 extends Frame implements Runnable, ActionListener {     private Button button1;     private TextArea textarea1, textarea2;     private Label label1, label2;     public static void main(String[] args)     {         new Intercom1();     }     public Intercom1()     {         setLayout(null);          .         .         .         label2 = new Label("Intercom 1");         label2.setFont(new Font("Times New Roman", Font.BOLD, 36));         label2.setBounds(100, 35, 200, 30);         add(label2);         setSize(400, 400);         setTitle("Intercom 1");         setVisible(true);         textarea2.requestFocus();         this.addWindowListener(new WindowAdapter(){             public void windowClosing(                 WindowEvent e){                     System.exit(0);                     try{                         socket.close();                     }catch(Exception ex){}                 }             }         );         .         .         . } 

That's it for Intercom 1's GUI. The next step is to start the server and wait for a connection from Intercom 2. Intercom 1 acts as the server for the connection, waiting for connections from clients, so it's based on the Java java.net.ServerSocket class; Intercom 1 uses an object of this class to accept connections from Intercom 2.

Connecting to Intercom 2

ServerSocket connections let you create TCP/IP connections on the Internet, just as you would if you were writing your own web server. In fact, you can write a web server yourself in just a few lines, and you can host it yourself if you have a fixed IP address. Here's how: Just create a new ServerSocket object that will listen on port 80 (the port web browsers use), in a program called, say, Server.java. (More is coming up on how to use ServerSocket and what methods are available when this chapter develops the Intercom code next.)

 import java.io.*; import java.net.*; public class Server {     public static void main(String[] args )     {         try {             ServerSocket socket = new ServerSocket(80);         .         .         .         }         catch (Exception e) {}      } } 

You can wait for connections to your new web server with the ServerSocket object's accept method and use a PrintWriter object to write to web browsers:

 import java.io.*; import java.net.*; public class Server {     public static void main(String[] args )     {         try {             ServerSocket socket = new ServerSocket(80);             Socket insocket = socket.accept();             PrintWriter out = new PrintWriter (                 insocket.getOutputStream(), true);              .             .             .         }         catch (Exception e) {}      } } 

After a browser connects to the web server, you can send a web page back to the browser, like this:

 import java.io.*; import java.net.*;  public class Server {     public static void main(String[] args )     {         try {             ServerSocket socket = new ServerSocket(80);             Socket insocket = socket.accept();             PrintWriter out = new PrintWriter (                 insocket.getOutputStream(), true);             out.println("<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.0 "                 + "transitional//EN'>");             out.println("<html>");             out.println("<head>");             out.println("<title>");             out.println("A new web page");             out.println("</title>");             out.println("</head>");             out.println("<body>");             out.println("<h1>");             out.println("A custom web server! Not bad.");             out.println("</h1>");             out.println("</body>");             out.println("</html>");             insocket.close();         }         catch (Exception e) {}      } } 

After compiling Server.java, run it to start the server waiting for connections. In a browser on your or any Internet-connected machine, enter http://nnn.nnn.nnn.nnn, where nnn.nnn.nnn.nnn is your fixed IP address, and you'll see the web page Server.java creates, as shown in Figure 9.10.

Figure 9.10. A custom web server.


Congratulations, you've written your own custom web server, all using the built-in TCP/IP socket support in Java.

Intercom 1 centers around a ServerSocket object that Intercom 2 will connect to. Here's how that object is created in Intercom 1note that this application communicates using port 8765, which is very rarely used by other applications (if you run across a conflict with other software, change this port number to some other four-digit number; using a value over 8000 helps avoid conflicts with most other software):

 import java.io.*;  import java.net.*; import java.awt.*; import java.awt.event.*; public class Intercom1 extends Frame implements Runnable, ActionListener {     private Button button1;     private TextArea textarea1, textarea2;     private Label label1, label2;     ServerSocket socket;     public static void main(String[] args)     {         new Intercom1();     }     public Intercom1()     {         .         .         .         try {             socket = new ServerSocket(8765);         .         .         .         }         catch (Exception e)         {             textarea1.setText(e.getMessage());         }      }         .         .         . } 

REAL-WORLD SCENARIO: JAVA AND SOCKETS

Sockets are an unusually powerful part of Java. As you just saw, the socket support in Java is strong enough to let you write your own web server. And it's strong enough to let you write the whole Intercom project.

In the early days of Java, developers asked if there was some easy way to add socket support to Java, and Sun looked into the matter. The idea was to match Unix's way of working with sockets, which is to work with sockets much as you work with filesopening, writing, reading, and closing sockets just as you would files.

Developers liked that idea.

There are two main protocols for sockets: TCP/IP and UDP/IP. Thankfully, Sun chose the right one to support: TCP/IP.

User Datagram Protocol (UDP) operates in a connectionless way, and you send data using "datagrams." Because the connection isn't saved, you have to provide a socket descriptor each time you send a datagram, as well as the other socket's address. There's also a limit of 64 kilobytes per datagram. But the real issue with UDP is that it's unreliableyou can't assume that the datagrams you send are going to be received in the order you sent them, which has caused developers a lot of problems.

Transfer Control Protocol (TCP), on the other hand, is a streaming protocol that makes sure the packets you send arrive in the order you sent them. And once you make a connection, that connection is preserved unless it times out or is closed; there's no need to refresh the connection each time you want to send data, as in UDP. And there's no data size limit in TCP, as there is in UDP.

For all these reasons, Java sockets use the TCP/IP protocol by default, and that has made developers very happy. Just by using Java, you have a way to connect over the Internet with custom applications, such as the Intercom project. You don't need a browser if you don't want to use one. Using Java sockets, you can create your own entirely custom Internet applications like the ones that already have been developedFTP, Telnet, SSH, and web browsers.


You can find the significant methods of the ServerSocket class in Table 9.2.

Table 9.2. Significant Methods of the java.net.ServerSocket Class

Method

Does This

Socket accept()

Listens for a connection attempt to this socket and accepts it if possible

void bind(SocketAddress endpoint)

Binds the ServerSocket object to the given address (which includes both an IP address and a port number)

void close()

Closes this socket's connection

ServerSocketChannel getChannel()

Returns the ServerSocketChannel object associated with this socket, if there is any

InetAddress getInetAddress()

Returns the local address of this server socket

int getLocalPort()

Returns the port on which this socket is set up to listen

SocketAddress getLocalSocketAddress()

Returns the address of the endpoint this socket is bound to. Returns null if it is not yet bound to an endpoint

int getSoTimeout()

Returns the SO_TIMEOUT setting

boolean isBound()

Returns TRue if the socket is bound

boolean isClosed()

Returns true if the socket is closed

void setSoTimeout(int timeout)

Sets the SO_TIMEOUT value to the given timeout (in milliseconds)


The ServerSocket object's accept method listens for and accepts connections, which is how you use a server socket. This method returns the Socket object you can use to communicate with Intercom 2. Here's what that looks like in code:

 import java.io.*; import java.net.*; import java.awt.*; import java.awt.event.*; public class Intercom1 extends Frame implements Runnable, ActionListener {     private Button button1;     private TextArea textarea1, textarea2;     private Label label1, label2;     ServerSocket socket;     PrintWriter out;     Socket insocket;     public static void main(String[] args)     {         new Intercom1();     }     public Intercom1()     {         .         .         .         try {             socket = new ServerSocket(8765);             insocket = socket.accept();         .         .         .         }         catch (Exception e)         {             textarea1.setText(e.getMessage());         }      }         .         .         . } 

You can find the significant methods of the Socket class in Table 9.3; these are the methods the code will use to communicate with Intercom 2.

Table 9.3. Significant Methods of the java.net.Socket Class

Method

Does This

void bind(SocketAddress bindpoint)

Binds this Socket object to a local address

void close()

Closes this Socket object

void connect(SocketAddress endpoint)

Connects this Socket object to the given server

void connect(SocketAddress endpoint, int timeout)

Connects this Socket object to the given server, subject to the specified timeout

SocketChannel getChannel()

Returns the SocketChannel object for this socket, if there is one

InetAddress getInetAddress()

Returns the address to which the socket is connected

InputStream getInputStream()

Returns an input stream object for this socket for I/O operations

InetAddress getLocalAddress()

Returns the local address to which the Socket object is bound

int getLocalPort()

Returns the local port to which this Socket object is bound

SocketAddress getLocalSocketAddress()

Returns the address of the endpoint this socket is bound to. Returns null if the Socket object is not yet bound

OutputStream getOutputStream()

Returns an output stream object for this socket for I/O operations

int getPort()

Returns the remote port to which this Socket object is connected

SocketAddress getRemoteSocketAddress()

Returns the address of the endpoint this socket is connected to. Returns null if it is not connected

int getSoTimeout()

Returns the value of the current SO_TIMEOUT setting

boolean isBound()

Returns TRue if the Socket object is bound

boolean isClosed()

Returns true if the Socket object is closed

boolean isConnected()

Returns true if the Socket object is connected

boolean isInputShutdown()

Returns true if the reading part of the Socket object is closed

boolean isOutputShutdown()

Returns true if the writing part of the Socket object is closed

void setReceiveBufferSize(int size)

Sets the receiving buffer size to the specified value in bytes

void setSendBufferSize(int size)

Sets the sending buffer size to the specified value in bytes

void setSoTimeout(int timeout)

Sets the SO_TIMEOUT setting to the specified timeout (in milliseconds)

void shutdownInput()

Shuts down the input stream

void shutdownOutput()

Shuts down the output stream


Sending Text to Intercom 2

Once the connection is made, you can use the Socket object's getOutputStream method to get an OutputStream object and create a PrintWriter object named out, which will let the user type to Intercom 2.

How do you handle both incoming and outgoing text in the same application, potentially at the same time? To do that, Intercom 1 is clever and launches a new thread for the incoming text. It creates the PrintWriter object named out first to handle outgoing text, and then it starts the new thread for the incoming text this way:

 import java.io.*;  import java.net.*; import java.awt.*; import java.awt.event.*; public class Intercom1 extends Frame implements Runnable, ActionListener {     private Thread thread;     private Button button1;     private TextArea textarea1, textarea2;     private Label label1, label2;     ServerSocket socket;     PrintWriter out;      Socket insocket;     public static void main(String[] args)     {         new Intercom1();     }     public Intercom1()     {         .         .         .         try {             socket = new ServerSocket(8765);             insocket = socket.accept();             out = new PrintWriter(insocket.getOutputStream(), true);             thread = new Thread(this);             thread.start();         }         catch (Exception e)         {             textarea1.setText(e.getMessage());         }      }         .         .         . } 

You can find the significant methods of the PrintWriter class in Table 9.4; this is the class Intercom 1 will use to actually write text to Intercom 2 across the Internet.

Table 9.4. Significant Methods of the java.io.PrintWriter Class

Method

Does This

PrintWriter append(char c)

Appends the given character to this writer's stream

PrintWriter append(CharSequence csq)

Appends the given character sequence to this writer's stream

PrintWriter append(CharSequence csq, int start, int end)

Appends the given part of a character sequence to this writer's stream

void close()

Closes the stream connected to this writer

void flush()

Flushes the stream connected to this writer

void print(boolean b)

Prints a Boolean value using this writer object

void print(char c)

Prints a character using this writer object

void print(char[] s)

Prints an array of characters using this writer object

void print(double d)

Prints a double-precision floating-point number using this writer object

void print(float f)

Prints a floating-point number using this writer object

void print(int i)

Prints an integer using this writer object

void print(long l)

Prints a long integer using this writer object

void print(Object obj)

Prints an object using this writer object

void print(String s)

Prints a string using this writer object

void println()

Writes the line separator string using this writer object

void println(boolean x)

Prints a Boolean value followed by the line separator string using this writer object

void println(char x)

Prints a character followed by the line separator string using this writer object

void println(char[] x)

Prints an array of characters followed by the line separator string using this writer object

void println(double x)

Prints a double-precision floating-point number followed by the line separator string using this writer object

void println(float x)

Prints a floating-point number followed by the line separator string using this writer object

void println(int x)

Prints an integer followed by the line separator string using this writer object

void println(long x)

Prints a long integer followed by the line separator string using this writer object

void println(Object x)

Prints an object followed by the line separator string using this writer object

void println(String x)

Prints a string followed by the line separator string using this writer object

protected void setError()

Reports that an error has occurred to the user

void write(char[] buf)

Writes an array of characters using this writer object

void write(char[] buf, int off, int len)

Writes a portion of an array of characters using this writer object

void write(int c)

Writes a single character using this writer object

void write(String s)

Writes a string using this writer object

void write(String s, int off, int len)

Writes part of a string using this writer object


The user enters his text in the bottom text area, textarea2, and clicks the Send button. That executes the actionPerformed method, which simply has to send the text in the text area to the out object, which in turn sends that text to Intercom 2 (note that the code also clears the text area of text):

     public void actionPerformed(ActionEvent event)      {         if(event.getSource() == button1){             String text = textarea2.getText();             textarea2.setText("");             out.println(text);             textarea2.requestFocus();         }     } 

Reading Text from Intercom 2

What about reading text from Intercom 2? Because the code is divided up between threads, Intercom 1 will be able to both read and send text at the same time. The worker thread in Intercom 1 will be run in Intercom 1's run method, and it will listen for text from Intercom 2.

To catch text from Intercom 2, you can use the getInputStream method of the insocket object of the Socket class to get an InputStream object. To make working with that input stream easier, the code uses that InputStream object to create a BufferedReader object, which lets you read whole lines of text at a time.

Here's how to create the BufferedReader object in the worker thread's run method:

     public void run()     {         try {             BufferedReader in = new BufferedReader (new                 InputStreamReader(insocket.getInputStream()));         .         .         .         }catch (Exception e)         {             textarea1.setText(e.getMessage());         }     } 

You can find the significant methods of the BufferedReader class in Table 9.5.

Table 9.5. Significant Methods of the java.io.BufferedReader Class

Method

Does This

void close()

Closes the buffered stream object

int read()

Reads a single character using this object

int read(char[] cbuf, int off, int len)

Reads characters and stores them in a section of an array

String readLine()

Reads an entire line of text

boolean ready()

Returns TRue if this stream is ready to be read

long skip(long n)

Skips the specified number of characters


Now all you've got to do to read text from Intercom 2 is to use the BufferedReader object's readLine method, looping over that method repeatedly. Here's what that looks like in the run method, where the code waits until a line of text is ready and then appends it to the text in the top text area, textarea1:

     public void run()     {         String instring;         try {             BufferedReader in = new BufferedReader (new                 InputStreamReader(insocket.getInputStream()));             while((instring = in.readLine()) != null){                 textarea1.append(instring + "\n");             }         }catch (Exception e)          {             textarea1.setText(e.getMessage());         }     } 

That completes all the tasks in Intercom 1accepting connections from Intercom 2 on port 8765, reading text from Intercom 2, and sending text to Intercom 2.

Now it's time to get Intercom 2 working.

NOTE

The Intercom project is designed for two users only. Can you convert it into a multiuser chat program like the Chat project earlier? Yes, you can, but it would take some work.

Each time a new connection is made, you'd have to store a different Socket object in Intercom 1 and listen for text from all of them. Also, you'd have to echo the text you got from one client to all the clients.

In other words, you'd have to modify the server application, Intercom 1, to really act as a server for multiple clients, reading and sending text to all clients. This certainly can be done, but it would take some work to do it.




    Java After Hours(c) 10 Projects You'll Never Do at Work
    Java After Hours: 10 Projects Youll Never Do at Work
    ISBN: 0672327473
    EAN: 2147483647
    Year: 2006
    Pages: 128

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net