天天看點

Java網絡程式設計之簡單UDP通信

   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