怎样管理好你的密码
150 views 十二月 22, 11 by Timothy自从昨天CSDN爆出年度大乌龙后,貌似这种乌龙事件有愈演愈烈之势。今天,被爆出明文密码的又有7k7k,多玩,嘟嘟牛,还传闻有人人网的……且不说这些明文密码的真实性,至少CSDN的密码已经得到了验证,包括我的几个同事的帐号和密码都在其中…… Read More
自从昨天CSDN爆出年度大乌龙后,貌似这种乌龙事件有愈演愈烈之势。今天,被爆出明文密码的又有7k7k,多玩,嘟嘟牛,还传闻有人人网的……且不说这些明文密码的真实性,至少CSDN的密码已经得到了验证,包括我的几个同事的帐号和密码都在其中…… Read More
不知道拥有多个VPS的童鞋,平时是怎样来管理VPS的?在Windows下,我一般用SecureCRT来对VPS进行管理,原因是SecureCRT提供Tab标签管理的方式,多个VPS可以同时进行连接,并通过标签页进行快速切换,非常方便。至于在Linux下,我就只好老老实实的开个Console来连接VPS了。不过,今天发现一个很不错的开源软件,试用了一下,果然是Linux下管理多个VPS的利器,而且还有很多功能非常实用。
Pac Manager的官方地址,在SourceForge上:http://sourceforge.net/projects/pacmanager/
Linux下,可以直接下载发布的deb安装包进行安装。安装Pac Manager,还需要依赖另外一个安装包:libgnome2-vte-perl_0.09-1_i386.deb (64位系统,需要安装这个 libgnome2-vte-perl_0.09-1_amd64.deb),需要先安装依赖的安装包,再安装Pac Manager,否则会提示错误,找不到依赖的安装包,无法进行安装。
安装好后,就可以在主菜单的Internet子菜单中,找到Pac了。点击,即可启动。 Read More
OpenVPN是和我们常用的PPTP VPN,是目前两种最为常见的VPN方式。和PPTP VPN不同的是,OpenVPN需要通过证书来授权客户端,客户端也必须通过有效的证书,才能通过服务端的认证,并建立VPN连接。这样一来,OpenVPN的管理方式也和PPTP VPN有所不同,PPTN VPN可以直接对客户端帐户进行管理,而OpenVPN是通过客户端证书来实现管理。此文介绍OpenVPN中常用的对客户端证书管理的两种方法。
默认的OpenVPN配置,客户端证书有效期是10年。如何自定义客户端证书的时间呢?其实比较简单,编辑vars文件,找到export KEY_EXPIRE=3650这一行,把默认的3650,改为你想设置的天数即可。编辑后保存,运行一次vars,设置好环境变量,再用build-key生成客户端证书,即可。这样一来,客户端证书的有效期,就是你所设置的有效期了。
和PPTP VPN不一样,PPTP VPN直接删除客户端帐号,就可以了。在OpenVPN中,是通过revoke操作,吊销客户端证书,来实现禁止客户端连接OpenVPN的。
具体的方法如下:
1 2 3 4 5 6 | #进入OpenVPN配置文件所在目录 #执行vars,初始化环境 . vars #使用revoke-full命令,吊销客户端证书 ./revoke-full clientName #clientName是被吊销的客户端证书名称 |
命令执行后,我们能在keys目录中找到一个文件,名叫:crl.pem ,这个文件中包含了吊销证书的名单。然后,在服务端配置文件中,加入如下一行:
crl-verify crl.pem
最后一步,重启OpenVPN服务,即可
用上BB两天,发现BB还是挺好用的。无意中,又发现一款在BB上运行的SSH Client软件,这样的话,就可以通过手机来管理你的VPS了。想想你外出不在电脑旁的时候,可以随时随地通过手机控制你在大洋彼岸的VPS,那是相当的强大……
BB上可以使用的SSH Client客户端软件还比较多,比较了一下,选择了midpssh。大本营在这里。通过桌面工具进行安装,安装好后,程序菜单有如下的图标:
启动软件后,通过简单的设置,就可以连接VPS了,程序的菜单也比较简洁,不过有个不足的地方,没有看到在什么地方修改默认的SSH端口。为了安全,平时都没用默认的22端口,为了测试,俺又去VPS把22端口加到sshd里面。
接下来,连接,熟悉的界面出来了,大功告成:
从此可以在手机上管理你的VPS了。
希望该软件可以改进的地方:
1.可更改默认连接的SSH端口
2.连接后的输入命令,并不是直接在字符界面输入,而是要切换到另外一个文本界面,不方便,也不太直观
Unity根据我们在注册类型的时候所指定的生命周期来管理注册类型的创建和解析。当我们在向容器中注册类型的时候,如果我们没有显式的指明该类型的生命周期管理器(下称:Lifetime Manager),默认的情况下,容器会为我们注册的类型创建一个生命周期短暂的管理器。这样一来,当我们每次调用容器的Resolve方法或者ResolveAll方法,或者采用依赖机制注入实例到其他的类中的时候,容器都会为我们创建新的实例,并且容器不会保存对实例的引用。
容器的RegisterType函数包含多个支持泛型的重载,同时还包含了一一对应的非泛型重载。其中的重载函数,我们可以看到类似下面的声明:
1: RegisterType(LifetimeManager lifetime)
参数中的LifetimeManager类型,就是用来控制注册类型生命周期的。Unity中提供了几个继承自LifetimeManager的类作为注册类型的生命周期管理器。在目前的Unity 1.2版本中,共提供了3个LifetimeManager供我们直接在代码中调用。此外,我们也可以实现自己的LifetimeManager,不过必须实现LifetimeManager所必须的一些方法。
1.ContainerControlledLifetimeManager:
容器负责管理注册类型的生命周期,并且注册类型的生命周期和容器一致。当离开容器的作用域范围时,容器会被销毁,同时其中的注册类型也会被销毁。或者,当容器被显式销毁时,其中的注册类型也同样被销毁。但是在容器有效的作用域范围中,当我们使用Resolve方法,或者使用ResolveAll方法获取我们的注册类型的时候,容器会在第一次调用时,创建实例,但是在后面的调用中,我们始终只会得到相同的实例。我们可以利用这种Manager来实现Singleton模式。
2.ExternallyControlledLifetimeManager:
和上一种方式类似,不过容器在不会保留对注册类型的强引用,而只是保留弱引用。也就是说,如果这个注册类型没有在其他地方被强引用的时候,那么这个注册类型可能会被GC给干掉。
3.PerThreadLifetimeManager:
容器保证在每个线程中返回同一个对象实例,那么在不同的线程中,得到的实例是不同的。
下面我们可以试验一下不同的LifetimeManager的效果
a. 默认的情况,不显示的指明LifetimeManager
代码:
1: namespace UnityDemo
2: {
3: class Program
4: {
5: static void Main(string[] args)
6: {
7: IUnityContainer container = new UnityContainer();
8: container.RegisterType();
9:
10: INotify notify1 = container.Resolve();
11:
12: INotify notify2 = container.Resolve();
13:
14: Console.WriteLine("notify1:" + notify1.GetHashCode());
15: Console.WriteLine("notify2:" + notify2.GetHashCode());
16:
17: Console.ReadLine();
18: }
19: }
20: }
运行结果:
从结果我们可以看到,默认情况下不指定LifetimeManager的时候,每次我们获得的Instance其实不是同一个Instance.
b.使用ContainerControlledLifetimeManager
代码:
1: namespace UnityDemo
2: {
3: class Program
4: {
5: static void Main(string[] args)
6: {
7: IUnityContainer container = new UnityContainer();
8: container.RegisterType(new ContainerControlledLifetimeManager());
9:
10: INotify notify1 = container.Resolve();
11:
12: INotify notify2 = container.Resolve();
13:
14: Console.WriteLine("notify1:" + notify1.GetHashCode());
15: Console.WriteLine("notify2:" + notify2.GetHashCode());
16:
17: Console.ReadLine();
18: }
19: }
20: }
运行结果:
![]()
使用ContainerControlledLifetimeManager,在Container生命中期内,我们得到的Instance是同一个。
c.使用PerThreadLifetimeManager
代码:
1: namespace UnityDemo
2: {
3: class Program
4: {
5: static void Main(string[] args)
6: {
7: IUnityContainer container = new UnityContainer();
8: container.RegisterType(new PerThreadLifetimeManager());
9:
10: Thread thread1 = new Thread(new ParameterizedThreadStart(ThreadProc1));
11: Thread thread2 = new Thread(new ParameterizedThreadStart(ThreadProc2));
12:
13: thread1.Start(container);
14: thread2.Start(container);
15:
16: Console.ReadLine();
17: }
18:
19: static void ThreadProc1(object obj)
20: {
21: INotify notify1 = (obj as IUnityContainer).Resolve();
22: INotify notify2 = (obj as IUnityContainer).Resolve();
23:
24: Console.WriteLine("ThreadProc1 --- notify1:" + notify1.GetHashCode());
25: Console.WriteLine("ThreadProc1 --- notify2:" + notify2.GetHashCode());
26:
27: }
28:
29: static void ThreadProc2(object obj)
30: {
31: INotify notify1 = (obj as IUnityContainer).Resolve();
32: INotify notify2 = (obj as IUnityContainer).Resolve();
33:
34: Console.WriteLine("ThreadProc2 --- notify1:" + notify1.GetHashCode());
35: Console.WriteLine("ThreadProc2 --- notify2:" + notify2.GetHashCode());
36: }
37: }
38: }
运行结果:
在结果中可以看到,同一个线程中连续两次获取到的是同一个Instance,而不同的线程中获取到的Instance不一样。
前段时间工作中的一个新需求,有机会用到了Linq to SQL。使用后的第一感觉,就是方便很多,也为整个项目节约了一大把的开发时间,甚至代码量也少了很多。不过在程序的实际运行中,始终会遇到一些莫名其妙的异常,最令人不解的,就是“System.Data.Linq.ChangeConflictException: Row not found or changed.” 。当初凭自己和同事的判断,可能是数据库的数据异常所导致,后来发觉这个异常出现得越来越频繁,于是上MSDN查了查,原来是Linq中一个常见的问题:更新冲突。
这个词说起来比较玄乎,其实再平常不过了。下面可以通过一个简单的例子,来重现这个异常。
建立一个普通的测试表:LinqTest(如图)

