前面介紹瞭如何經過Socket接口傳輸文本與文件,在示例代碼中,Socket客戶端得先調用connect方法鏈接服務端,確認雙方成功連上後才能繼續運行後面的代碼,這種確認機制確保客戶端與服務端的的確確成功鏈接了,於是是可靠的網絡鏈接,而且該可靠鏈接屬於TCP鏈接。爲啥這麼說呢?由於TCP協議(全稱「Transmission Control Protocol」,傳輸控制協議)不只是一種傳輸層的通訊協議,並且它具有面向可靠鏈接、以及基於字節流兩大特徵。以前聯合Socket與ServerSocket實現消息通訊的過程,正是聽從TCP協議的精神
雖然可靠鏈接可以保證必定會把信息送達對方,可是有時須要批量向一羣目標設備發送消息,也就是俗稱的「羣發」,假若每一個設備都經歷創建鏈接、發送消息、關閉鏈接三個步驟,整個羣發操做的資源開銷將是巨大的。鑑於羣發功能通常爲單向過程,消息發送方既不關心那些接收方是否收到消息,也不期望那些接收方會有什麼反饋結果,總之消息發送方就像電臺作廣播那樣,在固定的頻率波段發送信息,它才無論別人的收音機有沒有開着、有沒有接收這個頻道,只有收音機開着且調至對應的頻道,方能收到該電臺的廣播節目。像這樣的廣播功能用到了傳輸層的另外一種UDP協議(全稱「User Datagram Protocol」,用戶數據報協議),因爲UDP並不是可靠鏈接,它只管扔沙包,而無論對方有沒有接到沙包,所以實現過程相較TCP要更簡單,畢竟隨便丟東西不費多少勁兒。
就UDP協議而言,Java給出的實現工具包括數據包套接字DatagramSocket和數據包裹DatagramPacket。其中DatagramSocket提供了設備間的數據交互動做,它的主要方法說明以下:
構造方法:對於服務端來講,構造方法須要指定待偵聽的端口號;對於客戶端來講,構造方法無需任何參數。
receive:該方法用於服務端接收數據。
send:該方法用於客戶端發送數據。
close:關閉數據包套接字。
注意上面的receive和send兩個方法,它們的輸入參數類型爲DatagramPacket,也就是說,必須先將數據封裝爲DatagramPacket格式,才能在UDO的服務端與客戶端之間傳輸。下面是DatagramPacket的主要方法說明:
用於服務端的構造方法:此時構造方法只有兩個參數,分別爲字節數組及其長度。
用於客戶端的構造方法:此時構造方法擁有四個參數,依次爲字節數組、數組長度、數據要發往的服務器InetAddress地址、服務器的端口號。
getData:獲取數據包裹裏的字節數組。
getOffset:獲取數據的起始偏移。
getLength:獲取數據的長度。html
接下來舉個簡單的應用案例,採起UDP協議在設備之間傳輸文本消息,此時的UDP服務端代碼示例以下:數組
//演示Socket服務器的運行(UDP協議的不可靠鏈接) public class TestUdpServer { private static final int UDP_PORT = 61000; // UDP傳輸專用端口 public static void main(String[] args) { startUdpServer(); // 啓動UDP服務器接收文本消息 } // 啓動UDP服務器接收文本消息 private static void startUdpServer() { PrintUtils.print("UDP服務器已啓動"); // 建立一個監聽指定端口的DatagramSocket對象 try (DatagramSocket socket = new DatagramSocket(UDP_PORT)) { byte[] data = new byte[1024]; // 接收數據的字節數組 // 建立一個DatagramPacket對象,並指定數據包的字節數組及其大小 DatagramPacket packet = new DatagramPacket(data, data.length); while (true) { // 持續偵聽 socket.receive(packet); // 接收到了數據包 // 把收到的數據轉換爲字符串。字符串構造方法的三個參數依次爲: // 已收到的數據、起始偏移、數據的長度。 String message = new String(packet.getData(), packet.getOffset(), packet.getLength()); PrintUtils.print("UDP服務器收到消息:" + message); } } catch (Exception e) { e.printStackTrace(); } } }
原來UDP方式的服務端代碼如此簡潔,UDP客戶端的代碼一樣簡約,即使是發送兩條消息的完整代碼也只有如下數行:服務器
//演示Socket客戶端的運行(UDP協議的不可靠鏈接) public class TestUdpClient { // 如下爲Socket服務器的IP和端口,根據實際狀況修改 private static final String SOCKET_IP = "192.168.1.8"; private static final int UDP_PORT = 61000; // UDP傳輸專用端口 public static void main(String[] args) { startUdpClient("Hello World"); // 啓動UDP客戶端發送文本消息 startUdpClient("你好,世界"); // 啓動UDP客戶端發送文本消息 } // 啓動UDP客戶端發送文本消息 private static void startUdpClient(String message) { PrintUtils.print("UDP客戶端發送消息:" + message); // 建立一個DatagramSocket對象 try (DatagramSocket socket = new DatagramSocket()) { // 根據IP地址得到對應的網絡地址對象 InetAddress serverAddress = InetAddress.getByName(SOCKET_IP); byte data[] = message.getBytes(); // 把字符串轉換爲字節數組 // 建立一個DatagramPacket對象,構造方法的四個參數依次爲: // 待發送的數據、數據的長度、服務器的網絡地址、服務器的端口號。 DatagramPacket packet = new DatagramPacket(data, data.length, serverAddress, UDP_PORT); socket.send(packet); // 向服務器發送數據包 } catch (Exception e) { e.printStackTrace(); } } }
而後前後運行服務端與客戶端的測試代碼,觀察到的客戶端日誌以下:網絡
12:16:12.316 main UDP客戶端發送消息:Hello World 12:16:12.366 main UDP客戶端發送消息:你好,世界
同時觀察到下面的服務端日誌:socket
12:15:46.998 main UDP服務器已啓動 12:16:12.366 main UDP服務器收到消息:Hello World 12:16:12.368 main UDP服務器收到消息:你好,世界
根據以上的客戶端日誌以及服務端日誌,可知經過UDP協議也成功完成了文本傳輸。工具
更多Java技術文章參見《Java開發筆記(序)章節目錄》測試