2014年8月27日星期三

Azure平台跨存储迁移虚拟机

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
Azure平台跨存储迁移虚拟机  阅读原文»

Azure平台跨存储迁移虚拟机

客户场景描述:

近段时间,客户注册了Azure测试账号(一个月的使用时间),进行测试使用,搭建了WEB网站服务,客户对Azure云平台,针对web开发,应用服务,非常满意,准备把web网站正式投入到生产,由于Azure测试账号只能试用一个月的时间,而测试账号不支持更转正式Azure账号使用。

客户如下需求:

Azure测试账号里的虚拟机和数据库迁移到正式的Azure上。

迁移虚拟机方法:

方法一:

虚拟机VHD和数据VHD文件,创建成磁盘,下载到本地,在进行上传到正式账号平台下,由于文件数据太大,下载和上传的速速太慢,无法接受,

方法二:

Azure平台跨存储账户复制VHD磁盘的方法

使用方法二进行迁移虚拟机:

1.由存储账户 A 复制到存储账户 B

2.首先您需要安装 Windows Azure Powershell

下载的链接为:http://azure.microsoft.com/en-us/documentation/articles/install-configure-powershell/?fb=zh-cn

3.在 Azure Powershell 执行 Get-AzureEnvironment

wKioL1P8mt6jlme9AAO13hOFZfs877.jpg

4.AzurePowershell执行Get-AzurePublishSettingsFile -Environment AzureChinaCloud,执行这个命令的目的:下载文件(PublishsettingsFile)

wKiom1P8mn-QVGQRAAQQ0d7cheo946.jpg5.下载文件时,需要客户在Azure平台上的输入B账户名和对应密码。 并保存文件位置

wKiom1P8nQ6yox7-AAMcEdgb8ec909.jpg6.Azure Powershell 执行Import-AzurePublishSettingsFile + 下载的文件路径(例如: D:\)导入下载的文件(PublishsettingsFile),从而成功进入订阅账户

wKioL1P8qCDj3K4vAAcFxCqr47g254.jpg

7.可以看到下面的截图,一元测试账号,已设定为新的默认订阅名称

wKiom1P8qrOTdq2pAAVSjdtOkW4014.jpg

8.查看B账号默认的存储账号

wKiom1P8qFvCyNooAAJQaLzbTrY376.jpg

9.在Azure Powershell执行Set-AzureSubscription CurrentStorageAccountName 存储账"portalvhdsqr56z0jf96rg8"执行这个命令的目的:设置B账号为当前订阅下默认的存储账号

wKiom1P8qcXibGacAAVo_5XiVy8471.jpg10.可以看到下面的截图,一元测试账号,已设定为新的默认订阅名称

wKioL1P8qxWhX2A5AAVcKfpX9K8118.jpg11.再次输入订阅名称:一元测试账号,如下图所示

wKioL1P8rBTxdajbAAVYdZ9uDNk315.jpg12.在AzurePowershell执行 $context = New-AzureStorageContext-StorageAccountName ,portalvhdss3nlhwwr7q21m,storageaccountkey tsD32gD0cV7bHS0Rg6MtJwh0TuZN5dL92309Cyo9vPxdYPicbpIR1azuxjw/k+7ZiY1T+/c2ghx/S0eyPVogZw==" -endpoint"core.chinacloudapi.cn"执行这个命令的目的:输入B存储账号名称以及密钥。

wKiom1P8rmPjqnIlAAUgqnZ8rE4108.jpg13.StorageAccountName(存储账户名称):portalvhds432bs5fb837mm ,可以在下面截图找到存储账户的名称:

wKioL1P8syeC5IvaAANF1VdP9yA941.jpg14.Storageaccountkey(存储账户密钥):tsD32gD0cV7bHS0Rg6MtJwh0TuZN5dL92309Cyo9vPxdYPicbpIR1azuxjw/k+7ZiY1T+/c2ghx/S0eyPVogZw==。可以在下面截图找到存储账户的密钥:

wKiom1P8u3GTySf_AAKFB9LccgA123.jpg

15.在进行跨存储账号间复制vhd文件之前,您订阅账户下A&B存储账号容器类型均要设置为公共(如果设置为私有,则无法完成复制),请参照以下截图:

wKiom1P8s_bQPmJ0AAHh1vfCyF0716.jpg16.在Azure Powershell执行Start-AzureStorageBlobCopy -SrcUri

-DestContainervhds -DestBlob web.vhd -DestContext $context

执行这个命令的目的:把A的vhd文件复制到另外一个存储账户上,web.vhd为复制到您另外一个存储账户的vhd文件名称(这个文件可以任意编写 vhd名称)。

wKioL1P8uvTgqAT7AAeHVrJRkdY308.jpg17.登陆B账号,查看复制的VH文件,文件已复制过来

wKiom1P8umiBROQLAAIP8QSysc0171.jpg18.在B账号创建磁盘

运维自动化之java编译自动化  阅读原文»

用户名:hh2o 文章数:34 评论数:14
访问量:9764:782:502:3 注册日期:2013-03-26

运维自动化之java编译自动化

【需求描述】 为了让代码开发之后,提升测试、部署上线的效率,需要将代码编译、部署过程自动化。
这里先介绍怎样使用javac自动化编译java代码。
因为项目目前暂未使用ant、maven等管理构建,所以需要使用比较原始的javac来实现,很伤有木有。

【背景说明】
代码目录结构
1、web类型的代码:达成war包(就一目录),使用tomcat来部署

web类型的工程目录结构介绍
# ls /home/souces/boss-web
src WebContent
src存放java的源代码:java文件,properties文件,xml文件等
WebContent存放html,js,css等文件

2、service类型的代码,最终会打成jar包部署

lib目录存放java项目依赖的jar包
src存放java的源代码:java文件,properties文件,xml文件等

ps:呃,这都是比较原始的项目结构了,后期要推动研发使用maven啊,虽然不用maven,但是作为运维,要见招拆招啊,所以也得在现有状况下给出方案滴。

3、编译目录结构梳理
/home/build/存放编译脚本:build.sh
/home/sources/存放源代码
/home/target/存放编译好的"目录"
/home/tgzs/存放编译后压缩好的tgz包
以后每次发布使用代码的tgz和config的tgz整合之后就可以发布了
test-web.20140826234520.p_3547.tgz
config_2.20140826234520.cfg_3544.tgz
其实我这里省略了对代码、配置文件的svn管理,及更新 /home/sources/的源代码的脚本,脚本就自己实现把。

