Java網絡通訊協議、UDP、TCP類加載整理

     網絡通訊協議

  網絡通訊協議java

網絡通訊協議有不少種,目前應用最普遍的是TCP/IP協議(Transmission Control Protocal/Internet Protoal傳輸控制協議/英特網互聯協議),它是一個包括TCP協議和IP協議,UDP(User Datagram Protocol)協議和其它一些協議的協議組,在學習具體協議以前首先了解一下TCP/IP協議組的層次結構。數組

 

 

 

1.1      InetAddress

 

 

 

package com.oracle.InetAddress;安全

 

import java.net.InetAddress;服務器

import java.net.UnknownHostException;網絡

 

public class Demo01 {多線程

    public static void main(String[] args) throws UnknownHostException {oracle

        //獲取本機地址dom

        InetAddress inet=InetAddress.getLocalHost();socket

        System.out.println(inet);post

        //根據主機名獲取inet對象

    /*  InetAddress inet1=InetAddress.getByName("DESKOP-NR4E1C5");

        //獲取主機名

        System.out.println(inet1.getHostName());*/

        //獲取ip地址

        String ip=inet.getHostAddress();

        System.out.println(ip);

       

    }

}

 

運行結果:

 

 

     UDP與TCP協議

在介紹TCP/IP結構時,提到傳輸層的兩個重要的高級協議,分別是UDP和TCP,其中UDP是User Datagram Protocol的簡稱,稱爲用戶數據報協議,TCP是Transmission Control Protocol的簡稱,稱爲傳輸控制協議。

2.1      UDP協議

 

UDP是無鏈接通訊協議,即在數據傳輸時,數據的發送端和接收端不創建邏輯鏈接。

 

可是在使用UDP協議傳送數據時,因爲UDP的面向無鏈接性,不能保證數據的完整性,所以在傳輸重要數據時不建議使用UDP協議。UDP的交換過程以下圖所示。

UDP傳輸數據被限制在64K之內

 

 

 

 

2.2      TCP協議

TCP協議是面向鏈接的通訊協議,即在傳輸數據前先在發送端和接收端創建邏輯鏈接,而後再傳輸數據,它提供了兩臺計算機之間可靠無差錯的數據傳輸。

 

 

因爲TCP協議的面向鏈接特性,它能夠保證傳輸數據的全性安,因此是一個被普遍採用的協議,例如在下載文件時,若是數據接收不完整,將會致使文件數據丟失而不能被打開,所以,下載文件時必須採用TCP協議。

 UDP通訊

3.1      DatagramPacket

UDP是一種面向無鏈接的協議,UDP通訊也是同樣,發送和接收的數據也須要使用「集裝箱」進行打包,爲此JDK中提供了一個DatagramPacket類,該類的實例對象就至關於一個集裝箱,用於封裝UDP通訊中發送或者接收的數據

接下來根據API文檔的內容,對DatagramPacket的構造方法進行逐一詳細地講解。

 

 

使用該構造方法在建立DatagramPacket對象時,指定了封裝數據的字節數組和數據的大小,沒有指定IP地址和端口號。很明顯,這樣的對象只能用於接收端,不能用於發送端。由於發送端必定要明確指出數據的目的地(ip地址和端口號),而接收端不須要明確知道數據的來源,只須要接收到數據便可。

 

 

用該構造方法在建立DatagramPacket對象時,不只指定了封裝數據的字節數組和數據的大小,還指定了數據包的目標IP地址(addr)和端口號(port)。該對象一般用於發送端,由於在發送數據時必須指定接收端的IP地址和端口號,就好像發送貨物的集裝箱上面必須標明接收人的地址同樣。

 

面咱們講解了DatagramPacket的構造方法,接下來對DatagramPacket類中的經常使用方法進行詳細地講解,

 

 

3.2      DatagramSocket

DatagramPacket數據包的做用就如同是「集裝箱」,能夠將發送端或者接收端的數據封裝起來。在程序中須要實現通訊只有DatagramPacket數據包也一樣不行,爲此JDK中提供的一個DatagramSocket類。DatagramSocket類的做用就相似於碼頭,使用這個類的實例對象就能夠發送和接收DatagramPacket數據包,發送數據的過程以下圖所示。

 

 

在建立發送端和接收端的DatagramSocket對象時,使用的構造方法也有所不一樣,下面對DatagramSocket類中經常使用的構造方法進行講解。

 

 

