2012年12月7日 星期五

Java 網路程式設計範例

Java 網路程式設計範例

The materials in this web page are collected from Java Network Programming and Distributed Computing written by David Reilly and Michael Reilly and the Internet. They are solely used for educational purposes. Hopefully, I am not violating any copyright issue here. If so, please do email me.
Written by: 國立中興大學資管系呂瑞麟 Eric Jui-Lin Lu

請勿轉貼
看其他教材

目錄

  1. java.net.InetAddress
  2. Data Streams
    1. java.io.InputStream
    2. java.io.OutputStream
    3. Filter Streams
    4. Readers and Writers
    5. Object Persistence and Serialization
  3. User Datagram Protocol
  4. Transmission Control Protocol
  5. 執行緒:Multi-Threading
  6. Some application protocols
    1. SMTP Client
    2. POP3 Client
    3. HTTP/1.0 Server
    4. Simple HTTP Client
  7. Java Multicasting


java.net.InetAddress

  • Example 1.
    import java.net.*;
    
    public class TestInet1 {
      public static void main(String argv[]) 
      {
        try {
          InetAddress myip = InetAddress.getLocalHost();
    
          System.out.println(myip.getHostName());
          System.out.println(myip.getHostAddress());
        } catch (UnknownHostException e) {
          System.out.println("Error: unable to resolve localhost");
        }
      }
    }
    
  • 練習題: 請將 /etc/hosts 的內容作修正,例如在 localhost 之後加上一個你喜歡的名稱,再將以上的程式執行一次,並看看他的結果。
  • Example 2.
    import java.net.*;
    
    public class TestInet2 {
      public static void main(String argv[]) throws UnknownHostException
      {
        // obtain an InetAddress of a hostname or IP address string
        // an IP address may be associated with many hostname
        // you can also check out this example by using nslookup
        InetAddress[] myip1 = InetAddress.getAllByName("java.sun.com");
    
        // print out its IP address
        System.out.println("java.sun.com:");
        for(int i=0; i<myip1.length; i++)
          System.out.println(myip1[i].getHostAddress());
    
    
        // NOTE: there is a bug for J2SE 1.4.0_00-b05 on Solaris
        //       if an address of java.sun.com was entered, it returns
        //       no hostname.
        // Please try out the other three IP addresses
        InetAddress[] myip2 = InetAddress.getAllByName("128.11.159.83");
        System.out.println("128.11.159.83");
    
        // if hostname is null, the loopback is returned
        //InetAddress[] myip2 = InetAddress.getAllByName(null);
        //System.out.println("null (or loopback):");
        for(int i=0; i<myip2.length; i++) {
          System.out.println(myip2[i].getHostName());
          System.out.println(myip2[i].getHostAddress());
        }
      }
    }
    
  • 練習題: 請利用 JOptionPane 寫一個簡易型的 nslookup 的工具.

Data Streams

  1. java.io.InputStream
    • Example 1
      import java.io.*;
      
      // Chapter 4, Listing 1
      public class FileInputStreamDemo {
        public static void main(String args[]) {
          if (args.length != 1) {
            System.err.println ("Syntax - FileInputStreamDemo file");
            return;
          }
      
          // Caution: what are the exceptions needs to be handled?
          try {
            // Create an input stream, reading from the specified file
            InputStream fileInput = new FileInputStream ( args[0] );
      
            // Read the first byte of data
            int data = fileInput.read();
      
            // Repeat : until end of file (EOF) reached
            while (data != -1) {   
              // Send byte to standard output
              System.out.write ( data );
       
              // Read next byte
              data = fileInput.read();
            }
      
            // Close the file
            fileInput.close();
          } catch (IOException ioe) {
            System.err.println ("I/O error - " + ioe);
          }
        }
      }
        
    • 練習題: 請利用 int read() 以及 int read(byte[] byteArray) 來讀取一個檔案。
    • 練習題: 執行程式的時候如果發生錯誤,如何判斷是開檔的時候錯誤 還是讀取檔案的時候出錯?
    • Example 2: read data from users by using System.in.
      // Interactively communicating with the user
      import java.io.*;
      
      public class PersonalHello
      {
        public static void main( String argv[] )
        {
          byte name[] = new byte[100];
          int nr_read = 0;
      
          // System.out is a PrintStream object
          System.out.print("What is your name? ");
      
          try {
      
            // System.in is an InputStream object
            nr_read = System.in.read(name);
      
            System.out.print("\nHello ");
            System.out.write(name, 0, nr_read);
          }
          // for jdk 1.1.x, if you input nothing, an IOException will be
          // thrown. For jdk 1.3.x and up, it will not.
          catch (IOException e) {
            System.out.println("I'm sorry. I didn't catch your name.");
          }
        }
      }
      
  2. java.io.OutputStream
    • Example 1
      import java.io.*;
      
      // Chapter 4, Listing 2
      public class FileOutputStreamDemo {
        public static void main(String args[]) {
      
          // Two parameters are required, the source and destination
          if (args.length != 2) {
            System.err.println ("Syntax - FileOutputStreamDemo src dest");
            return;
          }
      
          String source = args[0];
          String destination = args[1];
      
          try {
            // Open source file for input
            InputStream input = new FileInputStream( source );
      
            System.out.println ("Opened " + source + " for reading.");
      
            // Ouput output file for output
            OutputStream output = new FileOutputStream ( destination );
      
            // NOTE 1: To append data to the existing file, we use
            //OutputStream output = new FileOutputStream( destination, true );
      
            // NOTE 2: If the file exists but is a directory rather than a 
            // regular file, does not exist but cannot be created, or cannot 
            // be opened for any other reason then a FileNotFoundException is 
            // thrown.
      
            System.out.println ("Opened " + destination + " for writing.");
      
            int data = input.read();
      
            while ( data != -1) {
              // Write byte of data to our file
              // Note that only one byte is written to 
              // the output stream. The byte to be written is the eight 
              // low-order bits of the argument b. The 24 high-order bits of b 
              // are ignored.
              output.write (data);
      
              // Read next byte
              data=input.read();
            }
      
            // Close both streams
            input.close();
            output.close();
      
            System.out.println ("I/O streams closed");
          } catch (IOException ioe) {
            System.err.println ("I/O error - " + ioe);
          }
        }
      }
        
    • 練習題: 請更改以上的範例使得使用者可以知道究竟讀檔的時候 出錯或者是寫檔的時候出錯。
  3. Filter Streams
    • Example 1
      import java.io.*;
      
      public class TestFilter1 {
        public static void main(String args[]) {
      
          if (args.length != 2) {
            System.err.println ("Syntax - TestFilter1 src dest");
            return;
          }
      
          String source = args[0];
          String destination = args[1];
      
          try {
            // Open source file for input
            InputStream input = new FileInputStream(source);
      
            // chain input to filter DataInputStream to use readLine()
            // note that readLine() is deprecated
            DataInputStream din = new DataInputStream(input);
      
            // NOTE: if the object input will not be used later, we can
            // DataInputStream din = new DataInputStream(
            //                           new FileInputStream(source));
      
            System.out.println ("Opened " + source + " for reading.");
      
            // Ouput output file for output
            OutputStream output = new FileOutputStream ( destination );
      
            // chain output to filter PrintStream to use println()
            PrintStream pout = new PrintStream(output);
      
            System.out.println ("Opened " + destination + " for writing.");
      
            // readLine() is deprecated since v1.1. It was used only for
            // demonstration purpose. Also, the encoding is not converted
            // correctly.
            String line = din.readLine();
      
            // when EOF is read, readLine() returns null
            while ( line != null) {
              pout.println (line);
      
              // Read next line
              line=din.readLine();
            }
      
            // Close all streams
            din.close();
            pout.close();
            input.close();
            output.close();
      
            System.out.println ("I/O streams closed");
          } catch (IOException ioe) {
            System.err.println ("I/O error - " + ioe);
          }
        }
      }
        
    • 練習題: 請利用 java.io.InputStream 以及 java.io.BufferedInputStream 來讀取一個大型的檔案,並比較它們效率的差異。(你可以把一個檔案重複 append 多次來完成一個大的檔案)
    • Example 2
      import java.io.*;
      
      public class TestDataInput {
        public static void main( String[] argv ) {
          try {
      
            // connect to one filter stream and one low-level stream
            // is it all right to remove BufferedOutputStream?
            DataOutputStream out = new DataOutputStream(
                                       new BufferedOutputStream(
                                       new FileOutputStream("Data.txt")));
      
            out.writeDouble(3.14159);
            out.writeUTF("That was pi");
            out.writeDouble(1.41413);
            out.writeUTF("開根號之後的值");
            out.close();
      
            // check out the file Data.txt.
      
            DataInputStream in = new DataInputStream(
                                 new BufferedInputStream(
                                 new FileInputStream("Data.txt")));
      
            // Must use DataInputStream for data:
            System.out.println(in.readDouble());
      
            // Only readUTF() will recover the
            // Java-UTF String properly:
            System.out.println(in.readUTF());
            // Read the following double and String:
            System.out.println(in.readDouble());
            System.out.println(in.readUTF());
          } catch(EOFException e) {
            throw new RuntimeException(e);
          } catch(IOException e) {
            System.out.println("I/O 錯誤");
          }
        }
      }
      
    • Example 3
      import java.io.*;
      
      public class TestPushBack {
        public static void main( String[] argv ) {
          try {
            // declare a pushback input stream and a buffer of size 2
            PushbackInputStream in = new PushbackInputStream(
                                         new FileInputStream("Data.txt"), 2);
      
            byte data[] = new byte[2];
      
            // read the first two bytes
            in.read(data);
            System.out.println("Read: " + data[0] + " and " + data[1]);
      
            // push the data back
            in.unread(data);
      
            // re-read data.
            in.read(data);
            System.out.println("Re-read: " + data[0] + " and " + data[1]);
            System.out.println("Both byte should be the same!");
      
          } catch(IOException e) {
            System.out.println("I/O 錯誤");
          }
        }
      }
      
  4. Readers and Writers
    • Example 1
      import java.io.*;
      
      public class TestStringReader {
        public static void main( String[] argv ) {
          String msg = "Hello 老呂";
          try {
            StringReader in = new StringReader(msg);
      
            // check to see if mark/reset is supported
            if (in.markSupported())
              System.out.println("StringReader supports mark/reset");
      
            // skip 6 chars
            in.skip(6);
      
            // read next char and print it out
            System.out.println("next character is " + (char) in.read());
      
            // move the pointer back the first char
            in.reset();
            System.out.println("1st character is " + (char) in.read());
      
          } catch(IOException e) {
            System.out.println("I/O 錯誤");
          }
        }
      }
        
    • Example 2: read users' input from BufferedReader
      import java.io.*;
      
      // Chapter 4, Listing 3
      // Combining Streams and Readers
      public class InputStreamToReaderDemo {
        public static void main(String args[]) {
          try {
            System.out.print ("Please enter your name : ");
       
            // Get the input stream representing standard input
            InputStream input = System.in;
      
            // Create an InputStreamReader
            InputStreamReader reader = new InputStreamReader ( input );
      
            // Connect to a buffered reader, to use the readLine() method
            BufferedReader bufReader = new BufferedReader ( reader );
      
            String name = bufReader.readLine();
      
            System.out.println ("Pleased to meet you, " + name);
          } catch (IOException ioe) {
            System.err.println ("I/O error : " + ioe);
          }
        }
      }
        



