UDP

DatagramPacket

UDP在Socket網(wǎng)絡(luò)中都是通過DatagramPacket的數(shù)據(jù)格式進(jìn)行傳輸?shù)模簿褪菙?shù)據(jù)報(bào)的形式腺逛。UDP數(shù)據(jù)報(bào)是基于IP數(shù)據(jù)報(bào)建立的豺憔,UDP數(shù)據(jù)報(bào)同樣分為首部和主體迅腔,UDP數(shù)據(jù)報(bào)的首部比IP數(shù)據(jù)報(bào)的首部多了8個(gè)字節(jié),其中UDP的首部包括:源端口號(hào)和目標(biāo)端口號(hào)、 IP首部之后所有內(nèi)容的長(zhǎng)度嗽元、 可選的檢驗(yàn)和敛纲。 理論上UDP包中的數(shù)據(jù)長(zhǎng)度最大是65507字節(jié),但實(shí)際上總是比這少得多剂癌。

DatagramPacket相關(guān)API

  • 接收數(shù)據(jù)報(bào)的構(gòu)造函數(shù)
    public DatagramPacket(byte buf[], int length)
    public DatagramPacket(byte buf[], int offset, int length)

這兩個(gè)構(gòu)造函數(shù)可以創(chuàng)建新的DatagramPacket對(duì)象并從網(wǎng)絡(luò)接收數(shù)據(jù)淤翔。

  • 第一個(gè)構(gòu)造函數(shù):當(dāng)Socket接收一個(gè)數(shù)據(jù)報(bào)時(shí),它將數(shù)據(jù)報(bào)的數(shù)據(jù)部分存儲(chǔ)在buf字節(jié)數(shù)組中佩谷,從buf[0]開始一直到包完全存儲(chǔ)旁壮,或者直到向字節(jié)數(shù)組中寫入了length個(gè)字節(jié)為止。
  • 第二個(gè)構(gòu)造函數(shù):將從buf[offset]開始存儲(chǔ)谐檀,直到包完全存儲(chǔ)抡谐,或者直到向字節(jié)數(shù)組中寫入了length個(gè)字節(jié)為止。
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);

byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, 0, buf.length);
  • 發(fā)送數(shù)據(jù)報(bào)的構(gòu)造函數(shù)
    public DatagramPacket(byte buf[], int length, SocketAddress address)
    public DatagramPacket(byte buf[], int offset, int length, SocketAddress address)
    public DatagramPacket(byte buf[], int length,InetAddress address, int port)
    public DatagramPacket(byte buf[], int offset, int length,InetAddress address, int port)

這四個(gè)構(gòu)造函數(shù)可以創(chuàng)建新的DatagramPacket對(duì)象并從網(wǎng)絡(luò)發(fā)送數(shù)據(jù)桐猬。

  • 這個(gè)包用buf字節(jié)數(shù)據(jù)中從offset(如果沒有指定該參數(shù)則默認(rèn)為0)開始的length個(gè)字節(jié)填充麦撵,指定了要發(fā)送的數(shù)據(jù)。
  • InetAddress或SocketAddress對(duì)象指定了包要發(fā)送的目標(biāo)主機(jī)地址溃肪。
  • port參數(shù)表示該主機(jī)上的端口免胃。
