目錄
1.UDP協(xié)議介紹
2.UDP協(xié)議在Java中的類
2.1DatagramSocket類
2.2DatagramPacket
3.回顯服務(wù)器
3.1Sever端?
3.2Client端
1.UDP協(xié)議介紹
? UDP協(xié)議是一種網(wǎng)絡(luò)協(xié)議,它是無連接的,全雙工,并且是面向數(shù)據(jù)報(bào),不可靠的一種協(xié)議。常用于在線視頻播放,游戲這種實(shí)時(shí)性要求比較高的應(yīng)用?;蛘邿o需可靠傳輸?shù)膽?yīng)用,如DNS查詢 SNMP等。一次UDP數(shù)據(jù)報(bào)報(bào)文傳輸?shù)臄?shù)據(jù)最大為64kb,實(shí)際上,UDP因?yàn)轭^部占用八個(gè)字節(jié)。所以可傳輸?shù)木珳?zhǔn)大小為64kb-8b = 65507字節(jié)。
2.UDP協(xié)議在Java中的類
?UDP協(xié)議作為傳輸層協(xié)議,在Java中我們無需面對原生UDP協(xié)議,我們只需要調(diào)用Java封裝好的類來使用UDP協(xié)議來傳輸和接受數(shù)據(jù)即可。在Java中有兩個(gè)類,分別是DatagramSocket類和DatagramPacket類。
2.1DatagramSocket類
DatagramSocket用于創(chuàng)建Socket,綁定到端口號。它將網(wǎng)卡抽象成文件來方便程序猿來來操作。
DatagramSocket類的構(gòu)造方法:DatagramSocket類里的方法:
方法簽名 | 方法說明 |
void receive(DatagramPacket p) |
從此套接字接收數(shù)據(jù)報(bào)(如果沒有接收到數(shù)據(jù)報(bào),該方法會阻 塞等待) |
void send(DatagramPacket p) |
從此套接字發(fā)送數(shù)據(jù)報(bào)包(不會阻塞等待,直接發(fā)送) |
void close() | 關(guān)閉此數(shù)據(jù)報(bào)套接字 |
2.2DatagramPacket
DatagramPacket是UDP Socket發(fā)送和接收的數(shù)據(jù)報(bào)
DatagramPacket的構(gòu)造方法:
方法簽名 | 方法說明 |
DatagramPacket(byte[] buf, int length) |
構(gòu)造一個(gè)DatagramPacket以用來接收數(shù)據(jù)報(bào),接收的數(shù)據(jù)保存在 字節(jié)數(shù)組(第一個(gè)參數(shù)buf)中,接收指定長度(第二個(gè)參數(shù) length) |
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) |
構(gòu)造一個(gè)DatagramPacket以用來發(fā)送數(shù)據(jù)報(bào),發(fā)送的數(shù)據(jù)為字節(jié) 數(shù)組(第一個(gè)參數(shù)buf)中,從0到指定長度(第二個(gè)參數(shù) length)。address指定目的主機(jī)的IP和端口號 |
DatagramPacket的方法:
方法簽名 | 方法說明 |
InetAddress getAddress() |
從接收的數(shù)據(jù)報(bào)中,獲取發(fā)送端主機(jī)IP地址;或從發(fā)送的數(shù)據(jù)報(bào)中,獲取 接收端主機(jī)IP地址 |
int getPort() | 從接收的數(shù)據(jù)報(bào)中,獲取發(fā)送端主機(jī)的端口號;或從發(fā)送的數(shù)據(jù)報(bào)中,獲 取接收端主機(jī)端口號 |
byte[] getData() | 獲取數(shù)據(jù)報(bào)中的數(shù)據(jù) |
3.回顯服務(wù)器
為了方便大家理解和更好的使用UDP協(xié)議中的這兩個(gè)類來實(shí)現(xiàn)網(wǎng)絡(luò)編程,跨主機(jī)通信。
我們來寫個(gè)簡單的客戶端-服務(wù)器程序-回顯服務(wù)器,客戶端將數(shù)據(jù)發(fā)送到服務(wù)器上,服務(wù)器在返回給客戶端這個(gè)數(shù)據(jù)并且打印下來。主要目的是為了方便大家理解。
3.1Sever端?
在Sever端寫之前,我們先講明白幾件事,首先就是我們的構(gòu)造方法要不要指定端口號。答案是肯定的,因?yàn)檫@是服務(wù)器端,客戶端想要訪問它,肯定要有一個(gè)固定的地址,不然如何去訪問,所以在構(gòu)造方法中,我們直接從1024-65535這些端口號中選擇一個(gè)給綁定上。
還有就是我們的主要邏輯過程:
1.接受數(shù)據(jù)并解析
2.將這個(gè)數(shù)據(jù)進(jìn)行服務(wù)器的操作,即根據(jù)請求計(jì)算響應(yīng)。
3.將響應(yīng)返回給客戶端。
明白了這些以后,我們開始編寫代碼
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
public class UdpEchoSever {
DatagramSocket socket = null;
public UdpEchoSever (int sort) throws SocketException {
socket = new DatagramSocket(sort);//因?yàn)槭欠?wù)器程序,所以我們要指定端口號
}
public void start() throws IOException {
while (true){ //這里的while(true)是因?yàn)闀泻芏嗫蛻舳藖碓L問這個(gè)服務(wù)器,所以我們的服務(wù)器是7*24小時(shí)運(yùn)行的
System.out.println("服務(wù)器啟動(dòng)");
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes,0,bytes.length); //創(chuàng)建一個(gè)數(shù)據(jù)報(bào)用來接收,這是一個(gè)輸出型參數(shù)
socket.receive(packet); //如果沒有客戶端進(jìn)行訪問,就會進(jìn)行阻塞等待
String request = new String(packet.getData(),0, packet.getLength()); //將這個(gè)數(shù)據(jù)報(bào)解析成字符串的形式
String response = fun(request);
DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,packet.getSocketAddress());
//在構(gòu)造的時(shí)候要將數(shù)據(jù)報(bào)轉(zhuǎn)化為字符數(shù)組,并且指定IP地址和端口號發(fā)送,這里我們的IP地址和端口號,已經(jīng)被存入到,packet.getSocketAddress()里面了
System.out.printf("[%s :%d] req:%s,resp : %s\n",responsePacket.getAddress().toString(),responsePacket.getPort(),request,response);
socket.send(responsePacket);
}
}
private String fun(String request) {
return request;
}
public static void main(String[] args) throws IOException {
UdpEchoSever udpEchoSever = new UdpEchoSever(9090);
udpEchoSever.start();
}
}
3.2Client端
至于客戶端,我們的邏輯就是,在構(gòu)造方法里,要傳入服務(wù)器的IP地址和端口號,以方便后續(xù)使用。
至于主方法,我們的大概思路分為以下幾步
1.用戶通過控制臺輸入,并且構(gòu)造成DatagramPacket數(shù)據(jù)報(bào),此時(shí)這個(gè)類里面應(yīng)該有我們的數(shù)據(jù)和IP地址以及端口號
2.將這個(gè)數(shù)據(jù)報(bào)發(fā)送給服務(wù)器
3.從服務(wù)器拿到響應(yīng)并且解析
4.將解析的響應(yīng)打印出來
現(xiàn)在我們開始編程:
import javax.xml.ws.soap.Addressing;
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
public class UdpEchoClient {
DatagramSocket socket = null;
int severport;
String severIp;
public UdpEchoClient(String severIp,int severport) throws SocketException { //在構(gòu)造方法中傳入服務(wù)器的IP地址和端口號
socket = new DatagramSocket();
this.severIp = severIp;
this.severport = severport;
}
public void start() throws IOException {
Scanner scanner = new Scanner(System.in);
System.out.println("客戶端啟動(dòng)");
while (true){
System.out.print("->");
if(!scanner.hasNext()){ //用戶輸入到回車等這些空字符以后就結(jié)束
break;
}
String request = scanner.next();
DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,
InetAddress.getByName(severIp),severport); //將數(shù)據(jù)以及IP地址(這里的IP地址是字符串,
// 所以我們需要調(diào)用InetAddress.getByName())以及端口號也寫進(jìn)去
socket.send(requestPacket);//發(fā)送到服務(wù)器
byte[] bytes = new byte[1024];
DatagramPacket responsPacket = new DatagramPacket(bytes,bytes.length);//同樣是輸出型參數(shù),所以要先有一個(gè)空的字符數(shù)組
socket.receive(responsPacket);//接收服務(wù)器傳來的響應(yīng)
String respons = new String(responsPacket.getData(),0,responsPacket.getLength());//將響應(yīng)轉(zhuǎn)化為字符串
System.out.println(respons);//打印下來
}
}
public static void main(String[] args) throws IOException {
UdpEchoClient udpEchoClient = new UdpEchoClient("127.0.0.1",9090);
udpEchoClient.start();
}
}
我們來看看運(yùn)行結(jié)果
?可以看到客戶端沒有問題。我們再來看看服務(wù)器端的控制臺:文章來源:http://www.zghlxwxcb.cn/news/detail-814293.html
也和我們預(yù)期的結(jié)果一樣文章來源地址http://www.zghlxwxcb.cn/news/detail-814293.html
到了這里,關(guān)于[網(wǎng)絡(luò)編程]UDP協(xié)議,基于UDP協(xié)議的回顯服務(wù)器的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!