Object Persistence and Serialization

  • Example 1
    import java.io.*;
    import java.util.*;
    
    // Chapter 4, Listing 5
    public class SerializationDemo {
      public static void main(String args[]) {
        try {
          // Vector is Serializable
          Vector list;
    
          // Create a buffered reader for easy input
          BufferedReader reader = new BufferedReader
                                  ( new InputStreamReader ( System.in ) );
    
          System.out.println ("Checking for previous serialized list");
    
          // Check to see if serialized list exists
          // NOTE: nested try statements
          try {
    
            // after executing the program, check out list.out
            FileInputStream fin = new FileInputStream("list.out");
    
            // Connect an object input stream to the list
            ObjectInputStream oin = new ObjectInputStream(fin);
    
            try {
              // Read the vector back from the list
              Object obj = oin.readObject();
    
              // Cast back to a vector
              list = (Vector) obj;
            } catch (ClassCastException cce) {
              // Can't cast it, create a blank one
              list = new Vector();
            } catch (ClassNotFoundException cnfe) {
              // Can't read it, create a blank one
              list = new Vector();
            }
    
            fin.close();
          } catch (FileNotFoundException fnfe) {
            // Create a blank vector
            list = new Vector(); 
          }
    
          // Repeat indefinitely
          for (;;)
          {
            // Now, display menu
            System.out.println ("Menu :-");
            System.out.println ("1.. Add item");
            System.out.println ("2.. Delete item");
            System.out.println ("3.. List items");
            System.out.println ("4.. Save and quit");
            System.out.print   ("Choice : ");
    
            // Read choice
            String response = reader.readLine();
    
            // Convert to an int
            int choice = Integer.parseInt (response);
    
            switch (choice) {
              case 1 :
                // Add the item to list
                System.out.print ("Enter item : ");
                String item = reader.readLine();
                list.addElement(item);
                break;
              case 2 :
                // Delete the item from list
                System.out.print ("Enter item : ");
                String deadItem = reader.readLine();
                list.removeElement(deadItem);
                break;
              case 3 :
                // List the elements of the list
                for (Enumeration e = list.elements(); e.hasMoreElements();)
                  System.out.println (e.nextElement());
                break;
              case 4 :
                // Save list and terminate
                System.out.println ("Saving list");
                FileOutputStream fout = new FileOutputStream("list.out");
    
                // Construct an object output stream
                ObjectOutputStream oout = new ObjectOutputStream(fout);
    
                // Write the object to the stream
                oout.writeObject (list);
                fout.close();
                System.exit(0);
            }
          }
        } catch (IOException ioe) {
          System.err.println ("I/O error");
        }
      }
    }
    
  • Example 2
    //: c12:Worm.java
    // Demonstrates object serialization.
    // {Clean: worm.out}
    import java.io.*;
    import java.util.*;
    
    class Data implements Serializable {
      private int n;
      public Data(int n) { this.n = n; }
      public String toString() { return Integer.toString(n); }
    }
    
    public class Worm implements Serializable {
      private static Random rand = new Random();
      private Data[] d = {
        new Data(rand.nextInt(10)),
        new Data(rand.nextInt(10)),
        new Data(rand.nextInt(10))
      };
    
      // to create a link list
      // the last Worm segment is initialized to null.
      private Worm next;
      private char c;
    
      // Value of i == number of segments
      public Worm(int i, char x) {
        System.out.println("Worm constructor: " + i);
        c = x;
        if(--i > 0)
          next = new Worm(i, (char)(x + 1));
      }
    
      // this is the default argument which is a must
      public Worm() {
        System.out.println("Default constructor");
      }
    
      public String toString() {
        String s = ":" + c + "(";
        for(int i = 0; i < d.length; i++)
          s += d[i];
        s += ")";
        if(next != null)
          s += next;       // identical to s += next.toString()
        return s;
      }
    
      // Throw exceptions to console:
      public static void main(String[] args)
      throws ClassNotFoundException, IOException {
    
        // instatiate a Worm and serialize it to worm.out
        Worm w = new Worm(6, 'a');
        System.out.println("w = " + w);
        ObjectOutputStream out = new ObjectOutputStream(
          new FileOutputStream("worm.out"));
        out.writeObject("Worm storage\n");
        out.writeObject(w);
        out.close(); // Also flushes output
    
        // deserialize the worm from worm.out
        ObjectInputStream in = new ObjectInputStream(
          new FileInputStream("worm.out"));
        String s = (String)in.readObject();
        Worm w2 = (Worm)in.readObject();
        System.out.println(s + "w2 = " + w2);
    
        // You can read and write an object using serialization to any 
        // DataInputStream or DataOutputStream. In the followings, we use
        // ByteArrayOutputStream as example.
        ByteArrayOutputStream bout =
          new ByteArrayOutputStream();
        ObjectOutputStream out2 = new ObjectOutputStream(bout);
        out2.writeObject("Worm storage\n");
        out2.writeObject(w);
        out2.flush();
        ObjectInputStream in2 = new ObjectInputStream(
          new ByteArrayInputStream(bout.toByteArray()));
        s = (String)in2.readObject();
        Worm w3 = (Worm)in2.readObject();
        System.out.println(s + "w3 = " + w3);
      }
    }
    
    Note that no constructor, not even the default constructor, is called in the process of deserializing a Serializable object. The entire object is restored by recovering data from the InputStream.
  • Example 3: the transient keyword
    //: c12:Logon.java
    // Demonstrates the "transient" keyword.
    // {Clean: Logon.out}
    import java.io.*;
    import java.util.*;
    
    public class Logon implements Serializable {
      private Date date = new Date();
      private String username;
      private transient String password;
    
      // NOTE that there is no default constructor
      public Logon(String name, String pwd) {
        username = name;
        password = pwd;
      }
    
      public String toString() {
        String pwd = (password == null) ? "(n/a)" : password;
        return "logon info: \n   username: " + username +
          "\n   date: " + date + "\n   password: " + pwd;
      }
    
      public static void main(String[] args) throws Exception {
        Logon a = new Logon("Hulk", "myLittlePony");
        System.out.println( "logon a = " + a);
        ObjectOutputStream o = new ObjectOutputStream(
          new FileOutputStream("Logon.out"));
        o.writeObject(a);
        o.close();
    
        Thread.sleep(1000); // Delay for 1 second
    
        // Now get them back:
        ObjectInputStream in = new ObjectInputStream(
          new FileInputStream("Logon.out"));
        System.out.println("Recovering object at "+new Date());
        a = (Logon)in.readObject();
        System.out.println("logon a = " + a);
      }
    }
    