// 準(zhǔn)備要發(fā)送的數(shù)據(jù)
String str = "This is a test.";
// 轉(zhuǎn)化為byte字節(jié)數(shù)組
byte[] buf = str.getBytes("UTF-8");
// 構(gòu)造發(fā)送的目標(biāo)地址和端口
InetAddress address = InetAddress.getByName("www.ibiblio.org");
int port = 7;
// 構(gòu)造DatagramPacket
DatagramPacket packet = new DatagramPacket(buf, buf.length, address, port);
// 發(fā)送數(shù)據(jù)
DatagramSocket socket = new DatagramSocket();
socket.send(packet);
  • 獲取DatagramPacket信息的方法
    DatagramPacket有6個(gè)獲取數(shù)據(jù)報(bào)不同部分的方法,這些部分包括具體的數(shù)據(jù)以及首部的字段惫撰,這些方法主要用于從網(wǎng)絡(luò)接收的數(shù)據(jù)報(bào)羔沙。
    public synchronized InetAddress getAddress()
    public synchronized int getPort()
    public synchronized SocketAddress getSocketAddress()
    public synchronized byte[] getData()
    public synchronized int getLength()
    public synchronized int getOffset()
  • getAddress():返回一個(gè)InetAddress對(duì)象,指示遠(yuǎn)程主機(jī)的地址厨钻。這里有兩種情況:一是如果數(shù)據(jù)報(bào)是從Internet接收的撬碟,返回的地址則是發(fā)送該數(shù)據(jù)報(bào)的機(jī)器的地址(源地址);二是如果數(shù)據(jù)報(bào)是本地創(chuàng)建準(zhǔn)備發(fā)送到遠(yuǎn)程主機(jī)的莉撇,返回的地址則是要發(fā)往的遠(yuǎn)程主機(jī)的地址(目標(biāo)地址)。這個(gè)方法常用于確定發(fā)送UDP數(shù)據(jù)報(bào)的主機(jī)地址惶傻,使接收方可以回復(fù)棍郎。www.ibiblio.org/152.19.134.40
  • getPort():返回一個(gè)int整數(shù),指示遠(yuǎn)程端口號(hào)银室。同樣的涂佃,如果數(shù)據(jù)報(bào)是從Internet接收的,返回的端口號(hào)則是發(fā)送該數(shù)據(jù)報(bào)的機(jī)器的端口號(hào)(源端口號(hào))蜈敢;如果數(shù)據(jù)報(bào)是本地創(chuàng)建準(zhǔn)備發(fā)送到遠(yuǎn)程主機(jī)的辜荠,返回的端口號(hào)則是要發(fā)往的遠(yuǎn)程主機(jī)的端口號(hào)(目標(biāo)端口號(hào))。
  • getSocketAddress():返回一個(gè)SocketAddress對(duì)象抓狭,指示遠(yuǎn)程主機(jī)的IP地址和端口號(hào)伯病。如果數(shù)據(jù)報(bào)是從Internet接收的,返回的地址則是發(fā)送該數(shù)據(jù)報(bào)的機(jī)器的地址(源地址)否过;如果數(shù)據(jù)報(bào)是本地創(chuàng)建準(zhǔn)備發(fā)送到遠(yuǎn)程主機(jī)的午笛,返回的地址則是要發(fā)往的遠(yuǎn)程主機(jī)的地址(目標(biāo)地址)惭蟋。一般要在回復(fù)前調(diào)用這個(gè)方法,獲取發(fā)送這個(gè)DatagramPacket數(shù)據(jù)報(bào)的主機(jī)地址和端口號(hào)药磺,以便進(jìn)行回復(fù)告组。與同時(shí)調(diào)用getAddress()和getPort()相比,實(shí)際結(jié)果沒有顯著區(qū)別癌佩。www.ibiblio.org/152.19.134.40:7
  • getData():返回一個(gè)byte數(shù)組木缝,指示數(shù)據(jù)報(bào)中的數(shù)據(jù)部分。通常必須將接收到的字節(jié)數(shù)組轉(zhuǎn)化為其他的某種數(shù)據(jù)形式以便使用围辙。
  • getLength():返回一個(gè)int整數(shù)我碟,指示數(shù)據(jù)報(bào)中數(shù)據(jù)部分的字節(jié)數(shù)。它不一定等于getData()返回的數(shù)組長(zhǎng)度(即getData().length)酌畜,甚至可能小于怎囚。
  • getOffset():返回一個(gè)int整數(shù),指示該字節(jié)數(shù)組中的一個(gè)位置桥胞,即開始填充數(shù)據(jù)報(bào)的位置恳守。
