天天看點

黑馬程式員-網絡

——-android教育訓練java教育訓練期待與您交流!———-

1. 概述

網絡程式設計的本質是兩個裝置之間的資料交換,在計算機網絡中,裝置主要指計算機。

  • 網絡模型

    網絡傳輸方式中所細緻劃分層次的一個傳輸模型。每個層次都有自己功能作用。

黑馬程式員-網絡
1. OSI參考模型
     * 主要有七層定義:兩個裝置間通訊先會進行封裝資訊包的動作然後傳給要傳輸的裝置,接受裝置在進行拆包動作對資訊解析和接受。
 2. TCP/IP參考模型
     * 是對OSI模型的一個簡化,分為四層。網絡程式設計主要對應的是傳輸層和網際層。
     * 傳輸層對應的協定:TCP和UDP。網際層為:IP協定。應用層為HTTP、FTP等等協定。
           
  • 網絡通訊要素
    1. IP位址:網絡裝置辨別。本機回環IP位址:127.0.0.1或者localhost,也是預設。用途:可以測試網卡等。
    2. 端口:網絡裝置上應用程式的辨別,此辨別稱作端口(邏輯端口),範圍是0-65535任選,其中0-1024為系統使用或者保留端口。
    3. 傳輸協定:定義通信規則,此規則稱為協定。常見的協定有:國際通用協定為:TCP/IP,UDP。
package com.sergio.Network;

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * IP對象使用示例
 * Created by Sergio on 2015-05-19.
 */
public class IPDemo {
    public static void main(String[] args) {
        InetAddress i = null;
        InetAddress ia = null;
        try {
            i = InetAddress.getLocalHost();
            System.out.println(i.toString());
            System.out.println(i.getHostAddress());
            System.out.println(i.getHostName());

            //通過名稱主機名來解析位址和名字。但是還是以ip位址為主
            ia = InetAddress.getByName("www.baidu.com");
            System.out.println(ia.getHostAddress());
            System.out.println(ia.getHostName());
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }
}
           

2. UDP和TCP

  • UDP:
    1. 将資料及源和目的封裝成資料包,不需要建立連接配接
    2. 每個資料報的大小限制在64k内,有個封包動作
    3. 因無連接配接,是不可靠協定
    4. 不需要建立連接配接,速度快
    5. 應用場景:聊天,視訊,桌面共享等
  • TCP:
    1. 建立連接配接,形成傳輸資料的通道
    2. 在連接配接中進行大資料量傳輸
    3. 通過三次握手完成連接配接,是可靠協定
    4. 必須建立連接配接,效率會稍低
    5. 應用場景:下載下傳等

3. Socket

  • Socket是為網絡服務提供的一種機制
  • 通信兩端都有Socket
  • 網絡通信就是Socket間的通信
  • 資料在兩個Socket間通過IO傳輸

4. UDP應用

  • 對應的對象:DatagramSocket與DatagramPacket
  • 發送資料的步驟:
    1. 建立udp socket服務
    2. 提供資料,并将資料封裝到資料包中
    3. 通過socket服務的發送功能,将資料包發出去
    4. 關閉資源
package com.sergio.Network;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

/**
 * UDP發送資料步驟:
 * 1. 建立udp socket服務
 * 2. 提供資料,并将資料封裝到資料包中
 * 3. 通過socket服務的發送功能,将資料包發出去
 * 4。關閉資源
 * Created by Sergio on 2015-05-19.
 */
public class UDPSendDataDemo {
    public static void main(String[] args) throws Exception {
        //socket服務建立
        DatagramSocket ds = new DatagramSocket();
        //提供資料
        byte[] data = "udp send".getBytes();
        //封裝資料
        DatagramPacket dp =
            new DatagramPacket(data, data.length, InetAddress.getByName("192.168.1.123"), );
        //發送資料
        ds.send(dp);
        ds.close();
    }
}
           