User Datagram Protocol

  1. Example 1
    • PacketReceiveDemo.java
      import java.net.*;
      import java.io.*;
      
      // Chapter 5, Listing 1
      public class PacketReceiveDemo {
        public static void main (String args[]) {
          try {
            System.out.println ("Binding to local port 2000");
      
            // Create a datagram socket, bound to the specific port 2000
            DatagramSocket socket = new DatagramSocket(2000);
            System.out.println ("Bound to local port " + socket.getLocalPort());
      
            // Create a datagram packet, containing a maximum buffer of 256 bytes
            byte[] buf = new byte[256];
            DatagramPacket packet = new DatagramPacket( new byte[256], 256 );
      
            // Receive a packet - remember by default this is a blocking operation
            socket.receive(packet);
      
            System.out.println ("Packet received!");
      
            // Display packet information
            InetAddress remote_addr = packet.getAddress();
            System.out.println ("Sent by  : " + remote_addr.getHostAddress() );
            System.out.println ("Send from: " + packet.getPort());
      
            // Or, 你只需要
            //System.out.println(new String(buf));
      
            // Display packet contents, by reading from byte array
            ByteArrayInputStream bin = new ByteArrayInputStream (packet.getData());
      
            // Display only up to the length of the original UDP packet
            for (int i=0; i < packet.getLength(); i++) {
              int data = bin.read();
              if (data == -1)
                break;
              else
                System.out.print ( (char) data) ;
            }
         
            socket.close();
          } catch (IOException ioe) {
            System.err.println ("Error - " + ioe);
          }
      
        }
      }
        
    • PacketSendDemo.java
      import java.net.*;
      import java.io.*;
      
      // Chapter 5, Listing 2
      // If the corresponding receive process is not running, the message
      //  will be discarded at the destination.
      public class PacketSendDemo {
        public static void main(String args[]) {
          int argc = args.length;
      
          if(argc != 1) {
            System.out.println("Syntax:");
            System.out.println("java PacketSendDemo hostname");
            return;
          }
      
          String hostname = args[0];
      
          try {
            System.out.println("Binding to a local port");
      
            // Create a datagram socket, bound to nay available local port
            DatagramSocket socket = new DatagramSocket();
      
            System.out.println("Bound to local port " + 
                               socket.getLocalPort());
      
            // Create a message to send using a UDP packet
            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            PrintStream pout = new PrintStream(bout);
            pout.print("Greetings 大家");
      
            // Get the contents of our message as an array of bytes
            byte[] barray = bout.toByteArray();
      
            // Or, 你只需要
            //byte[] barray = "Greetings 大家".getBytes();
            // 注意,要能顯示中文,你必須確定你的系統能支援,例如
            // 在 Solaris,server 端要設定
            // setenv LANG="zh_TW.BIG5"
            // setenv LC_CTYPE="zh_TW.BIG5"
      
            // Create a datagram packet
            DatagramPacket packet = new DatagramPacket(barray, barray.length);
      
            // Or, you can
            //DatagramPacket packet = new DatagramPacket(barray, barray.length,
            //                            InetAddress.getByName(hostname), 2000);
      
            System.out.println("Looking up hostname " + hostname);
      
            // Looking up the specified hostname and get InetAddress
            InetAddress remote = InetAddress.getByName(hostname);
            System.out.println("Hostname resolved as " + remote.getHostAddress());
      
            // Address packet to sender
            // NOTE: it is the DatagramPacket which requires to know its
            //       destination.
            packet.setAddress(remote);
      
            // set port number to 2000
            packet.setPort(2000);
      
            // send the packet
            socket.send(packet);
      
            System.out.println("Packet sent!");
          } catch (UnknownHostException e) {
            System.err.println("Cannot find host " + hostname);
          } catch (IOException e) {
            System.err.println("Error - " + e);
          }
        }
      }
        
    • 練習題: What if the size of the sending messages is larger than the size specified in the receiving end?
    • 練習題: Since the size for each IP packet is 1500, try to send a message of size larger than 1500 and see what happened?
  2. Example: echo service
    • EchoServer.java
      import java.net.*;
      import java.io.*;
      
      // Chapter 5, Listing 3
      public class EchoServer {
        // UDP port to which service is bound
        public static final int SERVICE_PORT = 2007;
      
        // Max size of packet, large enough for almost any client
        public static final int BUFSIZE = 4096;
      
        // Socket used for reading and writing UDP packets
        private DatagramSocket socket;
      
        public EchoServer() {
          try {
          // Bind to the specified UDP port, to listen
          // for incoming data packets
          socket = new DatagramSocket( SERVICE_PORT );
      
          System.out.println ("Server active on port " + socket.getLocalPort() );
          } catch (Exception e) {
            System.err.println ("Unable to bind port");
          }
        }
      
        public void serviceClients() {
          // Create a buffer large enough for incoming packets
          byte[] buffer = new byte[BUFSIZE];
      
          for (;;) {
            try {
              // Create a DatagramPacket for reading UDP packets
              DatagramPacket packet = new DatagramPacket ( buffer, BUFSIZE );
      
              // Receive incoming packets
              socket.receive(packet);
      
              System.out.println ("Packet received from " + packet.getAddress() +
                      ":" + packet.getPort() + " of length " + packet.getLength() );
      
              // added for ensuring data is received
              System.out.println(new String(packet.getData(), 0, packet.getLength()));
      
              // the following is not appropriate for printing. Why?
              //System.out.println(new String(packet.getData()));
      
              // Echo the packet back - address and port 
              // are already set for us !
              socket.send(packet);
            } catch (IOException ioe) {
              System.err.println ("Error : " + ioe);
            }
          } 
        }
      
        public static void main(String args[]) {
          EchoServer server = new EchoServer();
          server.serviceClients();
        }
      }
        
    • EchoClient.java
      import java.net.*;
      import java.io.*;
      
      // Chapter 5, Listing 4
      // 由於 udp 支援一對多,所以同一個 server 可以對多個 client 作 echo
      public class EchoClient {
        // UDP port to which service is bound
        public static final int SERVICE_PORT = 2007;
      
        // Max size of packet
        public static final int BUFSIZE = 256;
      
        public static void main(String args[]) {
          if (args.length != 1) {
            System.err.println ("Syntax - java EchoClient hostname");
            return;
          }
      
          String hostname = args[0];
      
          // Get an InetAddress for the specified hostname
          InetAddress addr = null;
          try {
            // Resolve the hostname to an InetAddr
            addr = InetAddress.getByName(hostname);
          } catch (UnknownHostException uhe) {
            System.err.println ("Unable to resolve host");
            return;
          }
      
          try {
            // Bind to any free port
            DatagramSocket socket = new DatagramSocket();
      
            // Set a timeout value of two seconds
            // setSoTimeout() in milliseconds
            // the number of ms a read operation will block before throwing
            // exception.
            socket.setSoTimeout (2 * 1000);
      
            String message;
            for (int i = 1 ; i <= 10; i++) {
              // Copy some data to our packet
              message = "封包編號 " + i ;
      
              byte[] sendbuf = message.getBytes();
      
              // the followings can also be used to convert string to byte array
              // but Big5 message cannot be convertted correctly.
      //        char[] cArray = message.toCharArray();
      //        byte[] sendbuf = new byte[cArray.length];
      //        for (int offset = 0; offset < cArray.length ; offset++) {
      //          sendbuf[offset] = (byte) cArray[offset];
      //        }
      
              // Create a packet to send to the UDP server
              DatagramPacket sendPacket = new DatagramPacket(sendbuf, 
                                   sendbuf.length, addr, SERVICE_PORT);
      //                             cArray.length, addr, SERVICE_PORT);
      
              System.out.println ("Sending packet to " + hostname);
      
              // Send the packet
              socket.send (sendPacket);
      
              System.out.print ("Waiting for packet.... ");
      
              // Create a small packet for receiving UDP packets
              byte[] recbuf = new byte[BUFSIZE];
              DatagramPacket receivePacket = new DatagramPacket(recbuf, BUFSIZE);
      
              // Declare a timeout flag
              boolean timeout = false;
      
              // Catch any InterruptedIOException that is thrown
              // while waiting to receive a UDP packet
              try {
                socket.receive (receivePacket);
              } catch (InterruptedIOException ioe) {
                timeout = true;
              }
      
              if (!timeout) {
                System.out.println ("packet received!");
                System.out.println ("Details : " + receivePacket.getAddress() );
      
                // Obtain a byte input stream to read the UDP packet
                ByteArrayInputStream bin = new ByteArrayInputStream (
                receivePacket.getData(), 0, receivePacket.getLength() );
      
                // Connect a reader for easier access
                BufferedReader reader = new BufferedReader ( 
                                 new InputStreamReader ( bin ) );
      
                // Loop indefinitely
                String line;
                for (;;) {
                  line = reader.readLine();
      
                  // Check for end of data
                  if (line == null)
                    break;
                  else
                    System.out.println (line);
                }    
              }
              else {
                System.out.println ("packet lost!");
              }
      
              // Sleep for a second, to allow user to see packet
              try {
                Thread.sleep(1000);
              } catch (InterruptedException ie) {}
            }
          } catch (IOException ioe) {
            System.err.println ("Socket error " + ioe);
          }
        }
      }
        
    • 練習題: (1) 請嘗試把多個 client 對同一個 server 作傳送的動作, 並觀察封包到達的順序以及情形。(2) 經過 Internet 的傳送,看看有沒有掉封包的 情形。
    • 練習題: Please provide a Time service that returns time and date String like 民國 93 年 10 月 18 日上午 11 點 23 分。
  3. Example 3
    • DataRecv.java
      import java.net.*;
      import java.io.*;
      
      public class DataRecv {
        // UDP port to which service is bound
        public static final int SERVICE_PORT = 2007;
      
        // Max size of packet, large enough for almost any client
        public static final int BUFSIZE = 4096;
      
        // Socket used for reading and writing UDP packets
        private DatagramSocket socket;
      
        // Received Buffer
        private String recvbuf[] = new String[10];
      
        public DataRecv() {
          try {
          // Bind to the specified UDP port, to listen
          // for incoming data packets
          socket = new DatagramSocket( SERVICE_PORT );
      
          // set timeout value to 10 seconds.
          // try out with different timeout values: 10 vs. 2 (for example)
          socket.setSoTimeout(10 * 1000);
      
          System.out.println ("Server active on port " + socket.getLocalPort() );
          } catch (Exception e) {
            System.err.println ("Unable to bind port");
          }
        }
      
        public void serviceClients() {
          // Create a buffer large enough for incoming packets
          byte[] buffer = new byte[BUFSIZE];
      
          String m = null;
          int count = 0;
          for (;;) {
            try {
              // Create a DatagramPacket for reading UDP packets
              DatagramPacket packet = new DatagramPacket ( buffer, BUFSIZE );
      
              // Receive incoming packets
              socket.receive(packet);
      
              System.out.println ("Packet received from " + packet.getAddress() +
                      ":" + packet.getPort() + " of length " + packet.getLength() );
       
       m = new String(packet.getData(), 0, packet.getLength());
       count = Integer.parseInt(String.valueOf(m.charAt(0)));
              recvbuf[count] = new String(m);
            } catch (SocketException e) {
              System.err.println("Timeout exceed!");
            } catch (IOException ioe) {
              System.err.println ("Error : " + ioe);
            }
      
            // print out what we have received
            for(int i=0; i<recvbuf.length; i++)
              if(recvbuf[i] != null)
         System.out.println(recvbuf[i]);
      
          } 
        }
      
        public static void main(String args[]) {
          DataRecv server = new DataRecv();
          server.serviceClients();
        }
      }
        
    • DataSent.java
      import java.net.*;
      import java.io.*;
      
      public class DataSent {
        // UDP port to which service is bound
        public static final int SERVICE_PORT = 2007;
      
        // Max size of packet
        public static final int BUFSIZE = 256;
      
        // Initializa messages, which can be read from a file
        // the arriving order of packets can be observed when it hits 50
        // with the connection between penguin and dns. 
        private static String[] messages = {"0 I love Java!",
                                     "1 I love programming.",
                                     "2 I love networking.",
                "3 I love network programming.",
                "4 I love Java network programming.",
                "5 我愛 Java!",
                "6 我愛 programming.",
                                     "7 我愛 networking.",
                "8 我愛 network programming.",
                "9 我愛 Java network programming.",
                                     "10 I love Java!",
                                     "11 I love programming.",
                                     "12 I love networking.",
                                     "13 I love network programming.",
                                     "14 I love Java network programming.",
                                     "15 我愛 Java!",
                                     "16 我愛 programming.",
                                     "17 我愛 networking.",
                                     "18 我愛 network programming.",
                                     "19 我愛 Java network programming.",
                                     "20 I love Java!",
                                     "21 I love programming.",
                                     "22 I love networking.",
                                     "23 I love network programming.",
                                     "24 I love Java network programming.",
                                     "25 我愛 Java!",
                                     "26 我愛 programming.",
                                     "27 我愛 networking.",
                                     "28 我愛 network programming.",
                                     "29 我愛 Java network programming.",
                                     "30 I love Java!",
                                     "31 I love programming.",
                                     "32 I love networking.",
                                     "33 I love network programming.",
                                     "34 I love Java network programming.",
                                     "35 我愛 Java!",
                                     "36 我愛 programming.",
                                     "37 我愛 networking.",
                                     "38 我愛 network programming.",
                                     "39 我愛 Java network programming.",
                                     "40 I love Java!",
                                     "41 I love programming.",
                                     "42 I love networking.",
                                     "43 I love network programming.",
                                     "44 I love Java network programming.",
                                     "45 我愛 Java!",
                                     "46 我愛 programming.",
                                     "47 我愛 networking.",
                                     "48 我愛 network programming.",
                                     "49 我愛 Java network programming."};
      
        public static void main(String args[]) {
          if (args.length != 1) {
            System.err.println ("Syntax - java EchoClient hostname");
            return;
          }
      
          String hostname = args[0];
      
          // Get an InetAddress for the specified hostname
          InetAddress addr = null;
          try {
            // Resolve the hostname to an InetAddr
            addr = InetAddress.getByName(hostname);
          } catch (UnknownHostException uhe) {
            System.err.println ("Unable to resolve host");
            return;
          }
      
          try {
            // Bind to any free port
            DatagramSocket socket = new DatagramSocket();
      
            // Set a timeout value of two seconds
            socket.setSoTimeout (2 * 1000);
      
            String message = null;
            for (int i = 0 ; i < messages.length; i++) {
              // Copy some data to our packet
              message = messages[i];
      
              byte[] sendbuf = message.getBytes();
      
              // Create a packet to send to the UDP server
              DatagramPacket sendPacket = new DatagramPacket(sendbuf, 
                                   sendbuf.length, addr, SERVICE_PORT);
      
              // Send the packet which is non-blocking
              socket.send (sendPacket);
      
              System.out.println("Sending packet " + i + "...");
      
              // Sleep for a second, to allow user to see packet
      //        try {
      //          Thread.sleep(1000);
      //        } catch (InterruptedException ie) {}
            }
          } catch (IOException ioe) {
            System.err.println ("Socket error " + ioe);
          }
        }
      }
        