// 轉(zhuǎn)化接收到的字節(jié)數(shù)組的技巧
// 1. 直接調(diào)用String的構(gòu)造函數(shù)進(jìn)行轉(zhuǎn)化
String data = new String(packet.getData(), "UTF-8");
// 2. 如果數(shù)據(jù)報(bào)不包含文本,可以轉(zhuǎn)化為ByteArrayInputStream
InputStream in = new ByteArrayInputStream(packet.getData(), packet.getOffset(), packet.getLength());
DataInputStream din = new DataInputStream(in);
// 這里可以使用DataInputStream的readInt()贩虾、readChar()等方法直接讀取...
  • 設(shè)置DatagramPacket信息的方法
    DatagramPacket提供了6個(gè)方法可以在創(chuàng)建數(shù)據(jù)報(bào)之后改變數(shù)據(jù)催烘、遠(yuǎn)程地址、遠(yuǎn)程端口號(hào)缎罢。如果創(chuàng)建和銷毀DatagramPacket對(duì)象的時(shí)間會(huì)嚴(yán)重影響性能伊群,那么這些方法就很重要了。有些情況下策精,重用對(duì)象比構(gòu)造新對(duì)象要快得多舰始。
    public synchronized void setData(byte[] buf)
    public synchronized void setData(byte[] buf, int offset, int length)
    public synchronized void setAddress(InetAddress iaddr)
    public synchronized void setPort(int iport)
    public synchronized void setSocketAddress(SocketAddress address)
    public synchronized void setLength(int length)
  • setData():該方法會(huì)改變數(shù)據(jù)報(bào)的數(shù)據(jù)部分。如果要向遠(yuǎn)程主機(jī)發(fā)送大文件可能會(huì)用到這個(gè)方法咽袜。
  • setData():該重載方法提供另一個(gè)途徑來發(fā)送大量的數(shù)據(jù)丸卷。與發(fā)送大量新數(shù)組不同,可以將所有數(shù)據(jù)放在一個(gè)數(shù)據(jù)中询刹,每次發(fā)送一部分谜嫉。
  • setAddress():該方法會(huì)修改數(shù)據(jù)報(bào)發(fā)往的地址。允許將同一個(gè)數(shù)據(jù)報(bào)發(fā)送給多個(gè)不同的接收方凹联。
  • setPort():該方法會(huì)修改數(shù)據(jù)報(bào)發(fā)往的端口沐兰。
  • setSocketAddress():該方法會(huì)修改數(shù)據(jù)報(bào)要發(fā)往的地址和端口。在響應(yīng)回復(fù)時(shí)可以使用這個(gè)方法蔽挠。
  • setLength():該方法會(huì)修改內(nèi)部緩沖區(qū)中包含實(shí)際數(shù)據(jù)報(bào)數(shù)據(jù)的字節(jié)數(shù)住闯,而不包括未填充數(shù)據(jù)的空間。這個(gè)方法在接收數(shù)據(jù)報(bào)時(shí)很有用,當(dāng)接收到數(shù)據(jù)報(bào)時(shí)寞秃,其長(zhǎng)度設(shè)置為入站數(shù)據(jù)的長(zhǎng)度斟叼。

DatagramSocket

要發(fā)送和接受數(shù)據(jù)報(bào)DatagramPacket,必須通過DatagramSocket進(jìn)行傳輸春寿,所有DatagramSocket都綁定到一個(gè)本地端口朗涩,在這個(gè)端口上監(jiān)聽入站數(shù)據(jù),這個(gè)端口也會(huì)放置到出站數(shù)據(jù)報(bào)的首部中绑改,以便服務(wù)器用來響應(yīng)數(shù)據(jù)報(bào)的發(fā)送地址谢床。一般情況下,客戶端使用匿名端口厘线,服務(wù)器需要指定監(jiān)聽端口识腿。

DatagramSocket相關(guān)API

  • 構(gòu)造函數(shù)
    public DatagramSocket() throws SocketException
    public DatagramSocket(int port) throws SocketException
    public DatagramSocket(int port, InetAddress laddr) throws SocketException
    public DatagramSocket(SocketAddress bindaddr) throws SocketException
    protected DatagramSocket(DatagramSocketImpl impl)