  • 接收資料的步驟:
    1. 定義UDP socket服務,通常會監聽一個端口,用來接收該接受的應用程式
    2. 定義資料包,用來存儲接收到是位元組資料,因為資料包對象中有更多功能可以提取位元組資料的不同資訊,
    3. 通過socket服務的receive方法将接收到的資料存入一定以好資料包中,
    4. 通過資料包對象的特有功能,将這些不同的資料取出。
package com.sergio.Network;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

/**
 * UDP接受資料步驟:
 * 1. 定義UDP socket服務,通常會監聽一個端口,用來接收該接受的應用程式
 * 2. 定義資料包,用來存儲接收到是位元組資料,因為資料包對象中有更多功能可以提取位元組資料的不同資訊,
 * 3. 通過socket服務的receive方法将接收到的資料存入一定以好資料包中,
 * 4. 通過資料包對象的特有功能,将這些不同的資料取出。
 * Created by Sergio on 2015-05-19.
 */
public class UDPReceiveDataDemo {
    public static void main(String[] args) throws Exception {
        //建立udp socket服務,指定端口來接受該有的應用程式資訊
        DatagramSocket ds = new DatagramSocket();
        while (true) {
            //定義資料包,用來存儲接受到的資料包
            byte[] data = new byte[];
            DatagramPacket dp = new DatagramPacket(data, data.length);
            //通過服務的receive方法将受到資料存入資料包中
            ds.receive(dp);
            //通過資料包的方法提取資料資訊
            String ip = dp.getAddress().getHostAddress();
            //擷取應有長度的資料内容
            String data1 = new String(dp.getData(), , dp.getLength());
            int port = dp.getPort();
            System.out.println(data1 + ip + port);
        }
    }
}
           
  • 練習聊天:
package com.sergio.Network;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;

/**
 * 聊天程式
 * Created by Sergio on 2015-05-19.
 */
public class ChatDemo {
    public static void main(String[] args) throws Exception {
        //建立發送和接受對象
        DatagramSocket sendSocket = new DatagramSocket();
        DatagramSocket receiveSocket = new DatagramSocket();
        //啟動線程
        new Thread(new Send(sendSocket)).start();
        new Thread(new Receive(receiveSocket)).start();
    }
}


//發送資料端線程
class Send implements Runnable {
    private DatagramSocket ds;

    public Send(DatagramSocket ds) {
        this.ds = ds;
    }