【效果】

wKioL1P8rtCgubB4AADunoR8oo4730.jpg
【详细的脚本代码如下】

if[$#-lt1];then
echo-e'\033[31m输入参数错误!\033[37m'
echo-e"\033[31m例如:$0test-web\033[37m"
echo-e"\033[31m例如:$0config\033[37m"
JAVA_HOME=/usr/local/jdk/jre
PROJECT_PATH=/home/souces/$PROJECT#源代码路径
echo"$PROJECT"|grep-qservice#判断是web还是service类型
SERVICEorNOT=$?
JAR_PATH=$PROJECT_PATH/WebContent/WEB-INF/lib/#项目jar包路径
CLASS_PATH=$PROJECT_PATH/WebContent/WEB-INF/classes/#编译好的代码,class存放路径
TARGET=/home/target#编译好的代码,存放的根路径
TARGET_PROPERTIES_LOCATION="$TARGET/$PROJECT/WEB-INF/classes"#编译好之后,配置文件应该放的位置
SRC_PATH=$PROJECT_PATH/src#源代码的src的路径
TIME=`date+%Y%m%d%H%M%S`
if["$SERVICEorNOT"-eq0];then#如果是service类型
JAR_PATH="$PROJECT_PATH/lib/"
CLASS_PATH=$PROJECT_PATH/classes
TARGET_PROPERTIES_LOCATION="$TARGET/$PROJECT"
rm-rf$CLASS_PATH/*
mkdir-p$CLASS_PATH/META-INF
if[[$PROJECT!="config"&&$PROJECT!="config_2"]];then
JAVA_SOURCE_DIRS=`cd$SRC_PATH&&ls*/-d|sed's/\/*$//g'`#将src下面的com等目录取出
functionCompile_project(){
find$SRC_PATH-name*.java>$SRC_PATH/sources.list#将java的所有文件都找出
forJAVA_SOURCE_DIRin$JAVA_SOURCE_DIRS;do
rm-rf$CLASS_PATH/$JAVA_SOURCE_DIR
mkdir-p$CLASS_PATH/$JAVA_SOURCE_DIR#将源目录class下面的com等目录创建好,否则你拷贝class文件的时候就找不到目标目录拉
echo-e'\033[32m开始编译ing\033[37m'
#最关键的就是这里拉,-classpath需要说明编译的时候使用的lib是啥,-d说明的是,编译好之后,class应该生成到哪个目录
#-extdirs说明本project依赖的外部jar包情况,@就说明,需要编译的java文件列表,这就是之前为啥有爱哦findjava文件的原因
#使用-XDignore.symbol.file的原因:因为使用到了sun.awt.event.*不加这个参数会报错,比较好的解决办法是让开发修改掉,不要使用这些库

2014年8月26日星期二

Git的简单使用 - cpacm

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
Git的简单使用 - cpacm  阅读原文»

我以前用的是SVN,但最近发现Git的功能比SVN好多了。于是想配置Git,但是每次下载到一半就会失败(可能是网络原因),最后我就把它扔到一边了。昨天再尝试了一次,竟然成功了,那么今天我就把它简单整理一下发到这里来了。

一、Git介绍

Git是一个开源的分布式版本控制系统,用以有效、高速的处理从很小到非常大的项目版本管理。Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。Torvalds 开始着手开发 Git 是为了作为一种过渡方案来替代 BitKeeper,后者之前一直是 Linux 内核开发人员在全球使用的主要源代码工具。开放源码社区中的有些人觉得 BitKeeper 的许可证并不适合开放源码社区的工作,因此 Torvalds 决定着手研究许可证更为灵活的版本控制系统。尽管最初 Git 的开发是为了辅助 Linux 内核开发的过程,但是我们已经发现在很多其他自由软件项目中也使用了 Git。例如 最近就迁移到 Git 上来了,很多 Freedesktop 的项目也迁移到了 Git 上。

保存点 : Git的保存点可以追踪源码中的文件, 并能得到某一个时间点上的整个工程项目额状态; 可以在该保存点将多人提交的源码合并, 也可以会退到某一个保存点上;

Git离线操作性 :Git可以离线进行代码提交, 因此它称得上是完全的分布式处理, Git所有的操作不需要在线进行; 这意味着Git的速度要比SVN等工具快得多, 因为SVN等工具需要在线时才能操作, 如果网络环境不好, 提交代码会变得非常缓慢;

Git基于快照 : SVN等老式版本控制工具是将提交点保存成补丁文件, Git提交是将提交点指向提交时的项目快照, 提交的东西包含一些元数据(作者, 日期, GPG等);

Git的分支和合并 : 分支模型是Git最显著的特点, 因为这改变了开发者的开发模式, SVN等版本控制工具将每个分支都要放在不同的目录中, Git可以在同一个目录中切换不同的分支;
分支即时性 : 创建和切换分支几乎是同时进行的, 用户可以上传一部分分支, 另外一部分分支可以隐藏在本地, 不必将所有的分支都上传到GitHub中去;

分支灵活性 : 用户可以随时 创建 合并 删除分支, 多人实现不同的功能, 可以创建多个分支进行开发, 之后进行分支合并, 这种方式使开发变得快速, 简单, 安全。

Git通用客户端官方下载地址:http://git-scm.com/

二、Git安装

安装的话可以一路默认,路径可以自己指定。有关安装时参数的详细介绍,大家可以去这里看看,里面做了详细的介绍 http://www.ihref.com/read-16377.html

安装完后到你的安装目录下,找到一个叫做 Git Bash.vbs文件。配置同步需要使用到这个文件。双击打开,我们会得到一个命令行控制台界面。接下来我们来配置Git吧。

  1. Git上有三种传输方式(如下图),我们现在来选择SSH方式传输。在控制台输入ssh-keygen -t rsa -C "XXXXX@163.com" 。
    GitHub邮箱 : 该命令后面的邮箱就是GitHub的注册邮箱(没有账号的请先在Github上申请);
    路径选择 : 使用该命令之后, 会出现提示选择ssh-key生成路径, 这里直接点回车默认即可, 生成的ssh-key在默认路径中;
    密码确认 : 自设的一个密码。这里我就不使用密码进行登录了。

  2. 将SSH配置到GitHub网站中。进入生成的ssh目录 : C:\Documents and Settings\Administrator\.ssh (或者 C:\Users\自己电脑用户名\.ssh)中, 使用记事本打开 id_rsa.pub 文件, 将该文件中的内容复制;
    进入GitHub网站 : 登录GitHub, 选择Setting 进行用户设置:


    在左边的列表下找到SSH Keys的选项:

    然后将SSH Key值复制进去

    验证是否配置成功 :

    ssh -T git@github.com

    验证时可能让你输入YES。

    成功提示 : 如果出现Hi cpacm! You’ve successfully authenticated, but GitHub does not provide shell access. 就说明配置成功, 可以连接上GitHub;

  3. 配置本地邮箱

    用户名邮箱作用 : 我们需要设置一个用户名 和 邮箱, 这是用来上传本地仓库到GitHub中, 在GitHub中显示代码上传者;
    使用命令 :

    git config --global user.name "cpacm" //设置用户名
    git config --global user.email "xxx@163.com" //设置邮箱,不要求是注册邮箱。

到此Git的安装基本上就可以了。

三、Git的使用

  1. 我们现在会发现右键菜单新出来了三个选项
    功能分别是将本地作为本地仓库,打开Git Gui,打开Git Bash命令控制台。
    首先我们选择一个文件夹作为本地仓库

    在目录中右键执行 git init here,就可以创建一个 Git 仓库了。
    查看有哪些文件,使用ls指令。比如,我们这个目录,里头有个test.tet文件,可以用如下:

    $ ls
    test.txt

    也可以用cd来指定地址,将其仓库化

    $ cd 路径
    $ git init

    Initialized empty Git repository in /opt/konnichiwa/.git/
    # 在 /opt/konnichiwa/.git 目录初始化空 Git 仓库完毕。

    现在你可以看到在你的项目目录中有个 .git 的子目录。 这就是你的 Git 仓库了,所有有关你的此项目的快照数据都存放在这里。
    简而言之,用 git init 来在目录中创建新的 Git 仓库。 你可以在任何时候、任何目录中这么做,完全是本地化的。  

  2. clone一个项目到本地

    如果你需要与他人合作一个项目,或者想要复制一个项目,看看代码,你就可以克隆那个项目。 执行 git clone , 为你想要复制的项目地址,就可以了。

    $ git clone git://github.com/schacon/simplegit.git
  3. 添加文件到缓存,并上传
    在本地建立仓库后,右键选项会产生变化

    第一项:添加所有文件到本地缓存;第二项:提交工具,若本地缓存有变化,则会显示变化
    【Python⑤】python序列---list和tuple - 网络爬虫_小正  阅读原文»

    sequence 序列

    sequence(序列)是一组有顺序的对象的集合。序列可以包含一个或多个元素,也可以没有任何元素。

    我们之前所说的基本数据类型,都可以作为序列的对象。对象还可以是另一个序列。序列有两种:list (表) 和 tuple(元组) 。

    list和tuple的主要区别在于,一旦建立,tuple的各个元素不可再变更,而list的各个元素可以再变更。

    List

    获得list元素的个数:

    >>> lst=['更新慢','python',5.44,False]
    >>> len(lst)
    4

    引用访问时索引是从0开始,注意不要越界:

    >>> lst[0]
    '更新慢'
    >>> lst[1]
    'python'
    >>> lst[2]
    5.44
    >>> lst[3]
    False
    >>> lst[4]
    Traceback (most recent call last):
    File
    "<pyshell#30>", line 1, in <module>
    lst[
    4]
    IndexError: list index out of range

    -1做索引,直接获取最后一个元素:

    >>> lst[-1]
    False
    >>> lst[-2]
    5.44
    >>> lst[-3]
    'python'
    >>> lst[-4]
    '更新慢'
    >>> lst[-5]
    Traceback (most recent call last):
    File
    "<pyshell#35>", line 1, in <module>
    lst[
    -5]
    IndexError: list index out of range

    因为list是一个可变的有序表,所以,可以往list末尾追加元素:

    >>> lst.append('加我一个')
    >>> lst
    [
    '更新慢', 'python', 5.44, False, '加我一个']

    一次追加多个元素:

    >>> lst.extend(['A','B','C'])
    >>> lst
    [
    '更新慢', 'python', 5.44, False, '加我一个', 'A', 'B', 'C']

    要删除list末尾的元素,用pop()方法:

    >>> lst.pop()
    'C'
    >>> lst
    [
    '更新慢', 'python', 5.44, False, '加我一个', 'A', 'B']

    删除指定位置的元素,用pop(i)方法,其中i是索引位置:

    >>> lst.pop(0)
    '更新慢'
    >>> lst
    [
    'python', 5.44, False, '加我一个', 'A']

    list元素替换,可以直接赋值给对应的索引位置:

    >>> lst[-1]='100'
    >>> lst
    [
    'python', 5.44, False, '加我一个', '100']

    list元素也可以是另一个list,插入的那个list只算一个元素:

    >>> lst.append(lst1)
    >>> lst
    [
    'python', 5.44, False, '加我一个', '100', ['666', 'QWER']]
    >>> len(lst)
    6

    Tuple

    Tuple一旦初始化就不能修改。字符串是一种特殊的元素,因此可以执行元组的相关操作。

    >>> str='该睡觉了,晚安!'
    >>> print (str[:7])
    该睡觉了,晚安

    不可变的tuple意义就在于因为不可变,所以代码更安全。如果可能,能用tuple就尽量用tuple

    阅读更多内容

2014年8月25日星期一

如何挖掘NAND Flash的IO性能

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
如何挖掘NAND Flash的IO性能  阅读原文»

NAND Flash芯片是构成SSD的基本存储单元,NAND Flash芯片工艺的发展、结构的变化将会推动整个闪存存储产业的高速发展。在设计闪存存储系统的时候,特别是在设计NAND Flash控制器、SSD盘或者卡的时候,都需要深入的了解NAND Flash的操作方法、接口命令及其时序。一个NAND Flash芯片虽然非常小,采用LGA或者TSOP的封装形式,但是,其内部结构还是非常复杂的。特别是随着存储密度的不断提高,NAND Flash内部抽象的概念也越来越多,例如Flash颗粒、DeviceDiePlaneBlockPage。颗粒就是我们通常所看到的一个基本芯片封装颗粒;每个颗粒可以封装多个Device,每个Device可以看成是一个独立的Chip,拥有独立的控制、数据信号线;每个Device可以由多个Die构成,多个Die之间内部有独立的操作寄存器、状态指示信号,对外的信号线是共享的;一个Die又可以分成多个Plane,每个Plane拥有独立的数据寄存器组,可以在一定情况下对多个Plane进行并发操作;一个Plane可以分成若干个Block;每个Block又是一个独立的数据块擦除单元;一个Block最后又被分成很多个Page页,每个Page页是读写操作的基本单元。

以镁光的Flash芯片为例,MT29F32G芯片由一个Die构成,其中包括两个PlaneMT29F64G芯片由两个Die构成,并且这两个Die分别归属为两个Device,每个Die包括两个PlaneMT29F32GMT29F64G芯片的Die基本单元结构可以描述如下:

wKioL1P6A0WyY8OBAAE8CH7yLs8210.jpg

对于MT29F32GMT29F64G芯片的地址信息可以定义如下表:

wKiom1P6AkXBkR_5AADYgD73rWU029.jpg

对于镁光的MT29F128G芯片而言,由于存储密度提升了,所以整个芯片由两个Device构成,每个Device包括两个Die,每个Die容纳了两个PlaneMT29F128G芯片内部的基本存储单元Device的结构描述如下:

wKioL1P6A3LSn14mAAGooE66jWI246.jpg

MT29F128G的地址信息定义如下表:

wKiom1P6AnDwDJg_AADVgivbI3Y433.jpg

在了解到NAND Flash的内部结构之后,我们需要思考从软件层面如何利用好NAND Flash的内部结构,从而提升整体的IO性能。

Plane单元拥有独立的数据寄存器,是否可以并发Plane操作从而提升IO性能呢?以MT29F128G芯片为例,每个Die可以被分成2个物理Plane。每个Plane包含一个字节的数据寄存器,一个字节的数据Cache寄存器,以及一个由4K页构成的Block Array。由于两个Plane的数据寄存器是物理上独立的,因此,这两个Plane可以同时执行ProgramReadErase操作,通过这种方式可以提升NAND Flash的系统IO性能。两个Plane同时读数据的时序图如下所示:

wKioL1P6A5-QuJrdAAEie1b7Suw561.jpg

从上面的时序图可以看出,两个Plane之间的并发操作不是那么随意的。当需要从两个Plane同时读取数据的时候,首先加载第一个Plane的地址信息,然后加载第二个Plane的地址信息,当两个地址信息都加载完毕之后,发出结束命令30H。随后整个Die进入忙状态,R/B#信号置低。在Die处于忙状态时,无法对其进行任何操作,在这个阶段,数据从NAND Flash介质中加载到两个Plane的寄存器中。当R/B#信号恢复之后,可以读取两个Plane中的数据。值得注意的是,第二个Plane中的数据读取需要06H-E0H命令的支持。从这点上来看,由于两个Plane只是独立了数据寄存器,共享了操作寄存器,所以,不能很好的做到非常随意的数据并发。

两个Plane的并发写操作时序如下图所示:

wKiom1P6Ap_ytIBnAABVRZ4he5U657.jpg

<

openvpn2.3.4服务器部署  阅读原文»

一、openvpn与pptp的抉择

PPTP

点对点隧道协议(pptp)是一种实现虚拟专用网络的方法。pptp使用用于封装ppp数据包的tcp及GRE隧道控制通道。

OpenVPN是一免费开源软件,以路由器或桥接配置和远程访问设备方式实现虚拟专用网络(vpn)创建安全的点 对点或站对站连接的解决方案。它使用SSL / TLS安全加密,具有穿越网络地址转换(NATs)和防火墙的功能。

PPTP与OpenVPN之比较和抉择?

在pptp和openvpn二者之间做出选择的一个重要考虑因素,也是我们无法控制的因素,就是有时互联网服务供应商会阻止 PPTP连接。次情况下我们无计可施,只能选择使用openvpn。 pptp具有一些独 特优势,但此刻用openvpn会是不错的选择。

二、部署openvpn

本次部署openvpn服务器,因为使用了最新的openvpn2.3.4,而这个包里面没有包含最重要的证书制作部分:easy-rsa

openvpn官网也给出明确说明:Starting with openvpn-2.3_alpha2easy-rsais no longer part of the OpenVPN source or binary packages

所以,我们需要事先下载好easyrsa,可以到GitHub上进行下载,配置过程将在下面第3步进行,本次部署使用了easy-rsa3,与easy-rsa2.0的操作完全不同,网上其它关于easy-rsa2.0的教程不适合本次部署

1、安装lzo

lzo是致力于解压速度的一种数据压缩算法

  [root@vpn ~]# tar xf lzo-2.08.tar.gz  [root@vpn ~]# cd lzo-2.08  [root@vpn lzo-2.08]# ./configure && make && make install  

2、安装openvpn

  [root@vpn ~]# tar xf openvpn-2.3.4.tar.gz  [root@vpn ~]# cd openvpn-2.3.4  [root@vpn openvpn-2.3.4]# ./configure --with-lzo-headers=/usr/local/include/ --with-lzo-lib=/usr/local/lib  [root@vpn openvpn-2.3.4]# make && make install  [root@vpn openvpn-2.3.4]#  [root@vpn openvpn-2.3.4]# which openvpn  /usr/local/sbin/openvpn      #看到这里,说明安装openvpn成功  

3、配置easyrsa服务端

openvpn-2.3.4软件包不包含证书(ca证书,服务端证书,客户端证书)制作工具,所以还需要单独下载easy-rsa,最新的为easy-rsa3

Starting with openvpn-2.3_alpha2easy-rsais no longer part of the OpenVPN source or binary packages(来源openvpn官网)

  [root@vpn ~]# unzip easy-rsa-master.zip  [root@vpn ~]# mv easy-rsa-master easy-rsa  [root@vpn ~]# cp -R easy-rsa/ openvpn-2.3.4/  [root@vpn ~]# cd openvpn-2.3.4/easy-rsa/easyrsa3/  [root@vpn easyrsa3]# cp vars.example vars  [root@vpn easyrsa3]# vim vars  set_var EASYRSA_REQ_COUNTRY "CN"  set_var EASYRSA_REQ_PROVINCE "Beijing"  set_var EASYRSA_REQ_CITY "Beijing"  set_var EASYRSA_REQ_ORG "nmshuishui Certificate"  set_var EASYRSA_REQ_EMAIL "353025240@qq.com"  set_var EASYRSA_REQ_OU "My OpenVPN"  

4、创建服务端证书及key

(1)初始化

  [root@vpn easyrsa3]# ls  easyrsa  openssl-1.0.cnf  vars  vars.example  x509-types  [root@vpn easyrsa3]#  [root@vpn easyrsa3]# ./easyrsa init-pki  Note: using Easy-RSA configuration from: ./vars  init-pki complete; you may now create a CA or requests.  Your newly created PKI dir is: /root/openvpn-2.3.4/easy-rsa/easyrsa3/pki  

(2)创建根证书

  [root@vpn easyrsa3]# ./easyrsa build-ca  Note: using Easy-RSA configuration from: ./vars  Generating a 2048 bit RSA private key  .............................................+++  ........+++  writing new private key to '/root/openvpn-2.3.4/easy-rsa/easyrsa3/pki/private/ca.key'  Enter PEM pass phrase:                      #输入密码,此密码用途证书签名  Verifying - Enter PEM pass phrase:          #确认密码  -----  You are about to be asked to enter information that will be incorporated  into your certificate request.  What you are about to enter is what is called a Distinguished Name or a DN.  There are quite a few fields but you can leave some blank  For some fields there will be a default value,  If you enter '.', the field will be left blank.  -----  Common Name (eg: your user, host, or server name) [Easy-RSA CA]:nmshuishui  #输入一个Common Name  CA creation complete and you may now import and sign cert requests.  Your new CA certificate file for publishing is at:  /root/openvpn-2.3.4/easy-rsa/easyrsa3/pki/ca.crt  

(3)创建服务器端证书

  [root@vpn easyrsa3]# ./easyrsa gen-req server nopass  Note: using Easy-RSA configuration from: ./vars  Generating a 2048 bit RSA private key  ................................+++  ......+++  writing new private key to '/root/openvpn-2.3.4/easy-rsa/easyrsa3/pki/private/server.key'  -----  You are about to be asked to enter information that will be incorporated  into your certificate request.  What you are about to enter is what is called a Distinguished Name or a DN.  There are quite a few fields but you can leave some blank  For some fields there will be a default value,  If you enter '.', the field will be left blank.  -----  Common Name (eg: your user, host, or server name) [server]:nmshuishui-BJ  #该Common Name一定不要与创建根证书时的                                                                            #Common Name一样,这是血与泪的教训  Keypair and certificate request completed. Your files are:  req: /root/openvpn-2.3.4/easy-rsa/easyrsa3/pki/reqs/server.req  key: /root/openvpn-2.3.4/easy-rsa/easyrsa3/pki/private/server.key  

(4)签约服务器端证书

  [root@vpn easyrsa3]# ./easyrsa sign server server  Note: using Easy-RSA configuration from: ./vars  You are about to sign the following certificate.  Please check over the details shown below for accuracy. Note that this request  has not been cryptographically verified. Please be sure it came from a trusted  source or that you have verified the request checksum with the sender.  Request subject, to be signed as a server certificate for 3650 days:  subject=      commonName                = nmshuishui  Type the word 'yes' to continue, or any other input to abort.    Confirm request details: yes        #输入yes继续  Using configuration from /root/openvpn-2.3.4/easy-rsa/easyrsa3/openssl-1.0.cnf  Enter pass phrase for /root/openvpn-2.3.4/easy-rsa/easyrsa3/pki/private/ca.key:    #输入刚才创建根证书时的密码  Check that the request matches the signature  Signature ok  The Subject's Distinguished Name is as fo

阅读更多内容

2014年8月24日星期日

Jscript复选框 - 健康生活吧

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
Jscript复选框 - 健康生活吧  阅读原文»

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="Generator" content="EditPlus®">
<meta name="Author" content="">
<meta name="Keywords" content="">
<meta name="Description" content="">
<title>Document</title>
<script type="text/javascript">
<!--全选框的方法-->
function check(
object){
var checks=document.getElementsByName("checks");
if (checks!=null)
{
for (var i=0;i<checks.length;i++ )
{
checks.
checked=document.getElementById("checkAll").checked;
}
}
};
<!--这里要注意如果 var checkall=document.getElementById("checkAll").checked; 下面判断 checkall==true 语句是错的!逻辑是对的,语法是错的-->
function checks(){
var checkall=document.getElementById("checkAll");
var checks=document.getElementsByName("checks");
var count=0;
var sum=0;
for (var i=0;i<checks.length ;i++ )
{
if (checks.checked==true)
{
count
=count+1;
}
if(checks.checked==false){
sum
=sum+1;
}
}
alert(sum);
if (count==checks.length)
{
checkall.
checked=true;
}
if (sum>0)
{
if (checkall.checked==true)
{
checkall.
checked=false;
}
}

}


</script>
</head>
<body>
<div id="" class="">
<table>
<tr>
<td><input type="checkbox" id="checkAll" onclick="check(this)"></td>
<td>商品名称</td>
<td>商品价格</td>
<td>商品描述</td>
</tr>
<tr>
<td><input type="checkbox" name="checks" onclick="checks()"></td>
<td>酒精</td>
<td>12</td>
<td>酒精你懂的</td>
</tr>
<tr>
<td><input type="checkbox" name="checks" onclick="checks()"></td>
<td>饭盒</td>
<td>15</td>
<td>吃饭的工具,你不知道?</td>
</tr>
<tr>
<td><input type="checkbox" name="checks" onclick="checks()"></td>
<td>酒精</td>
<td>12</td>
<td>酒精你懂的</td>
</tr>
<tr>
<td><input type="checkbox" name="checks" onclick="checks()"></td>
<td>饭盒</td>
<td>15</td>
<td>吃饭的工具,你不知道?</td>
</tr>
<tr>
<td><input type="checkbox" name="checks" onclick="checks()"></td>
<td>酒精</td>
<td>12</td>
<td>酒精你懂的</td>
</tr>
<tr>
<td><input type="
Sql2008R2的一个补丁BUG-大家使用时请注意 - shanks_gao  阅读原文»

我们都知道Sqlserver为了提高并发,允许乐观隔离级别(读提交快照,快照)以便读与写之间不阻塞.这里有一个在Sqlserver2008R2 SP2 的热补丁(CU11)下RCSI(读提交快照)隔离级别下的异常.希望大家注意.

这里我通过实例给大家呈现.

Code 测试数据 (Sql2008R2 sp2 cu11)

create database testbug

select @@VERSION --Microsoft SQL Server 2008 R2 (SP2) - 10.50.4302.0 (Intel X86)

use testbug
go
create table testbug
(
id
int identity(1,1) primary key,
str1
char(10)
)

insert into testbug select 'aa'
go 10000


ALTER DATABASE testbug
SET READ_COMMITTED_SNAPSHOT ON
with rollback immediate-------------修改库隔离级别为RCSI

开启session 1,显式事务update

begin tran ttt
update testbug set str1='cc'

开启session 2,select 将被阻塞.

select * from testbug ---将被阻塞

出乎意料,不是说好的乐观隔离级别下读与写不阻塞吗??

原因分析

我们从DMV sys.dm_tran_locks中查看具体阻塞情况如图1-1

select * from sys.dm_tran_locks

2014年8月23日星期六

hdu 1875 畅通工程再续 - 若忆_star

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
hdu 1875 畅通工程再续 - 若忆_star  阅读原文»

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1875

畅通工程再续

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 15473 Accepted Submission(s): 4791


Problem Description
相信大家都听说一个“百岛湖”的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小船来实现。现在政府决定大力发展百岛湖,发展首先要解决的问题当然是交通问题,政府决定实现百岛湖的全畅通!经过考察小组RPRush对百岛湖的情况充分了解后,决定在符合条件的小岛间建上桥,所谓符合条件,就是2个小岛之间的距离不能小于10米,也不能大于1000米。当然,为了节省资金,只要求实现任意2个小岛之间有路通即可。其中桥的价格为 100元/米。

Input
输入包括多组数据。输入首先包括一个整数T(T <= 200),代表有T组数据。
每组数据首先是一个整数C(C <= 100),代表小岛的个数,接下来是C组坐标,代表每个小岛的坐标,这些坐标都是 0 <= x, y <= 1000的整数。

Output
每组输入数据输出一行,代表建桥的最小花费,结果保留一位小数。如果无法实现工程以达到全部畅通,输出”oh!”.

Sample Input
2
2
10 10
20 20
3
1 1
2 2
1000 1000

Sample Output
1414.2
oh!
题目大意:要找最小的花费,那么也就可以理解为最短的路就一定为最少花费了,这里多一个的限制条件多注意一下就好了。。就是2个小岛之间的距离不能小于10米,也不能大于1000米。注意是不大于和不小于!!!
因为这里有限制条件,所以要使所有的路都连通,就需要标记一下,来看是否所有的路都走过~标记方法有很多,代码供参考。
1 #include<iostream>
2 #include<cstdio>
3 #include<cmath>
4 using namespace std;
5 double map[1010][1010],node[1010],s,Min;
6 int m,flag;
7 const double INF=999999;
8
9 void prim()
10 {
11 int vis[1010]= {0};
12 int tm=1,v=1;
13 flag=0;
14 s=0;
15 vis[tm]=1;
16 node[tm]=0;
17 for (int k=1; k<=m; k++)
18 {
19 Min=INF;
20 for (int i=1; i<=m; i++)
21 if (!vis)
22 {
23 //cout<<node<<" "<<map[tm]<<endl;
24 if(node>map[tm]&&map[tm]>=10&&map[tm]<=1000)
25 node=map[tm];
26 if (Min>node)
27 {
28 Min=node;
29 v=i;
30
31 }
32 }
33 //s+=node[v];
34 vis[v]=1;
35 tm=v;
36 }
37 for (int i=1; i<=m; i++)
38 {
39 s+=node;
40 if (node!=INF)
41 flag++;
42 }
43 }
44
45 int main ()
46 {
47 int n,a[1010],b[1010];
48 cin>>n;
49 while (n--)
50 {
51 //memset (map,INF,sizeof (map));
52 cin>>m;
53 for (int i=1; i<=m; i++)
54 {
55 cin>>a>>b;
56 }
57 for(int i=【代码优化】调用optional delegates的最佳方法 - NSTopGun  阅读原文»

【转载请注明出处】http://www.cnblogs.com/lexingyu/p/3932475.html

本文是以下两篇blog的综合脱水,感谢两位作者为解放码农生产力所做的深入思考=。=
Smart Proxy Delegation
Elegant Delegation

使用delegate的情境通常是这样

定义class和delegate

@protocol TestObjectDelegate <NSObject>
@optional
- (void)testObjectMethod;
- (NSString *)testObjectMethodWithReturnValue;

@end


@interface TestObject : NSObject

@property (nonatomic, weak) id<TestObjectDelegate> delegate;

- (void)print;
- (void)printWithLog;

@end

在类的内部调用delegate的方法

- (void)print
{
//call the delegate to do the real work
}


调用的方法通常有以下两种

普通青年:

if ([self.delegate respondsToSelector:@selector(testObjectMethod)])
{
[self.delegate testObjectMethod];
}

这个办法的缺点是
1)引入了大量glue code,每个optional function都需要3行代码。尤其在开启clang的-Warc-repeated-use-of-weak时,多次使用self.delegate(通常情况下,是weak)会被警告;

所以很可能还得这么写

- (void)print
{
id <TestObjectDelegate> delegate = self.delegate;
if ([delegate respondsToSelector:@selector(testObjectMethod)])
{
[delegate testObjectMethod];
}
}

2)调用的方法名需要写两次,很可能写错导致方法未被调用;
3)对于高频率调用的方法而言,意味着需要反复调用respondToSeletor,性能上有所影响(RunTime可能会对respondToSeletor进行缓存,因此在大部分应用上这一点不需要计入考量)。

文艺青年
先添加flag

@interface TestObject : NSObject
{
struct
{
unsigned int respond2TestObjectMethod:1;
}_flags;
}

@property (nonatomic, weak) id<TestObjectDelegate> delegate;

- (void)print;

@end

再重载setDelegate以设置flag,将respondToSeletor的结果缓存起来

- (void)setDelegate:(id<TestObjectDelegate>)delegate
{
_delegate = delegate;

BOOL respond2TestObjectMethod = [delegate respondsToSelector:@selector(testObjectMethod)];
_flags.respond2TestObjectMethod = respond2TestObjectMethod ? 1 : 0;
}

最后在print中直接使用缓存的结果

- (void)print
{
if (_flags.respond2TestObjectMethod)
{
[self.delegate testObjectMethod];
}
}

这个方法被Apple广泛采用,在SDK中随处可见。
它的优点是将respondToSeletor的结果手动缓存了起来,不需要做性能上的猜测,同时避开了
-Warc-repeated-use-of-weak的警告。
但遗憾的是,代码的冗余并没有被移除,反而更为严重(调用时仍然需要3行glue code,且在头文件和setDelegate中添加了大量代码)。当delegate中的方法名需要变动时,需要同时修改多处代码,真如噩梦一般。

嗯。。。。。。抱歉这里没有二逼青年

外国友人的想法

实际上我们真正想要的是类似于这样的东西

- (void)print
{
[self.delegateProxy testObjectMethod];
}

把glue code也好,其他额外处理也好,都放到一个统一的地方。在调用的时候,一句话简单明了,解决问题。
那么具体怎么做呢?
其实,OC的方法调用,或者准确地说,消息传递,就是这样一种机制。这里上一张自绘的图以便说明

OC中任何一次方法调用,都会从1开始走这个流程,一个步骤不行就进行下一步。若所有4个步骤走完仍然无法找到对应的impletation,则触发异常,程序crash。简单说一下各个步骤的作用
1)在类的方法表(methodList)中,根据seletor查找对应的impletation;
2) resolveInstanceMethod用于集中处理类中一些类似的方法,比如在使用core ,它们的setter和getter就可以集中在这个方法里做;
3)forwardingTargetForSelector,作用是将本对象无法处理的调用信息转给另一个对象处理,但不改变调用信息;
4)forwardInvocation,作用是根据methodSignatureForSelector和调用参数等信息生成的NSInvocation来指定一个对象处理本次调用,在指定时可以对调用信息做任意的修改,比如增加参数个数。

3被称为Fast message forwarding,相应地4则是Regular message forwarding,二者合在一起才是完整的Message forwarding

C语言在调用函数时,需要知道函数的原型,以便将参数放入寄存器或压入栈中,并视情况预留返回值的空间。OC作为C语言的超集,也需要顾及这一点。函数的调用信息在OC中以NSMethodSignature的形式存在,在Regular message forwarding中由methodSignatureForSelector返回。

从以上说明不难看出,1和2的作用是在类内部寻找impletation,而3和4则是在类外部寻找合适的其他类的实例来处理调用信息。显而易见,3和4正是delegateProxy所需要的。

铺垫了这么多,终于到了正题。

用Message forwarding机制,来构建一个delegateProxy

在这里构建了一个NSProxy的派生类作为delegateProxy,像这样

@interface CDDelegateProxy : NSProxy

@property (nonatomic, weak, readonly) id delegate;
@property (nonatomic, strong, readonly) Protocol *protocol;
@property (nonatomic, strong, readonly) NSValue *defaultReturnValue;

@end

delegateProxy中分别保存了被代理的delegate对象、delegate对应的protocol和方法未找到时提供的默认值。
在.m文件中,首先将glue code放入,像这样

//供外部需要时使用
- (BOOL)respondsToSelector:(SEL)selector
{
return [_delegate respondsToSelector:selector];
}

//Fast message forwarding, 存放glue code
- (id)forwardingTargetForSelector:(SEL)selector
{
id delegate = _delegate;
return [delegate respondsToSelector:selector] ? delegate : self;
}

嗯。。。至此似乎就完事了=。=
大部分情况下确实如此。但当方法不存在又需要一个默认返回值时,比如

- (void)printWithLog
{
//这里已经用上delegateProxy了,哈哈
NSString *logInfo = [self.delegateProxy testObjectMethodWithReturnValue];
NSLog(@"%@", logInfo);
}

就需要用到Regular message forwarding了。具体做法如下

//Regular message forwarding
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
id delegate = _delegate;
NSMethodSignature *signature = [delegate methodSignatureForSelector:selector];

//若delegate未实现对应方法,则从protocol的声明中获取MethodSignature
if (!signature)
{
if (!_signatures) _signatures = [self methodSignaturesForProtocol:_protocol];
signature = CFDictionaryGetValue(_signatures, selector);
}

//此处如果return nil, 则不会触发forwardInvocation
return signature;
}

- (void)forwardInvocation:(NSInvocation *)invocation
{
//若默认返回值和invocation中指定的返回值一致,则取默认返回值
if (_defaultReturnValue
&& strcmp(_defaultReturnValue.objCType, invocation.methodSignature.methodReturnType) == 0)
{
char buffer;
[_defaultReturnValue getValue:buffer];
;
}
}

首先由methodSignatureForSelector根据protocol中的方法声明,返回一个signature,再由forwardInvocation判断与默认的返回值是否类型一致,一致则返回预设的默认值(即刚才提到的defaultReturnValue)。

这样,delegateProxy就构建完毕了。在使用的时候,应注意delegateProxy的作用只是在类内部保持调用的简洁,对于外部代码而言,它应该是透明的。具体来说,首先应该将deleagteProxy定义在class extension中

//.m文件中
@interface SomeObject ()<TestObjectDelegate>

@property (nonatomic, strong) id<TestObjectDelegate> delegateProxy;

@end

这里将delegateProxy直接声明为id的形式,目的是使之后编码时仍然能够享有Xcode对protocol中方法的自动提示补全。
接着override delegate(真正id被定义在头文件中)

- (void)setDelegate:(id <TestObjectDelegate>)delegate
{
self.delegateProxy = delegate ? (id <TestObjectDelegate>)[[CDDelegateProxy alloc] initWithDelegate:delegate] : nil;
}
- (id <TestObjectDelegate>)delegate
{
return ((CDDelegateProxy *)self.delegateProxy).delegate;
}

这个步骤看着有些繁琐,可以通过宏来简化,比如

#define CD_DELEGATE_PROXY_CUSTOM(protocolname, GETTER, SETTER) \
- (id<protocolname>)GETTER { return ((PSTDelegateProxy *)self.GETTER##Proxy).delegate; } \
- (void)SETTER:(id<protocolname>)delegate { self.GETTER##Proxy = delegate ? (id<protocolname>)[[PSTDelegateProxy alloc] initWithDelegate:delegate conformingToProtocol:@protocol(protocolname) defaultReturnValue:nil] : nil; }

#define CD_DELEGATE_PROXY(protocolname) PST_DELEGATE_PROXY_CUSTOM(protocolname, delegate, setDelegate)

在使用的使用可以简单地

CD_DELEGATE_PROXY(id <PSPDFResizableViewDelegate>)

当然,对于比较个性化的delegate的名称,可以通过扩展这个宏来实现。

如此一来,外部访问delegate时,获取到的仍然是正确的对象。
以上,就是调用optional delegates的最佳方法,从起因到原理到解决方案的完整阐述。

文中为便于说明,使用了我自己写的一个简化版的delegateProxy,这里提供一?p>阅读更多内容

2014年8月22日星期五

RHEL Linux6.3vnc°×°§

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
RHEL Linux6.3vnc°×°§  阅读原文»

RHEL Linux6.3下的vnc安装和多用户配置

VNC (Virtual Network Computer)是虚拟网络计算机的缩写。VNC 是一款优秀的远程控制工具软件,由著名的 AT&T 的欧洲研究实验室开发的。VNC 是在基于 UNIX 和 Linux 操作系统的免费的开源软件,远程控制能力强大,高效实用,其性能可以和 Windows 和 MAC 中的任何远程控制软件媲美。 在 Linux 中,VNC 包括以下四个命令:vncserver,vncviewer,vncpasswd,和vncconnect。大多数情况下用户只需要其中的两个命令:vncserver 和 vncviewer。下面我们讲一下在RHEL Linux6.3下的vnc安装和多用户配置。

一、安装VNC

RHEL6.3中有关VNC的rpm包是:

客户端:tigervnc-1.0.90-0.17.20110314svn4359.el6.x86_64.rpm

服务端:tigervnc-server-1.0.90-0.17.20110314svn4359.el6.x86_64.rpm

1、yum安装:(配置本地YUM源)

[root@localhost yum.repos.d]# cat rhel6.repo

[rhel6]

name=Red Hat Enterprise Linux6.3

baseurl=file:///rhel6

enabled=1

gpgcheck=0

[root@rac1 oracle]# yum -y install tigervnc-server

Loaded plugins: product-id, refresh-packagekit, security, subscription-manager

Installing : tigervnc-server-1.0.90-0.17.20110314svn4359.el6.x86_64 1/1

Installed products updated.

Verifying : tigervnc-server-1.0.90-0.17.20110314svn4359.el6.x86_64 1/1

Installed:

tigervnc-server.x86_64 0:1.0.90-0.17.20110314svn4359.el6

Complete!

2、启动vnc服务

#service vncserver start

3、添加系统启动

#chkconfig vncserver on

4、启动VNC桌面

[root@rac1 oracle]# vncserver

You will require a password to access your desktops.

Password:

Verify:

xauth: creating new authority file /root/.Xauthority

New 'rac1.localdomain:1 (root)' desktop is rac1.localdomain:1

Creating default startup script /root/.vnc/xstartup

Starting applications specified in /root/.vnc/xstartup

Log file is /root/.vnc/rac1.localdomain:1.log

注: 第一次启动时系统会提示设置连接VNC时的登录密码,这个和ROOT设置的认证密码是可以不同的。

二、配置VNC

查看vnc桌面配置文件

[root@bogon ~]# vi /root/.vnc/xstartup

#######################################################################

1 #!/bin/sh

2

3 [ -r /etc/sysconfig/i18n ] && . /etc/sysconfig/i18n

4 export LANG

5 export SYSFONT

6 vncconfig -iconic &

7 unset SESSION_MANAGER

8 unset DBUS_SESSION_BUS_ADDRESS

9 OS=`uname -s`

10 if [ $OS = 'Linux' ]; then

11 case "$WINDOWMANAGER" in

12 *gnome*)

13 if [ -e /etc/SuSE-release ]; then

14 PATH=$PATH:/opt/gnome/bin

15 export PATH

16 fi

17 ;;

18 esac

19 fi

20 if [ -x /etc/X11/xinit/xinitrc ]; then

21 exec /etc/X11/xinit/xinitrc

22 fi

23 if [ -f /etc/X11/xinit/xinitrc ]; then

24 exec sh /etc/X11/xinit/xinitrc

25 fi

26 [ -r $HOME/.Xresources ] && xrdb $HOME/.Xresources

27 xsetroot -solid grey

28 xterm -geometry 80x24+10+10 -ls -title "$VNCDESKTOP Desktop" &

29 twm &

######################################################################################

注: 左边的1-29是VIM显示的行号,便于编辑。

第7行和第21或24行在红帽5版本中默认是被注释掉的,是要启用的,RHEL6.3是默认是启用的。

只需要把最后一句twm &改为gnome-session &即可。

然后vncserver -kill :1

再vncserver :1启用一下,就可以使用客户端正常连接了。(注:需关闭防火墙或放行相应端口)

三、多用户配置

修改vncserver配置文件

[root@bogon ~]# vi /etc/sysconfig/vncservers

#####################################################################################

1 # The VNCSERVERS variable is a list of display:user pairs.

2 #

3 # Uncomment the lines below to start a VNC server on display :2

4 # as my 'myusername' (adjust this to your own). You will also

5 # need to set a VNC password; run 'man vncpasswd' to see how

6 # to do that.

7 #

8 # DO NOT RUN THIS SERVICE if your local area network is

9 # untrusted! For a secure way of using VNC, see this URL:

10 # http://kbase.redhat.com/faq/docs/DOC-7028

11

12 # Use "-nolisten tcp" to prevent X connections to your VNC server via TC P.

13

14 # Use "-localhost" to prevent remote VNC clients connecting except when

15 # doing so through a secure tunnel. See the "-via" option in the

16 # `man vncviewer' manual page.

17

18 #VNCSERVERS="2:myusername"

19 #VNCSERVERARGS[2]="-geometry 800x600 -nolisten tcp -localhost"

###############################

阅读更多内容