主要内容
1,網絡通信協定
2,UDP通信
3,TCP通信
網絡通信協定
通過計算機網絡可以使多台計算機實作連接配接,位于同一個網絡中的計算機在進行連接配接和通信時需要遵守一定的規則,這就好比在道路中行駛的汽車一定要遵守交通規則一樣。在計算機網絡中,這些連接配接和通信的規則被稱為網絡通信協定,它對資料的傳輸格式、傳輸速率、傳輸步驟等做了統一規定,通信雙方必須同時遵守才能完成資料交換。
網絡通信協定有很多種,目前應用最廣泛的是TCP/IP協定(Transmission Control Protocal/Internet Protoal傳輸控制協定/英特網互聯協定),它是一個包括TCP協定和IP協定,UDP(User Datagram Protocol)協定和其它一些協定的協定組,在學習具體協定之前首先了解一下TCP/IP協定組的層次結構。
在進行資料傳輸時,要求發送的資料與收到的資料完全一樣,這時,就需要在原有的資料上添加很多資訊,以保證資料在傳輸過程中資料格式完全一緻。TCP/IP協定的層次結構比較簡單,共分為四層.
TCP/IP協定中的四層分别是應用層、傳輸層、網絡層和鍊路層,每層分别負責不同的通信功能,接下來針對這四層進行詳細地講解。
鍊路層:鍊路層是用于定義實體傳輸通道,通常是對某些網絡連接配接裝置的驅動協定,例如針對光纖、網線提供的驅動。
網絡層:網絡層是整個TCP/IP協定的核心,它主要用于将傳輸的資料進行分組,将分組資料發送到目标計算機或者網絡。
傳輸層:主要使網絡程式進行通信,在進行網絡通信時,可以采用TCP協定,也可以采用UDP協定。
應用層:主要負責應用程式的協定,例如HTTP協定、FTP協定等。
1.1IP位址與端口号
要想使網絡中的計算機能夠進行通信,必須為每台計算機指定一個辨別号,通過這個辨別号來指定接受資料的計算機或者發送資料的計算機。
在TCP/IP協定中,這個辨別号就是IP位址,它可以唯一辨別一台計算機,目前,IP位址廣泛使用的版本是IPv4,它是由4個位元組大小的二進制數來表示,如:00001010000000000000000000000001。由于二進制形式表示的IP位址非常不便記憶和處理,是以通常會将IP位址寫成十進制的形式,每個位元組用一個十進制數字(0-255)表示,數字間用符号“.”分開,如 “192.168.1.100”。
随着計算機網絡規模的不斷擴大,對IP位址的需求也越來越多,IPV4這種用4個位元組表示的IP位址面臨枯竭,是以IPv6 便應運而生了,IPv6使用16個位元組表示IP位址,它所擁有的位址容量約是IPv4的8×1028倍,達到2128個(算上全零的),這樣就解決了網絡位址資源數量不夠的問題。
通過IP位址可以連接配接到指定計算機,但如果想通路目标計算機中的某個應用程式,還需要指定端口号。在計算機中,不同的應用程式是通過端口号區分的。端口号是用兩個位元組(16位的二進制數)表示的,它的取值範圍是0~65535,其中,0~1023之間的端口号用于一些知名的網絡服務和應用,使用者的普通應用程式需要使用1024以上的端口号,進而避免端口号被另外一個應用或服務所占用。
位于網絡中一台計算機可以通過IP位址去通路另一台計算機,并通過端口号通路目标計算機中的某個應用程式。
1.2InetAddress
JDK中提供了一個InetAdderss類,該類用于封裝一個IP位址,并提供了一系列與IP位址相關的方法
InetAddress的四個常用方法。其中,前兩個方法用于獲得該類的執行個體對象,第一個方法用于獲得表示指定主機的InetAddress對象,第二個方法用于獲得表示本地的InetAddress對象。通過InetAddress對象便可擷取指定主機名,IP位址等,接下來通過一個案例來示範InetAddress的常用方法,如下所示。
public class Inet {
public static void main(String[] args) throws UnknownHostException {
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost);
System.out.println(localHost.getHostAddress());
System.out.println(localHost.getHostName());
InetAddress name = InetAddress.getByName("www.baidu.com");
System.out.println(name);
}
}
UDP與TCP協定
UDP協定
UDP是無連接配接通信協定,即在資料傳輸時,資料的發送端和接收端不建立邏輯連接配接。簡單來說,當一台計算機向另外一台計算機發送資料時,發送端不會确認接收端是否存在,就會發出資料,同樣接收端在收到資料時,也不會向發送端回報是否收到資料。
由于使用UDP協定消耗資源小,通信效率高,是以通常都會用于音頻、視訊和普通資料的傳輸例如視訊會議都使用UDP協定,因為這種情況即使偶爾丢失一兩個資料包,也不會對接收結果産生太大影響。
但是在使用UDP協定傳送資料時,由于UDP的面向無連接配接性,不能保證資料的完整性,是以在傳輸重要資料時不建議使用UDP協定。
TCP協定
TCP協定是面向連接配接的通信協定,即在傳輸資料前先在發送端和接收端建立邏輯連接配接,然後再傳輸資料,它提供了兩台計算機之間可靠無差錯的資料傳輸。在TCP連接配接中必須要明确用戶端與伺服器端,由用戶端向服務端發出連接配接請求,每次連接配接的建立都需要經過“三次握手”。第一次握手,用戶端向伺服器端發出連接配接請求,等待伺服器确認,第二次握手,伺服器端向用戶端回送一個響應,通知用戶端收到了連接配接請求,第三次握手,用戶端再次向伺服器端發送确認資訊,确認連接配接。
由于TCP協定的面向連接配接特性,它可以保證傳輸資料的安全性,是以是一個被廣泛采用的協定,例如在下載下傳檔案時,如果資料接收不完整,将會導緻檔案資料丢失而不能被打開,是以,下載下傳檔案時必須采用TCP協定。
UDP通信
JDK了解下
DatagramPacket類
在通信時發送端和接收端不用建立連接配接。UDP通信的過程就像是貨運公司在兩個碼頭間發送貨物一樣。在碼頭發送和接收貨物時都需要使用集裝箱來裝載貨物,UDP通信也是一樣,發送和接收的資料也需要使用“集裝箱”進行打包,為此JDK中提供了一個DatagramPacket類,該類的執行個體對象就相當于一個集裝箱,用于封裝UDP通信中發送或者接收的資料。
DatagramSocket類
DatagramPacket資料包的作用就如同是“集裝箱”,可以将發送端或者接收端的資料封裝起來。然而運輸貨物隻有“集裝箱”是不夠的,還需要有碼頭。在程式中需要實作通信隻有DatagramPacket資料包也同樣不行,為此JDK中提供的一個DatagramSocket類。DatagramSocket類的作用就類似于碼頭,使用這個類的執行個體對象就可以發送和接收DatagramPacket資料包,
UDP網絡程式
public class UDPsent {
public static void main(String[] args) throws IOException {
//建立DatagramSocket對象
DatagramSocket send = new DatagramSocket();
//建立DatagramPacket對象,并封裝資料
byte[] buf = "hello 請接收資料".getBytes();
int length = buf.length;
InetAddress address = InetAddress.getByName("172.18.21.211");
DatagramPacket dp = new DatagramPacket(buf, length,address,);
//發送資料
send.send(dp);
//釋放流資源
send.close();
}
}
public class UDPreceive {
public static void main(String[] args) throws IOException {
//建立DatagramSocket對象,比指定發送端端口号
DatagramSocket receive = new DatagramSocket();
//建立DatagramPacket對象,建立一個空的倉庫
byte[] buf = new byte[];
DatagramPacket dp = new DatagramPacket(buf,);
//接收資料存儲到DatagramPacket對象中
receive.receive(dp);
InetAddress address = dp.getAddress();
System.out.println(address);
byte[] data = dp.getData();
int length = dp.getLength();
System.out.println(new String(data,,length));
receive.close();
}
}
TCP通信
TCP通信同UDP通信一樣,都能實作兩台計算機之間的通信,通信的兩端都需要建立socket對象。
差別在于,UDP中隻有發送端和接收端,不區分用戶端與伺服器端,計算機之間可以任意地發送資料。
而TCP通信是嚴格區分用戶端與伺服器端的,在通信時,必須先由用戶端去連接配接伺服器端才能實作通信,伺服器端不可以主動連接配接用戶端,并且伺服器端程式需要事先啟動,等待用戶端的連接配接。
在JDK中提供了兩個類用于實作TCP程式,一個是ServerSocket類,用于表示伺服器端,一個是Socket類,用于表示用戶端。
通信時,首先建立代表伺服器端的ServerSocket對象,該對象相當于開啟一個服務,并等待用戶端的連接配接,然後建立代表用戶端的Socket對象向伺服器端發出連接配接請求,伺服器端響應請求,兩者建立連接配接開始通信。
TCP網絡程式
要實作TCP通信需要建立一個伺服器端程式和一個用戶端程式,為了保證資料傳輸的安全性,首先需要實作伺服器端程式
public class TCPserver {
public static void main(String[] args)throws IOException {
//建立伺服器ServerSocet對象,指定伺服器端口
ServerSocket ss = new ServerSocket();
//開啟伺服器 等待用戶端的連結 當客戶連接配接後 可以擷取到連接配接伺服器的用戶端Socket對象
Socket accept = ss.accept();
//給用戶端回報資訊
//a 擷取用戶端的輸出流
OutputStream out = accept.getOutputStream();
//b在伺服器端 通過用戶端的輸出流寫資料給用戶端
out.write("你已經連接配接上伺服器".getBytes());
out.close();
ss.close();
}
}
完成了伺服器端程式的編寫,接下來編寫用戶端程式。
public class TCPClint {
public static void main(String[] args)throws IOException {
//建立用戶端Socket對象 指定要連接配接的伺服器端位址與端口号
Socket socket = new Socket("172.18.21.211", );
//擷取伺服器端的回報回來的資訊
InputStream in = socket.getInputStream();
byte[] buf = new byte[];
int i = in.read(buf);
//顯示資料
System.out.println(new String(buf,,i));
in.close();
socket.close();
}
}
檔案上傳案例
目前大多數伺服器都會提供檔案上傳的功能,由于檔案上傳需要資料的安全性和完整性,很明顯需要使用TCP協定來實作。接下來通過一個案例來實作圖檔上傳的功能。
●首先編寫伺服器端程式,用來接收圖檔。
public class TCPServer {
public static void main(String[] args) throws IOException {
//,建立伺服器,等待用戶端連接配接
ServerSocket serverSocket = new ServerSocket();
Socket clientSocket = serverSocket.accept();
//顯示哪個用戶端Socket連接配接上了伺服器
InetAddress ipObject = clientSocket.getInetAddress();//得到IP位址對象
String ip = ipObject.getHostAddress(); //得到IP位址字元串
System.out.println("小樣,抓到你了,連接配接我!!" + "IP:" + ip);
//,擷取Socket的輸入流
InputStream in = clientSocket.getInputStream();
//,建立目的地的位元組輸出流 D:\\upload\\.().jpg
BufferedOutputStream fileOut = new BufferedOutputStream(new FileOutputStream("D:\\upload\\192.168.74.58(1).jpg"));
//,把Socket輸入流中的資料,寫入目的地的位元組輸出流中
byte[] buffer = new byte[];
int len = -;
while((len = in.read(buffer)) != -){
//寫入目的地的位元組輸出流中
fileOut.write(buffer, , len);
}
//-----------------回報資訊---------------------
//10,擷取Socket的輸出流, 作用:寫回報資訊給用戶端
OutputStream out = clientSocket.getOutputStream();
//11,寫回報資訊給用戶端
out.write("圖檔上傳成功".getBytes());
out.close();
fileOut.close();
in.close();
clientSocket.close();
//serverSocket.close();
●編寫用戶端,完成上傳圖檔
public class TCPClient {
public static void main(String[] args) throws IOException {
//,建立用戶端Socket,連接配接伺服器
Socket socket = new Socket("192.168.74.58", );
//,擷取Socket流中的輸出流,功能:用來把資料寫到伺服器
OutputStream out = socket.getOutputStream();
//,建立位元組輸入流,功能:用來讀取資料源(圖檔)的位元組
BufferedInputStream fileIn = new BufferedInputStream(new FileInputStream("D:\\NoDir\\test.jpg"));
//,把圖檔資料寫到Socket的輸出流中(把資料傳給伺服器)
byte[] buffer = new byte[];
int len = -;
while ((len = fileIn.read(buffer)) != -){
//把資料寫到Socket的輸出流中
out.write(buffer, , len);
}
//6,用戶端發送資料完畢,結束Socket輸出流的寫入操作,告知伺服器端
socket.shutdownOutput();
//-----------------回報資訊---------------------
//12,擷取Socket的輸入流 作用: 讀回報資訊
InputStream in = socket.getInputStream();
//13,讀回報資訊
byte[] info = new byte[1024];
//把回報資訊存儲到info數組中,并記錄位元組個數
int length = in.read(info);
//顯示回報結果
System.out.println( new String(info, 0, length) );
//關閉流
in.close();
fileIn.close();
out.close();
socket.close();
}
}