網絡編程

第一  概述

一、概述:

1、網絡模型:OSI參考模型和TCP/IP參考模型

 

2、網絡通訊要素:

1)IP地址:InetAddress

   .網絡中設備的標識
   .不易記憶,可用主機名

Internet上的主機有兩種方式表示地址:域名:www.baidu.com,IP 地址:202.108.35.210 

InetAddress 類對象含有一個 Internet 主機地址的域名和IP地址:www.baidu.com。域名容易記憶,當在連接網絡時輸入一個主機的域名後,域名服務器(DNS)負責將域名轉化成IP地址,這樣才能和主機建立連接。 
2)端口號
.用於標識進程的邏輯地址,不同進程的標識
.有效地址0~65535,其中0~1024系統使用或保留端口
3)傳輸協議:
通訊規則
    .常見協議:TCP、UDP

①UDP(面向無連接)-->聊天、網絡視頻會議、步話機

 

  •  將數據及源和目的封裝成數據包中,不需要建立連接
  • .每個數據包的大小限制在64k內
  • .因無連接,是不可靠的協議
  • .不需要建立連接,速度快

 

②TCP(面向連接)-->下載,打電話

 

  • 建立連接,形成傳輸數據的通道
  • 在連接中進行大數據量的傳輸
  • 通過三次握手完成連接,是可靠的協議
  • .必須建立連接,效率會稍低

 

注:三次握手:第一次本方發送請求,第二次對方確認連接,第三次本方再次發送確認信息告訴對方,這樣雙方就都知道了,從而才能建立連接

 

3、通信的步驟:

1)IP:找到需要通訊的IP地址

2)端口:數據要發送到對象指定應用程序,爲標識這些應用程序,所以給這些網絡應用程序都用數字標識,爲方便稱呼這個數字,叫做端口,即邏輯端口。每個網絡程序都有自己唯一的標識端口。

3)定義通信規則,稱之爲協議。國際組織定義了通用協議,即TCP/IP。

注意:必須要有數字標識才能將數據發送到應用程序上。因爲端口是明確數據需要有哪個應用程序來處理的標識。

 

二、網絡模型:

1、對於TCP/IP協議,開發處於傳輸層和網際層

      應用層:FTP和HTTP協議等

      傳輸層:UDP和TCP等

      網際層:IP

三、網絡通信要素:

IP地址:java中對應的是InetAddress類,存在於java.net包中。

InetAddress類:

1、無構造函數,可通過getLocalHost()方法獲取InetAddress對象,此方法是靜態的,返回此對象。

       InetAddress i = InetAddress.getLocalHost();

2、方法:

1)static InetAddress getByName(String host):在給定主機名的情況下獲取主機的IP地址

2)String getHostAddress():返回IP地址字符串文本形式,以這個爲主,即以IP地址爲主。

3)String getHostName():返回IP地址主機名。

3、如何獲取任意一臺主機的IP地址對象:
  1. publicclassIPDemo{
  2. publicstaticvoid main(String[] args)throwsUnknownHostException{
  3. // 獲取本地主機ip地址對象。
  4. InetAddress ip =InetAddress.getLocalHost();
  5. System.out.println(ip.getHostAddress());//192.168.1.167
  6. System.out.println(ip.getHostName());//PC201508162051
  7. // // 獲取其他主機的ip地址對象。只要輸入iP或域名
  8. InetAddress byName =InetAddress.getByName("PC201508162051");// PC201508162051/192.168.1.167
  9. InetAddress byName2 =InetAddress.getByName("www.baidu.com");// www.baidu.com/61.135.169.121
  10. System.out.println(byName);
  11. System.out.println(byName2);

  12. }
  13. }

第二  UDP

一、概述:

Socket:

 

  1. Socket就是爲網絡服務提供的一種機制
  2. 通訊的兩端都必須有Socket(套接字),相當於港口
  3. 網絡通訊其實就是Socket間的通訊
  4. 數據在兩個Socket間通過IO傳輸
  5. IP 地址標識 Internet 上的計算機,端口號標識正在計算機上運行的進程(程序)。端口號與IP地址的組合得出一個網絡套接字。

 

