UDP是一種基于不可靠連接配接的協定,它無法保證傳輸的資料能不丢失不重複到達,盡自己努力傳輸,但是不會重傳,不需要建立連接配接,則它所需要的時間會很快。它是基于資料報為機關進行傳輸的,不想TCP是一種基于流進行傳輸的。在UDP中沒有所謂的Socket和ServerSocket來區分一個是用戶端一個是伺服器端,相反在UDP中用戶端和伺服器端都是基于相同的DatagramSocket來進行傳輸的,差別在于使用的構造函數。
利用TCP和UDP進行傳輸的應用層協定如下:
基于TCP的有FTP、Telnet、SMTP、HTTP、POP3與DNS
基于UDP的有TFTP、SNMP與DNS
其中DNS既可以基于TCP,也可以基于UDP。
利用UDP進行網絡通信主要涉及兩個類,一個是DatagramPacket,主要用來将資料位元組填充到UDP資料報中,用來解包接受資料的,用來收和發UDP資料報。一個是DatagramSocket主要用來是建立用戶端和伺服器端,用來接受和發送資料報資料的。
題注:在Socket連接配接中,Socket會每次在構造器後自動利用host和port來嘗試連接配接主機。
ServerSocket在每次構造器後,會嘗試綁定于指定的port端口
DatagramSocket在每次構造器後,當使用無參數時候,系統自動配置設定一個端口綁定上
當使用有參的時候,系統将該socket綁定于該端口,可以調用connect來遠端連接配接host和port
MulticastSocket是DatagramSocket一樣,因為它是DatagramSocket的子類
DatagramPacket類:
UDP首部向IP首部添加了8個位元組,包含了源端口和目标端口,IP首部以後内容的長度和校驗和,最多有65507個位元組數。UDP所使用的端口和TCP使用的端口不一樣的,是一個final類。
對于接受資料,将接受到的資料存儲到DatagramPacket,然後從該對象中讀取資料。
對于發送資料,将發送的資料先存到DatagramPacket中,然後将該對象發送。
接受資料報構造函數:
DatagramPacket(byte[] buffer,int length)
DatagramPacket(byte[] buffer,int offset,int length)
socket将接受到的資料部分存儲到buffer,一般buffer的大小最多定義為8192或者512大小即可
發送資料報構造函數:
由于DatagramPacket将資料填充到UDP資料報中,而資料報需要源端口和目标端口,用戶端一般建立的端口是匿名的,會在填充的過程中自動的加上,而源端口必須要首先顯式的在DatagramPacket中設定,這樣才能填充到UDP資料報中。發送資料都必須要把資料以位元組形式發送。以API 1.6
DatagramPacket(byte[] buffer,int length,InetAddress dest,int port)
DatagramPacket(byte[] buffer,int offset,int length,InetAddress dest,int port)
DatagramPacket(byte[] buffer,int length,SocketAddress dest)
DatagramPacket(byte[] buffer,int offset,int length,SocketAddress dest)
注意:SocketAddress是一個抽象類,主要儲存了主機名、IP和端口号,
一般可以SocketAddress address=new InetSocketAddress("www.baidu.com",2000)
InetAddress隻是用來儲存主機名和IP的。
InetAddress getAddress()、getPort()擷取發送資料目标位址、端口和接受到資料的源位址、端口
SocketAddress getSocketAddress()(最常用的)一樣的意思。
利用getData()擷取接受到的資料報資料的位元組數組,一般利用
String res=new String(packet.getData(),"ASCII")或
String s=new String(packet.getData(),packet.getOffset(),packet.getLength(),"UTF-8");
擷取資料。getLength()傳回UDP中資料的位元組數。getOffset()資料報中資料開始的點。
對于已經構造好的DatagramPacket,可以在發送之前更改它的一些狀态。修改資料報的屬性,一般是先建立一個接受資料報的構造函數,然後對其報進行更改屬性。
setData(byte[] data)
setData(byte[] data,int offset,int length) 可以用來連續發送大量的資料塊
setAddress(InetAddress remote)
setPort(int port)
setAddress(SocketAddress remote)相當于上面兩個方法。可以利用這些方法來設定一個資料報發送不同的ip和端口。
setLength(int length)設定包的長度,主要是指定緩沖區中将要發送的位元組數,或用來将要接收資料的包資料緩沖區的位元組數。
DatagramSocket類
在UDP中沒有明顯的用戶端類和伺服器端類,用戶端既可以發消息也可以接受消息。均在建立的過程會有SocketException異常。
建立UDP用戶端構造器
DatagramSocket();建立一個對于用戶端來說匿名的端口,發送UDP的過程會自動加上該端口号,伺服器接受消息也會按照該端口号發送。
建立UDP伺服器構造器
DatagramSocket(int port)
DatagramSocket(int port,InetAddress interface);用于一個主機有多個網絡接口的時候
DatagramSocket(SocketAddress interface)
發送資料報
直接調用send(DatagramPacket dp),異常有IOException
接受資料報
receive(DatagramPacket dp);異常有IOException
從網絡中接受一個UDP資料報,存儲在某一個DatagramPacket。在資料未到達之前會一直阻塞後面的運作,一般在無限循環中接受。
管理連接配接
connect(InetAddress host,int port)來設定其隻對指定的遠端主機和指定遠端的接受和發送包
getPort()、getInetAddress()傳回其連接配接的遠端主機。一般在接受到消息後,需要調用
packet.getSocketAddress(),擷取遠端主機基本資訊
簡單UDP示例:
用戶端UDP
package com.udpclient;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
//Discard以端口9,該伺服器主要就是丢棄所有的資料
publicclass UDPDiscardClient {
//discard 的端口為9
privatestaticfinalint DEFAULT_PORT=9;
publicstaticvoid main(String[] args) {
// TODO Auto-generated method stub
String hostname="localhost";
int port=DEFAULT_PORT;
try{
InetAddress server=InetAddress.getByName(hostname);
BufferedReader userIn=new BufferedReader(new InputStreamReader(System.in));
//建立UDP用戶端
DatagramSocket client=new DatagramSocket();
while(true)
{
String inline=userIn.readLine();
if(inline.indexOf('.')!=-1)break;
byte[] data=inline.getBytes("UTF-8");
//資料報
DatagramPacket thepacket=new DatagramPacket(data,data.length,server,port);
client.send(thepacket);
}
client.close();
}catch(UnknownHostException e)
{
e.printStackTrace();
}catch(SocketException e)
}catch(IOException e)
}
}
}
伺服器UDP
package com.udpserver;
publicclass UDPDiscardServer {
privatefinalstaticint DEFAULT_PORT=9;
privatefinalstaticint MAX_PACKET_SIZE=65507;
int port= DEFAULT_PORT;
byte[] buffer=newbyte[MAX_PACKET_SIZE];
DatagramSocket server=new DatagramSocket(port);
DatagramPacket packet=new DatagramPacket(buffer,buffer.length);
server.receive(packet);
String s=new String(packet.getData(),packet.getOffset(),packet.getLength(),"UTF-8");
System.out.println(packet.getAddress()+" at port:"
+packet.getPort()+ " says:\n"+s);
//設定以後需要接受的長度
packet.setLength(buffer.length);
}catch(SocketException e)
{
}catch(IOException e)
}
本文轉自 zhao_xiao_long 51CTO部落格,原文連結:http://blog.51cto.com/computerdragon/1194280