实例介绍
【实例简介】基于Android官方例子ToyVpn进行的VPN开发
VPN开发,sdk25版本,ndk15版本,vpn开发太难找了做参考吧,用官方给的文件自己搭建的VPN服务器,服务器是我领的免费阿里云,2018/7/31到期
【实例截图】
【核心代码】
package com.example.pc.service;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.net.VpnService;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import android.widget.Toast;
import com.example.pc.Activity.R;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
public class ToyVpnService extends VpnService implements Handler.Callback, Runnable {
private static final String TAG = "ToyVpnService";
private String mServerAddress;
private String mServerPort;
private byte[] mSharedSecret;
private PendingIntent mConfigureIntent;
private Handler mHandler;
private Thread mThread;
private ParcelFileDescriptor mInterface;
private String mParameters;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (mHandler == null) {
mHandler = new Handler(this);
}
if (mThread != null) {
mThread.interrupt();
}
String prefix = getPackageName();
mServerAddress = intent.getStringExtra(prefix ".ADDRESS");
mServerPort = intent.getStringExtra(prefix ".PORT");
mSharedSecret = intent.getStringExtra(prefix ".SECRET").getBytes();
mThread = new Thread(this, "ToyVpnThread");
mThread.start();
return START_STICKY;
}
@Override
public void onDestroy() {
if (mThread != null) {
mThread.interrupt();
}
}
@Override
public boolean handleMessage(Message message) {
if (message != null) {
Toast.makeText(this, message.what, Toast.LENGTH_SHORT).show();
}
return true;
}
@Override
public synchronized void run() {
try {
Log.i(TAG, "Starting");
InetSocketAddress server = new InetSocketAddress(
mServerAddress, Integer.parseInt(mServerPort));
for (int attempt = 0; attempt < 10; attempt) {
mHandler.sendEmptyMessage(R.string.connecting);
if (run(server)) {
attempt = 0;
}
Thread.sleep(3000);
}
Log.i(TAG, "Giving up");
} catch (Exception e) {
Log.e(TAG, "Got " e.toString());
} finally {
try {
mInterface.close();
} catch (Exception e) {
}
mInterface = null;
mParameters = null;
mHandler.sendEmptyMessage(R.string.disconnected);
Log.i(TAG, "Exiting");
}
}
private boolean run(InetSocketAddress server) throws Exception {
DatagramChannel tunnel = null;
boolean connected = false;
try {
tunnel = DatagramChannel.open();
if (!protect(tunnel.socket())) {
throw new IllegalStateException("Cannot protect the tunnel");
}
tunnel.connect(server);
tunnel.configureBlocking(false);
handshake(tunnel);
connected = true;
mHandler.sendEmptyMessage(R.string.connected);
FileInputStream in = new FileInputStream(mInterface.getFileDescriptor());
FileOutputStream out = new FileOutputStream(mInterface.getFileDescriptor());
ByteBuffer packet = ByteBuffer.allocate(32767);
int timer = 0;
while (true) {
boolean idle = true;
int length = in.read(packet.array());
if (length > 0) {
packet.limit(length);
tunnel.write(packet);
packet.clear();
idle = false;
if (timer < 1) {
timer = 1;
}
}
length = tunnel.read(packet);
if (length > 0) {
if (packet.get(0) != 0) {
out.write(packet.array(), 0, length);
}
packet.clear();
idle = false;
if (timer > 0) {
timer = 0;
}
}
if (idle) {
Thread.sleep(100);
timer = (timer > 0) ? 100 : -100;
if (timer < -15000) {
packet.put((byte) 0).limit(1);
for (int i = 0; i < 3; i) {
packet.position(0);
tunnel.write(packet);
}
packet.clear();
timer = 1;
}
if (timer > 20000) {
throw new IllegalStateException("Timed out");
}
}
}
} catch (InterruptedException e) {
throw e;
} catch (Exception e) {
Log.e(TAG, "Got " e.toString());
} finally {
try {
tunnel.close();
} catch (Exception e) {
// ignore
}
}
return connected;
}
private void handshake(DatagramChannel tunnel) throws Exception {
ByteBuffer packet = ByteBuffer.allocate(1024);
packet.put((byte) 0).put(mSharedSecret).flip();
for (int i = 0; i < 3; i) {
packet.position(0);
tunnel.write(packet);
}
packet.clear();
for (int i = 0; i < 50; i) {
Thread.sleep(100);
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 && parameters.equals(mParameters)) {
Log.i(TAG, "Using the previous interface");
return;
}
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);
}
}
try {
mInterface.close();
} catch (Exception e) {
// ignore
}
mInterface = builder.setSession(mServerAddress)
.setConfigureIntent(mConfigureIntent)
.establish();
mParameters = parameters;
Log.i(TAG, "New interface: " parameters);
}
}
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明
网友评论
我要评论