Android 中的 UDP 多播丢包
Packet losses in UDP multicast in Android
我创建了一个应用程序,它提供了 android 中 UDP 数据包丢失的统计信息。这是我的应用程序架构。
1)多播UDP数据包的应用程序。下面是它的代码:
package rockwell.multicastserverproj;
import android.content.Context;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
public class MainActivity extends AppCompatActivity {
EditText txtMsg;
EditText txtPackets;
EditText txtMs;
EditText txtBytes;
EditText txtCount;
byte[] rtpData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
/*Thread thrClient = new Thread(new ReceiveMulticast());
thrClient.start();*/
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public void onBtnClicked(View view)
{
Thread threadTotalPackets = new Thread(new SendMulticast());
threadTotalPackets.start();
Thread thread = new Thread(new MulticastPackets());
thread.start();
//Toast.makeText(this,"Message multicasted",Toast.LENGTH_LONG).show();
}
public class MulticastPackets implements Runnable{
@Override
public void run() {
InetAddress group = null;
MulticastSocket multiSocket = null;
int PORT = 6500;
txtPackets =(EditText)findViewById(R.id.txtPackets);
txtMs = (EditText)findViewById(R.id.txtMs);
txtBytes = (EditText)findViewById(R.id.txtBytes);
txtCount = (EditText)findViewById(R.id.txtCount);
int noOfPackets = Integer.parseInt(txtPackets.getText().toString());
int delayMS = Integer.parseInt(txtMs.getText().toString());
int packetSize = Integer.parseInt(txtBytes.getText().toString());
int cntPacket = Integer.parseInt(txtCount.getText().toString());
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiManager.MulticastLock mLock = wifi.createMulticastLock("mylock");
mLock.acquire();
try{
group = InetAddress.getByName("230.0.0.1");
multiSocket = new MulticastSocket(PORT);
} catch (IOException e) {
e.printStackTrace();
}
for(int pcktCnt=1; pcktCnt<=noOfPackets; pcktCnt++) {
rtpData = new byte[packetSize];
int cnt = unsigned_int(pcktCnt);
byte[] seqArr = null;
seqArr = toBytes(cnt);
byte varFirst = 0xa;
byte varSecond = 0x5;
for(int i=4;i<packetSize;i+=2)
{
if(i%4 ==0) {
rtpData[i] = varFirst;
rtpData[i + 1] = varFirst;
}
else {
rtpData[i] = varSecond;
rtpData[i + 1] = varSecond;
}
}
for(int i=0;i<4;i++)
{
rtpData[i] = seqArr[i];
}
DatagramPacket requestPacket = new DatagramPacket(rtpData, rtpData.length, group, PORT);
try {
for(int i=0;i<cntPacket;i++) {
multiSocket.send(requestPacket);
Thread.sleep(delayMS, 0);
}
int test = fromByteArray(seqArr);
Log.i("Multicast", "Packet send. Sequence number is: " + test);
} catch (Exception e) {
e.printStackTrace();
}
int test = fromByteArray(seqArr);
}
try{
multiSocket.leaveGroup(group);
multiSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
mLock.release();
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this,"Packet sent",Toast.LENGTH_LONG).show();
}
});
}
}
public class SendMulticast implements Runnable{
@Override
public void run() {
InetAddress group = null;
MulticastSocket multiSocket = null;
int PORT = 5500;
txtPackets =(EditText)findViewById(R.id.txtPackets);
txtBytes = (EditText)findViewById(R.id.txtBytes);
String requestString = txtPackets.getText().toString();
String strPackSize = txtBytes.getText().toString();
requestString = requestString +";" + strPackSize;
Log.i("reqstring",requestString);
byte[] requestData = new byte[requestString.length()];
requestData = requestString.getBytes();
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiManager.MulticastLock mLock = wifi.createMulticastLock("mylock");
mLock.acquire();
try{
group = InetAddress.getByName("230.0.0.1");
multiSocket = new MulticastSocket(PORT);
multiSocket.joinGroup(group);
} catch (IOException e) {
e.printStackTrace();
}
try{
DatagramPacket requestPacket = new DatagramPacket(requestData, requestData.length, group, PORT);
multiSocket.send(requestPacket);
Log.i("multicastproj","message multicasted");
} catch (IOException e) {
e.printStackTrace();
}
try{
multiSocket.leaveGroup(group);
multiSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
mLock.release();
}
}
static int unsigned_int(int nb) {
if (nb >= 0)
return (nb);
else
return (256 + nb);
}
public byte[] toBytes(int i)
{
byte[] result = new byte[4];
result[0] = (byte) (i >> 24);
result[1] = (byte) (i >> 16);
result[2] = (byte) (i >> 8);
result[3] = (byte) (i /*>> 0*/);
return result;
}
public int fromByteArray(byte[] bytes) {
return bytes[0] << 24 | (bytes[1] & 0xFF) << 16 | (bytes[2] & 0xFF) << 8 | (bytes[3] & 0xFF);
}
public class ReceiveMulticast implements Runnable{
@Override
public void run() {
byte[] requestData = new byte[1024];
InetAddress group = null;
MulticastSocket multiSocket = null;
int PORT = 4500;
WifiManager wifi = (WifiManager) getSystemService(getApplicationContext().WIFI_SERVICE);
WifiManager.MulticastLock mLock = wifi.createMulticastLock("mylock");
mLock.acquire();
try{
group = InetAddress.getByName("230.0.0.1");
multiSocket = new MulticastSocket(PORT);
multiSocket.joinGroup(group);
} catch (IOException e) {
e.printStackTrace();
}
try{
while(true)
{
DatagramPacket requestPacket = new DatagramPacket(requestData, requestData.length);
multiSocket.receive(requestPacket);
String requestString = new String(requestPacket.getData(), 0, requestPacket.getLength());
Log.d("CreateMulticastServer", "Got request = " + requestString);
/*txtMsg = (EditText)findViewById(R.id.txtMsg);
txtMsg.setText(requestString);*/
}
} catch (IOException e) {
e.printStackTrace();
}
try{
multiSocket.leaveGroup(group);
multiSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
mLock.release();
}
}
}
接收这些组播 UDP 数据包的另一个应用程序
持续运行并接收组播数据包的服务:
package rockwell.packetstatistics;
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.WifiManager;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
/**
* Created by mmjoshi on 2/10/2016.
*/
public class PacketReceive_Service extends IntentService {
boolean flag = true;
int packetSize = 0;
public PacketReceive_Service() {
super("PacketReceive_Service");
}
@Override
protected void onHandleIntent(Intent intent) {
String strVar = intent.getStringExtra("vari");
Log.i("onstartservice","string is " + strVar);
Thread thread = new Thread(new PacketThread());
thread.setPriority(Thread.MAX_PRIORITY);
thread.start();
Thread thread1 = new Thread(new TotalPackets());
thread1.start();
}
public class PacketThread implements Runnable
{
@Override
public void run() {
InetAddress group = null;
MulticastSocket multiSocket = null;
WifiManager.MulticastLock mLock = null;
int prevSeqNo=0;
String strMissingPackets="";
int TotalpacketsReceived = 0;
try {
if(packetSize == 0)
packetSize = 1036;
byte[] requestData = new byte[packetSize];
int PORT = 6500;
byte varFirst = 0xa;
byte varSecond = 0x5;
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
mLock = wifi.createMulticastLock("mylock");
mLock.setReferenceCounted(true);
mLock.acquire();
try{
group = InetAddress.getByName("230.0.0.1");
multiSocket = new MulticastSocket(PORT);
multiSocket.joinGroup(group);
} catch (IOException e) {
e.printStackTrace();
}
while (flag) {
final DatagramPacket requestPacket = new DatagramPacket(requestData, requestData.length);
multiSocket.receive(requestPacket);
byte[] resultData = requestPacket.getData();
byte[] seqArr = new byte[4];
for(int i=0;i<4;i++){
seqArr[i] = resultData[i];
}
int seqNo = fromByteArray(seqArr);
Log.i("RecvPackets","multiple packet received # is: " + seqNo);
if(prevSeqNo!=seqNo)
{
TotalpacketsReceived++;
if(prevSeqNo!=0)
{
if((seqNo - prevSeqNo)>1)
{
for(int k=(prevSeqNo+1);k<seqNo;k++)
{
strMissingPackets += k + ", ";
sendResultMessage("Missing;" + String.valueOf(k));
Log.i("RecvPackets","Packet missing. Missing# is: " + k);
}
}
}
for(int i=4;i<packetSize;i+=2)
{
if(i%4 ==0) {
if(resultData[i] != varFirst || resultData[i+1] != varFirst)
{
if(seqNo != 1) {
sendResultMessage("DataError;" + String.valueOf(seqNo));
Log.i("DataCheck", "Error in data");
}
}
}
else {
if(resultData[i] != varSecond || resultData[i+1] != varSecond)
{
if(seqNo != 1) {
sendResultMessage("DataError;" + String.valueOf(seqNo));
Log.i("DataCheck", "Error in data");
}
}
}
}
prevSeqNo = seqNo;
Log.i("MulticastService", "Packet size is: " + packetSize + " Packet receive. Sequence number is: " + seqNo);
sendResultMessage("TotalPacketsReceived;" + String.valueOf(TotalpacketsReceived));
}
}
} catch (IOException e) {
Log.i("DEU Service", "In cache");
flag = false;
e.printStackTrace();
}
finally {
try {
if(multiSocket != null) {
if(group != null)
multiSocket.leaveGroup(group);
multiSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if(mLock != null)
mLock.release();
}
}
}
private void sendResultMessage(String strPacks) {
Intent intent = new Intent("intData");
intent.putExtra("result",strPacks);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
private void sendTotalPackets(String strPacks) {
Intent intent = new Intent("intPacket");
intent.putExtra("result",strPacks);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
public int fromByteArray(byte[] bytes) {
return bytes[0] << 24 | (bytes[1] & 0xFF) << 16 | (bytes[2] & 0xFF) << 8 | (bytes[3] & 0xFF);
}
public class TotalPackets implements Runnable{
@Override
public void run() {
byte[] requestData = new byte[1024];
InetAddress group = null;
MulticastSocket multiSocket = null;
int PORT = 5500;
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiManager.MulticastLock mLock = wifi.createMulticastLock("mylock");
mLock.acquire();
try{
group = InetAddress.getByName("230.0.0.1");
multiSocket = new MulticastSocket(PORT);
multiSocket.joinGroup(group);
} catch (IOException e) {
e.printStackTrace();
}
try{
while(true)
{
DatagramPacket requestPacket = new DatagramPacket(requestData, requestData.length);
multiSocket.receive(requestPacket);
String requestString = new String(requestPacket.getData(), 0, requestPacket.getLength());
Log.i("requestString",requestString);
String[] spltStr = requestString.split(";");
packetSize = Integer.parseInt(spltStr[1].toString());
Log.i("service","Packet size is: " + spltStr[1].toString() + " Total Packs: " + spltStr[0]);
sendTotalPackets(spltStr[0].toString());
/*txtMsg = (EditText)findViewById(R.id.txtMsg);
txtMsg.setText(requestString);*/
}
} catch (IOException e) {
e.printStackTrace();
}
try{
multiSocket.leaveGroup(group);
multiSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
mLock.release();
}
}
}
所以,我的问题是,在服务端,当我收到数据包时,大部分数据包丢失了 5-7%。这意味着,如果我以 5 毫秒的间隔发送 1000 个 512 字节的数据包,接收端将丢失 50-70 个数据包。
有什么办法可以减少丢包吗?或者我的代码是否有任何改进的机会,以便减少丢包?
提前致谢。
您是否尝试将间隔增加到 >5 毫秒?您是否也尝试在没有 wifi 干扰的情况下测试此应用程序?
你无能为力。
UDP 是一个没有传递保证的传输层。
wifi 上的数据包丢失会因接入点和运行设备的不同 makes/models/configurations 而异。
例如,5ghz 可能表现更好,因为空气波通常更干净,但它不像 2.4 ghz 那样穿透墙壁。
并非所有 Android 设备都使用相同的 wifi 无线电。
如果您使用在 MAC 层进行多播到单播转换的接入点,您实际上可以获得几乎 0% 的数据包丢失。所以你在你的应用软件中使用UDP。然后接入点在 802.11 层内部进行重传。例如,Cisco 和 Xirrus 具有多播到单播的转换选项,并且产生几乎 0% 的数据包丢失。然而,这是要付出代价的,因为它不能很好地扩展,因为每个多播流都是单独发送到每个订阅的设备。
嗯...你能用软件做什么....
“处理”多播丢包的方法:
前向纠错。
- 您可以将每个数据包发送两次。
AABBCCDDEE
- 您可以发送每个数据包两次但延迟:
ABACBDCED
- 部分数据可以发送两次:
AABCCDE
任何前向纠错方案都会增加带宽并增加延迟。
丢失隐瞒
- 你可以尝试估计损失之间的数据。
您没有真正陈述您的申请,因此很难就损失处理提出建议。由于你的 5ms 限制,听起来你正在传输 48khz 音频的 240 帧数据包。
我创建了一个应用程序,它提供了 android 中 UDP 数据包丢失的统计信息。这是我的应用程序架构。 1)多播UDP数据包的应用程序。下面是它的代码:
package rockwell.multicastserverproj;
import android.content.Context;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
public class MainActivity extends AppCompatActivity {
EditText txtMsg;
EditText txtPackets;
EditText txtMs;
EditText txtBytes;
EditText txtCount;
byte[] rtpData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
/*Thread thrClient = new Thread(new ReceiveMulticast());
thrClient.start();*/
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public void onBtnClicked(View view)
{
Thread threadTotalPackets = new Thread(new SendMulticast());
threadTotalPackets.start();
Thread thread = new Thread(new MulticastPackets());
thread.start();
//Toast.makeText(this,"Message multicasted",Toast.LENGTH_LONG).show();
}
public class MulticastPackets implements Runnable{
@Override
public void run() {
InetAddress group = null;
MulticastSocket multiSocket = null;
int PORT = 6500;
txtPackets =(EditText)findViewById(R.id.txtPackets);
txtMs = (EditText)findViewById(R.id.txtMs);
txtBytes = (EditText)findViewById(R.id.txtBytes);
txtCount = (EditText)findViewById(R.id.txtCount);
int noOfPackets = Integer.parseInt(txtPackets.getText().toString());
int delayMS = Integer.parseInt(txtMs.getText().toString());
int packetSize = Integer.parseInt(txtBytes.getText().toString());
int cntPacket = Integer.parseInt(txtCount.getText().toString());
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiManager.MulticastLock mLock = wifi.createMulticastLock("mylock");
mLock.acquire();
try{
group = InetAddress.getByName("230.0.0.1");
multiSocket = new MulticastSocket(PORT);
} catch (IOException e) {
e.printStackTrace();
}
for(int pcktCnt=1; pcktCnt<=noOfPackets; pcktCnt++) {
rtpData = new byte[packetSize];
int cnt = unsigned_int(pcktCnt);
byte[] seqArr = null;
seqArr = toBytes(cnt);
byte varFirst = 0xa;
byte varSecond = 0x5;
for(int i=4;i<packetSize;i+=2)
{
if(i%4 ==0) {
rtpData[i] = varFirst;
rtpData[i + 1] = varFirst;
}
else {
rtpData[i] = varSecond;
rtpData[i + 1] = varSecond;
}
}
for(int i=0;i<4;i++)
{
rtpData[i] = seqArr[i];
}
DatagramPacket requestPacket = new DatagramPacket(rtpData, rtpData.length, group, PORT);
try {
for(int i=0;i<cntPacket;i++) {
multiSocket.send(requestPacket);
Thread.sleep(delayMS, 0);
}
int test = fromByteArray(seqArr);
Log.i("Multicast", "Packet send. Sequence number is: " + test);
} catch (Exception e) {
e.printStackTrace();
}
int test = fromByteArray(seqArr);
}
try{
multiSocket.leaveGroup(group);
multiSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
mLock.release();
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this,"Packet sent",Toast.LENGTH_LONG).show();
}
});
}
}
public class SendMulticast implements Runnable{
@Override
public void run() {
InetAddress group = null;
MulticastSocket multiSocket = null;
int PORT = 5500;
txtPackets =(EditText)findViewById(R.id.txtPackets);
txtBytes = (EditText)findViewById(R.id.txtBytes);
String requestString = txtPackets.getText().toString();
String strPackSize = txtBytes.getText().toString();
requestString = requestString +";" + strPackSize;
Log.i("reqstring",requestString);
byte[] requestData = new byte[requestString.length()];
requestData = requestString.getBytes();
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiManager.MulticastLock mLock = wifi.createMulticastLock("mylock");
mLock.acquire();
try{
group = InetAddress.getByName("230.0.0.1");
multiSocket = new MulticastSocket(PORT);
multiSocket.joinGroup(group);
} catch (IOException e) {
e.printStackTrace();
}
try{
DatagramPacket requestPacket = new DatagramPacket(requestData, requestData.length, group, PORT);
multiSocket.send(requestPacket);
Log.i("multicastproj","message multicasted");
} catch (IOException e) {
e.printStackTrace();
}
try{
multiSocket.leaveGroup(group);
multiSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
mLock.release();
}
}
static int unsigned_int(int nb) {
if (nb >= 0)
return (nb);
else
return (256 + nb);
}
public byte[] toBytes(int i)
{
byte[] result = new byte[4];
result[0] = (byte) (i >> 24);
result[1] = (byte) (i >> 16);
result[2] = (byte) (i >> 8);
result[3] = (byte) (i /*>> 0*/);
return result;
}
public int fromByteArray(byte[] bytes) {
return bytes[0] << 24 | (bytes[1] & 0xFF) << 16 | (bytes[2] & 0xFF) << 8 | (bytes[3] & 0xFF);
}
public class ReceiveMulticast implements Runnable{
@Override
public void run() {
byte[] requestData = new byte[1024];
InetAddress group = null;
MulticastSocket multiSocket = null;
int PORT = 4500;
WifiManager wifi = (WifiManager) getSystemService(getApplicationContext().WIFI_SERVICE);
WifiManager.MulticastLock mLock = wifi.createMulticastLock("mylock");
mLock.acquire();
try{
group = InetAddress.getByName("230.0.0.1");
multiSocket = new MulticastSocket(PORT);
multiSocket.joinGroup(group);
} catch (IOException e) {
e.printStackTrace();
}
try{
while(true)
{
DatagramPacket requestPacket = new DatagramPacket(requestData, requestData.length);
multiSocket.receive(requestPacket);
String requestString = new String(requestPacket.getData(), 0, requestPacket.getLength());
Log.d("CreateMulticastServer", "Got request = " + requestString);
/*txtMsg = (EditText)findViewById(R.id.txtMsg);
txtMsg.setText(requestString);*/
}
} catch (IOException e) {
e.printStackTrace();
}
try{
multiSocket.leaveGroup(group);
multiSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
mLock.release();
}
}
}
接收这些组播 UDP 数据包的另一个应用程序
持续运行并接收组播数据包的服务:
package rockwell.packetstatistics;
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.WifiManager;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
/**
* Created by mmjoshi on 2/10/2016.
*/
public class PacketReceive_Service extends IntentService {
boolean flag = true;
int packetSize = 0;
public PacketReceive_Service() {
super("PacketReceive_Service");
}
@Override
protected void onHandleIntent(Intent intent) {
String strVar = intent.getStringExtra("vari");
Log.i("onstartservice","string is " + strVar);
Thread thread = new Thread(new PacketThread());
thread.setPriority(Thread.MAX_PRIORITY);
thread.start();
Thread thread1 = new Thread(new TotalPackets());
thread1.start();
}
public class PacketThread implements Runnable
{
@Override
public void run() {
InetAddress group = null;
MulticastSocket multiSocket = null;
WifiManager.MulticastLock mLock = null;
int prevSeqNo=0;
String strMissingPackets="";
int TotalpacketsReceived = 0;
try {
if(packetSize == 0)
packetSize = 1036;
byte[] requestData = new byte[packetSize];
int PORT = 6500;
byte varFirst = 0xa;
byte varSecond = 0x5;
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
mLock = wifi.createMulticastLock("mylock");
mLock.setReferenceCounted(true);
mLock.acquire();
try{
group = InetAddress.getByName("230.0.0.1");
multiSocket = new MulticastSocket(PORT);
multiSocket.joinGroup(group);
} catch (IOException e) {
e.printStackTrace();
}
while (flag) {
final DatagramPacket requestPacket = new DatagramPacket(requestData, requestData.length);
multiSocket.receive(requestPacket);
byte[] resultData = requestPacket.getData();
byte[] seqArr = new byte[4];
for(int i=0;i<4;i++){
seqArr[i] = resultData[i];
}
int seqNo = fromByteArray(seqArr);
Log.i("RecvPackets","multiple packet received # is: " + seqNo);
if(prevSeqNo!=seqNo)
{
TotalpacketsReceived++;
if(prevSeqNo!=0)
{
if((seqNo - prevSeqNo)>1)
{
for(int k=(prevSeqNo+1);k<seqNo;k++)
{
strMissingPackets += k + ", ";
sendResultMessage("Missing;" + String.valueOf(k));
Log.i("RecvPackets","Packet missing. Missing# is: " + k);
}
}
}
for(int i=4;i<packetSize;i+=2)
{
if(i%4 ==0) {
if(resultData[i] != varFirst || resultData[i+1] != varFirst)
{
if(seqNo != 1) {
sendResultMessage("DataError;" + String.valueOf(seqNo));
Log.i("DataCheck", "Error in data");
}
}
}
else {
if(resultData[i] != varSecond || resultData[i+1] != varSecond)
{
if(seqNo != 1) {
sendResultMessage("DataError;" + String.valueOf(seqNo));
Log.i("DataCheck", "Error in data");
}
}
}
}
prevSeqNo = seqNo;
Log.i("MulticastService", "Packet size is: " + packetSize + " Packet receive. Sequence number is: " + seqNo);
sendResultMessage("TotalPacketsReceived;" + String.valueOf(TotalpacketsReceived));
}
}
} catch (IOException e) {
Log.i("DEU Service", "In cache");
flag = false;
e.printStackTrace();
}
finally {
try {
if(multiSocket != null) {
if(group != null)
multiSocket.leaveGroup(group);
multiSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if(mLock != null)
mLock.release();
}
}
}
private void sendResultMessage(String strPacks) {
Intent intent = new Intent("intData");
intent.putExtra("result",strPacks);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
private void sendTotalPackets(String strPacks) {
Intent intent = new Intent("intPacket");
intent.putExtra("result",strPacks);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
public int fromByteArray(byte[] bytes) {
return bytes[0] << 24 | (bytes[1] & 0xFF) << 16 | (bytes[2] & 0xFF) << 8 | (bytes[3] & 0xFF);
}
public class TotalPackets implements Runnable{
@Override
public void run() {
byte[] requestData = new byte[1024];
InetAddress group = null;
MulticastSocket multiSocket = null;
int PORT = 5500;
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiManager.MulticastLock mLock = wifi.createMulticastLock("mylock");
mLock.acquire();
try{
group = InetAddress.getByName("230.0.0.1");
multiSocket = new MulticastSocket(PORT);
multiSocket.joinGroup(group);
} catch (IOException e) {
e.printStackTrace();
}
try{
while(true)
{
DatagramPacket requestPacket = new DatagramPacket(requestData, requestData.length);
multiSocket.receive(requestPacket);
String requestString = new String(requestPacket.getData(), 0, requestPacket.getLength());
Log.i("requestString",requestString);
String[] spltStr = requestString.split(";");
packetSize = Integer.parseInt(spltStr[1].toString());
Log.i("service","Packet size is: " + spltStr[1].toString() + " Total Packs: " + spltStr[0]);
sendTotalPackets(spltStr[0].toString());
/*txtMsg = (EditText)findViewById(R.id.txtMsg);
txtMsg.setText(requestString);*/
}
} catch (IOException e) {
e.printStackTrace();
}
try{
multiSocket.leaveGroup(group);
multiSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
mLock.release();
}
}
}
所以,我的问题是,在服务端,当我收到数据包时,大部分数据包丢失了 5-7%。这意味着,如果我以 5 毫秒的间隔发送 1000 个 512 字节的数据包,接收端将丢失 50-70 个数据包。
有什么办法可以减少丢包吗?或者我的代码是否有任何改进的机会,以便减少丢包?
提前致谢。
您是否尝试将间隔增加到 >5 毫秒?您是否也尝试在没有 wifi 干扰的情况下测试此应用程序?
你无能为力。
UDP 是一个没有传递保证的传输层。
wifi 上的数据包丢失会因接入点和运行设备的不同 makes/models/configurations 而异。
例如,5ghz 可能表现更好,因为空气波通常更干净,但它不像 2.4 ghz 那样穿透墙壁。
并非所有 Android 设备都使用相同的 wifi 无线电。
如果您使用在 MAC 层进行多播到单播转换的接入点,您实际上可以获得几乎 0% 的数据包丢失。所以你在你的应用软件中使用UDP。然后接入点在 802.11 层内部进行重传。例如,Cisco 和 Xirrus 具有多播到单播的转换选项,并且产生几乎 0% 的数据包丢失。然而,这是要付出代价的,因为它不能很好地扩展,因为每个多播流都是单独发送到每个订阅的设备。
嗯...你能用软件做什么....
“处理”多播丢包的方法:
前向纠错。
- 您可以将每个数据包发送两次。
AABBCCDDEE
- 您可以发送每个数据包两次但延迟:
ABACBDCED
- 部分数据可以发送两次:
AABCCDE
任何前向纠错方案都会增加带宽并增加延迟。
丢失隐瞒
- 你可以尝试估计损失之间的数据。
您没有真正陈述您的申请,因此很难就损失处理提出建议。由于你的 5ms 限制,听起来你正在传输 48khz 音频的 240 帧数据包。