数据包已发送,但无法接收数据包

我一直在为vpn编辑androids toyvpn示例项目,并且为我的示例应用程序提供了这个示例项目

在这里输入图像说明

我知道有一些错误/我的代码丢失,因为当我手动设置通过Android设置的VPN,有数据包接收,这就是为什么我一直在search如何接收数据包,我不知道如何得到这个工作。

这里是我的源代码, 即扩展VpnService的VCL

import android.app.PendingIntent; import android.net.VpnService; 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 VpnService { private static final String TAG = "VpnClientLibrary"; 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 vpn 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 vpn 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 = "";//vpn 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, "VpnRunnable"); //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 vpn interface call the vclRun method inside VCL class * */ this.vclRun(); } 

首先,检查是否有字节被发送到您的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, "ToyVpnThread"); 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); } /..../ 

你没有很好地pipe理你的线程动作。 build议在尝试运行之前收到需要接收的任何字节。 不这样做可能会导致问题。
我会回头看看你的代码,把你拿出来的东西放进去。 我也build议你在这里改变你的代码:

 packet.put((byte) 0).put(password.getBytes()).flip(); 

尝试使用显式编码:

 packet.put((byte) 0).put(password.getBytes("UTF-8")).flip(); 

因为没有它,数据可能会丢失。 看到这个答案:
https://stackoverflow.com/a/7947911/3956566

我已经检查过,你的项目正在使用“UTF-8”。

让我知道如果这没有帮助。