二、UDP傳輸:發送端和接收端是兩個獨立運行的程序

1、UDP傳輸的流程:

 

  • .DatagramSocke(創建Socket對象在發送端和接收端通訊)和DatagramPacket(發送端將數據封包,接收端將數據解包)
  • .建立發送端、接收端
  • .建立數據包
  • .調用Socket的發送和接收方法
  • .關閉Socket

 

 

 

DatagramPacket(byte[] buf, int length)接收
          構造 DatagramPacket,用來接收長度爲 length 的數據包。
DatagramPacket(byte[] buf, int length, InetAddress address, int port)發送
          構造數據報包,用來將長度爲 length 的包發送到指定主機上的指定端口號。

 

2、方法:

 

  • 創建 UDPSocket發送服務對象:DatagramSocket(),可不指定端口
  • 創建 UDPSocket接收服務對象:DatagramSocket(int port),
  • 發送:void send(DatagramPacket p)
  • 接收:void receive(DatagramPacket p)

 

其中DatagramPacket:數據報包用來實現無連接包投遞服務的,每條報文僅根據該包中包含的信息從一臺機器路由到另一臺機器中。

凡是帶地址(InetAddress)的都是用於發送包的。

實例:

  1. /*
  2. * 需求:通過udp傳輸方式,將一段文字發送出去
  3. * 定義一個udp發送端
  4. */
  5. publicclassUDPSend{
  6. publicstaticvoid main(String[] args)throwsSocketException,Exception{
  7. // 1、建立udp服務,通過DategramSocket對象
  8.  
  9. DatagramSocket ds =newDatagramSocket(8888);
  10. // 2、確定數據,並封裝成數據包DatagramPacket(byte[] buf, int length, InetAddress,address, int port)
  11. byte[] buf ="udp send message come on".getBytes();// 數據 ,轉成字節數組
  12. DatagramPacket dp =newDatagramPacket(buf, buf.length,
  13. InetAddress.getByName("192.168.229.1"),1000);
  14. // 發到哪 InetAddress.getByName("192.168.229.1"),1000別寫系統端口

  15. // 3、通過socket服務的send方法將數據包發送出去
  16. ds.send(dp);

  17. // 4、關閉資源
  18. ds.close();
  19. }
  20. }
數據包的方法
 InetAddress getAddress()
          返回某臺機器的 IP 地址,此數據報將要發往該機器或者是從該機器接收到的。
 byte[] getData()
          返回數據緩衝區。
 int getLength()
          返回將要發送或接收到的數據的長度。
  1. /*
  2. * 需求:定義一個應用程序,用於接收udp協議傳輸的數據並處理
  3. *
  4. * 定義udp接收端口
  5. * 思路:
  6. * 1、定義udp的socket服務,通常會監聽一個端口。其實就是給這個接收網絡應用程序定義一個數字標識,
  7. * 明確哪些數據過來該應用程序可以處理
  8. * 2、定義一個數據包,用於存儲接收到的字節數據,可以方便提取數據中的信息
  9. * 3、通過socket的receive方法將接收到的數據存入以定義好的數據包中
  10. * 4、通過數據包中特有功能,將不同的數據取出
  11. * 5、關閉資源
  12. */
  13. publicclassUDPReceive{
  14. publicstaticvoid main(String[] args)throwsException{
  15. // 1、建立udp的socket服務,並指定端點
  16. DatagramSocket ds =newDatagramSocket(1000);

  17. // 2、定義數據包,用於存儲數據
  18. byte[] buf =newbyte[1024];
  19. DatagramPacket dp =newDatagramPacket(buf, buf.length);

  20. // 3、通過socket服務的receive方法將接收到的數據存入數據包中
  21. ds.receive(dp);// 阻塞式方法 ,不發送就一直接收

  22. // 4、通過數據包的方法獲取其中的數據
  23. // String getHostAddress():返回IP地址字符串文本形式,以這個爲主,即以IP地址爲主。
  24. String ip = dp.getAddress().getHostAddress();// 獲取ip
  25. String data =newString(dp.getData(),0, dp.getLength());// dp.getData()獲取數據,不需要獲取1024,獲取指定長度就行
  26. int port = dp.getPort();// 獲取端口號,這裏的端口和ip是發送端的,他是隨機的,可以在套接字中指定,不指定系統隨機分配
  27. System.out.println(ip +"::"+ data +"::"+ port);

  28. // 5、關閉資源
  29. ds.close();
  30. }
  31. }
 

