Java網路程式設計UDP通訊原理

2926143939發表於2021-02-28

前言

繼續今天我們的Java網路程式設計——TCP和UDP通訊

一、TCP和UDP概述

傳輸層通常以TCP和UDP協議來控制端點與端點的通訊

 TCPUDP
協議名稱 傳輸控制協議 使用者資料包協議
是否連線 面向連線的協議。資料必須要建立連線 無連線的協議,每個資料包中都給出完整的地址資訊,因此不需要事先建立傳送方和接受方的連線
是否可靠 可靠協議。確保收方完全地獲取傳送方所傳送的全部資料 不可靠協議。傳送方所傳送的資料包並不一定以相同的次序到達接收方。
可以傳輸的資料大小 傳輸資料大小不受限制。一旦連線建立,雙方可以按統一的格式傳輸大的資料 傳輸資料時是有大小限制的。每個被傳輸的資料包必須限定在64KB之類
資料傳輸方式 IO流 DatagramPacket

二、UDP

1.UDP通訊概述

UDP協議是一種對等通訊的實現,傳送方只需要接受方的IP(地址)和Port(埠),就可以直接向它傳送資料,不需要線連線。每個程式都可以作為伺服器,也可以作為客戶端。UDP是一種無連線的傳輸協議,每個資料包的大小限定在64KB以內。資料包是一個在網路上傳送的獨立資訊,它的到達。到達時間以及內容本身等都不能得到保證。這種傳輸方式是無序的,也不能確保絕對的安全可靠,但它很簡單也具有較高的效率。
使用UDP協議進行資料傳輸是,需要將需要傳輸資料定義為資料包(DatagramPaket),在資料包中指明資料所要到達Socket(主機地址和埠號),然後再將資料包傳送出去。例項化DatagramPacket時使用引數port和沒有使用引數port的區別在與,提供port的一方可以讓別人主動傳送訊息過來,而沒有引數port的則會在傳送訊息時自動繫結一個本地沒有使用的埠。在接收到傳送的資料包(DatagramPaket)時,不僅可以獲取資料,還可以獲得傳送方的IP和Port,這樣就可以向傳送方傳送資料,因此,本質上二者是對等的。

2.UDP通訊特點

1、UDP是一種無連線的協議,每個資料包都是一個獨立的資訊,包括完整的原地址或目的地址,它在網路上任何可能的路徑傳往目的地,因此能否到達目的地,到達目的地的時間以及內容的正確性都是不能被保證的。
2、UDP不屬於連線型協議,因而具有資源消耗小,處理速度快的優點,所以通常音訊視訊和普通資料在傳輸時使用UDP較多,因為它們即使偶爾丟一兩個資料包,也不會對接收結果產生太大的影響。
程式碼如下(示例):

3.UDP通訊傳輸實現的基石

UDP通訊的Socket使用DatagramSocket類實現,資料包使用DatagramPaket實現

3.1、DatagramPake常用方法

InetAddress getAddress()得到傳送方IP地址
int getPort() 得到傳送方的埠號
byte[] getData() 返回接收緩衝區,這是一個byte[]
int getLength() 接收位元組的真實大小,通常用於從byte[]中提取出有效資料
int getOffset() 返回將要傳送或則接收的資料偏移量

3.2、DatagramSocket常用方法

DatagramSocket()空建構函式
DatagramSocket(int port) 指定通訊埠
void receive(DatagramPaket p) 接收資料包
void send(DatagramPaket p) 傳送資料包
void close() 關閉Socket

4.UDP通訊實現原理