Transmission Control Protocol

  1. Example 1
    1. DaytimeServer.java
      import java.net.*;
      import java.io.*;
      
      // Chapter 6, Listing 2
      public class DaytimeServer {
        public static final int SERVICE_PORT = 2013;
      
        public static void main(String args[]) {
          try {
            // Bind to the service port, to grant clients access to
            // the TCP daytime service
            ServerSocket server = new ServerSocket (SERVICE_PORT);
      
            System.out.println ("Daytime service started");
      
            // Loop indefinitely, accepting clients
            for (;;) {
              // Get the next TCP client
              Socket nextClient = server.accept();
      
              // Display connection details
              System.out.println ("Received request from " +
              nextClient.getInetAddress() + ":" + nextClient.getPort() );
      
              // Don't read, just write the message
              OutputStream out = nextClient.getOutputStream();
              PrintStream pout = new PrintStream (out);
      
              // Write the current date out to the user
              pout.print( new java.util.Date() );
      
              // Flush unsent bytes
              out.flush();
      
              // Close the connection
              nextClient.close();
            }
          } catch (BindException be) {
            System.err.println ("Service already running on port " + SERVICE_PORT );
          } catch (IOException ioe) {
            System.err.println ("I/O error - " + ioe);
          }
        }
      }
        
    2. DaytimeClient.java
      import java.net.*;
      import java.io.*;
      
      // Chapter 6, Listing 1
      public class DaytimeClient {
        public static final int SERVICE_PORT = 2013;
      
        public static void main(String args[]) {
          // Check for hostname parameter
          if (args.length != 1) {
            System.out.println ("Syntax - DaytimeClient host");
            return;
          }
      
          // Get the hostname of server
          String hostname = args[0];
      
          try {
            // Get a socket to the daytime service
            Socket daytime = new Socket (hostname, SERVICE_PORT);
      
            System.out.println ("Connection established");
      
            // Set the socket option just in case server stalls
            daytime.setSoTimeout ( 2000 );
      
            // Read from the server
            BufferedReader reader = new BufferedReader ( 
            new InputStreamReader(daytime.getInputStream()));
      
            System.out.println ("Results : " + reader.readLine());
      
            // Close the connection
            daytime.close();
          } catch (IOException ioe) {
            System.err.println ("Error " + ioe);
          }
        }
      }
        
  2. Example 2: an on-line chatting
    1. Server.java
      // Fig. 18.4: Server.java
      // by Deitel & Deitel
      // Set up a Server that will receive a connection from a client, send 
      // a string to the client, and close the connection.
      import java.io.*;
      import java.net.*;
      import java.awt.*;
      import java.awt.event.*;
      import javax.swing.*;
      
      public class Server extends JFrame {
        private JTextField enterField;
        private JTextArea displayArea;
        private ObjectOutputStream output;
        private ObjectInputStream input;
        private ServerSocket server;
        private Socket connection;
        private int counter = 1;
      
        // set up GUI
        public Server() {
          super( "Server" );
      
          Container container = getContentPane();
      
          // create enterField and register listener
          enterField = new JTextField();
          enterField.setEditable( false );
          enterField.addActionListener(
          new ActionListener() {
            // send message to client
            public void actionPerformed( ActionEvent event ) {
              sendData( event.getActionCommand() );
              enterField.setText( "" );
            }}  
          ); 
      
          container.add( enterField, BorderLayout.NORTH );
      
          // create displayArea
          displayArea = new JTextArea();
          container.add(new JScrollPane( displayArea ), 
                        BorderLayout.CENTER );
      
          setSize( 300, 150 );
          setVisible( true );
      
        } // end Server constructor
      
        // set up and run server 
        public void runServer() {
          // set up server to receive connections; process connections
          try {
            // Step 1: Create a ServerSocket.
            server = new ServerSocket(12345);
      
            while ( true ) {
              try {
                waitForConnection(); // Step 2: Wait for a connection.
                getStreams();        // Step 3: Get input & output streams.
                processConnection(); // Step 4: Process connection.
              }
              // process EOFException when client closes connection 
              catch ( EOFException eofException ) {
                System.err.println( "Server terminated connection" );
              }
              finally {
                closeConnection();   // Step 5: Close connection.
                ++counter;
              }
            } // end while
          } // end try
      
          // process problems with I/O
          catch ( IOException ioException ) {
            ioException.printStackTrace();
          }
      
        } // end method runServer
      
        // wait for connection to arrive, then display connection info
        private void waitForConnection() throws IOException {
          displayMessage( "Waiting for connection\n" );
          connection = server.accept(); // allow server to accept connection            
          displayMessage( "Connection " + counter + " received from: " +
               connection.getInetAddress().getHostName() );
        }
      
        // get streams to send and receive data
        private void getStreams() throws IOException {
          // set up output stream for objects
          output = new ObjectOutputStream( connection.getOutputStream() );
          output.flush(); // flush output buffer to send header information
      
          // set up input stream for objects
          input = new ObjectInputStream( connection.getInputStream() );
      
          displayMessage( "\nGot I/O streams\n" );
        }
      
        // process connection with client
        private void processConnection() throws IOException {
          // send connection successful message to client
          String message = "Connection successful";
          sendData( message );
      
          // enable enterField so server user can send messages
          enterField.setEditable( true );
      
          do { // process messages sent from client
            // read message and display it
            try {
              message = ( String ) input.readObject();
              displayMessage( "\n" + message );
            }
            // catch problems reading from client
            catch ( ClassNotFoundException classNotFoundException ) {
              displayMessage( "\nUnknown object type received" );
            }
          } while ( !message.equals( "CLIENT>>> TERMINATE" ) );
        } // end method processConnection
      
        // close streams and socket
        private void closeConnection() {
          displayMessage( "\nTerminating connection\n" );
          enterField.setEditable( false ); // disable enterField
      
          try {
            output.close();
            input.close();
            connection.close();
          } catch( IOException ioException ) {
            ioException.printStackTrace();
          }
        }
      
        // send message to client
        private void sendData( String message ) {
          // send object to client
          try {
            output.writeObject( "SERVER>>> " + message );
            output.flush();
            displayMessage( "\nSERVER>>> " + message );
          }
          // process problems sending object
          catch ( IOException ioException ) {
            displayArea.append( "\nError writing object" );
          }
        }
      
        private void displayMessage( final String messageToDisplay ) {
          displayArea.append( messageToDisplay );
          displayArea.setCaretPosition(displayArea.getText().length() );
        }
      
        public static void main( String args[] ) {
          Server application = new Server();
          application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
          application.runServer();
        }
      }
        
    2. Client.java
      // Fig. 18.5: Client.java
      // by Deitel & Deitel
      // Client that reads and displays information sent from a Server.
      import java.io.*;
      import java.net.*;
      import java.awt.*;
      import java.awt.event.*;
      import javax.swing.*;
      
      public class Client extends JFrame {
        private JTextField enterField;
        private JTextArea displayArea;
        private ObjectOutputStream output;
        private ObjectInputStream input;
        private String message = "";
        private String chatServer;
        private Socket client;
      
        // initialize chatServer and set up GUI
        public Client( String host ) {
          super( "Client" ); 
          chatServer = host; // set server to which this client connects
      
          Container container = getContentPane();
      
          // create enterField and register listener
          enterField = new JTextField();
          enterField.setEditable( false );
          enterField.addActionListener(
               new ActionListener() {
                  // send message to server
                  public void actionPerformed( ActionEvent event ) {
                    sendData( event.getActionCommand() );
                    enterField.setText( "" );
                  }
               }  
            ); 
      
          container.add( enterField, BorderLayout.NORTH );
      
          // create displayArea
          displayArea = new JTextArea();
          container.add(new JScrollPane(displayArea), BorderLayout.CENTER);
      
          setSize( 300, 150 );
          setVisible( true );
        } // end Client constructor
      
        // connect to server and process messages from server
        private void runClient() {
          // connect to server, get streams, process connection
          try {
            connectToServer(); // Step 1: Create a Socket to make connection
            getStreams();      // Step 2: Get the input and output streams
            processConnection(); // Step 3: Process connection
          }
          // server closed connection
          catch ( EOFException eofException ) {
            System.err.println( "Client terminated connection" );
          }
          // process problems communicating with server
          catch ( IOException ioException ) {
            ioException.printStackTrace();
          } finally {
            closeConnection(); // Step 4: Close connection
          }
        }
      
        // connect to server
        private void connectToServer() throws IOException {      
          displayMessage( "Attempting connection\n" );
      
          // create Socket to make connection to server
          client = new Socket( InetAddress.getByName( chatServer ), 12345 );
      
          // display connection information
          displayMessage( "Connected to: " + 
               client.getInetAddress().getHostName() );
        }
      
        // get streams to send and receive data
        private void getStreams() throws IOException {
          // set up output stream for objects
          output = new ObjectOutputStream( client.getOutputStream() );      
          output.flush(); // flush output buffer to send header information
      
          // set up input stream for objects
          input = new ObjectInputStream( client.getInputStream() );
      
          displayMessage( "\nGot I/O streams\n" );
        }
      
        // process connection with server
        private void processConnection() throws IOException {
          // enable enterField so client user can send messages
          enterField.setEditable( true );
      
          do { // process messages sent from server
            // read message and display it
            try {
              message = ( String ) input.readObject();
              displayMessage( "\n" + message );
            }
            // catch problems reading from server
            catch ( ClassNotFoundException classNotFoundException ) {
              displayMessage( "\nUnknown object type received" );
            }
          } while ( !message.equals( "SERVER>>> TERMINATE" ) );
        } // end method processConnection
      
        // close streams and socket
        private void closeConnection() {
          displayMessage( "\nClosing connection" );
          enterField.setEditable( false ); // disable enterField
      
          try {
            output.close();
            input.close();
            client.close();
          } catch( IOException ioException ) {
             ioException.printStackTrace();
          }
        }
      
        // send message to server
        private void sendData( String message ) {
          // send object to server
          try {
            output.writeObject( "CLIENT>>> " + message );
            output.flush();
            displayMessage( "\nCLIENT>>> " + message );
          }
          // process problems sending object
          catch ( IOException ioException ) {
            displayArea.append( "\nError writing object" );
          }
        }
      
        private void displayMessage( final String messageToDisplay ) {
          displayArea.append( messageToDisplay );
          displayArea.setCaretPosition(displayArea.getText().length() );
        }
      
        public static void main( String args[] ) {
          Client application;
      
          if ( args.length == 0 )
            application = new Client( "127.0.0.1" );
          else
            application = new Client( args[ 0 ] );
      
          application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
          application.runClient();
        }
      }
        