在看一個獲取鍵盤錄入的發送端,接收端就不寫了,都差不多:
  1. 複製代碼
    /*  
     * 發送鍵盤錄入信息  
     */  
    public class UDPSend2 {  
        public static void main(String[] args) throws Exception {  
            DatagramSocket ds = new DatagramSocket();  
            BufferedReader bfr = new BufferedReader(  
                    new InputStreamReader(System.in));  //轉換流,轉成字節
            String line = null;  
          
           byte[] buf = null;  
            DatagramPacket dp = null;  
            while ((line = bfr.readLine()) != null) {  
                buf = line.getBytes();  
                dp = new DatagramPacket(buf, buf.length,  
                        InetAddress.getByName("192.168.229.1"), 10000);
    //192.168.1.255廣播地址,在這個頻段裏的所有ip都可以接收,聊天室  
                ds.send(dp);  
                  
                if("886".equals(line)){  
                    break;  
                }  
            }  
            ds.close();  
            buf.clone();  
        }  
    }  
    複製代碼

     

 

練習:編寫一個簡單的聊天程序:

分析:

有收數據的部分,有發數據的部分,這兩部分需要同時執行,那就需要多線程技術,一個線程控制接收,一個線程控制發。

因爲收和發的動作不一致,所以要定義兩個run方法,而且這個兩個方法要封裝到不同的類中。

  1. 複製代碼
    public class UDPChatDemo {  
        public static void main(String[] args) throws IOException {  
            DatagramSocket sendSocket = new DatagramSocket();  
            DatagramSocket ReceiveSocket = new DatagramSocket(10002);  
              
            new Thread(new ChatSend(sendSocket)).start();  
            new Thread(new ChatReceive(ReceiveSocket)).start();  
        }  
    }  
    /*  
     * 聊天的發送端  
     */  
    public class ChatSend implements Runnable{  
          
        private DatagramSocket ds;  
          
        public ChatSend(DatagramSocket ds){  
            this.ds = ds;  
        }  
      
        @Override  
        public void run() {  
            BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));  
            byte[] buf = null;  
            String line = null;  
            try {  
                while((line=bfr.readLine()) != null){  
                    buf = line.getBytes();  
                    DatagramPacket dp = new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.1.255"), 10002);  
                    ds.send(dp);  
                }  
            } catch (UnknownHostException e) {  
                e.printStackTrace();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }finally{  
                ds.close();  
                try {  
                    bfr.close();  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
            }  
        }  
          
    }  
    /*  
     * 聊天,接收端  
     */  
    public class ChatReceive implements Runnable{  
          
        private DatagramSocket ds;  
          
        public ChatReceive(DatagramSocket ds){  
            this.ds = ds;  
        }  
      
        @Override  
        public void run() {  
            while(true){  
                byte[] buf = new byte[1024];  
                DatagramPacket dp = new DatagramPacket(buf, buf.length);  
                try {  
                    ds.receive(dp);  
                    String ip = dp.getAddress().getHostAddress();  
                    String data = new String(dp.getData(),0,dp.getLength());  
                    int port = dp.getPort();  
                    System.out.println(ip + "::" + data + "::" + port);  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
            }  
        }  
      
    }  
    複製代碼

     

 
 

第三  TCP傳輸

TCP傳輸:

1、流程:

 

  • Socket(客戶端)和ServiceSocket服務端()
  • 建立客戶端和服務端
  • 建立連接後,通過socket中的IO流進行數據的傳輸

 

關閉socket

2、方法:

1)創建客戶端對象: Socket(String host,int port),指定要接收的IP地址和端口號

2)創建服務端對象:ServerSocket(int port):指定接收的客戶端的端口

