Java UDP 编程简介.
一.UDP 協(xié)議簡介
UPD協(xié)議 是常見的 網(wǎng)絡(luò)傳輸協(xié)議之一, 當(dāng)然另1個是TCP協(xié)議.
UPD協(xié)議 是一種不靠的協(xié)議.
是因為發(fā)送方不會關(guān)心接受方的狀態(tài), 直接向接收方發(fā)送數(shù)據(jù)包, 也就是說這個數(shù)據(jù)包有可能因為對方不在線而丟失.
二. Java UDP編程的幾個關(guān)鍵的類(或數(shù)組).
1. Byte[], 字節(jié)數(shù)組, 在UDP協(xié)議中, 任何數(shù)據(jù)(圖片, 字符..) 都必須轉(zhuǎn)化成ByteArray.?? 字節(jié)數(shù)組相當(dāng)與要發(fā)送或接受的貨物.
2. DatagramPacket, 字節(jié)數(shù)組不能網(wǎng)絡(luò)在傳輸,? 就如貨物不能直接在海上運(yùn)輸一樣.
?? DatagramPacket 就相當(dāng)于1個容器或集裝箱, 我們可以把字節(jié)數(shù)組放在這個容器, 然后在容器上貼上關(guān)鍵的信息.(目標(biāo)地址和端口號)
?? 就如我們call順豐必須要事先把物品打包, 寫上地點(diǎn)和收件人一樣, 道理很簡單.
?? DatagramPacket 就是所謂的數(shù)據(jù)包, 把字節(jié)數(shù)組放入DatagramPacket的行為就叫數(shù)據(jù)打包.
3. DatagramSocket,? 這個類相當(dāng)與1個碼頭, 碼頭與發(fā)送和接受集裝箱(DatagramPacket), 但是碼頭不會直接發(fā)送和接受貨物(ByteArray).
??
4. InetAddress, 這個是java中表示ip地址的1個類.
?? 它沒有提供公開的構(gòu)造函數(shù), 但是它提供靜態(tài)方法getByName(String ip)來返回1個靜態(tài)對象(singleTone).
?? 一般我們會將1個InetAddress對象貼到DatagramPacket對象上.
5. ByteAarryInputStream, ByteArrayOutputStream, DataInputStream, DataOutputStream...
?? 這個些流是把各種類型的數(shù)據(jù)轉(zhuǎn)換為字節(jié)數(shù)組的工具.
也就是說.
a. 所有的要發(fā)送的數(shù)據(jù)都必須轉(zhuǎn)換成字節(jié)數(shù)組.
b. 所有要發(fā)送的字節(jié)數(shù)組都必須打包(DatagramPacket), 并貼上目標(biāo)ip, 和端口.
c. 所有的DatagramPacket都必須經(jīng)過DatagramSocket來發(fā)送或接受.
三. DatagramSocket 簡介
上面說過了,? 這個類相當(dāng)于1個發(fā)送和接受集裝箱(DatagramPacket)的碼頭.
下面介紹若干個它的關(guān)鍵方法.
3.1 DatagramSocket()
首先介紹構(gòu)造方法, 這個構(gòu)造方法是不帶任何參數(shù)的(ip, 端口).
這個構(gòu)造方法一般用于構(gòu)造1個發(fā)送端的碼頭,? 它可以向各個目標(biāo)ip和端口發(fā)送數(shù)據(jù)包, 前提是目標(biāo)ip和端口都附加在數(shù)據(jù)包(DatagramPacket).
3.2 DatagramSocket(int port)
這個方法一般用于構(gòu)造接收數(shù)據(jù)包(DatagramPacket)的碼頭. 表示只接受指定端口的數(shù)據(jù)包.?
原理很簡單, 例如你發(fā)郵件, 可以向不同郵箱發(fā)送地址, 但是你只會接受發(fā)給你自己的郵件.
3.3 send(DatagramPacket dp)
將1個數(shù)據(jù)包發(fā)送出去, 發(fā)送哪里? 取決于數(shù)據(jù)包上面的ip和端口信息.
注意, 參數(shù)dp必須具有目標(biāo)ip, 端口信息, 否則回throw Exception.
3.4 receive(DatagramPacket dp)
用1個數(shù)據(jù)包(集裝箱)來接受發(fā)送過來的數(shù)據(jù),? 也就是dp這個參數(shù)的值會被修改.
這個方法一旦被執(zhí)行, 程序會等待(hold 住), 知道收到1個數(shù)據(jù)包為止.
3.5 close()
關(guān)閉這個碼頭, DatagramSocket使用完后可以執(zhí)行close()來釋放資源, 注意一旦close(), 就不能重新打開, 就如stream一樣.
四. DatagramPacket 簡介
上面提到過了, DatagramPacket 實(shí)際上是1個存放字節(jié)數(shù)組的容器.? 并可以貼上ip和端口信息用于發(fā)送.
下面也介紹若干個關(guān)鍵方法.
4.1 DatagramPacket(byte[] buf, int length)
首先也是構(gòu)造方法, DatagramPacket并沒有提供參數(shù)為空的構(gòu)造方法, 而且各個構(gòu)造方法必須有1個字節(jié)數(shù)組參數(shù).
這個字節(jié)數(shù)組就是DatagramPacket的內(nèi)核數(shù)組.
也就是說, 我們不能構(gòu)造1個為"空"的DatagramPacket.
4.2 setData(byte[] buf, int offset, int length),
但是我們可以用別的字節(jié)數(shù)組來替換掉原來的內(nèi)核字節(jié)數(shù)組, 就是用這個setData方法了, 這個方法一般用于發(fā)送端, 在編程中, 我們可以利用同1個DatagramPacket對象來不斷發(fā)送不同的數(shù)據(jù).
int offset, int length這個參數(shù)是指定 byteArray中的有效數(shù)據(jù)起始位置和長度.
4.3 setAddress(InetAddress iaddr)
為包裹貼上目標(biāo)ip地址, 一般用于發(fā)送端.
注意參數(shù)是1個對象, 也就是我們必須實(shí)現(xiàn)構(gòu)造1個InetAddress對象, 上面有提過.
4.4 setPort(int port)
為包裹貼上端口信息, 例如發(fā)送包裹到太古匯1座12F 匯豐公司(ip), 但是里面很多人啊, 誰來收呢. 所以還有加上收件人信息啊(port)
4.5 byte[] getData()
返回內(nèi)核數(shù)組, 也就是把貨物從包裹中提取出來啦, 一般用于接收端.
這得注意的是, DatagramPacket這個容器一般可以重復(fù)利用.
對于發(fā)送端來講很簡單, 不斷利用setData(byte[] bArr)來替換內(nèi)核數(shù)組(貨物)就ok了.
但是對于接受來講, DatagramPacket .的內(nèi)核數(shù)組會用于接受數(shù)據(jù).
那么這個內(nèi)核數(shù)組的高位位置可能存在上次接受的數(shù)據(jù).
DatagramPacket并沒有提供重置內(nèi)核數(shù)組的方法.
所以我們需要用Arrays.fill()方法來手動重置它的內(nèi)核數(shù)組(當(dāng)然你也可以在接受前利用setData()來給它1個新的內(nèi)核數(shù)組).
五. 一個UPD編程例子.
這個例子很簡單, 無非1個發(fā)送端放在本機(jī), 1個接收端放在另1臺機(jī)器.
發(fā)送端會可以發(fā)送字符串(消息)給接受端, 接收端回在終端上顯示這個信息.
這個程序有四個類.
分別是
UDP_Server1.java???? ->?? 接收端
UPD_SocketReceive??? ->?? 接收端調(diào)用這個類來接受數(shù)據(jù)
UPD_Client1.Java????? ->? 發(fā)送端
UDP_SocketSend????? ->?? 發(fā)送端調(diào)用這個類來發(fā)送數(shù)據(jù).
5.1 UDP_SocketSend?
這個類的提供下面關(guān)鍵方法:
start()????? 執(zhí)行這個方法后, 可以發(fā)送數(shù)據(jù).
send(byte[] bArr,int sLength, String ip, int port)??? 發(fā)送字節(jié)數(shù)組到指定ip 和端口
close()???? 關(guān)閉這個socket.
代碼如下:
package UDP_kng;import java.net.*; import java.io.*;public class UDP_SocketSend{private boolean startedFlag;private InetAddress ipSend;private DatagramSocket dataSocket; //it just like a wharf or portprivate DatagramPacket dataPacket = new DatagramPacket(new byte[1],0); //it just like a containerpublic UDP_SocketSend(){this.startedFlag = false;} //build a wharfpublic int start(){if (true == this.startedFlag){System.out.println("Err: This UDP Client is started..");return -2;}try{dataSocket = new DatagramSocket();System.out.println("This socket started successfully!!");}catch(Exception e){e.printStackTrace();System.out.println("Err: Failed to instantiate a UDP Socket..!!");return -1;}this.startedFlag = true;return 0;}public int close(){if (false == this.startedFlag){System.err.println("Err: The socket is not started yet!");return -2;}try{dataSocket.close(); //once the socket is closed, it cannot be reopen, we hava to new another socket if we want to sendout data.System.out.println("this socket closed successfully!!");}catch(Exception e){e.printStackTrace();System.err.println("Err: Fail to close the Socket!!");return -1;}this.startedFlag = false;return 0;}public int send(byte[] bArr,int sLength, String ip, int port){if (false == this.startedFlag){System.err.println("Err: The socket is not started yet!");return -2;}if (0 >= port){System.err.println("Err: The port provided is not vaild!");return -1;}try{ipSend = InetAddress.getByName(ip); }catch(Exception e){System.err.println("Err: Failed to setup the ip address!");}dataPacket.setPort(port); //attach a labeldataPacket.setData(bArr,0,sLength); //put the data into this containerdataPacket.setAddress(ipSend);try{dataSocket.send(dataPacket); //send out the container to ipSend}catch(Exception e){e.printStackTrace();System.err.println("Err: Failed to send out the data package!");return -3;}return 0;}}5.2 UDP_Client1
這個類調(diào)用上面的UDP_SocketSend,可以不斷地讓用戶發(fā)送消息到制定的ip和端口.
代碼:
package UDP_kng;import java.net.*; import java.io.*; import UDP_kng.*;public class UDP_Client1{private static int port = 9001;//private static String ip = "127.0.0.1";private static String ip = "192.168.1.106";public static void f() throws Exception{ByteArrayOutputStream bas = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bas);DataInputStream dis = new DataInputStream(System.in);UDP_SocketSend uSender = new UDP_SocketSend();uSender.start();System.out.println("Please input your message, type EOF to exit.");String msg = dis.readLine();while(!msg.equals("EOF")){bas.reset();dos.writeBytes(msg);dos.flush();uSender.send(bas.toByteArray(), bas.size(),ip, port);System.out.println("Please input your message, type EOF to exit.");msg = dis.readLine();}uSender.close();dos.close();dis.close();//uSender.send(dstream.toByteArray(),"127.0.0.1", port);} }
5.3 UDP_SocketReceive
這個類提供receive()方法, 返回1個DatagramPacket數(shù)據(jù)包.
package UDP_kng;import java.net.*; import java.util.Arrays;public class UDP_SocketReceive{private DatagramSocket dataSocket; //just like a wharfprivate byte[] bArr = new byte[1024];private DatagramPacket dataPacket = new DatagramPacket(bArr,bArr.length); //just like a containerprivate int port;private boolean startedFlag = false;public UDP_SocketReceive(int port){this.port = port;this.start(); } public int start(){if (true == startedFlag){System.err.println("This socket is stated already!");return -1;}try{dataSocket = new DatagramSocket(this.port);}catch(Exception e){e.printStackTrace();System.err.println("fail to new a DatagramSocket, please try to start once again!");this.startedFlag = false;return -2;}this.startedFlag = true;return 0;} public DatagramPacket receive(){if (false == startedFlag){System.err.println("This socket is not stated yet!");return null;}byte b = 0;Arrays.fill(bArr,b); //clean the dataPacket, avoid to show previous data.try{dataSocket.receive(this.dataPacket);//after this step, the container have got the data from sender.}catch(Exception e){e.printStackTrace();System.err.println("Failed receive a datapackage!");return null;}return dataPacket;}}5.4 UDP_SocketServer1
這個類不斷循環(huán)調(diào)用上面那個UDP_SocketReceive 來接受數(shù)據(jù)包, 實(shí)際上就是在監(jiān)聽制定的端口, 一旦接受到數(shù)據(jù)包, 就把數(shù)據(jù)包里的數(shù)據(jù)轉(zhuǎn)化為字符串輸出到終端.
5.5 執(zhí)行結(jié)果
將編譯后的UDP_Server1 放在虛擬機(jī)的xp里執(zhí)行(java跨平臺),? UDP_Client1放在本機(jī)執(zhí)行, 如下:
5.6 小結(jié)
上面例子的功能十分簡單, 一端只能發(fā)送, 一端只能接受, 但是如果我們利用多線程,? 在兩端都打開發(fā)送和接受線程, 就相當(dāng)于1個簡單的UDP聊天工具了..
總結(jié)
以上是生活随笔為你收集整理的Java UDP 编程简介.的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java Web 编程入门知识
- 下一篇: Java 接口(interface)的用