所有構(gòu)造函數(shù)都只處理本地地址和端口,遠(yuǎn)程地址和端口存儲(chǔ)在DatagramPacket中造壮,一個(gè)DatagramSocket可以從多個(gè)遠(yuǎn)程主機(jī)和端口收發(fā)數(shù)據(jù)報(bào)渡讼。

  1. 該構(gòu)造函數(shù)創(chuàng)建一個(gè)綁定到匿名端口的Socket,系統(tǒng)會(huì)自動(dòng)為客戶端分配一個(gè)端口耳璧。
  2. 該構(gòu)造函數(shù)創(chuàng)建一個(gè)指定端口的Socket成箫,可以使用這個(gè)方法編寫在已知端口監(jiān)聽的服務(wù)器。
  3. 該構(gòu)造函數(shù)創(chuàng)建在指定端口和網(wǎng)絡(luò)接口的Socket旨枯,多用于多宿主主機(jī)(一個(gè)主機(jī)有多個(gè)IP地址)蹬昌。第二個(gè)參數(shù)是匹配該主機(jī)某個(gè)網(wǎng)絡(luò)接口的InetAddress對(duì)象。
  4. 該構(gòu)造函數(shù)與第3個(gè)相似攀隔,只是網(wǎng)絡(luò)接口地址和端口由SocketAddress包裝皂贩。
  5. 該構(gòu)造函數(shù)允許子類提供自己的UDP實(shí)現(xiàn),而不接受默認(rèn)實(shí)現(xiàn)昆汹。與其他四個(gè)方法不同明刷,這個(gè)Socket一開始沒有與端口綁定,使用前必須通過bind()方法綁定到一個(gè)SocketAddress满粗。
  • 發(fā)送和接受數(shù)據(jù)報(bào)
    public void send(DatagramPacket p) throws IOException
    public synchronized void receive(DatagramPacket p) throws IOException
    public void close()
    public int getLocalPort()
    public InetAddress getLocalAddress()
  • getLocalPort():返回一個(gè)int整數(shù)遮精,表示Socket正在監(jiān)聽的本地端口。如果創(chuàng)建了一個(gè)匿名端口的DatagramSocket败潦,可以使用該方法獲取到監(jiān)聽的端口號(hào)。
  • getLocalAddress():返回一個(gè)InetAddress對(duì)象准脂,表示Socket綁定到的本地地址劫扒。實(shí)際中很少這樣做,因?yàn)槟阋呀?jīng)知道了監(jiān)聽的地址狸膏。
  • 管理連接
    public void connect(InetAddress address, int port)
    public void connect(SocketAddress addr) throws SocketException
    public void disconnect()
    public int getPort()
    public InetAddress getInetAddress()
    public SocketAddress getRemoteSocketAddress()

利用上面5個(gè)方法沟饥,可以選擇允許收發(fā)數(shù)據(jù)報(bào)的主機(jī),而拒絕其它所有主機(jī)的包。

  • connect():并不真正建立TCP意義上的連接贤旷,不過它確實(shí)指定了DatagramSocket只對(duì)指定遠(yuǎn)程主機(jī)和指定遠(yuǎn)程端口發(fā)送和接受數(shù)據(jù)報(bào)广料。試圖向其它主機(jī)和端口發(fā)送數(shù)據(jù)報(bào)將拋出異常,而從其它主機(jī)和端口接受的數(shù)據(jù)報(bào)將直接丟棄幼驶,沒有異常也沒有通知艾杏。
  • disconnect():中斷連接,從而可以再次收發(fā)其它主機(jī)和端口的數(shù)據(jù)報(bào)盅藻。
  • getPort():當(dāng)且僅當(dāng)DatagramSocket已連接時(shí)购桑,該方法返回所連接的遠(yuǎn)程端口,否則返回-1氏淑。
  • getInetAddress():當(dāng)且僅當(dāng)DatagramSocket已連接時(shí)勃蜘,該方法返回所連接的遠(yuǎn)程主機(jī)地址,否則返回null假残。
  • getRemoteSocketAddress():如果DatagramSocket已連接缭贡,該方法返回所連接的遠(yuǎn)程主機(jī)的地址,否則返回null辉懒。

設(shè)置DatagramSocket屬性

  • SO_TIMEOUT
  • SO_RCVBUF
  • SO_SNDBUF
  • SO_REUSEADDR
  • SO_BROADCAST
  • IP_TOS
  1. SO_TIMEOUT
    public synchronized void setSoTimeout(int timeout) throws SocketException

該屬性是receive()方法在拋出InterruptedException異常前等待接收數(shù)據(jù)報(bào)的時(shí)間阳惹。如果該屬性值為0,則receive()方法永遠(yuǎn)不會(huì)超時(shí)耗帕。如果要實(shí)現(xiàn)一個(gè)安全協(xié)議穆端,需要在一定時(shí)間內(nèi)響應(yīng)就可能需要設(shè)置該屬性。setSoTimeout()方法可以設(shè)置超時(shí)時(shí)間仿便,如果超時(shí)了体啰,阻塞的receive()方法就會(huì)拋出SocketTimeoutException異常。必須在receive()方法前調(diào)用嗽仪。

  1. SO_RCVBUF
    public synchronized void setReceiveBufferSize(int size) throws SocketException