    @Override
    public void run() {
        try {
            //讀取鍵盤錄入并發送資料
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            String line = null;
            while ((line = br.readLine()) != null) {
                if ("886".equals(line))
                    break;

                byte[] buf = line.getBytes();
                DatagramPacket dp =
                    new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.1.123"), );
                ds.send(dp);
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}


//接受資料的線程
class Receive implements Runnable {
    private DatagramSocket ds;

    public Receive(DatagramSocket ds) {
        this.ds = ds;
    }

    @Override
    public void run() {
        try {
            //循環解析資料
            while (true) {
                byte[] buf = new byte[];
                DatagramPacket dp = new DatagramPacket(buf, buf.length);
                ds.receive(dp);
                String ip = dp.getAddress().getHostAddress();
                String data = new String(dp.getData(), , dp.getLength());

                System.out.println(ip + "::" + data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
           

5. TCP應用

  • 對應的對象為:Socket和ServerSocket
  • TCP分用戶端和服務端。用戶端對應的對象為Socket、服務端為:ServerSocket。

    步驟:

  • 一. 用戶端:
    1. 建立Socket服務,并指定要連接配接的主機和端口。
    2. 擷取Socket流的中的輸出流,将資料寫到該流中,通過網絡發送給服務端。
    3. 關閉Scoket。
    4. 二. 服務端:
    1. 建立服務端的Socket服務,ServerSocket();
    2. 擷取連接配接過來的用戶端對象,通過ServerSocket的accept方法連接配接,此方法是阻塞式的。
    3. 用戶端如果發來資料,服務端需要使用對應的用戶端對象,并擷取到該用戶端對象的讀取流來讀取發來的資料。
    4. 關閉服務端(可選)。
  • 注意:服務端沒有輸入輸出流,主要是利用用戶端對象的輸出輸入流來讀取資料資訊。
package com.sergio.Network;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

/**
 * 互動式用戶端示例
 * Created by Sergio on 2015-05-20.
 */
public class TCPClientDemo2 {
    public static void main(String[] args) throws IOException {
        //建立Socket服務,指定連接配接主機和端口号
        Socket s = new Socket("192.168.1.123", );
        //擷取Socket流中的輸出流,并寫入到該流中
        OutputStream out = s.getOutputStream();
        out.write("互動式資訊發送".getBytes());

        //互動部分代碼輸入,讀取資料
        InputStream in = s.getInputStream();
        byte[] buf = new byte[];
        int len = in.read(buf);
        System.out.println(new String(buf, , len));
        s.close();

    }
}
           
package com.sergio.Network;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 互動式服務端示例
 * Created by Sergio on 2015-05-20.
 */
public class TCPServerDemo2 {
    public static void main(String[] args) throws IOException {
        //建立ServerSocket服務,并監聽10004端口
        ServerSocket ss = new ServerSocket();
        //通過accept方法擷取用戶端對象
        Socket s = ss.accept();
        //列印用戶端的ip位址
        String ip = s.getInetAddress().getHostAddress();
        System.out.println(ip + "連接配接進來");

        //擷取用戶端的輸入流,并讀取資料
        InputStream is = s.getInputStream();
        byte[] buf = new byte[];
        int len = is.read(buf);
        System.out.println(new String(buf, , len));

        //與用戶端互動部分,寫入資料
        OutputStream out = s.getOutputStream();
        out.write("服務端受到資訊".getBytes());
        s.close();
        ss.close();
    }
}
           
  • 鍵盤錄入資料服務端傳回大寫格式資訊示例:
package com.sergio.Network;

import java.io.*;
import java.net.Socket;

/**
 * 将用戶端發送給服務端的字元轉成大寫。注意讀取鍵盤錄入資料的結束标記換行和回車符。
 * Created by Sergio on 2015-05-20.
 */
public class TransClientDemo {
    public static void main(String[] args) throws IOException {
        Socket s = new Socket("192.168.1.123", );
        //定義讀取鍵盤資料的流對象
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        //定義目的,将資料寫入到socket輸出流,發送給服務端
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        //對上一句替換語句//PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
        //定義一個socket讀取流,讀取服務端傳回的大寫資訊
        BufferedReader brIn = new BufferedReader(new InputStreamReader(s.getInputStream()));

        String line = null;
        while ((line = br.readLine()) != null) {
            if ("over".equals(line))
                break;
            bw.write(line);
            //需要有個回車符結束标記
            bw.newLine();
            bw.flush();
            //對上面三句的替換//pw.print(line);
            //讀取服務端傳回的資訊
            String str = brIn.readLine();
            System.out.println("server::" + str);
        }
        br.close();
        s.close();
    }
}


package com.sergio.Network;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 将用戶端發送給服務端的字元轉成大寫。注意讀取鍵盤錄入資料的結束标記換行和回車符。
 * Created by Sergio on 2015-05-20.
 */
public class TransServerDemo {
    public static void main(String[] args) throws Exception {
        ServerSocket ss = new ServerSocket();
        Socket s = ss.accept();

        String ip = s.getInetAddress().getHostAddress();
        System.out.println(ip + "連接配接進來");

        //讀取socket讀取流中的資料
        BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
        //目的socket輸出流将大小資料寫入到socket暑促胡柳,并發送給用戶端
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        //PrintWriter pw = new PrintWriter(s.getOutputStream());
        String line = null;
        while ((line = br.readLine()) != null) {
            //pw.print(line.toUpperCase());
            bw.write(line.toUpperCase());
            bw.newLine();
            bw.flush();
        }
        s.close();
        ss.close();
    }
}
           
  • 用戶端登入伺服器示例:
package com.sergio.Network;

import java.io.*;
import java.net.Socket;

/**
 * 上傳圖檔示例,用戶端
 * 步驟:1.服務端點,2.讀取用戶端已有的資料,3.通過Socket輸出流将資料發給服務端,
 * 4.讀取服務端發聩資訊,5.關閉
 * Created by Sergio on 2015-05-22.
 */
public class UploadPicClient {
    public static void main(String[] args) throws Exception {
        //用來判斷上傳圖檔的上傳要求
        //為空
        if (args.length != ) {
            System.out.println("請選擇一個jpg格式的圖檔");
            return;
        }
        File file = new File(args[]);
        if (file.exists() && file.isFile()) {
            System.out.println("該檔案有問題");
            return;
        }
        if (!file.getName().endsWith(".jpg")) {
            System.out.println("圖檔格式錯誤");
        }
        if (file.length() >  *  * ) {
            System.out.println("檔案過大");
            return;
        }

        Socket s = new Socket("192.168.1.123", );
        FileInputStream fis = new FileInputStream(file);
        OutputStream out = s.getOutputStream();
        byte[] buf = new byte[];
        int len = ;
        while ((len = fis.read(buf)) != -) {
            out.write(buf, , len);
        }
        //告訴服務端資料已經傳完
        s.shutdownOutput();

        //讀取回報的資訊
        InputStream in = s.getInputStream();
        byte[] bufIn = new byte[];
        int num = in.read(bufIn);
        System.out.println(new String(bufIn, , num));
        fis.close();
        s.close();
    }
}

package com.sergio.Network;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 上傳圖檔示例,并發處理服務端
 * Created by Sergio on 2015-05-22.
 */
public class UploadPicServer {
    public static void main(String[] args) throws Exception {
        ServerSocket ss = new ServerSocket();
        while (true) {
            //擷取用戶端連接配接并監聽位址和端口
            Socket s = ss.accept();
            //啟動服務端并發處理的線程
            new Thread(new PicThread(s)).start();
        }
    }
}


//服務端上傳圖檔線程
class PicThread implements Runnable {
    private Socket s;

    PicThread(Socket s) {
        this.s = s;
    }

    @Override
    public void run() {
        //用來重複上傳圖檔計數
        int count = ;
        String ip = s.getInetAddress().getHostAddress();
        try {
            System.out.println(ip + "連接配接進來了");
            InputStream in = s.getInputStream();
            //處理重複上傳判斷和處理
            File file = new File(ip + "(" + (count) + ")" + ".jpg");
            while (file.exists()) {
                file = new File(ip + "(" + (count++) + ")" + ".jpg");
            }
            //讀取圖檔
            FileOutputStream fos = new FileOutputStream(file);
            byte[] buf = new byte[];
            int len = ;
            while ((len = in.read(buf)) != -) {
                fos.write(buf, , len);
            }

            //服務端回應用戶端
            OutputStream out = s.getOutputStream();
            out.write("上傳成功".getBytes());
            fos.close();
            s.close();
        } catch (Exception e) {
            throw new RuntimeException(ip + "上傳失敗");
        }
    }
}
           

URL和URLConnection

  • URL是對底層傳輸層功能封裝的對象。
  • URLConnection相當于應用層對URL的功能封裝,更簡便。

1.URL

package com.sergio.Network;

import java.net.MalformedURLException;
import java.net.URL;

/**
 * URL對象示例,對網址進行解析
 * Created by Sergio on 2015-05-24.
 */
public class URLDemo {
    public static void main(String[] args) throws MalformedURLException {
        URL url = new URL("https://www.amazon.cn/clouddrive?sf=1&ref_=nav_Photos_Files");
        System.out.println("協定" + url.getProtocol());
        System.out.println("主機" + url.getHost());
        System.out.println("端口" + url.getPort());
        System.out.println("路徑" + url.getPath());
        System.out.println("檔案" + url.getFile());
        System.out.println("查詢" + url.getQuery());
    }
}
           

2.URLConnection

package com.sergio.Network;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;

/**
 * URLConnection對象使用,對連接配接解析并擷取網頁内容。
 * Created by Sergio on 2015-05-24.
 */
public class URLConnectionDemo {
    public static void main(String[] args) throws IOException {
        URL url = new URL("https://www.amazon.cn.");
        //應用層URLConnection對象封裝,打開socket流
        URLConnection conn = url.openConnection();
        System.out.println(conn);

        InputStream in = conn.getInputStream();
        byte[] buf = new byte[];
        int len = in.read(buf);
        //列印擷取到的資料資訊
        System.out.println(new String(buf, , len));
    }
}