Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/apache-kafka/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android:使用VPN服务的VPN连接_Android_Android Vpn Service - Fatal编程技术网

Android:使用VPN服务的VPN连接

Android:使用VPN服务的VPN连接,android,android-vpn-service,Android,Android Vpn Service,我正在尝试以编程方式建立并连接到我们自己的vpn(不是默认的vpn提供商,即,Android设置->无线和网络中存在的PPTP、L2TP等) 我想知道,从2017年起,这是否已经可行 这里有我使用的参考资料 在使用数据报通道时,我得到了一个PortUnreactableException。这就是我的代码的样子: @Override public void run() { try { Log.i(getTag(), "Starting"); // If

我正在尝试以编程方式建立并连接到我们自己的vpn(不是默认的vpn提供商,即,Android设置->无线和网络中存在的PPTP、L2TP等)

我想知道,从2017年起,这是否已经可行

这里有我使用的参考资料

  • 在使用数据报通道时,我得到了一个PortUnreactableException。这就是我的代码的样子:

    @Override
    public void run() {
        try {
            Log.i(getTag(), "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.
            final SocketAddress serverAddress = new InetSocketAddress(mServerName, mServerPort);
            // We try to create the tunnel several times.
            // TODO: The better way is to work with ConnectivityManager, trying only when the
            //       network is available.
            // Here we just use a counter to keep things simple.
            for (int attempt = 0; attempt < 10; ++attempt) {
                // Reset the counter if we were connected.
                if (run(serverAddress)) {
                    attempt = 0;
                }
                // Sleep for a while. This also checks if we got interrupted.
                Thread.sleep(3000);
            }
            Log.i(getTag(), "Giving up");
        } catch (IOException | InterruptedException | IllegalArgumentException e) {
            Log.e(getTag(), "Connection failed, exiting", e);
        }
    }
    private boolean run(SocketAddress server)
            throws IOException, InterruptedException, IllegalArgumentException {
        ParcelFileDescriptor iface = null;
        boolean connected = false;
        // Create a DatagramChannel as the VPN tunnel.
        try (DatagramChannel tunnel = DatagramChannel.open()) {
            // Protect the tunnel before connecting to avoid loopback.
            if (!mService.protect(tunnel.socket())) {
                throw new IllegalStateException("Cannot protect the tunnel");
            }
            // Connect to the server.
            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.
            iface = handshake(tunnel);
            // Now we are connected. Set the flag.
            connected = true;
            // Packets to be sent are queued in this input stream.
            FileInputStream in = new FileInputStream(iface.getFileDescriptor());
            // Packets received need to be written to this output stream.
            FileOutputStream out = new FileOutputStream(iface.getFileDescriptor());
            // Allocate the buffer for a single packet.
            ByteBuffer packet = ByteBuffer.allocate(MAX_PACKET_SIZE);
            // Timeouts:
            //   - when data has not been sent in a while, send empty keepalive messages.
            //   - when data has not been received in a while, assume the connection is broken.
            long lastSendTime = System.currentTimeMillis();
            long lastReceiveTime = System.currentTimeMillis();
            // We keep forwarding packets till something goes wrong.
            while (true) {
                // 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;
                    lastReceiveTime = System.currentTimeMillis();
                }
                // 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;
                    lastSendTime = System.currentTimeMillis();
                }
                // If we are idle or waiting for the network, sleep for a
                // fraction of time to avoid busy looping.
                if (idle) {
                    Thread.sleep(IDLE_INTERVAL_MS);
                    final long timeNow = System.currentTimeMillis();
                    if (lastSendTime + KEEPALIVE_INTERVAL_MS <= timeNow) {
                        // We are receiving for a long time but not sending.
                        // 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();
                        lastSendTime = timeNow;
                    } else if (lastReceiveTime + RECEIVE_TIMEOUT_MS <= timeNow) {
                        // We are sending for a long time but not receiving.
                        throw new IllegalStateException("Timed out");
                    }
                }
            }
        } catch (SocketException e) {
            Log.e(getTag(), "Cannot use socket", e);
        } finally {
            if (iface != null) {
                try {
                    iface.close();
                } catch (IOException e) {
                    Log.e(getTag(), "Unable to close interface", e);
                }
            }
        }
        return connected;
    }
    
    MyVPN服务:

        class MyVpnService  extends VpnService{
    private static final String TAG = MyVpnService.class.getSimpleName();
    
    private Thread mThread;
    private ParcelFileDescriptor mInterface;
    //a. Configure a builder for the interface.
    Builder builder = new Builder();
    public static final String ACTION_CONNECT = "com.example.android.toyvpn.START";
    
    public static final String ACTION_DISCONNECT = "com.example.android.toyvpn.STOP";
    private Handler mHandler;
    private PendingIntent mConfigureIntent;
    private final AtomicReference<Thread> mConnectingThread = new AtomicReference<>();
    private final AtomicReference<Connection> mConnection = new AtomicReference<>();
    private AtomicInteger mNextConnectionId = new AtomicInteger(1);
    private static class Connection extends Pair<Thread, ParcelFileDescriptor> {
        public Connection(Thread thread, ParcelFileDescriptor pfd) {
            super(thread, pfd);
        }
    }
    
    @Override
    public void onCreate() {
        Log.e("MyVpnService","onCreate");
    
        // The handler is only used to show messages.
        if (mHandler == null) {
            mHandler = new Handler();
        }
    
        //Create the intent to "configure" the connection (just start ToyVpnClient).
        mConfigureIntent = PendingIntent.getActivity(this, 0, new Intent(this, ToyVpnClient.class),
                PendingIntent.FLAG_UPDATE_CURRENT);
    }
    
    // Services interface
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // Start a new session by creating a new thread.
        mThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //a. Configure the TUN and get the interface.
                    mInterface = builder.setSession("MyVPNService")
                            .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.
                    tunnel.connect(new InetSocketAddress("61.31.92.159", 1723));
                    //tunnel.connect(new InetSocketAddress("127.0.0.1", 8087));
                    //d. Protect this socket, so package send by it will not be feedback to the vpn service.
                    protect(tunnel.socket());
                    //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
                        Log.e("MyVpnService","true");
    
                        Thread.sleep(100);
                    }
    
                } catch (Exception e) {
                    // Catch any exception
                    Log.e(TAG,"Exception:"+e.toString());
    
                    e.printStackTrace();
                } finally {
                    try {
                        if (mInterface != null) {
                            mInterface.close();
                            mInterface = null;
                        }
                    } catch (Exception e) {
                        Log.e(TAG,"Exception2:"+e.toString());
                    }
                }
            }
    
        }, "MyVpnRunnable");
    
        //start the service
        mThread.start();
    
        if (intent != null && ACTION_DISCONNECT.equals(intent.getAction())) {
            disconnect();
            return START_NOT_STICKY;
        } else {
            connect();
            return START_STICKY;
        }
    }
    
    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        if (mThread != null) {
            mThread.interrupt();
        }
        super.onDestroy();
    }
    
    private void connect() {
        // Become a foreground service. Background services can be VPN services too, but they can
        // be killed by background check before getting a chance to receive onRevoke().
        updateForegroundNotification(R.string.connecting);
        mHandler.sendEmptyMessage(R.string.connecting);
        // Extract information from the shared preferences.
        final SharedPreferences prefs = getSharedPreferences(ToyVpnClient.Prefs.NAME, MODE_PRIVATE);
        final String server = "61.31.92.159";//prefs.getString(ToyVpnClient.Prefs.SERVER_ADDRESS, "");
        final byte[] secret = "123456789".getBytes();//= prefs.getString(ToyVpnClient.Prefs.SHARED_SECRET, "").getBytes();
        final int port;
        try {
            port = Integer.parseInt("1723");//Integer.parseInt(prefs.getString(ToyVpnClient.Prefs.SERVER_PORT, ""));
        } catch (NumberFormatException e) {
            Log.e("MyVPN", "Bad port: " + prefs.getString(ToyVpnClient.Prefs.SERVER_PORT, null), e);
            return;
        }
        // Kick off a connection.
        startConnection(new ToyVpnConnection(
                this, mNextConnectionId.getAndIncrement(), server, port, secret));
    }
    private void disconnect() {
        mHandler.sendEmptyMessage(R.string.disconnected);
        setConnectingThread(null);
        setConnection(null);
        stopForeground(true);
    }
    private void updateForegroundNotification(final int message) {
        startForeground(1, new Notification.Builder(this)
                //.setSmallIcon(R.drawable.ic_vpn)
                .setContentText(getString(message))
                .setContentIntent(mConfigureIntent)
                .build());
    }
    private void startConnection(final ToyVpnConnection connection) {
        // Replace any existing connecting thread with the  new one.
        final Thread thread = new Thread(connection, "ToyVpnThread");
        setConnectingThread(thread);
        // Handler to mark as connected once onEstablish is called.
        connection.setConfigureIntent(mConfigureIntent);
        connection.setOnEstablishListener(new ToyVpnConnection.OnEstablishListener() {
            public void onEstablish(ParcelFileDescriptor tunInterface) {
                mHandler.sendEmptyMessage(R.string.connected);
                mConnectingThread.compareAndSet(thread, null);
                setConnection(new Connection(thread, tunInterface));
            }
        });
        thread.start();
    }
    
    private void setConnectingThread(final Thread thread) {
        final Thread oldThread = mConnectingThread.getAndSet(thread);
        if (oldThread != null) {
            oldThread.interrupt();
        }
    }
    private void setConnection(final Connection connection) {
        final Connection oldConnection = mConnection.getAndSet(connection);
        if (oldConnection != null) {
            try {
                oldConnection.first.interrupt();
                oldConnection.second.close();
            } catch (IOException e) {
                Log.e(TAG, "Closing VPN interface", e);
            }
        }
    }
    
    classmyvpnservice扩展了VpnService{
    私有静态最终字符串标记=MyVpnService.class.getSimpleName();
    私有线程mThread;
    私人包裹面;
    //a、 为接口配置生成器。
    Builder=新的Builder();
    public static final String ACTION_CONNECT=“com.example.android.toyvpn.START”;
    public static final String ACTION_DISCONNECT=“com.example.android.toyvpn.STOP”;
    私人经理人;
    私有挂起内容MConfigureContent;
    私有最终原子引用mConnectingThread=新原子引用();
    私有最终原子引用mConnection=新原子引用();
    私有AtomicInteger mNextConnectionId=新的AtomicInteger(1);
    私有静态类连接扩展对{
    公共连接(线程、包文件描述符pfd){
    超级(螺纹,pfd);
    }
    }
    @凌驾
    public void onCreate(){
    Log.e(“MyVpnService”、“onCreate”);
    //处理程序仅用于显示消息。
    if(mHandler==null){
    mHandler=新处理程序();
    }
    //创建“配置”连接的意图(只需启动YVPNClient)。
    mconfigureContent=pendingent.getActivity(this,0,newintent(this,ToyVpnClient.class)),
    PendingEvent.FLAG_UPDATE_CURRENT);
    }
    //服务接口
    @凌驾
    公共int onStartCommand(Intent Intent、int标志、int startId){
    //通过创建新线程启动新会话。
    mThread=new Thread(new Runnable()){
    @凌驾
    公开募捐{
    试一试{
    //a、 配置TUN并获取接口。
    mInterface=builder.setSession(“MyVPN服务”)
    .addAddress(“192.168.0.1”,24)
    .addDnsServer(“8.8.8.8”)
    .addRoute(“0.0.0.0”,0).build();
    //b、 要发送的数据包在此输入流中排队。
    FileInputStream in=新的FileInputStream(
    mInterface.getFileDescriptor());
    //b、 接收到的数据包需要写入此输出流。
    FileOutputStream out=新的FileOutputStream(
    mInterface.getFileDescriptor());
    //为单个数据包分配缓冲区。
    ByteBuffer数据包=ByteBuffer.allocate(32767);
    //c、 UDP通道可用于向服务器传递/从服务器获取ip包
    DatagramChannel隧道=DatagramChannel.open();
    //连接到服务器,localhost仅用于演示。
    隧道连接(新的InetSocketAddress(“61.31.92.159”,1723));
    //tunnel.connect(新的InetSocketAddress(“127.0.0.1”,8087));
    //d、 保护此套接字,使其发送的包不会反馈到vpn服务。
    保护(tunnel.socket());
    //e、 使用循环传递数据包。
    while(true){
    //拿包进去
    //将数据包放入隧道
    //从隧道获取数据包
    //返回不带输出的数据包
    //睡觉是必须的
    Log.e(“MyVpnService”、“true”);
    睡眠(100);
    }
    }捕获(例外e){
    //抓住任何例外
    Log.e(标记“Exception:+e.toString());
    e、 printStackTrace();
    }最后{
    试一试{
    if(mInterface!=null){
    mInterface.close();
    mInterface=null;
    }
    }捕获(例外e){
    Log.e(标记“Exception2:+e.toString());
    }
    }
    }
    },“MyVpnRunnable”);
    //启动服务
    mThread.start();
    if(intent!=null&&ACTION_DISCONNECT.equals(intent.getAction())){
    断开连接();
    返回开始时间不粘;
    }否则{
    connect();
    返回开始时间;
    }
    }
    @凌驾
    公共空间{
    //TODO自动生成的方法存根
    if(mThread!=null){
    中断();
    }
    super.ondestory();
    }
    专用void connect(){
    //成为前台服务。后台服务也可以是VPN服务,但它们可以
    //在获得接收onRevoke()的机会之前,被背景检查扼杀。
    updateForegroundNotification(R.string.connecting);
    mHandler.sendEmptyMessage(R.string.connecting);
    //从共享首选项中提取信息。
    final SharedPreferences prefs=getSharedPreferences(ToyVpnClient.prefs.NAME,MODE_PRIVATE);
    final String server=“61.31.92.159”//prefs.getString(ToyVpnClient.prefs.server_ADDRESS,”;
    最终字节[]secret=“123456789.getBytes();/=prefs.getString(ToyVpnClient.prefs.SHARED_secret,”).getBytes();
    最终国际端口;
    试一试{
    port=Integer.parseInt(“1723”);//Integer.parseInt(prefs.getString(ToyVpnClient.prefs.SERVER_port,”);
    }捕获(数字格式){
    Log.e(“MyVPN”,“坏端口:”+prefs.getString(ToyVpnClient.prefs.SERVER_port,null),e);
    返回;
    }
    //启动连接。
    startConnection(新TOYVPN连接(
    这是,mNextConnectionId.getAndIncrement(),服务器,端口,机密);
    }
    私有无效断开连接(){
    mHandler.sendEmptyMessage(R.string.disconnected);
    SetConnectionRead(空);
    设置连接(空);
    停止前景(真);
    }
    私有void updateForeg
    
        class MyVpnService  extends VpnService{
    private static final String TAG = MyVpnService.class.getSimpleName();
    
    private Thread mThread;
    private ParcelFileDescriptor mInterface;
    //a. Configure a builder for the interface.
    Builder builder = new Builder();
    public static final String ACTION_CONNECT = "com.example.android.toyvpn.START";
    
    public static final String ACTION_DISCONNECT = "com.example.android.toyvpn.STOP";
    private Handler mHandler;
    private PendingIntent mConfigureIntent;
    private final AtomicReference<Thread> mConnectingThread = new AtomicReference<>();
    private final AtomicReference<Connection> mConnection = new AtomicReference<>();
    private AtomicInteger mNextConnectionId = new AtomicInteger(1);
    private static class Connection extends Pair<Thread, ParcelFileDescriptor> {
        public Connection(Thread thread, ParcelFileDescriptor pfd) {
            super(thread, pfd);
        }
    }
    
    @Override
    public void onCreate() {
        Log.e("MyVpnService","onCreate");
    
        // The handler is only used to show messages.
        if (mHandler == null) {
            mHandler = new Handler();
        }
    
        //Create the intent to "configure" the connection (just start ToyVpnClient).
        mConfigureIntent = PendingIntent.getActivity(this, 0, new Intent(this, ToyVpnClient.class),
                PendingIntent.FLAG_UPDATE_CURRENT);
    }
    
    // Services interface
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // Start a new session by creating a new thread.
        mThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //a. Configure the TUN and get the interface.
                    mInterface = builder.setSession("MyVPNService")
                            .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.
                    tunnel.connect(new InetSocketAddress("61.31.92.159", 1723));
                    //tunnel.connect(new InetSocketAddress("127.0.0.1", 8087));
                    //d. Protect this socket, so package send by it will not be feedback to the vpn service.
                    protect(tunnel.socket());
                    //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
                        Log.e("MyVpnService","true");
    
                        Thread.sleep(100);
                    }
    
                } catch (Exception e) {
                    // Catch any exception
                    Log.e(TAG,"Exception:"+e.toString());
    
                    e.printStackTrace();
                } finally {
                    try {
                        if (mInterface != null) {
                            mInterface.close();
                            mInterface = null;
                        }
                    } catch (Exception e) {
                        Log.e(TAG,"Exception2:"+e.toString());
                    }
                }
            }
    
        }, "MyVpnRunnable");
    
        //start the service
        mThread.start();
    
        if (intent != null && ACTION_DISCONNECT.equals(intent.getAction())) {
            disconnect();
            return START_NOT_STICKY;
        } else {
            connect();
            return START_STICKY;
        }
    }
    
    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        if (mThread != null) {
            mThread.interrupt();
        }
        super.onDestroy();
    }
    
    private void connect() {
        // Become a foreground service. Background services can be VPN services too, but they can
        // be killed by background check before getting a chance to receive onRevoke().
        updateForegroundNotification(R.string.connecting);
        mHandler.sendEmptyMessage(R.string.connecting);
        // Extract information from the shared preferences.
        final SharedPreferences prefs = getSharedPreferences(ToyVpnClient.Prefs.NAME, MODE_PRIVATE);
        final String server = "61.31.92.159";//prefs.getString(ToyVpnClient.Prefs.SERVER_ADDRESS, "");
        final byte[] secret = "123456789".getBytes();//= prefs.getString(ToyVpnClient.Prefs.SHARED_SECRET, "").getBytes();
        final int port;
        try {
            port = Integer.parseInt("1723");//Integer.parseInt(prefs.getString(ToyVpnClient.Prefs.SERVER_PORT, ""));
        } catch (NumberFormatException e) {
            Log.e("MyVPN", "Bad port: " + prefs.getString(ToyVpnClient.Prefs.SERVER_PORT, null), e);
            return;
        }
        // Kick off a connection.
        startConnection(new ToyVpnConnection(
                this, mNextConnectionId.getAndIncrement(), server, port, secret));
    }
    private void disconnect() {
        mHandler.sendEmptyMessage(R.string.disconnected);
        setConnectingThread(null);
        setConnection(null);
        stopForeground(true);
    }
    private void updateForegroundNotification(final int message) {
        startForeground(1, new Notification.Builder(this)
                //.setSmallIcon(R.drawable.ic_vpn)
                .setContentText(getString(message))
                .setContentIntent(mConfigureIntent)
                .build());
    }
    private void startConnection(final ToyVpnConnection connection) {
        // Replace any existing connecting thread with the  new one.
        final Thread thread = new Thread(connection, "ToyVpnThread");
        setConnectingThread(thread);
        // Handler to mark as connected once onEstablish is called.
        connection.setConfigureIntent(mConfigureIntent);
        connection.setOnEstablishListener(new ToyVpnConnection.OnEstablishListener() {
            public void onEstablish(ParcelFileDescriptor tunInterface) {
                mHandler.sendEmptyMessage(R.string.connected);
                mConnectingThread.compareAndSet(thread, null);
                setConnection(new Connection(thread, tunInterface));
            }
        });
        thread.start();
    }
    
    private void setConnectingThread(final Thread thread) {
        final Thread oldThread = mConnectingThread.getAndSet(thread);
        if (oldThread != null) {
            oldThread.interrupt();
        }
    }
    private void setConnection(final Connection connection) {
        final Connection oldConnection = mConnection.getAndSet(connection);
        if (oldConnection != null) {
            try {
                oldConnection.first.interrupt();
                oldConnection.second.close();
            } catch (IOException e) {
                Log.e(TAG, "Closing VPN interface", e);
            }
        }
    }