2014年11月6日 星期四

[ Gossip in Java(2) ] 網路 : 入門 (Socket 類別)

前言 :
在 TCP/IP 底層的運作必須處理封包、標頭、格式、交握等的細節,這實在不是什麼好差事,為此Berkeley UNIX提出Socket的概念,將網路連線簡化為資料流(data stream)的概念,這個資料流在客戶端與伺服端各有一個接口(port),而資料流就像是在一個連接兩接口的纜線中傳遞,程式設計人員使用 Socket的概念來撰寫網路連線程式,只要處理主機資訊與連接埠,而不用關心底層的瑣碎運作.

Socket 類別 :
簡而言之,就如同檔案輸出入一樣,Socket將網路連線也視作一種輸出入的動作,資料的傳遞就像是將資料寫入與讀入.
在Java中提供 Socket類別 來支援Socket概念,底下為支援的建構式 :


您可以直接指定主機名稱來建立Socket物件,然而使用InetAddress會比較有效率,在真正進行Socket連線之前,如果在建立InetAddress物件時無法取得主機資訊,則可以提前進行相關的處理. 下面這個程式可以讓您掃描指定主機上所開啟的連接埠(0~1023),這邊指定本機為對象建立Socket連線,如果某個連接埠有開啟,就會建立連線,此時顯示該連接埠開啟的訊息 :
- ScanPort.java : 掃描本地端 Port 0~1024
  1. package john.net.basic;  
  2.   
  3. import java.io.IOException;  
  4. import java.net.InetAddress;  
  5. import java.net.Socket;  
  6. import java.net.UnknownHostException;  
  7.   
  8. public class ScanPort {  
  9.     public static void main(String[] args) {  
  10.         try {  
  11.             String hostname = "localhost";  
  12.             InetAddress address = InetAddress.getByName(hostname);   
  13.             for(int i = 0; i < 1024; i++) {   
  14.                 try {   
  15.                     Socket skt = new Socket(address, i);   
  16.                     // 連線表示有開啟 Port   
  17.                     System.out.printf("%nPort: %d Opened..", i);   
  18.                     skt.close();   
  19.                 }   
  20.                 catch(IOException e) {   
  21.                     System.out.print(".");   
  22.                     // 無法建立連線,沒有開啟 Port   
  23.                 }   
  24.             }   
  25.         }   
  26.         catch(UnknownHostException e) {   
  27.             e.printStackTrace();  
  28.         }   
  29.     }  
  30. }  

在建立了Socket物件之後,可以取得Socket物件的相關資訊,例如 :
public InetAddress getInetAddress()
public int getPort()
public int getLocalPort()
public inetAddress getLocalAddress()

以上的方法由上而下分別為取得Socket連接對象位址、連接對象連接埠、本機連接埠、本機位址.
如果要取過Socket物件接受或輸出資訊,可以使用 getInputStream() 與 getOutputStream() 兩個方法,就如同檔案I/O 一樣,您只要將它當作串流資料來處理即可,至於網路上的資訊是如何交換的,您並不用得知,Java會自動幫您完成相關的協定確認.
下面這個程式模擬Telnet程式,您可以用它來與遠端主機進行「以行為主」的文字或指令溝通,也就是每下一行文字或指令就按Enter鍵,然後程式會將您的指令傳送出去,並顯示遠端主機的回應訊息,為了同時處理遠端主機的回應與本機使用者的輸入,程式使用多執行緒 :
- SocketToStdout.java : 將 Socket 的回傳資料顯示在 Standout (Console)
  1. package john.net.basic;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.IOException;  
  5. import java.io.InputStreamReader;  
  6. import java.net.Socket;  
  7.   
  8. public class SocketToStdout implements Runnable {  
  9.     private Socket skt;  
  10.       
  11.     public SocketToStdout(Socket skt) {  
  12.         this.skt = skt;  
  13.     }  
  14.       
  15.     public void run() {  
  16.         BufferedReader sktReader;  
  17.         try {   
  18.             sktReader = new BufferedReader(  
  19.                     new InputStreamReader(skt.getInputStream()));  
  20.               
  21.             String sktMessage = null;  
  22.             while((sktMessage = sktReader.readLine()) != null) {  
  23.                 System.out.println(sktMessage);   
  24.             }  
  25.   
  26.             skt.close();   
  27.         }   
  28.         catch(IOException e) {   
  29.             System.out.println(e.toString());   
  30.         }   
  31.     }  
  32. }  