3)Socket accept():偵聽並接受到此套接字的連接,服務器用於接收客戶端socket對象的方法

注:服務器沒有socket流,也就沒有讀寫操作的流,服務器是通過獲取到客戶端的socket流然後獲取到其中的讀寫方法,對數據進行操作的,也正是因爲這樣服務器與客戶端的數據操作纔不會錯亂

4)void shutdownInput():此套接字的輸入流至於“流的末尾”

5)void shutdownOutput():禁用此套接字的輸出流

6)InputStream getInputStream():返回此套接字的輸入流

7)OutputStream getOutputStream():返回套接字的輸出流

實例:
 
定義tcp的服務端  
  • 建立服務端的socket服務,ServerSocket,並監聽一個端口  
  • 獲取連接過來的客服端對象,通過ServerSokcet的 accept方法。沒有連接就會等,所以這個方法阻塞式的。  
  • 客戶端如果發過來數據,那麼服務端要使用對應的客戶端對象,並獲取到該客戶端對象的讀取流來讀取發過來的數據。  
  • 關閉服務端(可選)  
  1. 複製代碼
    publicclassTCPServerDemo{
    publicstaticvoid main(String[] args)throwsIOException{
    // 建立服務端的socket服務,並監聽一個端口
    ServerSocket ss =newServerSocket(10003);
    // 通過accept方法獲取連接過來的客戶端對象
    Socket socket = ss.accept();
    String ip = socket.getInetAddress().getHostAddress();
    System.out.println(ip +"......connected");
    // 獲取客戶端發過來的數據,那麼要使用客戶端對象的讀取流來獲取數據
    InputStream in = socket.getInputStream();
    byte[] buf =newbyte[1024];
    int len = in.read(buf);
    System.out.println(newString(buf,0, len));
    socket.close();// 關閉客戶端
    ss.close();// 關閉服務端,可選的操作
    }
    }
    複製代碼

     

 
 
tcp分爲客戶端和服務端,客服端對象的對象是socket,服務端對應的是serversoceket  
  • 客戶端,在建立的時候就可以去連接指定的主機  
  • 因爲tcp是面向連接的,所以在建立socket時就需要有服務端存在  
  • 並連接成功,形成通路,才能在該通道上傳輸數據  
  1. 複製代碼
    publicclassTCPClientDemo{
    publicstaticvoid main(String[] args)throwsException{
    //1、創建客戶端的socket服務,指定目的主機和端口
    Socket socket =newSocket("192.168.229.1",10003);
    //2、獲取socket的輸出流,用於發送數據
    OutputStream out = socket.getOutputStream();
    //3、發送數據
    out.write("tcp client send message come on".getBytes());
    socket.close();
    }
    }
    複製代碼

     

 
