Java UDP 编程简介.
一.UDP 協議簡介
UPD協議 是常見的 網絡傳輸協議之一, 當然另1個是TCP協議.
UPD協議 是一種不靠的協議.
是因為發送方不會關心接受方的狀態, 直接向接收方發送數據包, 也就是說這個數據包有可能因為對方不在線而丟失.
二. Java UDP編程的幾個關鍵的類(或數組).
1. Byte[], 字節數組, 在UDP協議中, 任何數據(圖片, 字符..) 都必須轉化成ByteArray.?? 字節數組相當與要發送或接受的貨物.
2. DatagramPacket, 字節數組不能網絡在傳輸,? 就如貨物不能直接在海上運輸一樣.
?? DatagramPacket 就相當于1個容器或集裝箱, 我們可以把字節數組放在這個容器, 然后在容器上貼上關鍵的信息.(目標地址和端口號)
?? 就如我們call順豐必須要事先把物品打包, 寫上地點和收件人一樣, 道理很簡單.
?? DatagramPacket 就是所謂的數據包, 把字節數組放入DatagramPacket的行為就叫數據打包.
3. DatagramSocket,? 這個類相當與1個碼頭, 碼頭與發送和接受集裝箱(DatagramPacket), 但是碼頭不會直接發送和接受貨物(ByteArray).
??
4. InetAddress, 這個是java中表示ip地址的1個類.
?? 它沒有提供公開的構造函數, 但是它提供靜態方法getByName(String ip)來返回1個靜態對象(singleTone).
?? 一般我們會將1個InetAddress對象貼到DatagramPacket對象上.
5. ByteAarryInputStream, ByteArrayOutputStream, DataInputStream, DataOutputStream...
?? 這個些流是把各種類型的數據轉換為字節數組的工具.
也就是說.
a. 所有的要發送的數據都必須轉換成字節數組.
b. 所有要發送的字節數組都必須打包(DatagramPacket), 并貼上目標ip, 和端口.
c. 所有的DatagramPacket都必須經過DatagramSocket來發送或接受.
三. DatagramSocket 簡介
上面說過了,? 這個類相當于1個發送和接受集裝箱(DatagramPacket)的碼頭.
下面介紹若干個它的關鍵方法.
3.1 DatagramSocket()
首先介紹構造方法, 這個構造方法是不帶任何參數的(ip, 端口).
這個構造方法一般用于構造1個發送端的碼頭,? 它可以向各個目標ip和端口發送數據包, 前提是目標ip和端口都附加在數據包(DatagramPacket).
3.2 DatagramSocket(int port)
這個方法一般用于構造接收數據包(DatagramPacket)的碼頭. 表示只接受指定端口的數據包.?
原理很簡單, 例如你發郵件, 可以向不同郵箱發送地址, 但是你只會接受發給你自己的郵件.
3.3 send(DatagramPacket dp)
將1個數據包發送出去, 發送哪里? 取決于數據包上面的ip和端口信息.
注意, 參數dp必須具有目標ip, 端口信息, 否則回throw Exception.
3.4 receive(DatagramPacket dp)
用1個數據包(集裝箱)來接受發送過來的數據,? 也就是dp這個參數的值會被修改.
這個方法一旦被執行, 程序會等待(hold 住), 知道收到1個數據包為止.
3.5 close()
關閉這個碼頭, DatagramSocket使用完后可以執行close()來釋放資源, 注意一旦close(), 就不能重新打開, 就如stream一樣.
四. DatagramPacket 簡介
上面提到過了, DatagramPacket 實際上是1個存放字節數組的容器.? 并可以貼上ip和端口信息用于發送.
下面也介紹若干個關鍵方法.
4.1 DatagramPacket(byte[] buf, int length)
首先也是構造方法, DatagramPacket并沒有提供參數為空的構造方法, 而且各個構造方法必須有1個字節數組參數.
這個字節數組就是DatagramPacket的內核數組.
也就是說, 我們不能構造1個為"空"的DatagramPacket.
4.2 setData(byte[] buf, int offset, int length),
但是我們可以用別的字節數組來替換掉原來的內核字節數組, 就是用這個setData方法了, 這個方法一般用于發送端, 在編程中, 我們可以利用同1個DatagramPacket對象來不斷發送不同的數據.
int offset, int length這個參數是指定 byteArray中的有效數據起始位置和長度.
4.3 setAddress(InetAddress iaddr)
為包裹貼上目標ip地址, 一般用于發送端.
注意參數是1個對象, 也就是我們必須實現構造1個InetAddress對象, 上面有提過.
4.4 setPort(int port)
為包裹貼上端口信息, 例如發送包裹到太古匯1座12F 匯豐公司(ip), 但是里面很多人啊, 誰來收呢. 所以還有加上收件人信息啊(port)
4.5 byte[] getData()
返回內核數組, 也就是把貨物從包裹中提取出來啦, 一般用于接收端.
這得注意的是, DatagramPacket這個容器一般可以重復利用.
對于發送端來講很簡單, 不斷利用setData(byte[] bArr)來替換內核數組(貨物)就ok了.
但是對于接受來講, DatagramPacket .的內核數組會用于接受數據.
那么這個內核數組的高位位置可能存在上次接受的數據.
DatagramPacket并沒有提供重置內核數組的方法.
所以我們需要用Arrays.fill()方法來手動重置它的內核數組(當然你也可以在接受前利用setData()來給它1個新的內核數組).
五. 一個UPD編程例子.
這個例子很簡單, 無非1個發送端放在本機, 1個接收端放在另1臺機器.
發送端會可以發送字符串(消息)給接受端, 接收端回在終端上顯示這個信息.
這個程序有四個類.
分別是
UDP_Server1.java???? ->?? 接收端
UPD_SocketReceive??? ->?? 接收端調用這個類來接受數據
UPD_Client1.Java????? ->? 發送端
UDP_SocketSend????? ->?? 發送端調用這個類來發送數據.
5.1 UDP_SocketSend?
這個類的提供下面關鍵方法:
start()????? 執行這個方法后, 可以發送數據.
send(byte[] bArr,int sLength, String ip, int port)??? 發送字節數組到指定ip 和端口
close()???? 關閉這個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
這個類調用上面的UDP_SocketSend,可以不斷地讓用戶發送消息到制定的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數據包.
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
這個類不斷循環調用上面那個UDP_SocketReceive 來接受數據包, 實際上就是在監聽制定的端口, 一旦接受到數據包, 就把數據包里的數據轉化為字符串輸出到終端.
5.5 執行結果
將編譯后的UDP_Server1 放在虛擬機的xp里執行(java跨平臺),? UDP_Client1放在本機執行, 如下:
5.6 小結
上面例子的功能十分簡單, 一端只能發送, 一端只能接受, 但是如果我們利用多線程,? 在兩端都打開發送和接受線程, 就相當于1個簡單的UDP聊天工具了..
總結
以上是生活随笔為你收集整理的Java UDP 编程简介.的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java Web 编程入门知识
- 下一篇: Java 接口(interface)的用