数据包发送但收不到数据包
Posted
技术标签:
【中文标题】数据包发送但收不到数据包【英文标题】:Packet Sent but cannot Received Packets 【发布时间】:2015-11-17 08:23:35 【问题描述】:我一直在为 *** 编辑 androids toy*** 示例项目,我为我的示例应用程序得到了这个
我知道我的代码有问题/缺失,因为当我通过 android 设置手动设置 *** 时,有数据包接收,这就是原因 我一直在寻找如何接收数据包,但我不知道如何让它工作。
这是我的源代码,扩展了 ***Service 的 VCL
import android.app.PendingIntent;
import android.net.***Service;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
/**
* Created by Jameshwart Lopez on 8/18/15.
*/
public class VCL extends ***Service
private static final String TAG = "***ClientLibrary";
private Thread mThread;
private ParcelFileDescriptor mInterface;
private String mServerAddress;
private String mServerPort;
private PendingIntent mConfigureIntent;
private String mParameters;
//a. Configure a builder for the interface.
Builder builder = new Builder();
public void vclRun()
try
//a. Configure the TUN and get the interface.
mInterface = builder.setSession("thesessionname")
.addAddress("192.168.0.1",24)
.addDnsServer("8.8.8.8")
.addRoute("0.0.0.0", 0).establish();
//b. Packets to be sent are queued in this input stream.
FileInputStream in = new FileInputStream(mInterface.getFileDescriptor());
//b. Packets received need to be written to this output stream.
FileOutputStream out = new FileOutputStream(mInterface.getFileDescriptor());
// Allocate the buffer for a single packet.
ByteBuffer packet = ByteBuffer.allocate(32767);
//c. The UDP channel can be used to pass/get ip package to/from server
DatagramChannel tunnel = DatagramChannel.open();
// Connect to the server, localhost is used for demonstration only.
mServerAddress="";//some of the *** ip address here
mServerPort="1723";
InetSocketAddress server = new InetSocketAddress(mServerAddress, Integer.parseInt(mServerPort) );
tunnel.connect(server);
// For simplicity, we use the same thread for both reading and
// writing. Here we put the tunnel into non-blocking mode.
tunnel.configureBlocking(false);
// Authenticate and configure the virtual network interface.
handshake(tunnel);
//d. Protect this socket, so package send by it will not be feedback to the *** service.
protect(tunnel.socket());
int timer = 0;
//e. Use a loop to pass packets.
while (true)
//get packet with in
//put packet to tunnel
//get packet form tunnel
//return packet with out
//sleep is a must
// Assume that we did not make any progress in this iteration.
boolean idle = true;
// Read the outgoing packet from the input stream.
int length = in.read(packet.array());
if (length > 0)
// Write the outgoing packet to the tunnel.
packet.limit(length);
tunnel.write(packet);
packet.clear();
// There might be more outgoing packets.
idle = false;
// If we were receiving, switch to sending.
if (timer < 1)
timer = 1;
// Read the incoming packet from the tunnel.
length = tunnel.read(packet);
if (length > 0)
// Ignore control messages, which start with zero.
if (packet.get(0) != 0)
// Write the incoming packet to the output stream.
out.write(packet.array(), 0, length);
packet.clear();
// There might be more incoming packets.
idle = false;
// If we were sending, switch to receiving.
if (timer > 0)
timer = 0;
// If we are idle or waiting for the network, sleep for a
// fraction of time to avoid busy looping.
if (idle)
Thread.sleep(100);
// Increase the timer. This is inaccurate but good enough,
// since everything is operated in non-blocking mode.
timer += (timer > 0) ? 100 : -100;
// We are receiving for a long time but not sending.
if (timer < -15000)
// Send empty control messages.
packet.put((byte) 0).limit(1);
for (int i = 0; i < 3; ++i)
packet.position(0);
tunnel.write(packet);
packet.clear();
// Switch to sending.
timer = 1;
// We are sending for a long time but not receiving.
//if (timer > 20000)
// throw new IllegalStateException("Timed out");
//
catch (Exception e)
// Catch any exception
e.printStackTrace();
finally
try
if (mInterface != null)
mInterface.close();
mInterface = null;
catch (Exception e)
private void handshake(DatagramChannel tunnel) throws Exception
// To build a secured tunnel, we should perform mutual authentication
// and exchange session keys for encryption. To keep things simple in
// this demo, we just send the shared secret in plaintext and wait
// for the server to send the parameters.
// Allocate the buffer for handshaking.
ByteBuffer packet = ByteBuffer.allocate(1024);
// Control messages always start with zero.
String password = "";//*** password here
packet.put((byte) 0).put(password.getBytes()).flip();
// Send the secret several times in case of packet loss.
for (int i = 0; i < 3; ++i)
Log.e("packetsdata", packet.toString());
packet.position(0);
tunnel.write(packet);
packet.clear();
// Wait for the parameters within a limited time.
for (int i = 0; i < 50; ++i)
Thread.sleep(100);
// Normally we should not receive random packets.
int length = tunnel.read(packet);
if (length > 0 && packet.get(0) == 0)
configure(new String(packet.array(), 1, length - 1).trim());
return;
//throw new IllegalStateException("Timed out");
private void configure(String parameters) throws Exception
// If the old interface has exactly the same parameters, use it!
if (mInterface != null)
Log.i(TAG, "Using the previous interface");
return;
// Configure a builder while parsing the parameters.
Builder builder = new Builder();
for (String parameter : parameters.split(" "))
String[] fields = parameter.split(",");
try
switch (fields[0].charAt(0))
case 'm':
builder.setMtu(Short.parseShort(fields[1]));
break;
case 'a':
builder.addAddress(fields[1], Integer.parseInt(fields[2]));
break;
case 'r':
builder.addRoute(fields[1], Integer.parseInt(fields[2]));
break;
case 'd':
builder.addDnsServer(fields[1]);
break;
case 's':
builder.addSearchDomain(fields[1]);
break;
catch (Exception e)
throw new IllegalArgumentException("Bad parameter: " + parameter);
// Close the old interface since the parameters have been changed.
try
mInterface.close();
catch (Exception e)
// ignore
// Create a new interface using the builder and save the parameters.
mInterface = builder.setSession(mServerAddress)
.setConfigureIntent(mConfigureIntent)
.establish();
mParameters = parameters;
Log.i(TAG, "New interface: " + parameters);
这就是我使用上面的类的方式
private Thread mThread;
/*
* Services interface
* */
@Override
public int onStartCommand(Intent intent, int flags, int startId)
// Start a new session by creating a new thread.
mThread = new Thread(this, "***Runnable");
//start the service
mThread.start();
/*
*service is left "started" and will later be restarted by the system
* http://android-developers.blogspot.com.au/2010/02/service-api-changes-starting-with.html
*/
return START_STICKY;
@Override
public void onDestroy()
if (mThread != null)
mThread.interrupt();
super.onDestroy();
@Override
public synchronized void run()
/*
* to run the *** interface call the vclRun method inside VCL class
* */
this.vclRun();
【问题讨论】:
我在 toy*** 示例中得到了它。 我的想法是,当我将数据包写入隧道时完成 我写了哪一部分来发送而不是接收?你能在我的代码中指出它吗?这可能对我有帮助。 :) 【参考方案1】:首先,检查是否有字节发送到您的 Android 设备。因为如果没有要接收的内容,它将不会读取任何内容。
然后看看这个,因为它可能会破坏您的连接。
您需要在onStartCommand
中包含此内容:
// The handler is only used to show messages.
if (mHandler == null)
mHandler = new Handler(this);
// Stop the previous session by interrupting the thread.
if (mThread != null)
mThread.interrupt();
// Extract information from the intent.
String prefix = getPackageName();
mServerAddress = intent.getStringExtra(prefix + ".ADDRESS");
mServerPort = intent.getStringExtra(prefix + ".PORT");
mSharedSecret = intent.getStringExtra(prefix + ".SECRET").getBytes();
// Start a new session by creating a new thread.
mThread = new Thread(this, "Toy***Thread");
mThread.start();
return START_STICKY;
还有sychronized void
的详细信息(如下所示)。
@Override
public synchronized void run()
try
Log.i(TAG, "Starting");
// If anything needs to be obtained using the network, get it now.
// This greatly reduces the complexity of seamless handover, which
// tries to recreate the tunnel without shutting down everything.
// In this demo, all we need to know is the server address.
InetSocketAddress server = new InetSocketAddress(
mServerAddress, Integer.parseInt(mServerPort));
// We try to create the tunnel for several times. The better way
// is to work with ConnectivityManager, such as trying only when
// the network is avaiable. Here we just use a counter to keep
// things simple.
for (int attempt = 0; attempt < 10; ++attempt)
mHandler.sendEmptyMessage(R.string.connecting);
// Reset the counter if we were connected.
// See BELOW
if (run(server))
attempt = 0;
// Sleep for a while. This also checks if we got interrupted.
Thread.sleep(3000);
/..../
您没有很好地管理线程操作。建议在尝试运行之前接收任何需要接收的字节。不这样做会导致问题。 我会回顾你的代码并把你拿出来的东西放进去。 我还建议您在此处更改代码:
packet.put((byte) 0).put(password.getBytes()).flip();
尝试使用显式编码:
packet.put((byte) 0).put(password.getBytes("UTF-8")).flip();
因为没有它,数据可能会丢失。看到这个答案:https://***.com/a/7947911/3956566
我已检查,您的项目使用的是“UTF-8”。
如果这没有帮助,请告诉我。
【讨论】:
如何接收数据包?我不明白 我尝试为 *** 复制谷歌示例,它甚至发送了数据包,这就是我尝试编辑它的原因 我的意思是它甚至不发送数据包,我会遇到 PortUnreachableException 和 SocketException 现在我已经得到了 PortUnreachableException。我认为这是在 *** 服务器端无法访问的端口。以上是关于数据包发送但收不到数据包的主要内容,如果未能解决你的问题,请参考以下文章