## Java編程那些事兒105——網絡編程技術4
陳躍峰
出自:[http://blog.csdn.net/mailbomb](http://blog.csdn.net/mailbomb)
### 13.2.4 UDP編程
網絡通訊的方式除了TCP方式以外,還有一種實現的方式就是UDP方式。UDP(User Datagram Protocol),中文意思是用戶數據報協議,方式類似于發短信息,是一種物美價廉的通訊方式,使用該種方式無需建立專用的虛擬連接,由于無需建立專用的連接,所以對于服務器的壓力要比TCP小很多,所以也是一種常見的網絡編程方式。但是使用該種方式最大的不足是傳輸不可靠,當然也不是說經常丟失,就像大家發短信息一樣,理論上存在收不到的可能,這種可能性可能是1%,反正比較小,但是由于這種可能的存在,所以平時我們都覺得重要的事情還是打個電話吧(類似TCP方式),一般的事情才發短信息(類似UDP方式)。網絡編程中也是這樣,必須要求可靠傳輸的信息一般使用TCP方式實現,一般的數據才使用UDP方式實現。
UDP方式的網絡編程也在Java語言中獲得了良好的支持,由于其在傳輸數據的過程中不需要建立專用的連接等特點,所以在Java API中設計的實現結構和TCP方式不太一樣。當然,需要使用的類還是包含在java.net包中。
在Java API中,實現UDP方式的編程,包含客戶端網絡編程和服務器端網絡編程,主要由兩個類實現,分別是:
1.? DatagramSocket
DatagramSocket類實現“網絡連接”,包括客戶端網絡連接和服務器端網絡連接。雖然UDP方式的網絡通訊不需要建立專用的網絡連接,但是畢竟還是需要發送和接收數據,DatagramSocket實現的就是發送數據時的發射器,以及接收數據時的監聽器的角色。類比于TCP中的網絡連接,該類既可以用于實現客戶端連接,也可以用于實現服務器端連接。
2.? DatagramPacket
DatagramPacket類實現對于網絡中傳輸的數據封裝,也就是說,該類的對象代表網絡中交換的數據。在UDP方式的網絡編程中,無論是需要發送的數據還是需要接收的數據,都必須被處理成DatagramPacket類型的對象,該對象中包含發送到的地址、發送到的端口號以及發送的內容等。其實DatagramPacket類的作用類似于現實中的信件,在信件中包含信件發送到的地址以及接收人,還有發送的內容等,郵局只需要按照地址傳遞即可。在接收數據時,接收到的數據也必須被處理成DatagramPacket類型的對象,在該對象中包含發送方的地址、端口號等信息,也包含數據的內容。和TCP方式的網絡傳輸相比,IO編程在UDP方式的網絡編程中變得不是必須的內容,結構也要比TCP方式的網絡編程簡單一些。
下面介紹一下UDP方式的網絡編程中,客戶端和服務器端的實現步驟,以及通過基礎的示例演示UDP方式的網絡編程在Java語言中的實現方式。
UDP方式的網絡編程,編程的步驟和TCP方式類似,只是使用的類和方法存在比較大的區別,下面首先介紹一下UDP方式的網絡編程客戶端實現過程。
UDP客戶端編程涉及的步驟也是4個部分:建立連接、發送數據、接收數據和關閉連接。
首先介紹UDP方式的網絡編程中建立連接的實現。其中UDP方式的建立連接和TCP方式不同,只需要建立一個連接對象即可,不需要指定服務器的IP和端口號碼。實現的代碼為:
DatagramSocket ds = new DatagramSocket();
這樣就建立了一個客戶端連接,該客戶端連接使用系統隨機分配的一個本地計算機的未用端口號。在該連接中,不指定服務器端的IP和端口,所以UDP方式的網絡連接更像一個發射器,而不是一個具體的連接。
當然,可以通過制定連接使用的端口號來創建客戶端連接。
DatagramSocket ds = new DatagramSocket(5000);
這樣就是使用本地計算機的5000號端口建立了一個連接。一般在建立客戶端連接時沒有必要指定端口號碼。
接著,介紹一下UDP客戶端編程中發送數據的實現。在UDP方式的網絡編程中,IO技術不是必須的,在發送數據時,需要將需要發送的數據內容首先轉換為byte數組,然后將數據內容、服務器IP和服務器端口號一起構造成一個DatagramPacket類型的對象,這樣數據的準備就完成了,發送時調用網絡連接對象中的send方法發送該對象即可。例如將字符串“Hello”發送到IP是127.0.0.1,端口號是10001的服務器,則實現發送數據的代碼如下:
~~~
???????? ???????? String s = “Hello”;
?????????????????? String host = “127.0.0.1”;
?????????????????? int port = 10001;
???????? ???????? //將發送的內容轉換為byte數組
?????????????????? byte[] b = s.getBytes();
?????????????????? //將服務器IP轉換為InetAddress對象
?????????????????? InetAddress server = InetAddress.getByName(host);
?????????????????? //構造發送的數據包對象
?????????????????? DatagramPacket sendDp = new DatagramPacket(b,b.length,server,port);
?????????????????? //發送數據
?????????????????? ds.send(sendDp);
~~~
在該示例代碼中,不管發送的數據內容是什么,都需要轉換為byte數組,然后將服務器端的IP地址構造成InetAddress類型的對象,在準備完成以后,將這些信息構造成一個DatagramPacket類型的對象,在UDP編程中,發送的數據內容、服務器端的IP和端口號,都包含在DatagramPacket對象中。在準備完成以后,調用連接對象ds的send方法把DatagramPacket對象發送出去即可。
按照UDP協議的約定,在進行數據傳輸時,系統只是盡全力傳輸數據,但是并不保證數據一定被正確傳輸,如果數據在傳輸過程中丟失,那就丟失了。
UDP方式在進行網絡通訊時,也遵循“請求-響應”模型,在發送數據完成以后,就可以接收服務器端的反饋數據了。
下面介紹一下UDP客戶端編程中接收數據的實現。當數據發送出去以后,就可以接收服務器端的反饋信息了。接收數據在Java語言中的實現是這樣的:首先構造一個數據緩沖數組,該數組用于存儲接收的服務器端反饋數據,該數組的長度必須大于或等于服務器端反饋的實際有效數據的長度。然后以該緩沖數組為基礎構造一個DatagramPacket數據包對象,最后調用連接對象的receive方法接收數據即可。接收到的服務器端反饋數據存儲在DatagramPacket類型的對象內部。實現接收數據以及顯示服務器端反饋內容的示例代碼如下:
~~~
?????????????????? //構造緩沖數組
?????????????????? byte[] data = new byte[1024];
?????????????????? //構造數據包對象
?????????????????? DatagramPacket received = new DatagramPacket(data,data.length);
?????????????????? //接收數據
?????????????????? ds.receive(receiveDp);
?????????????????? //輸出數據內容
?????????????????? byte[] b = receiveDp.getData();? //獲得緩沖數組
?????????????????? int len = receiveDp.getLength(); //獲得有效數據長度
?????????????????? String s = new String(b,0,len);
?????????????????? System.out.println(s);
~~~
在該代碼中,首先構造緩沖數組data,這里設置的長度1024是預估的接收到的數據長度,要求該長度必須大于或等于接收到的數據長度,然后以該緩沖數組為基礎,構造數據包對象,使用連接對象ds的receive方法接收反饋數據,由于在Java語言中,除String以外的其它對象都是按照地址傳遞,所以在receive方法內部可以改變數據包對象receiveDp的內容,這里的receiveDp的功能和返回值類似。數據接收到以后,只需要從數據包對象中讀取出來就可以了,使用DatagramPacket對象中的getData方法可以獲得數據包對象的緩沖區數組,但是緩沖區數組的長度一般大于有效數據的長度,換句話說,也就是緩沖區數組中只有一部分數據是反饋數據,所以需要使用DatagramPacket對象中的getLength方法獲得有效數據的長度,則有效數據就是緩沖數組中的前有效數據長度個內容,這些才是真正的服務器端反饋的數據的內容。
UDP方式客戶端網絡編程的最后一個步驟就是關閉連接。雖然UDP方式不建立專用的虛擬連接,但是連接對象還是需要占用系統資源,所以在使用完成以后必須關閉連接。關閉連接使用連接對象中的close方法即可,實現的代碼如下:
ds.close();
需要說明的是,和TCP建立連接的方式不同,UDP方式的同一個網絡連接對象,可以發送到達不同服務器端IP或端口的數據包,這點是TCP方式無法做到的。
介紹完了UDP方式客戶端網絡編程的基礎知識以后,下面再來介紹一下UDP方式服務器端網絡編程的基礎知識。
UDP方式網絡編程的服務器端實現和TCP方式的服務器端實現類似,也是服務器端監聽某個端口,然后獲得數據包,進行邏輯處理以后將處理以后的結果反饋給客戶端,最后關閉網絡連接,下面依次進行介紹。
首先UDP方式服務器端網絡編程需要建立一個連接,該連接監聽某個端口,實現的代碼為:
DatagramSocket ds = new DatagramSocket(10010);
由于服務器端的端口需要固定,所以一般在建立服務器端連接時,都指定端口號。例如該示例代碼中指定10010端口為服務器端使用的端口號,客戶端端在連接服務器端時連接該端口號即可。
接著服務器端就開始接收客戶端發送過來的數據,其接收的方法和客戶端接收的方法一直,其中receive方法的作用類似于TCP方式中accept方法的作用,該方法也是一個阻塞方法,其作用是接收數據。
接收到客戶端發送過來的數據以后,服務器端對該數據進行邏輯處理,然后將處理以后的結果再發送給客戶端,在這里發送時就比客戶端要麻煩一些,因為服務器端需要獲得客戶端的IP和客戶端使用的端口號,這個都可以從接收到的數據包中獲得。示例代碼如下:
~~~
???? //獲得客戶端的IP
???? InetAddress clientIP = receiveDp.getAddress();
???????? //獲得客戶端的端口號
???????? Int clientPort = receiveDp.getPort();
~~~
使用以上代碼,就可以從接收到的數據包對象receiveDp中獲得客戶端的IP地址和客戶端的端口號,這樣就可以在服務器端中將處理以后的數據構造成數據包對象,然后將處理以后的數據內容反饋給客戶端了。
最后,當服務器端實現完成以后,關閉服務器端連接,實現的方式為調用連接對象的close方法,示例代碼如下:
ds.close();
介紹完了UDP方式下的客戶端編程和服務器端編程的基礎知識以后,下面通過一個簡單的示例演示UDP網絡編程的基本使用。
?
- 前言
- (1)序言
- (2)程序設計是什么?
- (3)你適合學習程序設計嗎?
- (4)如何學好程序設計?
- (5)程序設計介紹小結
- (6)計算機軟件基本概念
- (7)進制的概念
- (8)計算機內部的數據表達
- (9)網絡編程基礎
- (10)Java語言簡介
- (11)JDK的獲得、安裝和配置
- (12)第一個HelloWorld程序
- (13)Eclipse基本使用
- (14)Eclipse基礎使用進階
- (15)如何學好Java語法
- (16)代碼框架、關鍵字和標識符
- (17)基本數據類型
- (18)變量和常量
- (19)數據類型轉換
- (20)空白、語句結束和注釋
- (21)算術運算符
- (22)比較運算符
- (23)邏輯運算符
- (24)賦值運算符
- (25)位運算符
- (26)移位運算符
- (27)其它運算符
- (28)運算符優先級
- (29)表達式
- (30)流程控制基礎
- (31)if語句語法(1)
- (32)if語句語法(2)
- (33)if語句語法(3)
- (34)switch語句語法
- (35)while語句語法
- (36)do-while語句語法
- (37)for語句語法
- (38)break和continue語句
- (39)流程控制綜合示例1
- (40)流程控制綜合示例2
- (41)流程控制綜合示例3
- (42)流程控制綜合練習
- (43)數組概述
- (44)數組基礎語法
- (45)數組使用示例1
- (46)數組使用示例2
- (47)數組使用示例3
- (48)多維數組基礎
- (49)多維數組使用示例1
- (50)多維數組使用示例2
- (51)多維數組練習
- (52)方法聲明
- (53)方法聲明示例
- (54)方法調用
- (55)方法重載和參數傳遞
- (56)方法練習
- (57)面向對象基礎
- (58)類(一)
- (59)類(二)
- (60)對象
- (61)面向對象設計方法和面向對象特性(一)
- (62)繼承(二)
- (63)多態性
- (64)訪問控制符、修飾符和其它關鍵字
- (65)static修飾符
- (66)final修飾符
- (67)this和super
- (68)抽象類和接口(一)
- (69)抽象類和接口(二)
- (70)抽象類和接口(三)
- (71)內部類簡介
- (72)包的概念
- (73)JDK文檔使用
- (74)java.lang包介紹1
- (75)String類使用
- (76)StringBuffer類和System類
- (77)包裝類
- (78)時間和日期處理
- (79)Random隨機處理
- (80)集合框架簡述
- (81)異常處理概述
- (82)異常處理語法1
- (83)異常處理語法2
- (84)IO簡介
- (85)IO類體系
- (86)文件操作之File類使用
- (87)文件操作之讀取文件
- (88)文件操作之寫文件
- (89)讀取控制臺輸入
- (90)裝飾流使用1
- (91)裝飾流使用2
- (92)IO使用注意問題
- (93)多線程基礎
- (94)多線程實現方式1
- (95)多線程實現方式2
- (96)多線程使用示例1
- (97)多線程使用示例2
- (98)多線程問題及處理1
- (99)多線程問題及處理2
- (100)多線程問題及處理3
- (101)網絡編程概述
- (102)網絡編程技術1
- (103)網絡編程技術2
- (104)網絡編程技術3
- (105)網絡編程技術4
- (106)網絡編程技術5
- (107)網絡協議概念
- (108)網絡編程示例1
- (109)網絡編程示例2
- (110)網絡編程小結