對(duì)于相當(dāng)快的連接(如以太網(wǎng)的連接)荒勇,較大的緩沖區(qū)有助于提升性能,因?yàn)樵谝绯銮翱梢源鎯?chǔ)更多的入站數(shù)據(jù)報(bào)闻坚。與TCP相比沽翔,對(duì)于UDP而言,足夠大的接收緩沖區(qū)甚至更為重要窿凤,因?yàn)樵诰彌_區(qū)滿時(shí)到達(dá)的UDP數(shù)據(jù)報(bào)會(huì)丟失仅偎,而緩沖區(qū)滿時(shí)到達(dá)的TCP數(shù)據(jù)報(bào)最后還會(huì)重傳。

  1. SO_SNDBUF
    public synchronized void setSendBufferSize(int size) throws SocketException

設(shè)置網(wǎng)絡(luò)輸出的發(fā)送緩沖區(qū)大小雳殊。

  1. SO_REUSEADDR
    public synchronized void setReuseAddress(boolean on) throws SocketException

對(duì)于UDP來說橘沥,該屬性可以控制是否允許多個(gè)數(shù)據(jù)報(bào)Socket同時(shí)綁定到相同的端口和地址。如果多個(gè)Socket綁定到相同端口夯秃,接收的包將復(fù)制給綁定的所有Socket座咆。必須在新Socket綁定到端口前調(diào)用setReuseAddress()痢艺。

  1. SO_BROADCAST
    public synchronized void setBroadcast(boolean on) throws SocketException

該屬性控制是否允許一個(gè)Socket向廣播地址收發(fā)數(shù)據(jù)報(bào)。默認(rèn)為true介陶。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末堤舒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子哺呜,更是在濱河造成了極大的恐慌舌缤,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,378評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件弦牡,死亡現(xiàn)場(chǎng)離奇詭異友驮,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)驾锰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門卸留,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人椭豫,你說我怎么就攤上這事耻瑟。” “怎么了赏酥?”我有些...
    開封第一講書人閱讀 168,983評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵喳整,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我裸扶,道長(zhǎng)框都,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,938評(píng)論 1 299
  • 正文 為了忘掉前任呵晨,我火速辦了婚禮魏保,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘摸屠。我一直安慰自己谓罗,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,955評(píng)論 6 398
  • 文/花漫 我一把揭開白布季二。 她就那樣靜靜地躺著檩咱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪胯舷。 梳的紋絲不亂的頭發(fā)上刻蚯,一...
    開封第一講書人閱讀 52,549評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音桑嘶,去河邊找鬼炊汹。 笑死,一個(gè)胖子當(dāng)著我的面吹牛不翩,可吹牛的內(nèi)容都是我干的兵扬。 我是一名探鬼主播紫谷,決...
    沈念sama閱讀 41,063評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼胰坟,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼笑陈!你這毒婦竟也來了先改?” 一聲冷哼從身側(cè)響起蜂厅,我...
    開封第一講書人閱讀 39,991評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤蝇摸,失蹤者是張志新(化名)和其女友劉穎宿刮,沒想到半個(gè)月后是辕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體眉反,經(jīng)...
    沈念sama閱讀 46,522評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡昙啄,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,604評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了寸五。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片梳凛。...
    茶點(diǎn)故事閱讀 40,742評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖梳杏,靈堂內(nèi)的尸體忽然破棺而出韧拒,到底是詐尸還是另有隱情,我是刑警寧澤十性,帶...
    沈念sama閱讀 36,413評(píng)論 5 351
  • 正文 年R本政府宣布叛溢,位于F島的核電站,受9級(jí)特大地震影響劲适,放射性物質(zhì)發(fā)生泄漏楷掉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,094評(píng)論 3 335
  • 文/蒙蒙 一霞势、第九天 我趴在偏房一處隱蔽的房頂上張望烹植。 院中可真熱鬧,春花似錦支示、人聲如沸刊橘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽促绵。三九已至,卻和暖如春嘴纺,著一層夾襖步出監(jiān)牢的瞬間败晴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工栽渴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留尖坤,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,159評(píng)論 3 378
  • 正文 我出身青樓闲擦,卻偏偏與公主長(zhǎng)得像慢味,于是被迫代替她去往敵國(guó)和親场梆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,747評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容