1. 程式人生 > 其它 >12、網路程式設計

12、網路程式設計

12、網路程式設計

概述:

網路程式設計中的兩個主要問題:

  1. 如何準確定位網路上的主機,定位主機上的應用:

    • IP + 埠號
  2. 找到主機後如何可靠高效的進行資料傳輸

    • 網路通訊協議 TCP/IP參考模型

通訊要素一:IP和埠號

 IP:唯一標識Internet上的計算機 (127.0.0.1本地迴環地址)

 IP分類:IPv4 與 IPv6 ;全球資訊網 與 區域網

 Java中 InetAddress類 代表IP,

//例項化InetAddress
getByName(String host)//ip 或 域名
getLocalhost()    //獲取本機地址
//兩個常用方法
 .getHostName()
 .getHostAddress()

 埠號: 標識正在計算機上執行的程序(程式) 0~65535。
公認埠 0~1023 ,註冊埠 1024~49151,動態/私有埠 49152~65535

 埠號與IP 地址的組合得出一個網路套接字Socket

通訊要素二:網路通訊協議

TCP 協議:(傳輸控制協議)
 使用TCP協議前,須先建立TCP連線,形成傳輸資料通道
 傳輸前,採用“ 三次握手”方式,點對點通訊,是可靠的
 TCP協議進行通訊的兩個應用程序:客戶端、服務端。
 在連線中可進行大資料量的傳輸
 傳輸完畢,需釋放已建立的連線,效率低
UDP 協議:(使用者資料報協議)
 將資料、源、目的封裝成資料包,不需要建立連線


 每個資料報的大小限制在64K內
 傳送不管對方是否準備好,接收方收到也不確認,故是不可靠的
 可以廣播發送
 傳送資料結束時無需釋放資源,開銷小,速度快

Socket:
把網路連線當成一個流,資料在兩個Socket間通過IO傳輸
流套接字(stream socket):使用TCP提供可依賴的位元組流服務
資料報套接字(datagram socket):使用UDP提供“盡力而為”的資料報服務

TCP網路程式設計

客戶端:

  1. 建立Socket物件,指明伺服器端的 ip 和 埠號
  2. 獲取一個輸出流,用於輸出資料
  3. 寫出資料操作
  4. 關閉資源

客戶端:

  1. 建立伺服器端的 ServerSocke,指明自己的埠號
  2. 呼叫accept( ) 表示接收來自客戶端的socke
  3. 讀取輸入流中的資料
  4. 關閉資源

傳輸檔案:

public void client() throws Exception {
    //1.建立socket物件,指明伺服器端的 ip+埠
    Socket socket = new Socket(InetAddress.getLocalHost(), 4545);
    //2.獲取輸出流 ,寫出資料
    OutputStream os = socket.getOutputStream();
    FileInputStream fis = new FileInputStream("1.jpg"); //獲取圖片資料
    int len;
    byte[] buffer = new byte[1024];
    while ( (len=fis.read(buffer))!=-1 ){
        os.write(buffer,0,len);     //寫入輸出流
    }
    //3.關閉資源
    fis.close();
    os.close();
    socket.close();
}

public void server() throws Exception {
    //1.建立伺服器端的 ServerSocket,指明自己的埠號
    ServerSocket ss = new ServerSocket(4545);
    //2.呼叫accept() 表示接收來自客戶端的socket
    Socket socket = ss.accept();
    //3.獲取輸出流中的資料
    InputStream is = socket.getInputStream();
    FileOutputStream fos = new FileOutputStream("2.jpg");
    int len;
    byte[] buffer = new byte[1024];
    while ( (len=is.read(buffer))!=-1 ){
        fos.write(buffer,0,len);
    }
    //4.關閉資源
    fos.close();
    is.close();
    socket.close();
    ss.close();
}

伺服器接收完檔案後,給客戶端返回資訊:

