UDP通訊:html
一、UDP協議(用戶數據報協議)是無鏈接、不可靠、無序的。編程
二、UDP協議以數據報做爲數據傳輸的載體。小程序
三、使用UDP進行數據傳輸時,首先須要將要傳輸的數據定義成數據報(Datagram),在數據報中指明所要達到的Socket(主機地址和端口號),而後在將數據報發生出去。數組
四、相關操做類:安全
<DatagramPacket類>服務器
構造方法:網絡
1 DatagramPacket(byte[] buf,int length)//接受長度爲length的數據包 3 DatagramPacket(byte[] buf,int length,InetAddress address,int port)//將指定長度的字節發生到指定主機的指定端口
<DatagramSocket類>多線程
構造方法:socket
1 DatagramSocket(); 2 DatagramSocket(int port,InetAddress laddr);
經常使用方法:測試
1 close();//關閉DatagramSocket 2 getInetAddress();//獲取地址 3 getPort();//獲取端口號 4 send(DatagramPacket p);//今後套接字發送數據包 5 recrive(DatagramPacket p);//今後套接字接收數據包
經過寫一個用戶登陸的小程序,來直觀瞭解基於UDP的Socket通訊的工做過程,首先咱們得知道在客戶端和服務器通訊時,二者的運做流程是如何的,先從服務器入手。
服務器端實現步驟:
一、建立DatagramSocket,指定端口號
二、建立DatagramPacket
三、接收客戶端發送的數據信息
四、讀取數據
那麼用戶登陸的測試案例的服務器端類能夠這樣(待完善):
1 public static void main(String[] args) throws IOException { 2 // TODO Auto-generated method stub 3 4 try { 5 //1.建立服務器端DatagramSocket,指定端口 6 DatagramSocket ds=new DatagramSocket(8080); 7 //2.建立數據報DatagramPacket,用於接收客戶端發送的數據 8 byte[] data=new byte[1024];//建立字節數組,指定接受的數據報大小 9 DatagramPacket dp=new DatagramPacket(data, data.length); 10 //3.接收客戶端發送的數據 11 ds.receive(dp);//此方法在接收到數據報以前會一直阻塞 12 //4.讀取數據 13 //String info=Arrays.toString(data); 14 String info=new String(data, 0, dp.getLength()); 15 System.out.println("我是服務器,客戶端說:"+info); 16 } catch (SocketException e) { 17 // TODO Auto-generated catch block 18 e.printStackTrace(); 19 } 20 }
接着咱們看一下客戶端的運做過程,其實和服務器端差很少,可是其中的區別仍是要清楚的。
客戶端實現步驟:
一、定義發送信息
二、建立DatagramPacket:包含將要發送信息
三、建立DatagramSocket
四、發送數據
那麼用戶登陸的測試案例的客戶端類能夠這樣(待完善):
1 public static void main(String[] args) throws IOException { 2 // TODO Auto-generated method stub 3 //1.定義服務器的地址、端口號、數據 4 InetAddress add=InetAddress.getByName("localhost"); 5 int port=8080; 6 byte[] data="用戶名:admin;密碼:123".getBytes(); 7 //2.建立數據報,包含了發送的相關信息 8 DatagramPacket ap=new DatagramPacket(data, data.length, add, port); 9 //3.建立DatagramSocket對象 10 DatagramSocket ds=new DatagramSocket(); 11 //4.向服務器端發送數據報 12 ds.send(ap); 13 14 }
這樣服務端和客戶端就能進行最簡單的通訊了,目前這個還不能實現交互,下面會講二者的交互。
運行一下,看看服務器端是否能接收到客戶端發送的信息了呢...
分別啓動服務器和客戶端,注意必須先啓動服務器再啓動客戶端,不然客戶端找不到資源報錯:
完善用戶登陸之服務器響應客戶端
在上述的例子中,服務器和客戶端僅僅只是相互能夠通訊,但服務器對於接收到的客戶端信息並無向客戶端響應,客戶端沒有接收到服務器端的任何信息,這明顯是不完善不友好的,在這裏將對剛剛的例子進行完善,完成服務器對客戶端的響應。
修改後的服務器端:
1 public static void main(String[] args) throws IOException { 2 // TODO Auto-generated method stub 3 4 try { 5 /* 6 * 接收客戶端發送的數據 7 */ 8 //1.建立服務器端DatagramSocket,指定端口 9 DatagramSocket ds=new DatagramSocket(8080); 10 //2.建立數據報DatagramPacket,用於接收客戶端發送的數據 11 byte[] data=new byte[1024];//建立字節數組,指定接受的數據報大小 12 DatagramPacket dp=new DatagramPacket(data, data.length); 13 //3.接收客戶端發送的數據 14 System.out.println("服務器端已啓動,等待客戶端發送數據..."); 15 ds.receive(dp);//此方法在接收到數據報以前會一直阻塞 16 //4.讀取數據 17 //String info=Arrays.toString(data); 18 String info=new String(data, 0, dp.getLength()); 19 System.out.println("我是服務器,客戶端說:"+info); 20 /* 21 * 響應客戶端 22 */ 23 //1.定義客戶端的地址、端口號、數據 24 InetAddress add=dp.getAddress(); 25 int port=dp.getPort(); 26 byte[] data2="歡迎您!".getBytes(); 27 //2.建立數據報,包含響應的數據信息 28 DatagramPacket dp2=new DatagramPacket(data2, data2.length, add, port); 29 //3.響應客戶端 30 ds.send(dp2); 31 //4.關閉資源 32 ds.close(); 33 34 35 } catch (SocketException e) { 36 // TODO Auto-generated catch block 37 e.printStackTrace(); 38 } 39 }
修改後的客戶端:
1 public static void main(String[] args) throws IOException { 2 // TODO Auto-generated method stub 3 /* 4 * 向服務器發送數據 5 */ 6 //1.定義服務器的地址、端口號、數據 7 InetAddress add=InetAddress.getByName("localhost"); 8 int port=8080; 9 byte[] data="用戶名:admin;密碼:123".getBytes(); 10 //2.建立數據報,包含了發送的相關信息 11 DatagramPacket ap=new DatagramPacket(data, data.length, add, port); 12 //3.建立DatagramSocket對象 13 DatagramSocket ds=new DatagramSocket(); 14 //4.向服務器端發送數據報 15 ds.send(ap); 16 /* 17 * 接收服務器端的響應 18 */ 19 //1.建立數據報DatagramPacket,用於接收服務器發送的數據 20 byte[] data2=new byte[1024]; 21 DatagramPacket dp2= new DatagramPacket(data2, data2.length); 22 //2.接收響應 23 ds.receive(dp2); 24 //3.讀取數據 25 String info=new String(data2, 0, dp2.getLength()); 26 System.out.println("我是客戶端,服務器說:"+info); 27 //4.關閉資源 28 ds.close(); 29 }
運行結果:
應用多線程來實現服務器與多客戶端之間的通訊。<關於多線程更多的內容之後再總結>
多線程基本步驟:
1.服務器端建立DatagramSocket,循環調用receive()等待客戶端發送數據報。
2.客戶端建立一個DatagramSocket發送數據報到服務器端。
3.服務器端接收客戶端的數據報,建立DatagramPacket與該客戶創建專線接收數據報。
4.創建交互數據報在一個單獨的線程上對話。
5.服務器端繼續等待新的數據報。
------------------------------------------------------------------------------
下面再將上述的例子修改爲多線程的通訊
新建一個服務器線程處理類UDPServerThread,該類繼承Thread類:
1 /* 2 * 服務器線程處理類 3 */ 4 public class UDPServerThread extends Thread { 5 DatagramSocket ds=null; 6 DatagramPacket dp=null; 7 public UDPServerThread(DatagramSocket ds,DatagramPacket dp){ 8 this.ds=ds; 9 this.dp=dp; 10 } 11 12 13 public void run(){ 14 15 16 try { 17 /* 18 * 接收客戶端發送的數據 19 */ 20 21 //4.讀取數據 22 //String info=Arrays.toString(data); 23 byte[] data=dp.getData(); 24 String info=new String(data, 0, dp.getLength()); 25 System.out.println("我是服務器,客戶端說:"+info); 26 /* 27 * 響應客戶端 28 */ 29 //1.定義客戶端的地址、端口號、數據 30 InetAddress add=dp.getAddress(); 31 int port=dp.getPort(); 32 byte[] data2="歡迎您!".getBytes(); 33 //2.建立數據報,包含響應的數據信息 34 DatagramPacket dp2=new DatagramPacket(data2, data2.length, add, port); 35 //3.響應客戶端 36 ds.send(dp2); 37 38 39 } catch (IOException e) { 40 // TODO Auto-generated catch block 41 e.printStackTrace(); 42 } 43 44 } 45 }
服務器端:
1 /* 2 * 服務器端 3 */ 4 public class UDPSever { 5 6 public static void main(String[] args) throws IOException { 7 // TODO Auto-generated method stub 8 9 try { 10 11 // 1.建立服務器端DatagramSocket,指定端口 12 DatagramSocket ds = new DatagramSocket(8080); 13 System.out.println("服務器即將啓動,等待客戶端的鏈接..."); 14 byte[] data = new byte[1024]; 15 // 記錄客戶端的數量 16 int count = 0; 17 // 循環偵聽等待客戶端的鏈接 18 while (true) { 19 DatagramPacket dp = new DatagramPacket(data, data.length); 20 ds.receive(dp); 21 // 建立一個新的線程 22 UDPServerThread udp = new UDPServerThread(ds, dp); 23 // 啓動線程,執行與客戶端的交互 24 udp.start(); 25 count++; 26 System.out.println("此時客戶端數量爲:" + count); 27 InetAddress add = dp.getAddress(); 28 System.out.println("當前客戶端的ip地址爲" + add.getHostAddress()); 29 } 30 31 } catch (SocketException e) { 32 // TODO Auto-generated catch block 33 e.printStackTrace(); 34 } 35 } 36 37 }
多個客戶端的運行結果:
這樣一個簡單的多線程UDP通訊就完成了。
<解 惑>TCP和UDP編程都用在什麼地方?
<回 答>網絡通訊,例如QQ客戶端和服務器間的通訊。
TCP是面向鏈接的、可靠的,若是對通訊數據的可靠性要求比較高,確保數據對方能夠收到,可使用TCP。
UDP是無鏈接的,在通訊前不會預先創建鏈接,沒法保證可靠性,通常用於對數據可靠性要求不是那麼高的場合。
<解 惑>UDP和TCP相比較有什麼優缺點?
<回 答>UDP相較於TCP,不須要進行復雜的設定輸入輸出流,只須要設定數據報,即DatagramPacket。而TCP的發送以及接收消息,是經過socket.getInputStream()或者getOutputStream()方法,而UDP是直接設置了,DatagramSocket,經過其send()或者receive()方法來接收或發送消息。TCP的關鍵組成有server端的ServerSocket.accept()方法,這個方法是直到接收到了客戶端的鏈接纔會返回一個Socket,用於接下來的輸入和輸出。
因此說,TCP的數據傳輸是須要提早鏈接、三方握手,數據傳輸很是安全;
而UDP是不須要提早鏈接的,無需等待對方回答,因此不保證數據不丟失。
---------------點擊查看更多關於Socket信息------------------