示例二:下面是客戶端和服務端互動的例子,建立一個文本轉換機制,就是客戶端把從鍵盤錄入的數據發送給服務器,服務器將數據轉爲大寫再發給客戶端
  1.  
    複製代碼
    /*  
     * 需求:建立一個文本轉換服務器。  
     * 客戶端給服務端發送文本,服務單會將文本轉成大寫在返回給客戶端。  
     * 而且客戶度可以不斷的進行文本轉換。當客戶端輸入over時,轉換結束。  
     *   
     * 分析:  
     * 客戶端  
     * 既然是操作設備上的數據,那就可以使用IO技術,並按照io操作規律來思考  
     * 源:鍵盤錄入  
     * 目的:網絡設備,網絡輸出流  
     * 而且操作的是文本數據,可以用字符流  
     *   
     * 步驟: 
     * 1、建立服務  
     * 2、獲取鍵盤輸入  
     * 3、將數據發給客戶端  
     * 4、獲取服務端返回的數據  
     * 5、結束,關閉資源  
     */  
    class TransClient {  
        public static void main(String[] args) throws UnknownHostException,  
                IOException {  
            Socket s = new Socket(InetAddress.getLocalHost(), 10005);  
            BufferedReader bfrb = new BufferedReader(new InputStreamReader(  
                    System.in));  
      
            // 定義目的,將數據寫入socket輸出流,發給服務器  
            OutputStream out = s.getOutputStream();  
            OutputStreamWriter ow = new OutputStreamWriter(out);  
            BufferedWriter bfw = new BufferedWriter(ow);  
      
            // 定義讀取流  
            InputStream in = s.getInputStream();  
            InputStreamReader is = new InputStreamReader(in);  
            BufferedReader bfr = new BufferedReader(is);  
      
            String line = null;  
            while ((line = bfrb.readLine()) != null) {  
                bfw.write(line);  
                bfw.newLine();  
                bfw.flush();  
      
                // 讀取數據  
                String data = bfr.readLine();  
                System.out.println(data);  
            }  
      
            bfrb.close();  
            s.close();  
        }  
    }  
      
    /*  
     * 服務端: 源:socket讀取流 目的:socket輸出流。  
     */  
    class TransServer {  
        public static void main(String[] args) throws IOException {  
            ServerSocket ss = new ServerSocket(10005);  
            Socket s = ss.accept();  
      
            String ip = s.getInetAddress().getHostAddress();  
            System.out.println(ip + "....connected");  
      
            InputStream in = s.getInputStream();  
            InputStreamReader isr = new InputStreamReader(in);  
            BufferedReader bfr = new BufferedReader(isr);  
      
            // 目的。socket輸出流。將大寫數據寫入到socket輸出流,併發送給客戶端。  
            BufferedWriter bufOut = new BufferedWriter(new OutputStreamWriter(  
                    s.getOutputStream()));  
              
            String line = null;  
            while((line=bfr.readLine()) != null){  
                bufOut.write(line.toUpperCase());  
                bufOut.newLine();  
                bufOut.flush();  
            }  
            s.close();  
            ss.close();  
        }  
    }  
      
    public class TCPTransText{  
        public static void main(String[] args) {  
            new TransClient();  
            new TransServer();  
        }  
    } 
    複製代碼

     

 
示例三:TCP複製文件

1、客戶端:

源:硬盤上的文件;目的:網絡設備,即網絡輸出流。若操作的是文本數據,可選字符流,並加入高效緩衝區。若是媒體文件,用字節流。

2、服務端:

源:socket讀取流;目的:socket輸出流。

3、出現的問題:

現象:

a.文件已經上傳成功了,但是沒有得到服務端的反饋信息。

b.即使得到反饋信息,但得到的是null,而不是“上傳成功”的信息

原因:

a.因爲客戶端將數據發送完畢後,服務端仍然在等待這讀取數據,並沒有收到結束標記,就會一直等待讀取。

b.上個問題解決後,收到的不是指定信息而是null,是因爲服務端寫入數據後,也需要刷新,才能將信息反饋給客服端。

解決:

a.方法一:定義結束標記,先將結束標記發送給服務端,讓服務端接收到結束標記,然後再發送上傳的數據。但是這樣定義可能會發生定義的標記和文件中的數據重複而導致提前結束。

   方法二:定義時間戳,由於時間是唯一的,在發送數據前,先獲取時間,發送完後在結尾處寫上相同的時間戳,在服務端,接收數據前先接收一個時間戳,然後在循環中判斷時間戳以結束標記。

  方法三:通過socket方法中的shutdownOutput(),關閉輸入流資源,從而結束傳輸流,以給定結束標記。這裏主要用這個方法。

  1. 複製代碼
    /*  
     * 客戶端  
     */  
    class TextClient {  
        public static void main(String[] args) throws UnknownHostException,  
                IOException {  
            Socket s = new Socket(InetAddress.getLocalHost(), 10007);  
      
            File file = new File("AwtDemo.java");  
      
            BufferedReader bfr = new BufferedReader(new FileReader(file));  
      
            // 將數據寫入到socket流中  
            PrintWriter out = new PrintWriter(s.getOutputStream(), true);  
      
            String line = null;  
            while ((line = bfr.readLine()) != null) {  
                out.println(line);  
            }  
            // 關閉客戶端的輸出流。相當於給流中加入一個結束標記-1.  
            // 結束標記很重要,不然TCP中程序停不下來  
            s.shutdownOutput();  
      
            // 接收服務端發過來的數據  
            BufferedReader bfrs = new BufferedReader(new InputStreamReader(  
                    s.getInputStream()));  
      
            String data = bfrs.readLine();  
            System.out.println(data);  
      
            bfr.close();  
            s.close();  
        }  
    }  
      
    class TextServer {  
        public static void main(String[] args) throws IOException {  
            ServerSocket ss = new ServerSocket(10007);  
            Socket s = ss.accept();// 接收客戶端的socket流  
            String ip = s.getInetAddress().getHostAddress();  
            System.out.println(ip + "....connected");  
      
            //建立讀取客戶端數據的流  
            BufferedReader bfr = new BufferedReader(new InputStreamReader(  
                    s.getInputStream()));  
            //建立文件,關聯流  
            PrintWriter out = new PrintWriter(new FileWriter("server.java"),true);  
              
            String line = null;  
            while((line=bfr.readLine()) != null){  
                out.println(line);  
            }  
              
            //建立給客戶端回饋機制  
            PrintWriter outToC = new PrintWriter(s.getOutputStream(),true);  
            outToC.println("上傳成功");  
              
            out.close();  
            s.close();  
            ss.close();  
        }  
    }  
    複製代碼

     


