網(wǎng)絡(luò)編程之 udp
計(jì)算機(jī)網(wǎng)絡(luò),就是把分布在不同地理區(qū)域的計(jì)算機(jī)與專門的外部設(shè)備用通信線路互連成一個(gè)規(guī)模大、功能強(qiáng)的網(wǎng)絡(luò)系統(tǒng),從而使眾多的計(jì)算機(jī)可以方便地互相傳遞信息,共享硬件、軟件、數(shù)據(jù)信息等資源。
網(wǎng)絡(luò)體系結(jié)構(gòu):國際標(biāo)準(zhǔn)化組織 ISO 于 l978 年提出“開放系統(tǒng)互連參考模型”,即著名的 OSI ( OpenSystemInterconnection )模型。該模型把計(jì)算機(jī)網(wǎng)絡(luò)分成物理層、數(shù)據(jù)鏈路層、網(wǎng)絡(luò)層、傳輸層、會話層、表示層、應(yīng)用層等七層。
通信協(xié)議
計(jì)算機(jī)網(wǎng)絡(luò)中實(shí)現(xiàn)通信必須有一些約定,即通信協(xié)議。對速率、傳輸代碼、代碼結(jié)構(gòu)、傳輸控制步驟、出錯(cuò)控制等制定標(biāo)準(zhǔn)。
TCP 協(xié)議:提供可靠的數(shù)據(jù)傳輸服務(wù)的規(guī)則。
IP 協(xié)議進(jìn)行 IP 數(shù)據(jù)包的分割和組裝。
但是通過 IP 協(xié)議并不能清楚地了解到數(shù)據(jù)包是否順利地發(fā)送給目標(biāo)計(jì)算機(jī)。而使用 TCP 協(xié)議,它將數(shù)據(jù)包成功發(fā)送給目標(biāo)計(jì)算機(jī)后,會要求發(fā)送一個(gè)確認(rèn),如果在某個(gè)時(shí)間內(nèi)沒有收到確認(rèn), TCP 將重新發(fā)送數(shù)據(jù)包。
首先了解一下神馬是 UDP 協(xié)議 ;
UDP(UserDatagramProtocol) 協(xié)議是用戶數(shù)據(jù)報(bào),在網(wǎng)絡(luò)中它與 TCP 協(xié)議一樣用于處理數(shù)據(jù)包。在 OSI 模型中,在第四層——傳輸層,處于 IP 協(xié)議的上一層。
UDP 是一種無連接的協(xié)議,每個(gè)數(shù)據(jù)報(bào)都是一個(gè)獨(dú)立的信息,包括完整的源或目的地址,它在網(wǎng)絡(luò)上以任何可能的路徑傳往目的地,因此能否到達(dá)目的地,到達(dá)目的地的時(shí)間以及內(nèi)容的正確性都是不能被保證的。
為什么要使用 UDP ?
在網(wǎng)絡(luò)質(zhì)量令人不十分滿意的環(huán)境下, UDP 協(xié)議數(shù)據(jù)包丟失會比較嚴(yán)重。但是由于 UDP 的特性:它不屬于連接型協(xié)議,因而具有資源消耗小,處理速度快的優(yōu)點(diǎn),所以通常音頻、視頻和普通數(shù)據(jù)在傳送時(shí)使用 UDP 較多,因?yàn)樗鼈兗词古紶杹G失一兩個(gè)數(shù)據(jù)包,也不會對接收結(jié)果產(chǎn)生太大影響。比如聊天用的 ICQ 和 OICQ 就是使用的 UDP 協(xié)議。
上網(wǎng)搜索摸個(gè)網(wǎng)站的時(shí)候,本機(jī)是先訪問本地的 hosts 文件區(qū),去找該主機(jī)名是否有對應(yīng)的 ip 地址;
C:\Windows\System32\drivers\etc\hosts; 在里面可以加上你經(jīng)常進(jìn)的網(wǎng)站和 ip ;
InetAddress :用于描述 IP 地址的對象
InetAddress
類沒有提供構(gòu)造方法,而是提供了兩個(gè)靜態(tài)方法來獲取
InetAddress
實(shí)例
getByName(Stringhost)
:根據(jù)主機(jī)獲取對應(yīng)的
InetAddress
對象。
getByAddress(byte[]addr)
:根據(jù)原始
IP
地址來獲取對應(yīng)的
InetAddress
對象。
// 將指定 ip 封裝成 InetAddress 對象。
InetAddressia=InetAddress.getByName("127.0.0.1");
在
Java
中操縱
UDP
使用位于
JDK
中
Java.net
包下的
DatagramSocket
和
DatagramPacket
類,可以非常方便地控制用戶數(shù)據(jù)報(bào)文。
每個(gè)數(shù)據(jù)包的大小限制在 64k 內(nèi);
面向無連接,是不可靠協(xié)議,容易丟包;
不需要連接,速度快;
DatagramSocket 類:創(chuàng)建接收和發(fā)送 UDP 的 Socket 實(shí)例
DatagramSocket() :創(chuàng)建實(shí)例。通常用于客戶端編程,它并沒有特定監(jiān)聽的端口,僅僅使用一個(gè)臨時(shí)的。
DatagramSocket(intport) :創(chuàng)建實(shí)例,并固定監(jiān)聽 Port 端口的報(bào)文。
DatagramSocket(intport,InetAddresslocalAddr) :這是個(gè)非常有用的構(gòu)建器,當(dāng)一臺機(jī)器擁有多于一個(gè) IP 地址的時(shí)候,由它創(chuàng)建的實(shí)例僅僅接收來自 LocalAddr 的報(bào)文。
receive(DatagramPacketd) :接收數(shù)據(jù)報(bào)文到 d 中。 receive 方法產(chǎn)生一個(gè)“阻塞”。
send(DatagramPacketd) :發(fā)送報(bào)文 d 到目的地。
setSoTimeout(inttimeout) :設(shè)置超時(shí)時(shí)間,單位為毫秒。
close()
:關(guān)閉
DatagramSocket
。在應(yīng)用程序退出的時(shí)候,通常會主動釋放資源,關(guān)閉
Socket
,但是由于異常地退出可能造成資源無法回收。所以,應(yīng)該在程序完成時(shí),主動使用此方法關(guān)閉
Socket
,或在捕獲到異常拋出后關(guān)閉
Socket
。
建立一個(gè) upd 的發(fā)送端。
用于發(fā)送數(shù)據(jù)。
1, 建立 updsocket 服務(wù)。
2 ,將數(shù)據(jù)封裝成數(shù)據(jù)包。
3 ,通過 socket 服務(wù)的 send 方法。將數(shù)據(jù)包發(fā)出。
4 ,關(guān)閉資源。
*/
//1, 建立 udpsocket 服務(wù)。
DatagramSocketds=newDatagramSocket;
//2, 將數(shù)據(jù)封裝成數(shù)據(jù)包。要使用 DatagramPacket 對象
//2.1 先將要發(fā)送的數(shù)據(jù)變成字節(jié)數(shù)組。在指定發(fā)送的目的地和端口。
//2.2 將這些信息作為參數(shù)傳遞給數(shù)據(jù)包對象的構(gòu)造函數(shù)。
byte[]bf=”hahah,wolaile”.getBytes[];
InetAdressip=InetAdress.getName(“192.168.49.111”);
DatagramPacketdp=newDatagramPacket(bf,bf.getLength,ip,9909);
//3, 使用 Socket 服務(wù)的 send 方法將數(shù)據(jù)包發(fā)送出去。
Ds.send(dp);
//4, 關(guān)閉資源。
ds.close;
/*
建立 udp 的接收端。
1 ,建立 udp 接收端服務(wù),必須要監(jiān)聽一個(gè)端口,因?yàn)橐鞔_,哪個(gè)端口來的數(shù)據(jù)是由該應(yīng)用程序所處理的。
2 ,建立一個(gè)空的數(shù)據(jù)包,用于存儲接收到數(shù)據(jù),
將字節(jié)數(shù)據(jù)存儲到數(shù)據(jù)包對象中,可以使用數(shù)據(jù)包對象的方法獲取不同的數(shù)據(jù)信息。
3 ,使用 Socket 服務(wù)的 receive 方法將接收到的數(shù)據(jù)存儲到數(shù)據(jù)包中。
4 ,通過數(shù)據(jù)包的方法獲取指定數(shù)據(jù)信息。
5 ,關(guān)閉資源。
*/
//1, 建立 updsocket 服務(wù),監(jiān)聽一個(gè)端口。
DatagramSocketds=newDatagramSocket(9909);
//2, 建立一個(gè)執(zhí)行大小的數(shù)據(jù)包,用于存儲數(shù)據(jù),以便獲取。
byte[]bf=newbyte[1024];
DatagramPacketdp=newDatagramPacket(bf,bf.getLength);
//3, 使用 socket 的 receive 方法將數(shù)據(jù)存儲到數(shù)據(jù)包中。
ds.receive();
//4, 通過數(shù)據(jù)包對象的方法獲取其中的數(shù)據(jù)。
Stringip=getAddress().getHostAdress();
Stringdata=newString(dp.getData(),0,dp.getLength);
intport=dp.getPort();
System.out.println(ip+”:”+data+”::”+port);
//5, 關(guān)閉資源。
ds.close();
package com.csdn.hbsi; /* 需求: 制作一個(gè)dos版的聊天程序。 1,對于聊天分兩個(gè)動作,接收和發(fā)送。 2,接收和發(fā)送都需要同時(shí)運(yùn)行。這就使用到了多線程技術(shù)。 一個(gè)線程控制接收,一個(gè)線程控制發(fā)送。 3,既然要進(jìn)行群聊。那么就要使用socket網(wǎng)絡(luò)服務(wù)。這里我們使用Udp完成。 */ import java.net.*; import java.io.*; class ChatSend implements Runnable { private DatagramSocket ds; ChatSend(DatagramSocket ds) { this.ds = ds; } public void run() { BufferedReader bufr = null; try { bufr = new BufferedReader(new InputStreamReader(System.in)); String line = null; while((line=bufr.readLine())!=null) { if("886".equals(line)) break; byte[] buf = line.getBytes(); DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.49.255"),9008); ds.send(dp); } ds.close(); }catch (Exception e) { System.out.println(e.toString()); } } } class ChatRece implements Runnable { private DatagramSocket ds; ChatRece(DatagramSocket ds){ this.ds = ds;<!--EndFragment--> } public void run(){ while(true){ try{ byte[] buf = new byte[1024]; DatagramPacket dp = new DatagramPacket(buf,buf.length); ds.receive(dp); String ip = dp.getAddress().getHostAddress(); String data = new String(dp.getData(),0,dp.getLength()); System.out.println(ip+"::"+data); }catch (Exception e){ System.out.println(e.toString()); } } } } class ChatDemo { public static void main(String[] args) throws Exception{ DatagramSocket send = new DatagramSocket(); DatagramSocket rece = new DatagramSocket(9008); new Thread(new ChatSend(send)).start(); new Thread(new ChatRece(rece)).start(); } }
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