該構造方法用於建立發送端的DatagramSocket對象,在建立DatagramSocket對象時,並無指定端口號,此時,系統會分配一個沒有被其它網絡程序所使用的端口號。

 

 

該構造方法既可用於建立接收端的DatagramSocket對象,又能夠建立發送端的DatagramSocket對象,在建立接收端的DatagramSocket對象時,必需要指定一個端口號,這樣就能夠監聽指定的端口。

 

 

 

3.3      UDP網絡程序

 

 

 

要實現UDP通訊須要建立一個發送端程序和一個接收端程序,很明顯,在通訊時只有接收端程序先運行,才能避免因發送端發送的數據沒法接收,而形成數據丟失。所以,首先須要來完成接收端程序的編寫。

 

package com.oracle.InetAddress;

 

import java.io.IOException;

import java.net.DatagramPacket;

import java.net.DatagramSocket;

import java.net.InetAddress;

import java.util.Scanner;

 

 

//UDPend協議發送端

public class UDPend {

    public static void main(String[] args) throws IOException {

        Scanner  sc=new Scanner(System.in);

        String str=sc.next();

        //1.建立數據包對象,封裝要發送的信息、接收端的ip以及端口號

        byte[] bytes=str.getBytes();

        InetAddress inet=InetAddress.getByName("127.0.0.1");

        DatagramPacket dp=new DatagramPacket(bytes, bytes.length,inet,8888);

        //2.建立DatagramSocket對象

        DatagramSocket ds=new DatagramSocket();

        //3.發送數據包

        ds.send(dp);

        //4.釋放資源

        ds.close();

    }

}

 

 

 

package com.oracle.InetAddress;

 

import java.io.IOException;

import java.net.DatagramPacket;

import java.net.DatagramSocket;

import java.net.SocketException;

 

//UDPRecieve接收端

public class UDPRecieve {

    public static void main(String[] args) throws IOException {

        //建立DatagramSocket對象明確的端口號

        DatagramSocket ds=new DatagramSocket(8888);

        //建立字節數組接收數據

        byte[] bytes=new byte[1024];

        //建立數據包對象

        DatagramPacket dp=new DatagramPacket(bytes,bytes.length);

        //接收數據包

        ds.receive(dp);

        //拆包

        //獲取發送端的ip地址

        String ip=dp.getAddress().getHostAddress();

        //獲取發送端的端口號

        int post=dp.getPort();

        //獲取實際數據的長度

        int length=dp.getLength();

        System.out.println("ip地址爲:"+ip+",端口號爲:"+post+",發送內容爲:"+new String(bytes,0,length));

        //關閉資源

        ds.close();

    }

}

 

 

    TCP通訊

TCP通訊同UDP通訊同樣,都能實現兩臺計算機之間的通訊,通訊的兩端都須要建立socket對象。

區別

UDP中只有發送端和接收端,不區分客戶端與服務器端,計算機之間能夠任意地發送數據

而TCP通訊是嚴格區分客戶端與服務器端的,在通訊時,必須先由客戶端去鏈接服務器端才能實現通訊,服務器端不能夠主動鏈接客戶端,而且服務器端程序須要事先啓動,等待客戶端的鏈接。

 

在JDK中提供了兩個類用於實現TCP程序,一個是ServerSocket類,用於表示服務器端,一個是Socket類,用於表示客戶端。

4.1      ServerSocket

JDK的java.net包中提供了一個ServerSocket類,該類的實例對象能夠實現一個服務器段的程序。經過查閱API文檔可知,ServerSocket類提供了多種構造方法

 

 

使用該構造方法在建立ServerSocket對象時,就能夠將其綁定到一個指定的端口號上(參數port就是端口號)。

ServerSocket的經常使用方法:

 

 

ServerSocket對象負責監聽某臺計算機的某個端口號,在建立ServerSocket對象後,須要繼續調用該對象的accept()方法,接收來自客戶端的請求。當執行了accept()方法以後,服務器端程序會發生阻塞,直到客戶端發出鏈接請求,accept()方法纔會返回一個Scoket對象用於和客戶端實現通訊,程序才能繼續向下執行。

4.2      Socket

查閱API文檔可知Socket類一樣提供了多種構造方法

 

 

使用該構造方法在建立Socket對象時,會根據參數去鏈接在指定地址和端口上運行的服務器程序,其中參數host接收的是一個字符串類型的IP地址。

 

 