- StdInToSocket.java : 將鍵盤輸入內容, 藉由 Socket 傳送出去
  1. package john.net.basic;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.IOException;  
  5. import java.io.InputStreamReader;  
  6. import java.io.PrintStream;  
  7. import java.net.Socket;  
  8.   
  9. public class StdInToSocket implements Runnable {  
  10.     private Socket skt;  
  11.       
  12.     public StdInToSocket(Socket skt) {  
  13.         this.skt = skt;  
  14.     }  
  15.       
  16.     public void run() {  
  17.         String userInput;   
  18.         BufferedReader stdInReader;   
  19.         PrintStream socketStream;   
  20.   
  21.         try {   
  22.             stdInReader = new BufferedReader(  
  23.                             new InputStreamReader(System.in));   
  24.             socketStream = new PrintStream(skt.getOutputStream());   
  25.   
  26.             while(true) {   
  27.                 if(skt.isClosed()) {  
  28.                      break;   
  29.                 }  
  30.                 userInput = stdInReader.readLine();   
  31.                 socketStream.println(userInput);   
  32.             }   
  33.         }   
  34.         catch(IOException e) {   
  35.             e.printStackTrace();  
  36.         }   
  37.   
  38.     }  
  39. }  

- ConnectDemo.java : 主程式, 開啟與 ftp.isu.edu.tw 的Port 25 連線
  1. package john.net.basic;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.IOException;  
  5. import java.net.InetAddress;  
  6. import java.net.Socket;  
  7. import java.net.UnknownHostException;  
  8.   
  9. public class ConnectDemo {  
  10.     public static void main(String[] args) {  
  11.         String hostname = "ftp.isu.edu.tw";  
  12.         int port = 21;  
  13.         InetAddress address;  
  14.         BufferedReader buf;  
  15.         String read;  
  16.   
  17.         try {  
  18.             address = InetAddress.getByName(hostname);  
  19.             try {  
  20.                 Socket skt = new Socket(address, port);  
  21.                 Thread sktToStd = new Thread(new SocketToStdout(skt));  
  22.                 Thread stdToSkt = new Thread(new StdInToSocket(skt));  
  23.   
  24.                 sktToStd.start();  
  25.                 stdToSkt.start();  
  26.   
  27.             } catch (IOException e) {  
  28.                 e.printStackTrace();  
  29.             }  
  30.         } catch (UnknownHostException e) {  
  31.             System.out.println(e.toString());  
  32.         }  
  33.     }  
  34. }  

執行結果 : 下面的執行結果是連接至FTP站台的測試,可以輸入簡單的ASCII指令跟FTP站台互動(使用FTP協定指令)


補充說明 :
Wiki : TCP/IP model :
The TCP/IP model is a description framework for computer network protocols created in the 1970s by DARPA, an agency of the United States Department of Defense. It evolved from ARPANET, which was the world's first wide area network and a predecessor of the Internet. The TCP/IP Model is sometimes called the Internet Model or theDoD Model.

Java基本功:Socket Timeout有兩種
第一種,是會丟出SocketTimeoutExcpetion的,有找到Host但一直等不到回應。可以設 socket.setSoTimeout(timeout).
第二種,是會丟出UnknownHostException的,是找不到Host的,若在Local找不到這個Host很快就丟,但在Server通常內建一堆DNS解析IP,等全部巡完一輪都要等好久。所以時間內找不到就視為UnknownHostException作法如下:
  1. Socket socket = SocketFactory.getDefault().createSocket();  
  2. SocketAddress remoteaddr = new InetSocketAddress(host, port);  
  3. socket.connect(remoteaddr, timeout);   // 就在connect時設timeout  


沒有留言:

張貼留言

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...