在测试表中,插入一条测试数据(如图)

测试代码如下:
[code]
namespace LinqTest
{
class Program
{
static void Main(string[] args)
{
TestDataContext db = new TestDataContext();
db.Log = Console.Out;
var result = from p in db.LinqTests
where p.ID == 1
select p;
var info = result.FirstOrDefault();
if(info != null) //插入断点
{
info.Age = 25;
db.SubmitChanges();
}
Console.ReadLine();
}
}
}
[/code]
在测试代码中,将DataContext的日志定向到Console的输出部分,这样方便我们观察Linq实际执行的SQL语句是什么。重现的时候,我们需要在注释的地方,插入断点进行测试。对于示例中的代码,在正常情况下,是不会有错误的。执行过后,我们可以在Console的输出中,看到实际执行的SQL语句(如图)

再进行第二次调试,首先,恢复Age的数据到以前的样子。下面我们运行到断点处,然后偷偷去SQL Server Management Studio中,手动修改数据,将原始数据中的Age,由24,改为22。然后回到VS2008的IDE,按F5继续运行程序,这个时候,你会发现异常出现了(如图)

再回到Console的输出,查看,执行的SQL语句和刚才的一样。这就是问题的所在,在正常运行状态下,Linq在运行时,会把数据库的数据缓存到实体对象中,这是一种理想化的情况,并且在更新时,Linq会默认把除更新字段外的所有字段,作为Update语句中的Where条件。但是,如果此时有另外的程序,在访问数据库,并修改数据库数据的时候,比如刚才把Age改为22。此时Linq缓存起来的数据和实际数据库中的数据产生了不一致的情况。Linq此时仍然把被修改过的字段,作为Update的Where条件,但是数据库中Age早就被我们改过了,不再是25,Where条件始终匹配不到原有的数据。这时,就会抛出所谓的:“System.Data.Linq.ChangeConflictException: Row not found or changed.”异常。
产生此异常,主要是Linq缓存数据和实际数据库数据不一致的情况造成。解决次问题的情况,主要有几种:
1.比较简单的方法,不使用Linq提供的SubmitChanges()方式提交更改,而直接执行SQL语句,例如:
db.ExecuteCommand(“Update [dbo].[LinqTest] SET Age=25 Where ID = @p0″, 1);
这样虽然比较方便,但是感觉又回到了直接写SQL的时代,毕竟Linq to SQL的目的,就是为了让我们看不见SQL,避免写复杂的SQL语句,而直接操作实体对象,这样也可以避免程序可读性差、不便于维护。所以除非万不得已,还是不太推荐使用此方法。
2.参考MSDN的资料,采用Linq提供的解决更新冲突的方法,在异常中捕获冲突,然后手动解决冲突:
[code]
try
{
db.SubmitChanges(System.Data.Linq.ConflictMode.ContinueOnConflict);
}
catch (System.Data.Linq.ChangeConflictException ex)
{
foreach (System.Data.Linq.ObjectChangeConflict occ in db.ChangeConflicts)
{
//以下是解决冲突的三种方法,选一种即可
// 使用当前数据库中的值,覆盖Linq缓存中实体对象的值
occ.Resolve(System.Data.Linq.RefreshMode.OverwriteCurrentValues);
// 使用Linq缓存中实体对象的值,覆盖当前数据库中的值
occ.Resolve(System.Data.Linq.RefreshMode.KeepCurrentValues);
// 只更新实体对象中改变的字段的值,其他的保留不变
occ.Resolve(System.Data.Linq.RefreshMode.KeepChanges);
}
// 这个地方要注意,Catch方法中,我们前面只是指明了怎样来解决冲突,这个地方还需要再次提交更新,这样的话,值 //才会提交到数据库。
db.SubmitChanges();
}
[/code]
3. 这个方法也比较简单,也即MSDN中所说的Pessimistic Concurrency Control 。 我们可以来设定哪些字段需要放入Where条件,哪些字段不需要,这样就可以控制更新时候的条件匹配尺度。具体做法,就是在Linq to SQL Designer中,把一些字段的UpdateCheck属性设置为Never,这样,这些字段在更新的时候,就不会再出现在Where条件中了。其实比较推荐的做法,就是在表中设立主键,因为更新的时候,只要把主键作为Where条件,就可以单独的确立一行数据了。把除主键外的字段属性中UpdateCheck设置为Never即可。
关于Linq to SQL中如何管理更改冲突的更多资料,可以在MSDN找到
http://msdn.microsoft.com/zh-cn/library/bb399389.aspx