晉中網(wǎng)站開發(fā)關(guān)鍵詞智能優(yōu)化排名
一、TCP和UDP概述
傳輸層通常以TCP和UDP協(xié)議來控制端點與端點的通信
TCP | UDP | |
---|---|---|
協(xié)議名稱 | 傳輸控制協(xié)議 | 用戶數(shù)據(jù)包協(xié)議 |
是否連接 | 面向連接的協(xié)議。數(shù)據(jù)必須要建立連接 | 無連接的協(xié)議,每個數(shù)據(jù)報中都給出完整的地址信息,因此不需要事先建立發(fā)送方和接受方的連接 |
是否可靠 | 可靠協(xié)議。確保收方完全地獲取發(fā)送方所發(fā)送的全部數(shù)據(jù) | 不可靠協(xié)議。發(fā)送方所發(fā)送的數(shù)據(jù)報并不一定以相同的次序到達(dá)接收方。 |
可以傳輸?shù)臄?shù)據(jù)大小 | 傳輸數(shù)據(jù)大小不受限制。一旦連接建立,雙方可以按統(tǒng)一的格式傳輸大的數(shù)據(jù) | 傳輸數(shù)據(jù)時是有大小限制的。每個被傳輸?shù)臄?shù)據(jù)報必須限定在64KB之類 |
數(shù)據(jù)傳輸方式 | IO流 | DatagramPacket |
二、UDP
1.UDP通信概述
UDP協(xié)議是一種對等通信的實現(xiàn),發(fā)送方只需要接受方的IP(地址)和Port(端口),就可以直接向它發(fā)送數(shù)據(jù),不需要線連接。每個程序都可以作為服務(wù)器,也可以作為客戶端。UDP是一種無連接的傳輸協(xié)議,每個數(shù)據(jù)報的大小限定在64KB以內(nèi)。數(shù)據(jù)報是一個在網(wǎng)絡(luò)上發(fā)送的獨立信息,它的到達(dá)。到達(dá)時間以及內(nèi)容本身等都不能得到保證。這種傳輸方式是無序的,也不能確保絕對的安全可靠,但它很簡單也具有較高的效率。
使用UDP協(xié)議進(jìn)行數(shù)據(jù)傳輸是,需要將需要傳輸數(shù)據(jù)定義為數(shù)據(jù)報(DatagramPaket),在數(shù)據(jù)報中指明數(shù)據(jù)所要到達(dá)Socket(主機(jī)地址和端口號),然后再將數(shù)據(jù)報發(fā)送出去。實例化DatagramPacket時使用參數(shù)port和沒有使用參數(shù)port的區(qū)別在與,提供port的一方可以讓別人主動發(fā)送消息過來,而沒有參數(shù)port的則會在發(fā)送消息時自動綁定一個本地沒有使用的端口。在接收到發(fā)送的數(shù)據(jù)報(DatagramPaket)時,不僅可以獲取數(shù)據(jù),還可以獲得發(fā)送方的IP和Port,這樣就可以向發(fā)送方發(fā)送數(shù)據(jù),因此,本質(zhì)上二者是對等的。
2.UDP通信特點
1、UDP是一種無連接的協(xié)議,每個數(shù)據(jù)報都是一個獨立的信息,包括完整的原地址或目的地址,它在網(wǎng)絡(luò)上任何可能的路徑傳往目的地,因此能否到達(dá)目的地,到達(dá)目的地的時間以及內(nèi)容的正確性都是不能被保證的。
2、UDP不屬于連接型協(xié)議,因而具有資源消耗小,處理速度快的優(yōu)點,所以通常音頻視頻和普通數(shù)據(jù)在傳輸時使用UDP較多,因為它們即使偶爾丟一兩個數(shù)據(jù)包,也不會對接收結(jié)果產(chǎn)生太大的影響。
3.UDP通信傳輸實現(xiàn)的基石
UDP通信的Socket使用DatagramSocket類實現(xiàn),數(shù)據(jù)報使用DatagramPaket實現(xiàn)
3.1、DatagramPake常用方法
InetAddress getAddress() | 得到發(fā)送方IP地址 |
---|---|
int getPort() | 得到發(fā)送方的端口號 |
byte[] getData() | 返回接收緩沖區(qū),這是一個byte[] |
int getLength() | 接收字節(jié)的真實大小,通常用于從byte[]中提取出有效數(shù)據(jù) |
int getOffset() | 返回將要發(fā)送或則接收的數(shù)據(jù)偏移量 |
3.2、DatagramSocket常用方法
DatagramSocket() | 空構(gòu)造函數(shù) |
---|---|
DatagramSocket(int port) | 指定通信端口 |
void receive(DatagramPaket p) | 接收數(shù)據(jù)報 |
void send(DatagramPaket p) | 發(fā)送數(shù)據(jù)報 |
void close() | 關(guān)閉Socket |
4.UDP通信實現(xiàn)原理
無論一個UDP通信程序的功能多么功能齊全,程序多么復(fù)雜,七基本結(jié)構(gòu)都是一樣的,都包括以下四個基本步驟
1、在接收端指定一個端口號來創(chuàng)建DatagramSocket,然后創(chuàng)建一個接收數(shù)據(jù)報(DatagramPaket),使用recevie方法等待發(fā)送方請求報文,這將阻塞服務(wù)器線程
2、在發(fā)送方創(chuàng)建一個DatagramSocket,使用接收方的IP和端口來創(chuàng)建發(fā)送數(shù)據(jù)報(DatagramPaket),使用send方法發(fā)送?,F(xiàn)在接收方的recevie方法被喚醒,同時會將發(fā)送方的數(shù)據(jù)報內(nèi)容填充到接收方的DatagramPaket中。
3、接收方從發(fā)送方的數(shù)據(jù)報中獲得發(fā)送方的IP和端口,使用它們構(gòu)造一個發(fā)送數(shù)據(jù)報,然后發(fā)送給發(fā)送方,這樣就實現(xiàn)了發(fā)送方和接收方的通信
4、在通信完成后,在客服端和服務(wù)端中分別關(guān)閉Socket
5.UDP通信原理(代碼實現(xiàn))
代碼如下(發(fā)送端):
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;public class SendMessage {public static void main(String[] args) throws Exception {
// 創(chuàng)建發(fā)送端Socket對象
DatagramSocket sendSocket = new DatagramSocket();
// 準(zhǔn)備需要發(fā)送的數(shù)據(jù)
String message = "hello";
// 創(chuàng)建一個緩沖區(qū)
byte[] messageByte = message.getBytes();
// 獲取緩沖區(qū)中數(shù)據(jù)的真實長度
int messageLen = message.length();
// InetAddress實例化獲取本機(jī)通信地址
InetAddress address = InetAddress.getLocalHost();
// 設(shè)置通信端口號
int port = 12345;
// 打包數(shù)據(jù)
DatagramPacket sendPacket = new DatagramPacket(messageByte, messageLen, address, port);
// 發(fā)送數(shù)據(jù)
sendSocket.send(sendPacket);
// 發(fā)送端等待接收端成功接收信息后返回的回應(yīng)
// 創(chuàng)建一個緩沖區(qū),容量盡量設(shè)置大一點因為不知道發(fā)送過來的信息有多大
byte[] recevieByte = new byte[1024*10];
int len = recevieByte.length;
// 接收數(shù)據(jù)報
DatagramPacket receivePacket = new DatagramPacket(recevieByte, len);
// 接收數(shù)據(jù)
sendSocket.receive(receivePacket);
// 獲取接收端發(fā)送過來的真實長度以及數(shù)據(jù)
byte[] data = receivePacket.getData();
int length = receivePacket.getLength();
String receiveData = new String(data,0,length);
// 獲取發(fā)送者的IP
address = receivePacket.getAddress();
String ip = address.getHostAddress();
System.out.println("接收來自:"+ip+"的數(shù)據(jù),內(nèi)容是:"+receiveData);
// 關(guān)閉資源
sendSocket.close();
}
}
代碼如下(接收端):
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;public class RecevieMessage {public static void main(String[] args) throws Exception {
// 接收消息的端口(與發(fā)送端保持一致)
int port = 12345;
DatagramSocket recevieSocket = new DatagramSocket(port);
// 設(shè)置緩沖區(qū)接收發(fā)過來的信息
byte[] receiveByte = new byte[1024*10];
int len = receiveByte.length;
// 接收數(shù)據(jù)報
DatagramPacket receviePacket = new DatagramPacket(receiveByte, len);
// 接收數(shù)據(jù)
recevieSocket.receive(receviePacket);
// 獲取實際接收到的數(shù)據(jù)及其大小
byte[] data = receviePacket.getData();
int length = receviePacket.getLength();
String receiveData = new String(data,0,length);
// 獲取發(fā)送者的IP
InetAddress address = receviePacket.getAddress();
String ip = address.getHostAddress();
System.out.println("接收來自:"+ip+"的數(shù)據(jù),內(nèi)容是:"+receiveData);
// 接收端接收到信息后發(fā)送一條確認(rèn)接收的消息到發(fā)送端
String message = "OK";
byte[] messageByte = message.getBytes();
int messageLength = message.length();
// 從已收到的數(shù)據(jù)報中獲取IP和port
address = receviePacket.getAddress();
int port1 = receviePacket.getPort();
//構(gòu)造新數(shù)據(jù)報
DatagramPacket sendPacket = new DatagramPacket(messageByte, messageLength, address, port1);
// 發(fā)送數(shù)據(jù)
recevieSocket.send(sendPacket);
// 關(guān)閉資源
recevieSocket.close();
}
}
發(fā)送端輸出結(jié)果:
接收端輸出結(jié)果:
總結(jié)
注意:在發(fā)送端與接收端啟動測試時最好最好先啟動接收端,因為這樣才能確保信息能發(fā)送出去,接收端能接收到信息。