CentOS下安装配置VPN客户端

1.安装pptp与pptp-setup
yum install pptp pptp-setup

2.创建配置
格式如下:

pptpsetup --create myvpn --server ip --username user--password pass --encrypt

具体可以man pptpsetup查看

3.连接vpn
执行pppd call myvpn
ip a |grep ppp验证,如有返回诸如:

link/ppp
inet 172.16.6.2 peer 172.16.6.1/32 scope global ppp0

则表示连接成功。

4.添加路由
执行route -n返回

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
222.46.*.*   122.225.*.*   255.255.255.255 UGH   0      0        0 eth1
172.16.6.1      0.0.0.0         255.255.255.255 UH    0      0        0 ppp0
60.12.*.*    0.0.0.0         255.255.255.192 U     0      0        0 eth1
122.225.96.64   0.0.0.0         255.255.255.192 U     0      0        0 eth1
192.168.14.0    0.0.0.0         255.255.255.0   U     0      0        0 vmnet8
192.168.237.0   0.0.0.0         255.255.255.0   U     0      0        0 vmnet1
169.254.0.0     0.0.0.0         255.255.0.0     U     0      0        0 eth1
0.0.0.0         122.225.*.*   0.0.0.0         UG    0      0        0 eth1

注:这里用*隐藏了一些信息
可以看到ppp0接口只添加了一条172.16.6.1 0.0.0.0 255.255.255.255的路由信息,我想访问内网172.16.0.0的网段需要添加路由:执行 route add -net 172.16.0.0 netmask 255.255.0.0 dev ppp0
再次执行route -n可以看到路由已经加入:

...
172.16.0.0      0.0.0.0         255.255.0.0     U     0      0        0 ppp0
...

ping一个内网地址测试:

[root@localhost ~]# ping 172.16.4.110 -c 3
PING 172.16.4.110 (172.16.4.110) 56(84) bytes of data.
64 bytes from 172.16.4.110: icmp_seq=1 ttl=63 time=22.1 ms
64 bytes from 172.16.4.110: icmp_seq=2 ttl=63 time=26.2 ms
64 bytes from 172.16.4.110: icmp_seq=3 ttl=63 time=20.8 ms

--- 172.16.4.110 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 20.831/23.089/26.296/2.329 ms

5.关闭vpn
根据安装的ppp版本找到诸如:/usr/share/doc/ppp-2.4.4/scripts

[root@localhost /]# cp /usr/share/doc/ppp-2.4.4/scripts/pon /usr/sbin/
[root@localhost /]# cp /usr/share/doc/ppp-2.4.4/scripts/poff /usr/sbin/
[root@localhost /]# chmod +x /usr/sbin/pon
[root@localhost /]# chmod +x /usr/sbin/poff

方便的开启关闭vpn

[root@localhost /]# poff myvpn
[root@localhost /]# pon myvpn

[Thinking in Java]再读:字符串

1.不可变String

String对象是不可变的,String类中“修改字符串”的方法,实际上都是创建了一个全新的对象。

2.重载“+”与StringBuilder

String只读的特性会带来一定的效率的问题。例如:

public class StringTest {
	public static void main(String[] args) {
		String s = "abc";
		String x = "a" + "b" + s + "c";
	}
}

分析字节码,我们发现编译器并没有傻到一遍一遍的去新建对象:而是自动创建了“StringBuilder”,并每次都调用其append()方法,最后调用toString()将结果存在b中。

反编译 字节码:

D:\workspace\test\src>javap -c StringTest
Compiled from "StringTest.java"
public class StringTest {
public StringTest();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":
()V
4: return

public static void main(java.lang.String[]);
Code:
0: ldc #2 // String abc
2: astore_1
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."<
init>":()V
10: ldc #5 // String ab
12: invokevirtual #6 // Method java/lang/StringBuilder.ap
pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: aload_1
16: invokevirtual #6 // Method java/lang/StringBuilder.ap
pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: ldc #7 // String c
21: invokevirtual #6 // Method java/lang/StringBuilder.ap
pend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: invokevirtual #8 // Method java/lang/StringBuilder.to
String:()Ljava/lang/String;
27: astore_2
28: return
}

很显然编译器自动用了StringBuilder然后一个个.append();
这么看来我们能随便用String了?不

其实在复杂的字符串拼接中,这个并不可靠,比如循环中用+拼接字符串,可能会创建多个StringBuilder,编译后字节码变得很长,性能也会变差。

这种情形下(在toSring()中使用循环)自己创建StringBuilder是一个好的选择,此外你还可以为其配置大小来避免多次的重新分配缓冲。

陷阱append(a+":"+b) ,这种捷径写法会误导编译器,为新建StringBuilder对象来处理括弧中的字符串操作。

StringBuilder功能丰富:除了常用的append()和toString() 还有insert()\repleace()\subString()\reverse();

StringBuilder是java SE5引入的,在这之前用的是StringBuffer,区别是后者是线程安全的,开销也大一些。

3.无意识的递归
看一下这段代码,运行后将抛出长长的java.lang.StackOverflowError异常。

import java.util.ArrayList;
import java.util.List;

public class InfiniteRecursion {

@Override
public String toString() {
return "InfiniteRecursion address: " + this + "\n";
// return super.toString();
}

public static void main(String[] args) {
List<InfiniteRecursion> v = new ArrayList<InfiniteRecursion>();
for (int i = 0; i < 10; i++)
v.add(new InfiniteRecursion());
System.out.println(v);
}

}

由于在 "InfiniteRecursion address: " + this + "\n"发生了自动类型转换,“+”后面出现的不是String类型,于是编译器将this转换为String,即调用this的toString()方法,于是就发生了递归调用。打印内存地址的正确的用法:super.toString()(即Object.toString())。

4.String上的操作

具体可以参考doc(String)

5.格式化输出

java SE5推出了C语言printf()风格的格式化输出这一功能。

例如:

System.out.printf("Row 1: [%d %f] \n", x, y);

System.out.format("Row 1: [%d %f] \n", x, y);

format()与printf()是等价的.(format是java SE5引入的,可以用于PrintStream或PrintWriter)