該方法在使用上與第二個構造方法相似,參數address用於接收一個InetAddress類型的對象,該對象用於封裝一個IP地址。

在以上Socket的構造方法中,最經常使用的是第一個構造方法。

Socket的經常使用方法:

方法聲明

功能描述

int getPort()

該方法返回一個int類型對象,該對象是Socket對象與服務器端鏈接的端口號

InetAddress getLocalAddress()

該方法用於獲取Socket對象綁定的本地IP地址,並將IP地址封裝成InetAddress類型的對象返回

void close()

該方法用於關閉Socket鏈接,結束本次通訊。在關閉socket以前,應將與socket相關的全部的輸入/輸出流所有關閉,這是由於一個良好的程序應該在執行完畢時釋放全部的資源

InputStream getInputStream()

該方法返回一個InputStream類型的輸入流對象,若是該對象是由服務器端的Socket返回,就用於讀取客戶端發送的數據,反之,用於讀取服務器端發送的數據

OutputStream getOutputStream()

該方法返回一個OutputStream類型的輸出流對象,若是該對象是由服務器端的Socket返回,就用於向客戶端發送數據,反之,用於向服務器端發送數據

在Socket類的經常使用方法中,getInputStream()和getOutStream()方法分別用於獲取輸入流和輸出流。當客戶端和服務端創建鏈接後,數據是以IO流的形式進行交互的,從而實現通訊。

 

 

4.3      簡單的TCP網絡程序

 

/*

 * 實現TCP 服務器程序

 * 表示服務器程序的類 java.net.ServerSocket

 * 構造方法:

 *     ServerSocket(int port)傳遞端口號

 *     很重要的事情:必需要得到客戶端的套接字對象Socket

 *     Socket accept()

 *

 * 1,建立服務器ServerSocket對象(指定服務器端口號)

 * 2,開啓服務器了,等待客戶端的鏈接,當客戶端鏈接後,能夠獲取到鏈接服務器的客戶端Socket對象

 * 3,給客戶端反饋信息

 * 4,關閉流資源

 */

    //服務器程序

package com.oracle.Tcp;

 

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.ServerSocket;

import java.net.Socket;

 

public class TCPServer {

    public static void main(String[] args) throws IOException {

        //建立ServiceScoket對象,接收客戶端

        ServerSocket server=new ServerSocket(8080);

        //調用accept方法,獲取鏈接個人客戶端的Socket對象

        Socket socket=server.accept();

        //獲取輸入字節流

        InputStream in=socket.getInputStream();

        byte[] bytes=new byte[1024];

        int len=in.read(bytes);

        String ip=socket.getLocalAddress().getHostAddress();

        int port=socket.getPort();

        System.out.println("客戶端地址爲:"+ip+",端口號爲:"+port+"發送內容爲:"+new String(bytes,0,len));

        //回覆客戶端

        OutputStream out=socket.getOutputStream();

        out.write("哈哈".getBytes());

        //釋放資源

        server.close();

    }

}

 

/*

 * 實現TCP 客戶端,鏈接到服務器

 * 和服務器實現數據交換

 * 實現TCP客戶端程序的類 java.net.Soket

 * 構造方法

 *    Socket(String host,int port) 傳遞服務器IP和端口號

 *    注意:構造方法只要運行,就會和服務器進行鏈接,鏈接失敗,拋出異常

 

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

 *    做用:將數據輸出,輸出到服務器

 *    InputStream   getInputStream() 返回套接字的輸入流

 *    做用:從服務器端讀取數據

 

 *    客戶端服務器數據交換,必須使用套接字對象Socket中的獲取的IO流,本身new流,不行

 

 * 1,建立客戶端Socket對象,(指定要鏈接的服務器地址與端口號)

 * 2,獲取服務器端的反饋回來的信息

 * 3,關閉流資源

 */

//客戶端程序

package com.oracle.Tcp;

 

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.Socket;

 

 

public class TCPClient {

    public static void main(String[] args) throws IOException {

        //建立Socket對象,鏈接服務器

        Socket scoket=new Socket("127.0.0.1",8080);

        //獲取輸出字節流

        OutputStream out=scoket.getOutputStream();

        //發送數據

        out.write("嚶嚶嚶".getBytes());

        //接收服務器端的回覆

        InputStream in=scoket.getInputStream();

        byte[] bytes=new byte[1024];

        String ip=scoket.getLocalAddress().getHostAddress();

        int port=scoket.getPort();

        int len=in.read(bytes);

       System.out.println("服務端ip地址爲:"+ip+",端口號爲:"+port+",內容爲:"+new String(bytes,0,len));

        scoket.close();

       

       

       

    }

}

 

