我一直在编辑
androids
toyvpn vpn的示例项目,我得到这个为我的示例应用程序
我知道有一些错误/缺少我的代码,因为当我手动设置vpn通过Android设置,有数据包接收这就是为什么
我一直在搜索如何接收数据包,我不知道如何使这个工作.
这里是我的源代码,VCL扩展了VpnService
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(),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;
还有同步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://stackoverflow.com/a/7947911/3956566
我已经检查,您的项目正在使用“UTF-8”.
让我知道如果这没有帮助.