第四  實際應用

一、TCP併發執行請求

一)圖片上傳:

第一、客戶端:

1、創建服務端點

2、讀取客戶端以後圖片數據

3、通過Socket輸出流將數據發給服務端

4、讀取服務端反饋信息

5、關閉客戶端

第二、服務端

對於客戶端併發上傳圖片,服務端如果單純的使用while(true)循環式有侷限性的,當A客戶端連接上以後,被服務端獲取到,服務端執行具體的流程,這時B客戶端連接就只有等待了,因爲服務端還未處理完A客戶端的請求,還有循環來回執行下須accept方法,所以暫時獲取不到B客戶端對象,那麼爲了可讓多個客戶端同時併發訪問服務端,那麼服務端最好就是將每個客戶端封裝到一個單獨的線程,這樣就可以同時處理多個客戶端的請求。如何定義線程呢?只要明確每個客戶端要在服務端執行的代碼即可,將改代碼存入到run方法中。

  1. 複製代碼
    /*  
     * 客戶端  
     */  
    class PicCilent2 {  
        public static void main(String[] args) throws UnknownHostException,  
                IOException {  
            File file = new File(args[0]);  
            Socket s = new Socket("192.168.229.1", 10010);  
            // 讀取文件數據  
            BufferedInputStream bfr = new BufferedInputStream(new FileInputStream(  
                    file));  
            // 將數據寫到socket流中,傳遞給服務端  
            BufferedOutputStream out = new BufferedOutputStream(s.getOutputStream());  
      
            byte[] buf = new byte[1024];  
            int len = 0;  
            while ((len = bfr.read(buf)) != -1) {  
                out.write(buf, 0, len);  
            }  
            s.shutdownInput();// 結束標記  
      
            // 接收服務端反饋數據  
            InputStream in = s.getInputStream();  
            byte[] bufin = new byte[1024];  
            int num = in.read(bufin);  
            System.out.println(new String(bufin, 0, num));  
      
            bfr.close();  
            s.close();  
        }  
    }  
      
    /*  
     *   
     * 服務端:  
     */  
    class PicThread implements Runnable {  
      
        private Socket s;  
      
        PicThread(Socket s) {  
            this.s = s;  
        }  
      
        @Override  
        public void run() {  
            int count = 1;  
            String ip = s.getInetAddress().getHostAddress();  
            try {  
                System.out.println(ip + "....connected");  
      
                InputStream in = s.getInputStream();  
      
                File dir = new File("c:\\");  
      
                File file = new File(dir, ip + "(" + (count) + ")" + ".jpg");  
      
                while (file.exists())  
                    file = new File(dir, ip + "(" + (count++) + ")" + ".jpg");  
      
                FileOutputStream fos = new FileOutputStream(file);  
      
                byte[] buf = new byte[1024];  
      
                int len = 0;  
                while ((len = in.read(buf)) != -1) {  
                    fos.write(buf, 0, len);  
                }  
      
                OutputStream out = s.getOutputStream();  
      
                out.write("上傳成功".getBytes());  
      
                fos.close();  
      
                s.close();  
            } catch (Exception e) {  
                throw new RuntimeException(ip + "上傳失敗");  
            }  
        }  
      
    }  
      
    class Picserver2 {  
        public static void main(String[] args) throws IOException {  
            ServerSocket ss = new ServerSocket(10011);  
            while (true) {  
                Socket s = ss.accept();  
      
                new Thread(new PicThread(s)).start();  
            }  
        }  
    }  
    複製代碼

     

 