無論一個UDP通訊程式的功能多麼功能齊全,程式多麼複雜,七基本結構都是一樣的,都包括以下四個基本步驟
1、在接收端指定一個埠號來建立DatagramSocket,然後建立一個接收資料包(DatagramPaket),使用recevie方法等待傳送方請求報文,這將阻塞伺服器執行緒
2、在傳送方建立一個DatagramSocket,使用接收方的IP和埠來建立傳送資料包(DatagramPaket),使用send方法傳送。現在接收方的recevie方法被喚醒,同時會將傳送方的資料包內容填充到接收方的DatagramPaket中。
3、接收方從傳送方的資料包中獲得傳送方的IP和埠,使用它們構造一個傳送資料包,然後傳送給傳送方,這樣就實現了傳送方和接收方的通訊
4、在通訊完成後,在客服端和服務端中分別關閉Socket
在這裡插入圖片描述

5.UDP通訊原理(程式碼實現)

程式碼如下(傳送端):

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

public class SendMessage {

	public static void main(String[] args) throws Exception {
		// 建立傳送端Socket物件
		DatagramSocket sendSocket = new DatagramSocket();
		// 準備需要傳送的資料
		String message = "hello";
		// 建立一個緩衝區
		byte[] messageByte = message.getBytes();
		// 獲取緩衝區中資料的真實長度
		int messageLen = message.length();
		// InetAddress例項化獲取本機通訊地址
		InetAddress address = InetAddress.getLocalHost();
		// 設定通訊埠號
		int port = 12345;
		// 打包資料
		DatagramPacket sendPacket = new DatagramPacket(messageByte, messageLen, address, port);
		// 傳送資料
		sendSocket.send(sendPacket);
		// 傳送端等待接收端成功接收資訊後返回的回應
		// 建立一個緩衝區,容量儘量設定大一點因為不知道傳送過來的資訊有多大
		byte[] recevieByte = new byte[1024*10];
		int len = recevieByte.length;
		// 接收資料包
		DatagramPacket receivePacket = new DatagramPacket(recevieByte, len);
		// 接收資料
		sendSocket.receive(receivePacket);
		// 獲取接收端傳送過來的真實長度以及資料
		byte[] data = receivePacket.getData();
		int length = receivePacket.getLength();
		String receiveData = new String(data,0,length);
		// 獲取傳送者的IP
		address = receivePacket.getAddress();
		String ip = address.getHostAddress();
		System.out.println("接收來自:"+ip+"的資料,內容是:"+receiveData);
		// 關閉資源
		sendSocket.close();	
	}
}

程式碼如下(接收端):

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

public class RecevieMessage {

	public static void main(String[] args) throws Exception {
		// 接收訊息的埠(與傳送端保持一致)
		int port = 12345;
		DatagramSocket recevieSocket = new DatagramSocket(port);
		// 設定緩衝區接收發過來的資訊
		byte[] receiveByte = new byte[1024*10];
		int len = receiveByte.length;
		// 接收資料包
		DatagramPacket receviePacket = new DatagramPacket(receiveByte, len);
		// 接收資料
		recevieSocket.receive(receviePacket);
		// 獲取實際接收到的資料及其大小
		byte[] data = receviePacket.getData();
		int length = receviePacket.getLength();
		String receiveData = new String(data,0,length);
		// 獲取傳送者的IP
		InetAddress address = receviePacket.getAddress();
		String ip = address.getHostAddress();
		System.out.println("接收來自:"+ip+"的資料,內容是:"+receiveData);
		// 接收端接收到資訊後傳送一條確認接收的訊息到傳送端
		String message = "OK";
		byte[] messageByte = message.getBytes();
		int messageLength = message.length();
		// 從已收到的資料包中獲取IP和port
		address = receviePacket.getAddress();
		int port1 = receviePacket.getPort();
		//構造新資料包
		DatagramPacket sendPacket = new DatagramPacket(messageByte, messageLength, address, port1);
		// 傳送資料
		recevieSocket.send(sendPacket);
		// 關閉資源
		recevieSocket.close();
	}
}

傳送端輸出結果:
在這裡插入圖片描述
接收端輸出結果:
在這裡插入圖片描述

總結

**注意:**在傳送端與接收端啟動測試時最好最好先啟動接收端,因為這樣才能確保資訊能傳送出去,接收端鞥接收到資訊。

相關文章