目錄
UDP網(wǎng)絡(luò)通信編程
基本介紹
UDP編程的基本流程
應(yīng)用實例
本章習(xí)題
第一題
服務(wù)端
客戶端
第二題
服務(wù)端
客戶端
UDP網(wǎng)絡(luò)通信編程
基本介紹
UDP(User Datagram Protocol)是一種無連接的傳輸協(xié)議,不保證傳輸數(shù)據(jù)的可靠性。在網(wǎng)絡(luò)通信中,UDP常用于那些對實時性要求較高、可靠性要求較低的應(yīng)用程序,比如音視頻傳輸?shù)取?/p>
1.類 DatagramSocket 和 DatagramPacket[數(shù)據(jù)包/數(shù)據(jù)報] 實現(xiàn)了基于 UDP協(xié)議網(wǎng)絡(luò)程序
2.UDP數(shù)據(jù)報通過數(shù)據(jù)報套接字 DatagramSocket 發(fā)送和接收,系統(tǒng)不保證UDP數(shù)據(jù)報一定能夠安全送到目的地,也不能確定什么時候可以抵達
3.DatagramPacket 對象封裝了UDP數(shù)據(jù)報,在數(shù)據(jù)報中包含了發(fā)送端的IP地址和端口號以及接收端的IP地址和端口號
4.UDP協(xié)議中每個數(shù)據(jù)報都給出了完整的地址信息,因此無須建立發(fā)送方和接收方的連接
在Java中,進行UDP網(wǎng)絡(luò)通信可以使用Java自帶的java.net包中的DatagramSocket和DatagramPacket類。
- DatagramSocket類
DatagramSocket類是實現(xiàn)基于UDP協(xié)議的網(wǎng)絡(luò)通信的基礎(chǔ)。該類提供的方法包括:
- DatagramSocket(int port):創(chuàng)建一個DatagramSocket對象,并綁定到指定端口號。
- void send(DatagramPacket p):將數(shù)據(jù)報發(fā)送到指定的主機和端口。
- void receive(DatagramPacket p):等待接收數(shù)據(jù)報。
- void setSoTimeout(int timeout):設(shè)置socket的超時時間。
- DatagramPacket類
DatagramPacket類代表著數(shù)據(jù)報包,包含了要發(fā)送或接收的數(shù)據(jù)、數(shù)據(jù)的長度以及發(fā)送或接收方的IP地址和端口號等信息。該類提供的方法包括:
- DatagramPacket(byte[] buf, int length):創(chuàng)建一個DatagramPacket對象,用于接收數(shù)據(jù)報。
- DatagramPacket(byte[] buf, int length, InetAddress address, int port):創(chuàng)建一個DatagramPacket對象,用于發(fā)送數(shù)據(jù)報。
- byte[] getData():獲取數(shù)據(jù)報的數(shù)據(jù)。
- InetAddress getAddress():獲取發(fā)送或接收方的IP地址。
- int getPort():獲取發(fā)送或接收方的端口號。
UDP編程的基本流程
1.核心的兩個類/對象 DatagramSocket與DatagramPacket·
2.建立發(fā)送端,接收端(沒有服務(wù)端和客戶端概念)
3.發(fā)送數(shù)據(jù)前,建立數(shù)據(jù)包/報 DatagramPacket對象
4.調(diào)用DatagramSocket的發(fā)送、接收方法
5.關(guān)閉DatagramSocket
應(yīng)用實例
代碼演示:
首先我們先?創(chuàng)建 DatagramSocket 對象,準(zhǔn)備在8887端口 接收數(shù)據(jù)
第二步將需要發(fā)送的數(shù)據(jù),封裝到 DatagramPacket對象,主要要把發(fā)送的內(nèi)容轉(zhuǎn)換成字節(jié)數(shù)組
這里要注意一下?封裝的 DatagramPacket對象 bytes 內(nèi)容字節(jié)數(shù)組 , bytes.length , 主機(IP) , 端口
然后?構(gòu)建一個 DatagramPacket 對象,準(zhǔn)備接收數(shù)據(jù)?因為UDP 協(xié)議時一個數(shù)據(jù)包最大 64k
package com.homework;
/*
(1)編寫一個接收端A,和一個發(fā)送端B, 使用UDP協(xié)議完成
(2) 接收端在 8888端口等待接收數(shù)據(jù)(receive)
(3)發(fā)送端向接收端 發(fā)送 數(shù)據(jù)“四大名著是哪些"
(4)接收端接收到 發(fā)送端發(fā)送的 問題后,返回“四大名著是<<紅樓夢>> ...”,否則返回what?
(5)接收端和發(fā)送端程序退出
*/
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
/**
* 發(fā)送端B ====> 也可以接收數(shù)據(jù)
*/
public class Homework02SenderB {
public static void main(String[] args) throws IOException {
//1.創(chuàng)建 DatagramSocket 對象,準(zhǔn)備在8887端口 接收數(shù)據(jù)
DatagramSocket socket = new DatagramSocket(8887);
//2. 將需要發(fā)送的數(shù)據(jù),封裝到 DatagramPacket對象
System.out.println("請輸入你的問題: ");
Scanner scanner = new Scanner(System.in);
String question = scanner.next();
byte[] bytes = question.getBytes();//把要發(fā)送的內(nèi)容轉(zhuǎn)成字節(jié)數(shù)組
//說明: 封裝的 DatagramPacket對象 bytes 內(nèi)容字節(jié)數(shù)組 , bytes.length , 主機(IP) , 端口
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.55.57"), 8888);
socket.send(datagramPacket);//發(fā)送
//3.=== 接收從A端回復(fù)的信息
//(1) 構(gòu)建一個 DatagramPacket 對象,準(zhǔn)備接收數(shù)據(jù)
// 在前面講解UDP 協(xié)議時,說過一個數(shù)據(jù)包最大 64k
byte[] bytes1 = new byte[1024];
datagramPacket = new DatagramPacket(bytes1, bytes1.length);
//(2) 調(diào)用 接收方法, 將通過網(wǎng)絡(luò)傳輸?shù)?DatagramPacket 對象
// 填充到 datagramPacket對象
// 當(dāng)有數(shù)據(jù)包發(fā)送到 本機的8887端口時,就會接收到數(shù)據(jù)
// 如果沒有數(shù)據(jù)包發(fā)送到 本機的8887端口, 就會阻塞等待.
socket.receive(datagramPacket);
//(3) 可以把datagramPacket 進行拆包,取出數(shù)據(jù),并顯示.
int length = datagramPacket.getLength();//實際接收到的數(shù)據(jù)字節(jié)長度
byte[] data = datagramPacket.getData();//接收到數(shù)據(jù)
String s = new String(data, 0, length);//構(gòu)建一個字符串
System.out.println("接收到9999端口發(fā)來的信息");
System.out.println(s);
//關(guān)閉資源
socket.close();
System.out.println("B端退出");
}
}
package com.homework;
/*
(1)編寫一個接收端A,和一個發(fā)送端B, 使用UDP協(xié)議完成
(2) 接收端在 8888端口等待接收數(shù)據(jù)(receive)
(3)發(fā)送端向接收端 發(fā)送 數(shù)據(jù)“四大名著是哪些"
(4)接收端接收到 發(fā)送端發(fā)送的 問題后,返回“四大名著是<<紅樓夢>> ...”,否則返回what?
(5)接收端和發(fā)送端程序退出
*/
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
/**
* UDP接收端
*/
public class Homework02ReceiverA {
public static void main(String[] args) throws IOException {
//1. 創(chuàng)建一個 DatagramSocket 對象,準(zhǔn)備在8888接收數(shù)據(jù)
DatagramSocket socket = new DatagramSocket(8888);
//2. 構(gòu)建一個 DatagramPacket 對象,準(zhǔn)備接收數(shù)據(jù)
// 在前面講解UDP 協(xié)議時,說過一個數(shù)據(jù)包最大 64k
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
//3. 調(diào)用 接收方法, 將通過網(wǎng)絡(luò)傳輸?shù)?DatagramPacket 對象
// 填充到 datagramPacket對象
//當(dāng)有數(shù)據(jù)包發(fā)送到 本機的8888端口時,就會接收到數(shù)據(jù)
// 如果沒有數(shù)據(jù)包發(fā)送到 本機的8888端口, 就會阻塞等待.
System.out.println("接收端A 等待接收數(shù)據(jù)..");
socket.receive(datagramPacket);
//4. 可以把datagramPacket 進行拆包,取出數(shù)據(jù),并顯示
int length = datagramPacket.getLength();//實際接收到的數(shù)據(jù)字節(jié)長度
byte[] data = datagramPacket.getData();//接收到數(shù)據(jù)
String s = new String(data, 0, length);//構(gòu)建一個字符串
String s2 = "";//定義輔助變量
if (s.equals("四大名著是那些")) {
s2 = "四大名著 <<紅樓夢>> <<三國演示>> <<西游記>> <<水滸傳>>";
} else {
s2 = "what?";
}
//===回復(fù)信息給B端
//將需要發(fā)送的數(shù)據(jù),存放到bytes數(shù)組中
bytes = s2.getBytes();
//說明: 封裝的 DatagramPacket對象 bytes 內(nèi)容字節(jié)數(shù)組 , bytes.length , 主機(IP) , 端口
datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.55.57"), 8887);
socket.send(datagramPacket);//發(fā)送
//5. 關(guān)閉資源
socket.close();
System.out.println("A端退出...");
}
}
本章習(xí)題
第一題
代碼演示:
要求:文章來源:http://www.zghlxwxcb.cn/news/detail-459958.html
(1)使用字符流的方式,編寫一個客戶端程序和服務(wù)器端程序,
(2)客戶端發(fā)送“name”,服務(wù)器端接收到后,返回“我是 nova",nova 是你自己的名字
(3)客戶端發(fā)送“hobby”,服務(wù)器端接收到后,返回“編java程序”
(4)不是這兩個問題,回復(fù)“你說啥呢!
服務(wù)端代碼
package com.homework;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/*
(1)使用字符流的方式,編寫一個客戶端程序和服務(wù)器端程序,
(2)客戶端發(fā)送“name”,服務(wù)器端接收到后,返回“我是 nova",nova 是你自己的名字
(3)客戶端發(fā)送“hobby”,服務(wù)器端接收到后,返回“編java程序”
(4)不是這兩個問題,回復(fù)“你說啥呢!
*/
/**
* 服務(wù)端, 使用字符流方式讀寫
*/
public class Homework01Server {
public static void main(String[] args) throws IOException {
//思路
//1. 在本機 的9999端口監(jiān)聽, 等待連接
// 細(xì)節(jié): 要求在本機沒有其它服務(wù)在監(jiān)聽9999
// 細(xì)節(jié):這個 ServerSocket 可以通過 accept() 返回多個Socket[多個客戶端連接服務(wù)器的并發(fā)]
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服務(wù)端,在9999端口監(jiān)聽,等待連接..");
//2. 當(dāng)沒有客戶端連接9999端口時,程序會 阻塞, 等待連接
// 如果有客戶端連接,則會返回Socket對象,程序繼續(xù)
Socket socket = serverSocket.accept();
System.out.println("連接成功");
//3. 獲取socket相關(guān)聯(lián)的輸入流
InputStream inputStream = socket.getInputStream();
//4. IO讀取, 使用字符流, 老師使用 InputStreamReader 將 inputStream 轉(zhuǎn)成字符流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();//把讀取到的內(nèi)容存放到變量s中
String answer = "";//定義輔助變量
//對s進行判斷,返回不同的值
if (s.equals("name")) {
answer = "我是nova";
} else if (s.equals("hobby")) {
answer = "編寫Java程序";
} else {
answer = "你說啥呢";
}
//5. 獲取socket相關(guān)聯(lián)的輸出流
OutputStream outputStream = socket.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write(answer);//根據(jù)s的值返回不同的信息
bufferedWriter.flush();// 如果使用的字符流,需要手動刷新,否則數(shù)據(jù)不會寫入數(shù)據(jù)通道
socket.shutdownOutput();//設(shè)置結(jié)束標(biāo)記
//6.關(guān)閉流
bufferedWriter.close();
bufferedReader.close();
socket.close();
serverSocket.close();//關(guān)閉
}
}
客戶端代碼
package com.homework;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
/*
(1)使用字符流的方式,編寫一個客戶端程序和服務(wù)器端程序,
(2)客戶端發(fā)送“name”,服務(wù)器端接收到后,返回“我是 nova",nova 是你自己的名字
(3)客戶端發(fā)送“hobby”,服務(wù)器端接收到后,返回“編java程序”
(4)不是這兩個問題,回復(fù)“你說啥呢!
*/
/**
* 客戶端,發(fā)送 信息 給服務(wù)端, 使用字符流
*/
public class Homework01Client {
public static void main(String[] args) throws IOException {
//思路
//1. 連接服務(wù)端 (ip , 端口)
//解讀: 連接本機的 9999端口, 如果連接成功,返回Socket對象
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
//2. 連接上后,生成Socket, 通過socket.getOutputStream()
// 得到 和 socket對象關(guān)聯(lián)的輸出流對象
OutputStream outputStream = socket.getOutputStream();
//3. 通過輸出流,寫入數(shù)據(jù)到 數(shù)據(jù)通道, 使用字符流
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
Scanner scanner = new Scanner(System.in);
System.out.println("請輸入內(nèi)容");
String s1 = scanner.next();
bufferedWriter.write(s1);//創(chuàng)建一個scanner把我們輸入的內(nèi)容寫入到數(shù)據(jù)通道中
bufferedWriter.newLine();//插入一個換行符,表示寫入的內(nèi)容結(jié)束, 注意,要求對方使用readLine()!!!!
bufferedWriter.flush();// 如果使用的字符流,需要手動刷新,否則數(shù)據(jù)不會寫入數(shù)據(jù)通道
//4. 獲取和socket關(guān)聯(lián)的輸入流. 讀取數(shù)據(jù)(字符),并顯示
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
System.out.println("接收到服務(wù)端發(fā)來的信息");
String s = bufferedReader.readLine();//讀取數(shù)據(jù)通道中的內(nèi)容并輸出
System.out.println(s);
//5.關(guān)閉流
bufferedReader.close();
bufferedWriter.close();
socket.close();
}
}
第二題
代碼演示:
要求:
(1)編寫客戶端程序和服務(wù)器端程序
(2) 客戶端可以輸入 一個 音樂 文件名,比如 高山流水,服務(wù)端 收到音樂名后,可以給客戶端 返回這個 音樂文件,如果服務(wù)器沒有這個文件,返回 一個默認(rèn)的音樂即可。
(3) 客戶端收到文件后,保存到本地 e:
(4)提示: 該程序可以使用 StreamUtils.java文章來源地址http://www.zghlxwxcb.cn/news/detail-459958.html
服務(wù)端代碼
package com.homework;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/*
(1)編寫客戶端程序和服務(wù)器端程序
(2) 客戶端可以輸入 一個 音樂 文件名,比如 高山流水,服務(wù)端 收到音樂名后,可以給客戶端 返回這個 音樂文件,如果服務(wù)器沒有這個文件,返回 一個默認(rèn)的音樂即可。
(3) 客戶端收到文件后,保存到本地 e:
(4)提示: 該程序可以使用 StreamUtils.java
*/
public class Homework03Server {
public static void main(String[] args) throws Exception {
//1 在 9999端口監(jiān)聽
ServerSocket serverSocket = new ServerSocket(9999);
//2.等待客戶端連接
System.out.println("服務(wù)端在9999端口等待連接");
Socket socket = serverSocket.accept();
System.out.println("連接成功");
//讀取到客戶端發(fā)來要下載的文件名
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
//也可以使用while循化的方式讀取文件名
/*
InputStream inputStream = socket.getInputStream();
byte[] b = new byte[1024];
int len = 0;
String downLoadFileName = "";
while ((len = inputStream.read(b)) != -1) {
downLoadFileName += new String(b, 0 , len);
}
System.out.println("客戶端希望下載文件名=" + downLoadFileName);
*/
//在服務(wù)器上有兩個文件, 無名.mp3 高山流水.mp3
//如果客戶下載的是 高山流水 我們就返回該文件,否則一律返回 無名.mp3
//根據(jù)用戶發(fā)來的信息進行判斷
String resFile = "";
if (s.equals("src\\高山流水.mp3")) {
resFile = "src\\高山流水.mp3";
} else {
resFile = "src\\無名.mp3";
}
//根據(jù)客戶端發(fā)來的信息讀取文件 因為讀取的是音樂要使用字節(jié)流不可以使用字符流,否則可能造成數(shù)據(jù)的丟失
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(resFile));
//使用工具類把讀到的文件轉(zhuǎn)成一個字節(jié)數(shù)組
byte[] bytes = StreamUtils.streamToByteArray(bis);
//把字節(jié)數(shù)組發(fā)送到數(shù)據(jù)通道
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
bos.write(bytes);
bos.flush();
socket.shutdownOutput();//設(shè)置結(jié)束標(biāo)記就
//關(guān)閉流
bis.close();
bos.close();
inputStream.close();
socket.close();
serverSocket.close();
System.out.println("服務(wù)端退出...");
}
}
客戶端代碼
package com.homework;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
/*
(1)編寫客戶端程序和服務(wù)器端程序
(2) 客戶端可以輸入 一個 音樂 文件名,比如 高山流水,服務(wù)端 收到音樂名后,可以給客戶端 返回這個 音樂文件,如果服務(wù)器沒有這個文件,返回 一個默認(rèn)的音樂即可。
(3) 客戶端收到文件后,保存到本地 e:
(4)提示: 該程序可以使用 StreamUtils.java
*/
public class Homework03Client {
public static void main(String[] args) throws Exception {
//客戶端連接服務(wù)端,準(zhǔn)備發(fā)送
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
// 獲取和Socket關(guān)聯(lián)的輸出流
OutputStream outputStream = socket.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
// 接收用戶輸入,指定下載文件名
Scanner scanner = new Scanner(System.in);
System.out.println("請輸入要下載的音樂名");
String next = scanner.next();
bufferedWriter.write(next);//把要下載的文件名發(fā)送到服務(wù)端
bufferedWriter.flush();
//設(shè)置寫入結(jié)束的標(biāo)志
socket.shutdownOutput();
String filePath = "e:\\" + next + ".mp3";
InputStream inputStream = socket.getInputStream();
//從數(shù)據(jù)通道中讀取讀取服務(wù)端返回的文件(字節(jié)數(shù)據(jù))
BufferedInputStream bis = new BufferedInputStream(inputStream);
//使用工具類轉(zhuǎn)成一個字節(jié)數(shù)組
byte[] bytes = StreamUtils.streamToByteArray(bis);
// 得到一個字節(jié)輸出流,準(zhǔn)備將 bytes 寫入到磁盤文件
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
bos.write(bytes);
bos.flush();
//關(guān)閉流
bis.close();
bos.close();
bufferedWriter.close();
socket.close();
System.out.println("客戶端下載完畢,正確退出..");
}
}
到了這里,關(guān)于Java網(wǎng)絡(luò)編程——UDP的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!