二、其他方式訪問服務器:

1、瀏覽器

在瀏覽器地址欄輸入你的IP和你的服務器的端口號,這就可以成功通過瀏覽器訪問自己的服務器了。

2、telnet

telnet是windows提供的遠程登錄工具,可以連接服務器的任意一臺主機,並在通過dos命令行配置服務器 訪問方式:IP 端口號--> 192.168.229.1 端口號

2、 客戶端:瀏覽器。
 服務端:Tomcat服務器。

啓動tomcat服務器,自己寫點數據用於服務器返回給客戶端的數據,這裏是html文件,自己寫一個簡單的html文件放在tomcat的webapps目錄下就可以

3、客戶端:自定義。(圖形界面)
 服務端:Tomcat服務器。


第五  原理

最常見的客戶端:
瀏覽器 :IE。
最常見的服務端:
服務器:Tomcat。
 
原理:
自定義服務端,使用已有的客戶端IE,瞭解一下客戶端給服務端發了什麼請求?
  1. publicclassMyTomcat{

  2. /**
  3. * @param args
  4. * @throws IOException
  5. */
  6. publicstaticvoid main(String[] args)throwsIOException{

  7. ServerSocket ss =newServerSocket(9090);

  8. Socket s = ss.accept();
  9. System.out.println(s.getInetAddress().getHostAddress()+".....connected");

  10. InputStream in = s.getInputStream();

  11. byte[] buf =newbyte[1024];

  12. int len = in.read(buf);
  13. String text =newString(buf,0,len);
  14. System.out.println(text);


  15. //給客戶端一個反饋信息。
  16. PrintWriter out =newPrintWriter(s.getOutputStream(),true);

  17. out.println("<font color='red' size='7'>歡迎光臨</font>");

  18. s.close();
  19. ss.close();
  20. }

  21. }
發送的請求是(輸出的text):
GET / HTTP/1.1  請求行  請求方式  /myweb/1.html  請求的資源路徑   http協議版本。
請求消息頭 . 屬性名:屬性值
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, 
application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
Accept: */*     
Accept-Language: zh-cn,zu;q=0.5
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.2)
Host: 192.168.1.100:9090
//Host: www.huyouni.com:9090
Connection: Keep-Alive
//空行
//請求體。
 
知道了發送了什麼,那麼就可以模擬一個瀏覽器
  1. publicclassMyBrowser{

  2. /**
  3. * @param args
  4. * @throws IOException
  5. * @throws UnknownHostException
  6. */
  7. publicstaticvoid main(String[] args)throwsUnknownHostException,IOException{

  8. Socket s =newSocket("192.168.1.100",8080);

  9. //模擬瀏覽器,給tomcat服務端發送符合http協議的請求消息。
  10. PrintWriter out =newPrintWriter(s.getOutputStream(),true);
  11. out.println("GET /myweb/1.html HTTP/1.1");
  12. out.println("Accept: */*");
  13. out.println("Host: 192.168.1.100:8080");
  14. out.println("Connection: close");
  15. out.println();
  16. out.println();


  17. InputStream in = s.getInputStream();

  18. byte[] buf =newbyte[1024];
  19. int len = in.read(buf);

  20. String str =newString(buf,0,len);
  21. System.out.println(str);

  22. s.close();

  23. //http://192.168.1.100:8080/myweb/1.html
  24. }

  25. }
//服務端發回應答消息。
HTTP/1.1 200 OK   //應答行,http的協議版本   應答狀態碼   應答狀態描述信息
 