public void client() throws Exception {
    //1.建立socket物件,指明伺服器端的 ip+埠
    Socket socket = new Socket(InetAddress.getLocalHost(), 4545);
    //2.獲取輸出流 ,寫出資料
    OutputStream os = socket.getOutputStream();
    FileInputStream fis = new FileInputStream("1.jpg"); //獲取圖片資料
    int len;
    byte[] buffer = new byte[1024];
    while ( (len=fis.read(buffer))!=-1 ){
        os.write(buffer,0,len);     //寫入輸出流
    }
    //通知伺服器,傳輸完畢
    socket.shutdownOutput();    //表示客戶端傳輸完畢,不再輸出資料,服務端可以傳送資料
	
    //接收伺服器返回的資訊 並列印
    InputStream is = socket.getInputStream();
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    while ( (len=is.read(buffer))!=-1 ){
        baos.write(buffer,0,len);
    }
    System.out.println(baos.toString());

    //3.關閉資源
    fis.close();
    os.close();
    socket.close();
    baos.close();is.close();
}

public void server() throws Exception {
    //1.建立伺服器端的 ServerSocket,指明自己的埠號
    ServerSocket ss = new ServerSocket(4545);
    //2.呼叫accept() 表示接收來自客戶端的socket
    Socket socket = ss.accept();
    //3.獲取輸出流中的資料
    InputStream is = socket.getInputStream();
    FileOutputStream fos = new FileOutputStream("2.jpg");
    int len;
    byte[] buffer = new byte[1024];
    while ( (len=is.read(buffer))!=-1 ){    //read是一個阻塞式方法,需要標識是否傳輸完畢
        fos.write(buffer,0,len);
    }

    //接收完成後,給客戶端傳送資訊
    OutputStream os = socket.getOutputStream();
    os.write("照片接收已完成~".getBytes());

    //4.關閉資源
    fos.close();
    is.close();
    socket.close();
    ss.close();
    os.close();
}

UDP網路程式設計

  1. DatagramSocket與DatagramPacket
  2. 建立傳送端,接收端
  3. 建立資料包
  4. 呼叫Socket的傳送、接收方法
  5. 關閉Socket

 傳送端與接收端是兩個獨立的執行程式

public void sender() throws Exception {
    //1.建立一個Socket
    DatagramSocket socket = new DatagramSocket();
    //2.建包,封裝資料
    byte[] data = "我是UDP連線方式~".getBytes();
    InetAddress ip = InetAddress.getLocalHost();
    //封裝資料報                  DatePacket(位元組資料,資料開始,資料結束,ip,埠)
    DatagramPacket packet = new DatagramPacket(data,0,data.length,ip,5454);
    //3.傳送包
    socket.send(packet);
    //4.關閉資源
    socket.close();
}

public void receiver() throws IOException {
    //1.建立socket物件,指明埠號
    DatagramSocket socket = new DatagramSocket(5454);
    //2.建包,準備接收資料
    byte[] buffer = new byte[1024];
    DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length);
    //3.接收資料
    socket.receive(packet);  //此時資料已經存在 buffer中了
    //   System.out.println(new String(packet.getData(),0,packet.getLength()));
    System.out.println(new String(buffer,0,buffer.length));
    //4.關閉資源
    socket.close();
}

URL網路程式設計

 URL(Uniform Resource Locator):統一資源定位符,定位 Internet 上某一資源的地址。

 URL由五部分組成:傳輸協議://主機名: 埠號/檔名 #片段名 ?引數列表

常用方法:

public String getProtocol( ) 獲取該URL的協議名
public String getHost( ) 獲取該URL的主機名
public String getPort( ) 獲取該URL的埠號
public String getPath( ) 獲取該URL的檔案路徑
public String getFile( ) 獲取該URL的檔名
public String getQuery( ) 獲取該URL的查詢名

下載網站資源