Some Application Protocols

We'll discuss three simple application protocols which include SMTP, POP3, and HTTP/1.0. The details of these protocols can be found at IETF's Request for Comment where you can enter the RFC number to search for the documents. Otherwise, you can use RFC Index Search Engine to search documents by using names.
  1. SMTP Client
    The Simple Mail Transfer Protocol is used to send messages of various types between users over a TCP/IP network. The following program is a basic SMTP client which establishes a single connection to a mail server using a TCP socket, followed by a series of short protocol commands that specify the details of the email to be sent. The details is described in RFC 2821. For richer functionality of a SMTP client, please use JavaMail API.
    import java.io.*;
    import java.net.*;
    import java.util.*;
    
    // Chapter 8, Listing 1
    public class SMTPClientDemo {
      protected int port = 25;
      protected String hostname = "localhost";
      protected String from = "";
      protected String to = "";
      protected String subject = "";
      protected String body = "";
    
      protected Socket socket;
      protected BufferedReader br;
      protected PrintWriter pw;
    
      // Constructs a new instance of the SMTP Client
      public SMTPClientDemo() throws Exception {
        try {
          getInput();
          sendEmail();
        } catch (Exception e) {
          System.out.println ("Error sending message - " + e);
        }
      }
    
      public static void main(String[] args) throws Exception {
       // Start the SMTP client, so it can send messages
       SMTPClientDemo client = new SMTPClientDemo();
      }
    
      // Check the SMTP response code for an error message
      protected int readResponseCode() throws Exception {
        String line = br.readLine();
        System.out.println("< "+line);
        line = line.substring(0,line.indexOf(" "));
        return Integer.parseInt(line);
      }
    
      // Write a protocol message both to the network socket and to the screen
      protected void writeMsg(String msg) throws Exception {
        pw.println(msg);
        pw.flush();
        System.out.println("> "+msg);
      }
    
      // Close all readers, streams and sockets
      protected void closeConnection() throws Exception {
        pw.flush();
        pw.close();
        br.close();
        socket.close();
      }
    
      // Send the QUIT protocol message, and terminate connection
      protected void sendQuit() throws Exception {
        System.out.println("Sending QUIT");
        writeMsg("QUIT");
        readResponseCode();
    
        System.out.println("Closing Connection");
        closeConnection();
      }
    
      // Send an email message via SMTP, adhering to the protocol known as RFC 2821
      protected void sendEmail() throws Exception {
        System.out.println("Sending message now: Debug below");
        System.out.println("---------------------------------" + 
                           "-----------------------------");
    
        System.out.println("Opening Socket");
        socket = new Socket(this.hostname,this.port);
    
        System.out.println("Creating Reader & Writer");
        br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
    
        System.out.println("Reading first line");
        int code = readResponseCode();
        if(code != 220) { 
          socket.close(); 
          throw new Exception("Invalid SMTP Server"); 
        }
    
        System.out.println("Sending helo command");
        writeMsg("HELO "+InetAddress.getLocalHost().getHostName());
        code = readResponseCode();
        if(code != 250) {
          sendQuit();
          throw new Exception("Invalid SMTP Server");
        }
    
        System.out.println("Sending mail from command");
        writeMsg("MAIL FROM:<"+this.from+">");
        code = readResponseCode();
        if(code != 250) {
          sendQuit();
          throw new Exception("Invalid from address");
        }
    
        System.out.println("Sending rcpt to command");
        writeMsg("RCPT TO:<"+this.to+">");
        code = readResponseCode();
        if(code != 250) {
          sendQuit();
          throw new Exception("Invalid to address");
        }
    
        System.out.println("Sending data command");
        writeMsg("DATA");
        code = readResponseCode();
        if(code != 354) {
          sendQuit();
          throw new Exception("Data entry not accepted");
        }
    
        System.out.println("Sending message");
        writeMsg("Subject: "+this.subject);
        writeMsg("To: "+this.to);
        writeMsg("From: "+this.from);
        writeMsg("");
        writeMsg(body);
        code = readResponseCode();
        sendQuit();
        if(code != 250)
          throw new Exception("Message may not have been sent correctly");
        else
          System.out.println("Message sent");
      }
    
      // Obtain input from the user
      protected void getInput() throws Exception {
        // Read input from user console
        String data=null;
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    
        // Request hostname for SMTP server
        System.out.print("Please enter SMTP server hostname: ");
        data = br.readLine();
        if (data == null || data.equals("")) hostname="localhost";
        else hostname=data; 
    
        // Request the sender's email address
        System.out.print("Please enter FROM email address: ");
        data = br.readLine();
        from = data;
    
        // Request the recipient's email address
        System.out.print("Please enter TO email address :");
        data = br.readLine();
        if(!(data == null || data.equals("")))
          to=data;
    
        System.out.print("Please enter subject: ");
        data = br.readLine();
        subject=data;
    
        System.out.println("Please enter plain-text message ('.' character" +
                           "on a blank line signals end of message):");
        StringBuffer buffer = new StringBuffer();
    
        // Read until user enters a . on a blank line
        String line = br.readLine();
        while(line != null) {
          // Check for a '.', and only a '.', on a line
          if(line.equalsIgnoreCase(".")) {
            break;
          }
          buffer.append(line);
          buffer.append("\n");
          line = br.readLine();
        }
        buffer.append(".\n");
        body = buffer.toString();
      }
    }
    
    利用下列的輸出來解釋 SMTP 的協定比較容易。你也可以利用 telnet hostname 25 來連線並以手動的方式與 mail server 互動。
    D:\Test\Java\ch8>java SMTPClientDemo
    Please enter SMTP server hostname: msa.hinet.net
    Please enter FROM email address: jlu@linux.csie.ncue.edu.tw
    Please enter TO email address :jlu@cc.ncue.edu.tw
    Please enter subject: Test From Home
    Please enter plain-text message ('.' character on a blank line signals end of me
    ssage):
    
    this
    is
    a
    test
    訊息
    .
    Sending message now: Debug below
    --------------------------------------------------------------
    Opening Socket
    Creating Reader & Writer
    Reading first line
    < 220 msr61.hinet.net ESMTP Sendmail V8; Wed, 8 Dec 2004 12:05:18 +0800 (CST)
    Sending helo command
    > HELO win
    < 250 msr61.hinet.net Hello 220-134-107-112.HINET-IP.hinet.net [220.134.107.112], pleased to meet you
    Sending mail from command
    > MAIL FROM:<jlu@linux.csie.ncue.edu.tw>
    < 250 <jlu@linux.csie.ncue.edu.tw>... Sender ok
    Sending rcpt to command
    > RCPT TO:<jlu@cc.ncue.edu.tw>
    < 250 <jlu@cc.ncue.edu.tw>... Recipient ok
    Sending data command
    > DATA
    < 354 Enter mail, end with "." on a line by itself
    Sending message
    > Subject: Test From Home
    > To: jlu@cc.ncue.edu.tw
    > From: jlu@linux.csie.ncue.edu.tw
    >
    >
    this
    is
    a
    test
    訊息
    .
    
    < 250 MAA00065 Message accepted for delivery
    Sending QUIT
    > QUIT
    < 221 msr61.hinet.net closing connection
    Closing Connection
    Message sent
    
  2. POP3 Client
    The Post Office Protocol version 3 is one of the most popular protocol to receive emails. The following example will retrieve emails from a POP3 server. The POP3 protocol is a RFC 1939 document.
    import java.io.*;
    import java.net.*;
    import java.util.*;
    
    public class Pop3ClientDemo {
      protected int port = 110;
      protected String hostname = "localhost";
      protected String username = "";
      protected String password = "";
    
      protected Socket socket;
      protected BufferedReader br;
      protected PrintWriter pw;
    
      // Constructs a new instance of the POP3 client
      public Pop3ClientDemo() throws Exception {
        try {
          // Get user input
          getInput();
    
          // Get mail messages
          displayEmails();
        } catch(Exception e) {
          System.err.println ("Error occured - details follow");
          e.printStackTrace();
          System.out.println(e.getMessage());
        }
      }
    
      // Returns TRUE if POP response indicates success, FALSE if failure
      protected boolean responseIsOk() throws Exception {
        String line = br.readLine();
        System.out.println("< "+line);
    
        // 和 SMTP 不同的地方,POP3 的回覆不再是一個 number 而是
        // +OK 來代表要求成功。失敗則以 -ERR 來代表。
        return line.toUpperCase().startsWith("+OK");
      }
    
      // Reads a line from the POP server, and displays it to screen
      protected String readLine(boolean debug) throws Exception {
        String line = br.readLine();
    
        // Append a < character to indicate this is a server protocol response
        if (debug)
          System.out.println("< "+line);
        else
          System.out.println(line);
        return line;
      }
    
      // Writes a line to the POP server, and displays it to the screen
      protected void writeMsg(String msg) throws Exception {
        pw.println(msg);
        pw.flush();
        System.out.println("> "+msg);
      }
    
      // Close all writers, streams and sockets
      protected void closeConnection() throws Exception {
        pw.flush();
        pw.close();
        br.close();
        socket.close();
      }
    
      // Send the QUIT command, and close connection
      protected void sendQuit() throws Exception {
        System.out.println("Sending QUIT");
        writeMsg("QUIT");
        readLine(true);
    
        System.out.println("Closing Connection");
        closeConnection();
      }
    
      // Display emails in a message
      protected void displayEmails() throws Exception {
        BufferedReader userinput = new BufferedReader( new 
                                       InputStreamReader (System.in) );
    
        System.out.println("Displaying mailbox with protocol commands" +
                           "and responses below");
        System.out.println("-----------------------------------------" +
                           "---------------------");
    
        // Open a connection to POP3 server
        System.out.println("Opening Socket");
        socket = new Socket(this.hostname, this.port);
    
        br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
    
        // If response from server is not okay
        if(! responseIsOk()) {
          socket.close();
          throw new Exception("Invalid POP3 Server");
        }
    
        // Login by sending USER and PASS commands
        System.out.println("Sending username");
        writeMsg("USER "+this.username);
        if(!responseIsOk()) {
          sendQuit();
          throw new Exception("Invalid username");
        }
    
        System.out.println("Sending password");
        writeMsg("PASS "+this.password);
        if(!responseIsOk()) {
          sendQuit();
          throw new Exception("Invalid password");
        }
    
    
        // Get mail count from server ....
        System.out.println("Checking mail");
        writeMsg("STAT");
    
        // ... and parse for number of messages
        String line = readLine(true);
        StringTokenizer tokens = new StringTokenizer(line," ");
    
        // +OK
        tokens.nextToken();
    
        // number of messages
        int messages = Integer.parseInt(tokens.nextToken());
    
        // size of all messages
        int maxsize = Integer.parseInt(tokens.nextToken());
    
        if (messages == 0) {
          System.out.println ("There are no messages.");
          sendQuit();
          return;
        }
    
        System.out.println ("There are " + messages + " messages.");
        System.out.println("Press enter to continue.");
        userinput.readLine();
        
        for(int i = 1; i <= messages ; i++) {
          System.out.println("Retrieving message number "+i);
          writeMsg("RETR "+i);
          System.out.println("--------------------");
          line = readLine(false);
          while(line != null && !line.equals(".")) {
            line = readLine(false);
          }
          System.out.println("--------------------");
          System.out.println("Press enter to continue. To stop, " +
                             "type Q then enter");
          String response = userinput.readLine();
          if (response.toUpperCase().startsWith("Q"))
            break;
        }
        sendQuit();
      }
    
      public static void main(String[] args) throws Exception {
        Pop3ClientDemo client = new Pop3ClientDemo();
      }
    
      // Read user input
      protected void getInput() throws Exception {
        String data=null;
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.print("Please enter POP3 server hostname:");
        data = br.readLine();
        if(data == null || data.equals("")) hostname="localhost";
        else hostname=data;
    
        System.out.print("Please enter mailbox username:");
        data = br.readLine();
        if(!(data == null || data.equals("")))
          username=data;
    
        System.out.print("Please enter mailbox password:");
        data = br.readLine();
        if(!(data == null || data.equals("")))
          password=data;
      }
    }
    
    底下是一個執行的結果,你可以利用學校的帳號來讀取你的信件, 經由這個程式所讀到的信並不會從 email server 中刪除。 如果你想將所閱讀過的 emails 從 email server 中刪除,你必須 送出 DELE message_number
    D:\Test\Java\ch8>java Pop3ClientDemo
    Please enter POP3 server hostname:mail.e88.com.tw
    Please enter mailbox username:*****
    Please enter mailbox password:*****
    Displaying mailbox with protocol commands and responses below
    --------------------------------------------------------------
    Opening Socket
    < +OK POP3 mail.e88.com.tw v2001.78rh server ready
    Sending username
    > USER *****
    < +OK User name accepted, password please
    Sending password
    > PASS *****
    < +OK Mailbox open, 1 messages
    Checking mail
    > STAT
    < +OK 1 1080
    There are 1 messages.
    Press enter to continue.
    
    Retrieving message number 1
    > RETR 1
    --------------------
    +OK 1080 octets
    Return-Path: 
    Received: (from root@localhost)
            by mail.e88.com.tw (8.11.6/8.11.6) id iB896Qg19645
            for ejlu2003@mail.e88.com.tw; Wed, 8 Dec 2004 17:06:26 +0800
    Received: from penguin.im.cyut.edu.tw (penguin.im.cyut.edu.tw [163.17.9.2])
            by mail.e88.com.tw (8.11.6/8.11.6) with ESMTP id iB896DR19528
            for ; Wed, 8 Dec 2004 17:06:14 +0800
    From: jlu@penguin.im.cyut.edu.tw
    Received: by penguin.im.cyut.edu.tw (Postfix, from userid 514)
            id 3B1BE190208; Wed,  8 Dec 2004 17:06:28 +0800 (CST)
    Date: Wed, 8 Dec 2004 17:06:28 +0800
    To: ejlu2003@mail.e88.com.tw
    Subject: Test
    Message-ID: <20041208090628 data-blogger-escaped-.ga30803=".ga30803" data-blogger-escaped-penguin.im.cyut.edu.tw="penguin.im.cyut.edu.tw">
    Mime-Version: 1.0
    Content-Type: text/plain; charset=big5
    Content-Disposition: inline
    Content-Transfer-Encoding: 8bit
    User-Agent: Mutt/1.4.1i
    X-Spam-Checker-Version: SpamAssassin 2.63 (2004-01-11) on mail.e88.com.tw
    X-Spam-Status: No, hits=1.4 required=7.0 tests=NO_REAL_NAME,RCVD_IN_DSBL
            autolearn=no version=2.63
    X-Spam-Level: *
    Status:
    
    
    this
    is
    a
    test
    訊息
    .
    --------------------
    Press enter to continue. To stop, type Q then enter
    
    Sending QUIT
    > QUIT
    < +OK Sayonara
    Closing Connection
    
    練習題: 請將程式改成可以由使用者決定是否刪除信箱內的信件。
  3. HTTP/1.0 Server
    The HyperText Transfer Protocol originated as a means of sharing documents across the Internet. The first of HTTP is known as HTTP/1.0 (RFC 1945). The most recent version is HTTP/1.1 (RFC 2616). The following example is a simple web server which supplies text files and directories.
    import java.io.*;
    import java.net.*;
    import java.util.*;
    
    public class WebServerDemo {
      // Directory of HTML pages and other files 
      private String docroot;
      // Port number of web server
      private int port;
      // Socket for the web server
      private ServerSocket ss;
    
      // Handler for a HTTP request
      // You do not have to make Handler as an inner class.
      class Handler extends Thread {
        private Socket socket;
        private PrintWriter pw;
        private BufferedOutputStream bos;
        private BufferedReader br;
        private File docroot;
    
        public Handler(Socket _socket, String _docroot) throws Exception {
          socket=_socket;
          // Get the absolute directory of the filepath
          docroot=new File(_docroot).getCanonicalFile();
        }
    
        public void run() {
          try {
            // Prepare our readers and writers
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            bos = new BufferedOutputStream(socket.getOutputStream());
            pw = new PrintWriter(new OutputStreamWriter(bos));
    
            // Read HTTP request from user (hopefully GET /file...... )
            String line = br.readLine();
    
            // Places the input stream for this socket at "end of stream". Any 
            // data sent to the input stream side of the socket is acknowledged 
            // and then silently discarded. If you read from a socket input stream 
            // after invoking shutdownInput() on the socket, the stream will 
            // return EOF. 
            socket.shutdownInput();
    
            if(line == null) {
              socket.close();
              return;
            }
    
            // let's take a look at what the server received
            System.out.println(line);
    
            if(line.toUpperCase().startsWith("GET")) {
              // Eliminate any trailing ? data, such as for a CGI GET request
              StringTokenizer tokens = new StringTokenizer(line," ?");
              tokens.nextToken();
              String req = tokens.nextToken();
    
              // If a path character / or \ is not present, add it to the 
       // document root
              // and then add the file request, to form a full filename
              String name;
              if(req.startsWith("/") || req.startsWith("\\"))
                name = docroot + req;
              else
                name = docroot + File.separator + req;
    
              // Get absolute file path
              File file = new File(name).getCanonicalFile();
    
              // Check to see if request doesn't start with our document root ....
              if(!file.getAbsolutePath().startsWith(docroot.getAbsolutePath())) {
                pw.println("HTTP/1.0 403 Forbidden");
                pw.println();
              }
              // ... if it's missing .....
              else if(!file.exists()) {
                pw.println("HTTP/1.0 404 File Not Found");
                pw.println();
              }
              // ... if it can't be read for security reasons ....
              else if(!file.canRead()) {
                pw.println("HTTP/1.0 403 Forbidden");
                pw.println();
              }
              // ... if its actually a directory, and not a file ....
              else if(file.isDirectory()) {
                sendDir(bos,pw,file,req);
              }
              // ... or if it's really a file
              else {
                sendFile(bos, pw, file.getAbsolutePath());
              }
            }
            // If not a GET request, the server will not support it
            else {
              pw.println("HTTP/1.0 501 Not Implemented");
              pw.println();
            }
    
            pw.flush();
            bos.flush();
          } catch(Exception e) {
            e.printStackTrace();
          }
    
          try {
            socket.close();
          } catch(Exception e) {
            e.printStackTrace();
          }
       }
    
       protected void sendFile(BufferedOutputStream bos, PrintWriter pw, 
                               String filename) throws Exception {
          try {
            BufferedInputStream bis = new BufferedInputStream(new 
                                   FileInputStream(filename));
            byte[] data = new byte[10*1024];
            int read = bis.read(data);
    
            pw.println("HTTP/1.0 200 Okay");
            pw.println();
            pw.flush();
            bos.flush();
    
            while(read != -1) {
              bos.write(data,0,read);
              read = bis.read(data);
            }
            bos.flush();
          } catch(Exception e) {
            pw.flush();
            bos.flush();
          }
        }
    
        protected void sendDir(BufferedOutputStream bos, PrintWriter pw, 
                               File dir, String req) throws Exception {
          try {
            pw.println("HTTP/1.0 200 Okay");
            pw.println();
            pw.flush();
    
            pw.print("<html><head><title>Directory of ");
            pw.print(req);
            pw.print("</title></head><body><h1>Directory of ");
            pw.print(req);
            pw.println("</h1><table border=\"0\">");
    
            File[] contents=dir.listFiles();
    
            for(int i=0;i<contents.length;i++) {
              pw.print("<tr>");
              pw.print("<td><a href=\"");
              pw.print(req);
              pw.print(contents[i].getName());
              if(contents[i].isDirectory())
                pw.print("/");
              pw.print("\">");
              if(contents[i].isDirectory())
                pw.print("Dir -> ");
              pw.print(contents[i].getName());
              pw.print("</a></td>");
              pw.println("</tr>");
            }
            pw.println("</table></body></html>");
            pw.flush();
          } catch(Exception e) {
            pw.flush();
            bos.flush();
          }
        }
      }
    
      // Check that a filepath has been specified and a port number
      protected void parseParams(String[] args) throws Exception {
        switch(args.length) {
          case 1:
          case 0:
            System.err.println ("Syntax: <jvm> "+this.getClass().getName()+
                         " docroot port");
            System.exit(0);
    
          default:
            this.docroot = args[0];
            this.port = Integer.parseInt(args[1]);
            break;
        }
      }
    
      public WebServerDemo(String[] args) throws Exception {
        System.out.println ("Checking for paramters");
    
        // Check for command line parameters
        parseParams(args);
    
        System.out.print ("Starting web server...... ");
    
        // Create a new server socket
        ss = new ServerSocket(port);
    
        System.out.println ("OK");
    
        for (;;) {
          // Accept a new socket connection from our server socket
          Socket accept = ss.accept();
    
          // Start a new handler instance to process the request
          new Handler(accept, docroot).start();
        }
      }
    
      // Start an instance of the web server running
      public static void main(String[] args) throws Exception {
        WebServerDemo webServerDemo = new WebServerDemo(args);
      }
    }
    
    執行這個程式的語法是 java WebServerDemo docroot port, 例如 java WebServerDemo d:\jlu 80
  4. Simple HTTP Client
    1. Parsing with the URL class
      import java.net.*;
      
      // Chapter 9, Listing 1
      public class URLParser {
        public static void main(String args[]) {
          int argc = args.length;
      
          // Check for valid number of parameters
          if (argc != 1) {
            System.out.println ("Syntax :");
            System.out.println ("java URLParser url");
            return;
          }
      
          // Catch any thrown exceptions
          try {
            // Create an instance of java.net.URL
            java.net.URL myURL = new URL ( args[0] );
      
            System.out.println ("Protocol : " + myURL.getProtocol() );
            System.out.println ("Hostname : " + myURL.getHost() );
            System.out.println ("Port     : " + myURL.getPort() );
            System.out.println ("Filename : " + myURL.getFile() );
            System.out.println ("Reference: " + myURL.getRef() );
          }
          // MalformedURLException indicates parsing error
          catch (MalformedURLException mue) {
            System.err.println ("Unable to parse URL!");
            return;
          }
        }
      }
        
    2. Retrieving a Resource with the URL class
      import java.net.*;
      import java.io.*;
      
      // Chapter 9, Listing 2
      public class FetchURL {
        public static void main(String args[]) throws Exception {
          int argc = args.length;
      
          // Check for valid number of parameters
          if (argc != 1) {
            System.out.println ("Syntax :");
            System.out.println ("java FetchURL url");
            return;
          }
      
          // Catch any thrown exceptions
          try {
            // Create an instance of java.net.URL
            java.net.URL myURL = new URL ( args[0] );
      
            // Fetch the content, and read from an InputStream
            InputStream in = myURL.openStream();
      
            // Buffer the stream, for better performance
            BufferedInputStream bufIn = new BufferedInputStream(in);
      
            // Repeat until end of file
            for (;;) {
              int data = bufIn.read();
      
              // Check for EOF
              if (data == -1)
                break;
              else
                System.out.print ( (char) data);
            }
      
            // Pause for user
            System.out.println ();
            System.out.println ("Hit enter to continue");
            System.in.read();
      
          }
          // MalformedURLException indicates parsing error
          catch (MalformedURLException mue) {
            System.err.println ("Unable to parse URL!");
            return;
          }
          // IOException indicates network or I/O error
          catch (IOException ioe) {
            System.err.println ("I/O Error : " + ioe);
            return;
          }
        }
      }
        
    3. Retrieving a Resource with the URLConnection class: The URLConnection class allows a program to connect a resource, set request header fields, read response header fields, and read the contents of the resource.
      import java.net.*;
      import java.io.*;
      import java.util.*;
      
      // Chapter 9, Listing 3
      public class FetchURLConnection {
        public static void main(String args[]) throws Exception {
          int argc = args.length;
      
          // Check for valid number of parameters
          if (argc != 1) {
            System.out.println ("Syntax :");
            System.out.println ("java FetchURLConnection url");
            return;
          }
      
          // Catch any thrown exceptions
          try {
            // Create an instance of java.net.URL
            java.net.URL myURL = new URL ( args[0] );
      
            // Create a URLConnection object, for this URL
            // NOTE : no connection has yet been established
            URLConnection connection = myURL.openConnection();
      
            // Now open a connection
            connection.connect();
      
            // Display the MIME content-type of the resource (e.g. text/html)
            String MIME = connection.getContentType();
            System.out.println ("Content-type: " + MIME);
      
            // Display, if available, the content length
            int contentLength = connection.getContentLength();
            if (contentLength != -1) {
              System.out.println ("Content-length: " + contentLength);
            }
      
            // Display the "Date" field: web server's date info
            long date = connection.getDate();
            if (date != 0)
              System.out.println("Date: " + new Date(date).toString());
      
            long modified = connection.getLastModified();
            if (modified != 0)
              System.out.println("Last Modified: " + new Date(modified));
      
            // Pause for user
            System.out.println ("Hit enter to continue");
            System.in.read();
      
            // Read the contents of the resource from the connection
            InputStream in = connection.getInputStream();
      
            // Buffer the stream, for better performance
            BufferedInputStream bufIn = new BufferedInputStream(in);
      
            // Repeat until end of file
            for (;;) {
              int data = bufIn.read();
      
              // Check for EOF
              if (data == -1)
                break;
              else
                System.out.print ( (char) data);
            }
          }
          // MalformedURLException indicates parsing error
          catch (MalformedURLException mue) {
            System.err.println ("Unable to parse URL!");
            return;
          }
          // IOException indicates network or I/O error
          catch (IOException ioe) {
            System.err.println ("I/O Error : " + ioe);
            return;
          }
        }
      }
        
    4. Modifying and Examining Header Fields with URLConnection:如果配合修改之前的 web server,就可以非常清楚的看出 HTTP Protocol 的 request/reply 的一些訊息。
      import java.net.*;
      import java.io.*;
      
      // Chapter 9, Listing 4
      public class HTTPHeaders {
        public static void main(String args[]) throws Exception {
          int argc = args.length;
      
          // Check for valid number of parameters
          if (argc != 1) {
            System.out.println ("Syntax :");
            System.out.println ("java HTTPHeaders url");
            return;
          }
      
          // Catch any thrown exceptions
          try {
            // Create an instance of java.net.URL
            java.net.URL myURL = new URL ( args[0] );
      
            // Create a URLConnection object, for this URL
            // NOTE : no connection has yet been established
            URLConnection connection = myURL.openConnection();
      
            // Set some basic request fields
            // Set user agent, to identify the application as Netscape compatible
            connection.setRequestProperty ("User-Agent", 
                                           "Mozilla/4.0 (compatible; JavaApp)");
      
            // Set our referer field - set to any URL you'd like
            connection.setRequestProperty ("Referer", "http://www.davidreilly.com/");
      
            // Set use-caches field, to prevent caching
            connection.setUseCaches(false);
      
            // Now open a connection
            connection.connect();
      
            // Examine request properties, to verify their settings
            System.out.println ("Request properties...."); 
            System.out.println();
            System.out.println ("User-Agent: " +
                                connection.getRequestProperty("User-Agent"));
            System.out.println ("Referer: " + 
                                connection.getRequestProperty("Referer"));
            System.out.println (); System.out.println ();
      
            // Examine response properties, to see their settings
            System.out.println ("Response properties...."); System.out.println();
      
            // Search through each header field, until no more exist
            int i = 1;
            while ( connection.getHeaderField ( i ) != null ) {
              // Get the name of this header field
              String headerName = connection.getHeaderFieldKey(i);
      
              // Get the name of this header field
              String headerValue = connection.getHeaderField(i);
      
              // Output header field key, and header field value
              System.out.println ( headerName + ": " + headerValue);    
              // Goto the next element in the set of header fields
              i++;
            }
         
            // Pause for user
            System.out.println ("Hit enter to continue");
            System.in.read();   
          }
          // MalformedURLException indicates parsing error
          catch (MalformedURLException mue) {
            System.err.println ("Unable to parse URL!");
            return;
          }
          // IOException indicates network or I/O error
          catch (IOException ioe) {
            System.err.println ("I/O Error : " + ioe);
            return;
          }
        }
      }
        




Written by: 國立中興大學資管系呂瑞麟 Eric Jui-Lin Lu



沒有留言:

張貼留言