4.4      文件上傳案例多線程版本

目前大多數服務器都會提供文件上傳的功能,因爲文件上傳須要數據的安全性和完整性,很明顯須要使用TCP協議來實現。接下來經過一個案例來實現圖片上傳的功能

 

 

 

//服務器程序

package com.oracle.WenJian;

 

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.ServerSocket;

import java.net.Socket;

import java.util.Random;

 

public class TCPServer {

    public static void main(String[] args) throws IOException {

        //建立ServerSocket對象,接收客戶端

        ServerSocket server=new ServerSocket(8080);

        //調用accpt方法 建立鏈接並獲取客戶端socket對象

        Socket socket=server.accept();

        //獲取字節輸入流

        InputStream in=socket.getInputStream();

        //明確目的地

        File file=new File("E:\\test1");

        if(!file.exists()){

            file.mkdirs();

        }

        //文件路徑

       

        //文件名:域名+毫秒值+6位隨機數

        String filename="oracle"+System.currentTimeMillis()+new Random().nextInt(999999);

        String path=file.getAbsolutePath()+File.separator+filename+".png";

        FileOutputStream fos=new FileOutputStream(path);

       

        //開始複製

        byte[] bytes=new byte[1024];

        int len=0;

        while ((len=in.read(bytes))!=-1) {

            fos.write(bytes,0,len);

        }

        //回覆客戶端

        OutputStream out=socket.getOutputStream();

        out.write("上傳成功!!".getBytes());

        //釋放資源

        fos.close();

        server.close();

       

       

       

       

    }

}  

 

 

//客戶端程序

package com.oracle.WenJian;

 

 

import java.io.FileInputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.Socket;

 

public class TCPClient {

    public static void main(String[] args) throws IOException {

        //建立Socket對象,鏈接服務器

        Socket socket=new Socket("192.168.1.171",8080);

        //獲取字節流輸出

        OutputStream out=socket.getOutputStream();

        //建立字節輸入流,明確數據源

        FileInputStream fis=new FileInputStream("E:\\test\\b.png");

        byte[] bytes=new byte[1024];

        //開始複製

        int len=0;

        while ((len=fis.read(bytes))!=-1) {

            out.write(bytes,0,len);

           

        }

        //告訴服務器 添加一個結束標記

        socket.shutdownOutput();

        //接收服務器的回覆

        InputStream in=socket.getInputStream();

        len=in.read(bytes);

        System.out.println(new String(bytes,0,len));

        //釋放資源

        fis.close();

        socket.close();

       

    }

}

    類加載器

5.1      類的加載

當程序要使用某個類時,若是該類還未被加載到內存中,則系統會經過加載,鏈接,初始化三步來實現對這個類進行初始化。

加載

就是指將class文件讀入內存,併爲之建立一個Class對象。

任何類被使用時系統都會創建一個Class對象

鏈接

驗證 是否有正確的內部結構,並和其餘類協調一致

準備 負責爲類的靜態成員分配內存,並設置默認初始化值

解析 將類的二進制數據中的符號引用替換爲直接引用

初始化

就是咱們之前講過的初始化步驟

5.2      類初始化時機

1. 建立類的實例

2. 類的靜態變量,或者爲靜態變量賦值

3. 類的靜態方法

4. 使用反射方式來強制建立某個類或接口對應的java.lang.Class對象

5. 初始化某個類的子類

6. 直接使用java.exe命令來運行某個主類

5.3      類加載器

負責將.class文件加載到內存中,併爲之生成對應的Class對象。

雖然咱們不須要關心類加載機制,可是瞭解這個機制咱們就能更好的理解程序的運行

5.4      類加載器的組成

Bootstrap ClassLoader 根類加載器也被稱爲引導類加載器,負責Java核心類的加載

好比System,String等。在JDK中JRE的lib目錄下rt.jar文件中Extension ClassLoader 擴展類加載器

負責JRE的擴展目錄中jar包的加載。

在JDK中JRE的lib目錄下ext目錄

System ClassLoader 系統類加載器

負責在JVM啓動時加載來自java命令的class文件,以及classpath環境變量所指定的jar包和類路徑。

 

經過這些描述就能夠知道咱們經常使用的類,都是由誰來加載完成的。

相關文章
相關標籤/搜索