應答消息屬性信息。 屬性名:屬性值
Server: Apache-Coyote/1.1
ETag: W/"199-1323480176984"
Last-Modified: Sat, 10 Dec 2011 01:22:56 GMT
Content-Type: text/html
Content-Length: 199
Date: Fri, 11 May 2012 07:51:39 GMT
Connection: close
//空行
//應答體。
<html>
<head>
<title>這是我的網頁</title>
</head>
 
<body>
 
<h1>歡迎光臨</h1>
 
<font size='5' color="red">這是一個tomcat服務器中的資源。是一個html網頁。</font>
</body>
 
 
</html>
 
可是瀏覽器並沒有顯示應答消息屬性信息這些內容,因爲瀏覽器有自己的解析引擎,Java封裝了一個類URL可以解析引擎
  1. publicclassURLDemo{

  2. /**
  3. * @param args
  4. * @throws IOException
  5. */
  6. publicstaticvoid main(String[] args)throwsIOException{

  7. String str_url ="http://192.168.1.100:8080/myweb/1.html";

  8. URL url =new URL(str_url);

  9. // System.out.println("getProtocol:"+url.getProtocol());
  10. // System.out.println("getHost:"+url.getHost());
  11. // System.out.println("getPort:"+url.getPort());
  12. // System.out.println("getFile:"+url.getFile());
  13. // System.out.println("getPath:"+url.getPath());
  14. // System.out.println("getQuery:"+url.getQuery());
  15. //這一部簡化了下面的倆步
  16. // InputStream in = url.openStream();

  17. //獲取url對象的Url連接器對象。將連接封裝成了對象:java中內置的可以解析的具體協議的對象+socket.
  18. URLConnection conn = url.openConnection();

  19. // String value = conn.getHeaderField("Content-Type");
  20. // System.out.println(value);

  21. // System.out.println(conn);
  22. //sun.net.www.protocol.http.HttpURLConnection:http://192.168.1.100:8080/myweb/1.html

  23. InputStream in = conn.getInputStream();

  24. byte[] buf =newbyte[1024];
  25. int len = in.read(buf);

  26. String text =newString(buf,0,len);

  27. System.out.println(text);

  28. in.close();
  29. }

  30. }
 
網絡結構,
  • C/S  client/server
特點:
該結構的軟件,客戶端和服務端都需要編寫。
可發成本較高,維護較爲麻煩。
 
好處:
客戶端在本地可以分擔一部分運算。
 
  • B/S  browser/server
特點:
該結構的軟件,只開發服務器端,不開發客戶端,因爲客戶端直接由瀏覽器取代。 
開發成本相對低,維護更爲簡單。
缺點:所有運算都要在服務端完成。
 
 
 
 
 
 
 

小知識點

1、InetSocketAddress對象(IP+端口)

2、ServerSocket對象中的構造函數:

ServerSocket(int port,int backlog),其中的backlog表示隊列的最大長度,即最多連入客戶端的個數,即最大連接數。

3、在進行瀏覽器輸入網址訪問一臺主機所做的操作:

如http://192.168.229.1:8080/myweb/demo.html,一般直接輸入主機名:http://baidu.com等,那麼如何通過主機名獲取IP地址,從而連接到這臺主機的呢?這就需要將主機名翻譯成IP地址,即域名解析:DNS(存的是主機名和IP相對應的鍵值對)

在進行訪問的時候,會現在本地的hosts文件(C:\WINDOWS\system32\drivers\etc\hosts)中找對應的映射,若有,則直接返回請求,若無,則到公網的映射列表即DNS中找對應的映射,找到後,將主機名對應的IP地址返回給本機,本機通過這個IP地址找到對應的服務器。

域名解析示意圖:

host應用:

1、可屏蔽一些惡意網址,即將對應的映射關係寫入hosts中,將IP地址改爲本機的迴環地址,那麼會直接找到hosts,就不會將請求發送出去了。

2、不讓軟件更新,可以越過一些收費軟件的限制。

3、把經常上的網站寫入文件中,提高訪問速率。

 
發佈了6 篇原創文章 · 獲贊 2 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章