public void URL_download() throws Exception{
    //1.建立URL物件,獲取連線物件
    String ur = "http://m10.music.126.net/20220407201631/edf99a1e630704529b26cfb1cadddab5/ymusic/560e/5352/0f5b/ad656bf54ad8b8b421b4811622f27cb7.mp3";
    URL url = new java.net.URL(ur);
    
    HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
    urlConnection.connect();
    //2.獲取網站資源
    InputStream is = urlConnection.getInputStream();
    FileOutputStream fos = new FileOutputStream("url.jpg");
    byte[] buffer = new byte[1024];
    int len;
    while ( (len=is.read(buffer))!=-1 ){
        fos.write(buffer,0,len);
    }
    //3.關閉資源,關閉連線
    fos.close();
    is.close();
    urlConnection.disconnect();
}

PS: 附:忽略網站信任證書 工具類:HttpsURLValidator

點選檢視程式碼
/**     忽略證書信任問題
 *  一個信任 https證書的工具類,
在urlConnection請求前 加入一條語句 : HttpsURLValidator.httpsRequestTrue(url); //url為https請求地址
 */
//import lombok.extern.slf4j.Slf4j;
import sun.net.www.protocol.https.HttpsURLConnectionImpl;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;

//@Slf4j
public class HttpsURLValidator {
    HostnameVerifier hv = new HostnameVerifier() {
        public boolean verify(String urlHostName, SSLSession session) {
            System.out.println("Warning: URL Host: " + urlHostName + " vs. "
                               + session.getPeerHost());
            return true;
        }
    };

    /**
     * https忽略SSL的方法
     * @param url
     */
    public static void httpsRequestTrue(String url){//訪問https地址直接呼叫這個方法
        try {
            //忽略https證書的再請求
            HttpsURLValidator.trustAllHttpsCertificates();
            HostnameVerifier hv = new HostnameVerifier() {
                public boolean verify(String urlHostName, SSLSession session) {
                    return true;
                }
            };
            URL u = new URL(url);
            HttpsURLConnection.setDefaultHostnameVerifier(hv);
            URLConnection urlConnection = (HttpsURLConnectionImpl)u.openConnection();
        }catch (Exception e){
            e.printStackTrace();
            //     log.error(e.getMessage());
        }
    }

    protected final String retrieveResponseFromServer(final URL validationUrl,
                                                      final String ticket) {
        HttpURLConnection connection = null;
        try {
            connection = (HttpURLConnection) validationUrl.openConnection();
            final BufferedReader in = new BufferedReader(new InputStreamReader(
                connection.getInputStream()));

            String line;
            final StringBuffer stringBuffer = new StringBuffer(255);

            synchronized (stringBuffer) {
                while ((line = in.readLine()) != null) {
                    stringBuffer.append(line);
                    stringBuffer.append("\n");
                }
                return stringBuffer.toString();
            }

        } catch (final IOException e) {
            //    log.error(e.getMessage());
            e.printStackTrace();
            return null;
        } catch (final Exception e1){
            //   log.error(e1.getMessage());
            e1.printStackTrace();
            return null;
        }finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }
    protected static void trustAllHttpsCertificates() throws Exception {
        javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];
        javax.net.ssl.TrustManager tm = new miTM();
        trustAllCerts[0] = tm;
        javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext
            .getInstance("SSL");
        sc.init(null, trustAllCerts, null);
        javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc
                                                                    .getSocketFactory());
    }

    static class miTM implements javax.net.ssl.TrustManager,
    javax.net.ssl.X509TrustManager {
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        public boolean isServerTrusted(
            java.security.cert.X509Certificate[] certs) {
            return true;
        }

        public boolean isClientTrusted(
            java.security.cert.X509Certificate[] certs) {
            return true;
        }

        public void checkServerTrusted(
            java.security.cert.X509Certificate[] certs, String authType)
            throws java.security.cert.CertificateException {
            return;
        }

        public void checkClientTrusted(
            java.security.cert.X509Certificate[] certs, String authType)
            throws java.security.cert.CertificateException {
            return;
        }
    }
}