[英]Packet loss while receiving UDP broadcast in android device
為了從服務器接收UDP廣播包到android設備,我使用服務類並在線程中偵聽數據包。 它成功接收數據包。 問題是如果在同一時間從服務器發送多個數據包,那么將導致數據包丟失。
我甚至嘗試使用隊列並在單獨的線程中處理收到的數據包,然后我也沒有收到數據包。 我對網絡編程完全陌生,任何幫助都會受到廣泛贊賞
void startListenForUdpBroadcast() {
UDPBroadcastThread = new Thread(new Runnable() {
public void run() {
try {
InetAddress broadcastIP = InetAddress.getByName(UdpConstants.IP_ADDRESS);
Integer port = UdpConstants.RECEIVER_PORT;
while (shouldRestartSocketListen) {
listenAndWaitAndThrowIntent(broadcastIP, port);
}
} catch (Exception e) {
Log.i("UDP", "no longer listening for UDP broadcasts cause of error " + e.getMessage());
}
}
});
UDPBroadcastThread.setPriority(Thread.MAX_PRIORITY); //Setting The Listener thread to MAX PRIORITY to minimize packet loss.
UDPBroadcastThread.start();
}
此代碼偵聽新數據包並推送到隊列
private void listenAndWaitAndThrowIntent(InetAddress broadcastIP, Integer port) throws Exception {
byte[] recvBuf = new byte[64000];
if (socket == null || socket.isClosed()) {
socket = new DatagramSocket(port, broadcastIP);
socket.setBroadcast(true);
}
//socket.setSoTimeout(1000);
DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);
socket.receive(packet);
messQueue.add(packet);
}
這將檢查隊列中的新消息並對其進行處理
/**
* @purpose Checking queue and If anything is added to the queue then broadcast it to UI
*/
private void checkQueue() {
queueThread = new Thread(new Runnable() {
public void run() {
try {
while (shouldRestartSocketListen) {
if (!messQueue.isEmpty()) {
broadcastIntent(messQueue.poll());
}
}
} catch (Exception e) {
}
}
});
queueThread.start();
}
UDP的問題是您的發件人(您的服務器)不知道您(您的Android設備)錯過了一些。 它不會丟失,因為你無法快速讀取它,有時只是空中干擾/擁塞或繁忙的插座。
接收者只會知道:
一旦數據包丟失,它就會丟失。 你有兩個選擇:
(選項1:所有重發請求只是偽TCP,因此您可能只考慮放棄UDP並轉到TCP)
我認為你的問題主要是你通過wifi使用Udp Broadcast。
他們是兩個非常好的文檔答案,為什么這是一個非常慢的操作方式,以及為什么有更多的數據包丟失:
我為解決極慢的帶寬所做的事情是某種多單播協議:
這是java中的代碼:
DatagramPacket packet = new DatagramPacket(buffer, size);
packet.setPort(PORT);
for (byte[] clientAddress : ClientsAddressList) {
packet.setAddress(InetAddress.getByAddress(clientAddress));
transceiverSocket.send(packet);
}
如果您在短脈沖串中收到多個數據報,您的接收器循環可能無法跟上,並且套接字中的OS級RCVBUF可能會溢出(導致操作系統丟棄它確實收到的數據包)。
如果增加RCVBUF大小,可能會更好地處理短脈沖。 在此之前,通過socket.getReceiveBufferSize了解它已經有多大。 還要記住,接收緩沖區中的字節數不僅要包含有效負載,還要包含在內核中存儲數據包的頭和sk_buff結構(參見lxr.free-electrons.com/source/include/linux) / ......)。
您可以通過socket.setReceiveBufferSize調整接收緩沖區大小 - 但請記住,此消息只是一個提示,並且可能被內核中的設置覆蓋(如果您請求的大小超過當前內核網絡允許的最大大小)設置,那么你只會獲得最大尺寸)。
在請求更大的接收緩沖區之后,您應該通過調用socket.getReceiveBufferSize來仔細檢查內核允許的內容。
如果您擁有正確的權限,則應該能夠調整內核允許的最大緩沖區大小 - 請參閱https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Web_Platform/5/html/Administration_And_Configuration_Guide/jgroups-穿孔- udpbuffer.html
[請注意,一般情況下,這將適應數據報到達的快速突發,而客戶端循環可以讀取它們 - 但如果客戶端循環長度比數據報傳輸慢,那么由於溢出,您仍會偶爾丟失。 在這種情況下,您需要加快客戶端循環,或減慢發件人的速度。
另外,正如在其他答案中另有說明的那樣,您的網絡實際上可能會丟棄數據包 - 尤其是移動網絡可能容易發生這種情況 - 因此,如果您絕對需要保證交付,則應使用TCP。 但是,如果這是您的主要問題,即使您的服務器緩慢地發送它們,您也可能會看到丟棄的數據包,而不是在突發中。
我想你通過說你只捕獲一個數據包
socket.receive(packet);
這是一個阻塞I / O調用,它會無限期地等待,直到它收到一個數據包,所以一旦第一個數據包到達它就會完成等待,然后執行下一個命令,即
messQueue.add(packet);
但是,當收到多個數據包時,您需要繼續接收數據包。 在你的情況下,你剛剛在第一個包裹到達后停止接收包裹
注意:UDP是一個不可靠的協議,不能保證數據包傳輸,因此可能存在數據包丟失的情況。但是,這對於程序的每次運行都不是問題,但是檢查數據包是否是一個很好的方法是你的機器,問題在你的應用程序內(應用程序無法處理收到的數據包)使用tcpdump(它是基於Linux的操作系統或MAC的命令行實用程序)使用以下命令
sudo tcpdump -i <interface name(one that handles traffic) eth0, eth1 .. en0, en1 (for MAC)> host <ipaddress or hostname of UDP Broadcast server>
例:
sudo tcpdump -i en1 host 187.156.13.5
(如果找不到tcpdump命令,那么繼續前進並安裝它)
通過使用此命令,您將看到從終端上的目標ump服務器泵入的數據包,如果您看到多個數據包到達,那么您將確保數據包到達計算機,但是應用程序無法解決數據包
它可能有所幫助
參考上面的說明,我可以根據需要進行更改
我想您可以進行以下更改以使您的問題代碼工作而不是創建socket到listenAndWaitAndThrowIntent(InetAddress broadcastIP,Integer port)方法在startListenForUdpBroadcast()中創建它如下
socket = new DatagramSocket(port, broadcastIP);
socket.setBroadcast(true);
while (shouldRestartSocketListen) {
listenAndWaitAndThrowIntent(broadcastIP, port, socket);
}
現在您還需要更改listenAndWaitAndThrowIntent方法的實現,如下所示
private void listenAndWaitAndThrowIntent(InetAddress broadcastIP,
Integer port, DatagramSocket socket) throws Exception {
byte[] recvBuf = new byte[64000];
//socket.setSoTimeout(1000);
//change value of condition in for loop to desired number of packets you would like to receive in below example it is 2 so it captures two packets
for (int i=0 ; i <= 2 ; i++ ){
DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);
socket.receive(packet);
messQueue.add(packet);
}
}
試試這應該工作!! 它可能有所幫助
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.