幽灵狼

狼团队中的每一位成员,共同承担团体生存的责任, 并为此付出自己的独特技能和力量。 我是狼, 相信自己, 相信伙伴。
  IT博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

无意间
我抬头望向舞池
在飘舞的人群中
发现你熟悉的影子
你婀娜的身姿
是众人注目的焦点

踌躇间
我走进你的身边
音乐再一次响起的时候
向你伸出邀请的手
你莞尔的笑容
是我心中绽放的花朵

刹那间
你已轻轻站起
在我恍惚如梦境之时
你拉住了我微颤的手
乌黑瀑布般的长发
是我心中的沉醉

轻轻的
我们飘落舞池
美妙悠扬的旋律
是为我们的舞步弹奏
众人再一次的注目中
我的心逃离了自己

渐渐的
音乐快要结束
紧紧抓住你柔如丝的手
缓缓注视你娇艳的面颊
你清澈如水般的双眸
闪烁着我心中的梦幻

失落间
音乐已嘎然停止
你飘然离开我的怀抱
也带去我心灵的痕迹
我停留在空白的思维
宁静如悠远的梦魂

posted @ 2005-11-16 15:05 幽灵狼 阅读(217) | 评论 (0)编辑 收藏

本次世界拉丁舞冠军首访公演的艺术总监约瑟夫-冯先生,总监制主持人唱燕女士对拉丁舞的本质和核心做了如下诠释:

  浪漫--从某种意义上来说,拉丁舞是一个男女两性的能量交流。如何用一种关系、用一种生命、用一种身体的方式很美地表达出来,是拉丁舞核心的东西。

  激情--拉美的人说,在这一场舞蹈之后你会发现地板上有一种被爱灼伤过的痕迹。

  多元--拉丁舞蹈的概念实际上囊括了体育、时尚、舞蹈、戏剧、幽默等等,像精致美好的服装服饰也是拉丁舞蹈的一部分。

  动人的音乐--拉丁是煽情的音乐,比如伦巴,它是一种很完美的音乐,情感的音乐,他们自己可以律动起来。

  完美的体形--听着拉丁音乐去律动,整个精神与肉体都在律动的时候,你会觉得这是最好的运动,也可以给你带来最好的体形。

  快乐--人最美丽的时候就是心情最快乐的时候,自己做自己愿意做的事情。当都市生活的高压令你感到精神疲惫的时候,不妨听听拉丁音乐,让自己身体律动起来,这样可能给你带来一段欢愉。拉美人跳舞的时候不按什么具体的套路去走,他们只是一种感觉,一个细微的律动,他就觉得很满足,眯上眼睛,如果阳光照耀那就更美了。

  自由--如今风行世界的Salsa是由街头Style演变而来的,自由和随意,更能凸显个人风格。据说,这种古巴风格的Salsa源自街头,拉丁乐手在街上即兴奏起音乐,闻声起舞,空气顿时弥漫起Fiesta的欢悦。和同样作为拉丁舞的伦巴、桑巴、恰恰等相比,它在服装和舞技上更为随意,不需要固定的舞伴,舞姿也更为热烈奔放;而和迪斯科相比,它又多了高雅的气质;比起探戈、华尔兹,它少了束缚感而更具“煽动性”的风情与活力。

  感动--伦巴不像恰恰、桑巴那样热情奔放、激情四射,但它能让你走进你心里面,通过你的眼睛看到别人的内心世界,它的音乐非常感人,给你提供非常大的张力,能触动到你心灵当中非常敏感的地方。

posted @ 2005-11-16 15:02 幽灵狼 阅读(321) | 评论 (0)编辑 收藏

姿态

  伦巴舞和恰恰舞:
  1. 两脚自然轻松的靠拢站好。
  2. 挺胸、脊柱骨伸直,不可耸肩。
  3. 任一脚向侧跨出一步,支撑重心的另一只脚伸直,并将体重全部移到这只上面,以使骨盆可往旁边方移动,因而感觉上重量放在支撑脚的脚跟,其膝盖要向后锁紧。至于骨盆移动的幅度要以不影响上身的姿态为原则。


  森巴舞和捷舞:
  1. 两脚自然轻松的靠拢站好。
  2. 挺胸、腰杆伸直,不可耸肩。
  3. 任一脚向外跨出一步,支撑重心的另一只脚伸直,并将体重全部移到这只上面,使重量前移至前脚掌,而后脚跟仍不离地板,并且支撑脚的膝盖不可向后锁紧。某些舞步则是例外,如森巴舞中的分式摇滚步、后退缩步和卷褶步,以及捷舞里鸡走步。
  由于西班牙斗牛舞,没有骨盘或臀部的运动,其姿势与上述各种拉丁舞的不同处如下:
  1. 骨盘向前微倾。
  2. 重量由两个脚掌很均匀的承受。
  3. 当脚伸直时,膝盖不可向后扣紧。有一个例子除外,那就是西班牙舞姿。

  方位

  在图表之下的方位是用来说明,在舞室中舞者的身体所面对或背对的方向而言。当我们以肩引导(侧行)时,方位的正确与否十分重要。
  在伦巴舞、恰恰舞和捷舞是非前进式之舞蹈,森巴舞与西班牙斗牛舞则为前进式之舞蹈。

  转度

  在跳拉丁舞时两脚从不平行,除非两脚并拢时,才会平行。像这样的脚部转动,大半是向外转,其不过是脚带着全部或部分的体重而转,是属于“被动式的转动”或脚部的因应动作。由于,在跳舞脚部转动与上身的转量多半不同。最典型的例子有森巴舞中扫形步的第2步,在伦巴舞和恰恰舞中,抑制前进走步以及在伦巴舞和恰恰舞中所有的后退走步。
  因此当跳完某个舞步时,其脚部带动的重心和身上所面对的方向不同时,我们是以其上身的转量为准,而非脚部。
  (注1)在伦巴舞和恰恰舞中,后退走步本身的率动下,那只带动重心的脚会大约有1/16圈的外转。这种因为要让身体重心稳定,而造成的转动,被称之为“被动式的转动”。

posted @ 2005-11-16 13:31 幽灵狼 阅读(237) | 评论 (0)编辑 收藏

拉丁舞,闻名溯源,拉丁美洲是它的发源地。

    很多人一听到拉丁舞,便想到那扭腰摆臀、婀娜多姿的体态,以及热情奔放的步伐和动感十足的音乐,它的确是舞中之王。

   下面是我对拉丁舞的概述:

    拉丁舞分两大系:
    1. 民间大众化舞:Salsa, Merengue, Cumbia, Lambada, Samba, son, mambo…..
    2. 国际标准舞:伦巴、恰恰、桑巴、斗牛、牛仔。

    论及民间拉丁舞,Salsa是现在最流行的。它起源于古巴。随着它的发展和广泛流传,Salsa逐渐分为很多种风格,不同国家,不同地域的Salsa都有所不同(但基本步伐雷同):New York Salsa, Columbia Salsa, Cuba Salsa等。

    Merengue当今也非常盛行。它的发源地在多米尼加,在那里,它被视为国舞。当时它起源的地域居住了很多海地人,所以也有人称“海地人赋予了Merengue生命”。

    Mambo的发源地也在古巴,在古巴有很多黑人非常喜欢这种舞蹈。Cha Cha Cha其实是从Mambo演变而来的,只是它的节奏稍慢于Mambo。

    Samba众所周知是在每年巴西大大小小的狂欢节上必不可少的。Samba节奏明快,舞姿奔放,极易渲染气氛。

    目前,只有北京,上海,香港几个大城市盛行Salsa, Merengue 等。

    国际标准舞都是从以上这些民间舞蹈逐步发展、演变而来的,有很强的表演性,观赏性及竞技体育性。

    1986年,国标进入中国,在相关部门的大力支持下蓬勃发展。2000年,国标以被悉尼奥运会首次列为表演项目,并被列为2008年北京奥运会正式比赛项目。

   大家也可以这样理解两种风格不同的拉丁舞,前者—“下里巴人”,崇尚的是原始、自然,不加雕琢装饰;后者—“阳春白雪”,需要的是加工、修饰,从而以一种高雅的姿态呈现于世人面前。

    学习拉丁舞最重要的是什么?

    我认为舞蹈最重要的几大要素,第一是音乐:很多人跳舞没有节奏感,跟不上节拍,我认为,失去音乐就失去了舞蹈的灵魂;第二,协调:它包括很多,对自己肌肉控制能力,灵活性,重心,与舞伴之间的配合等,这就是大家常说的舞姿是否优美;第三,情感,这是最容易被忽略的一点,没有她,舞蹈就失去了最原始的魅力,但这并不是刻意追求所能得到的,它需要深刻体会音乐及所要表达的内容。拉丁舞除了以上三点之外,还有一个最关键的因素—性感!

   你所谓的情感是指什么,如何赋予拉丁舞情感?

   也可以说感情。我所看到很多跳舞的人,只是机械模仿动作和步伐,无论音乐节奏快或慢,只是在刻意追求舞步的变化。比如,我的学生和我跳舞的感觉就不一样,无论对方跳的熟练与否。想要赋予拉丁舞情感,一定要对音乐,拉丁文化有自己的理解,每一种文化都有它独特的内涵和底蕴。这是很微妙的。

    那你认为中国人的性格适合跳拉丁舞吗?因人而异。我所教过的学生中,有很多性格外向,活泼的女孩,她们会很快掌握拉丁舞。还有一些内向的学生,也不能否定她们无法跳好拉丁舞。

    那你的性格适合跳拉丁舞吗?

    我只感觉跳舞的时候流着拉丁血,我喜欢表现。

    那你觉得拉丁舞对你的生活产生什么影响?

……….(他沉吟片刻,说出了一句出人意料的话)“没有生活,只有拉丁”。

    那你还有什么要对拉丁舞爱好者说的吗?

    作为一名老师来讲,我希望我所教的学生都能跳好拉丁舞,并且我也会尽我所能毫无保留的来教好拉丁舞,对于还没有接触拉丁舞的学生来说,我希望你们能加入我们,从零开始没问题;对于有一定拉丁舞基础的学生来说,希望你们在熟练的基础之上,深刻地理解,赋予它生命,这样,才有魅力。

   希望更多的人热爱拉丁舞!

posted @ 2005-11-16 13:30 幽灵狼 阅读(349) | 评论 (0)编辑 收藏

拉丁舞包括恰恰、伦巴、桑巴、斗牛和牛仔舞;他们分别起源于不同的国家和地区,20世纪初期在英国被规范和发展并很快在许多国家流行起来;当时以社交、娱乐的形式在社交场所的酒吧非常盛行;三、四十年代的大上海也非常流行。后来,经过英国皇家舞蹈教师协会的统一规范使其成为一种国际赛事,一直延续至今;其中比较有名的赛事有英国“黑池”舞蹈节(78界)、英国UK国际锦标赛(51界)、英国国际公开赛、德国世界舞蹈运动锦标赛等。
  
  改革开放以后,随着人民物质生活的不断提高,1986年中国第一次在北京举办了首届“中国杯”国际标准舞锦标赛,1991年中国体育舞蹈运动协会在北京举办了首届体育舞蹈锦标赛。我省从1988年开始由省舞蹈家协会组织、开展了一系列国标舞活动。如今每年都有多项赛事,参赛队伍每年都在壮大;爱好者也非常之多。露天的广场、休闲的社区、时尚的健身房到处都可以见到拉丁舞者的身影。尤其是少儿拉丁舞近几年发展迅猛。 
 
  “青兰少儿拉丁舞培训中心” 96年创办,至今共获得100多项全国、全省国标舞大赛冠军,近千人获奖;有二十多人分别考入北京舞蹈学院、广州舞蹈学校、北京国标舞学院等全国艺术院校,并多次参加中央、河南、郑州电视台大型文艺晚会。编者:随着都市生活水平的提高,人们的健身方式也愈发地丰富多彩起来。为满足人们对于时尚体育的追求,我们特别开设了该栏目,为您介绍最新的体育时尚。

  也许你还在为身体日渐肥胖发愁,也许各种的体育锻炼无法引起追求时尚的你的兴趣,那么来吧,来跳拉丁舞吧!在高雅艺术的旋律中体会快乐与健康!

  作为体育舞蹈,拉丁舞最早起源于非洲,由那里的移民带入拉美并与当地的土风舞相互影响融合,逐渐形成了今天我们常常见到的恰恰、伦巴、牛仔、桑巴、斗牛等新的舞种。

  拉丁舞是以运动肩部、腹部、腰部、臀部为主的一种舞蹈艺术。参加运动的包括腹直肌、腹内斜肌、腹外斜肌、竖脊肌、背阔肌等上百块肌肉。从上世纪60年代至今,许多科研人员对体育舞蹈的生理和心理作用做过研究,平均每跳一曲拉丁舞,腰部的扭转有160—180次,女子的最高心率可达197次/分钟,男子的最高心率可达210次/分钟。大约能量代谢为8.5以上,相当于运动员完成一个800米的热能消耗量,大于网球和羽毛球的热能消耗。减脂效果可想而知。

  拉丁舞中最具代表的舞蹈是伦巴,它被誉为“拉丁之魂”。学习拉丁舞的人,一般会把伦巴作为入门的第一支舞来学习。伦巴是表现男女之间爱情故事的舞蹈,所以它的音乐较为柔美和缠绵,动作上能使女伴充分展现女性的柔媚和胯部、臀部的曲线美。男女伴之间若即若离,十分优美

。而另一种具有代表性的舞蹈———恰恰则起源于墨西哥,虽与伦巴有很多相通的地方,但它俏皮欢快,风格与伦巴截然不同,动作潇洒帅气而又充满活力。

posted @ 2005-11-16 13:29 幽灵狼 阅读(232) | 评论 (0)编辑 收藏

 

Author:   于明俭 <justiny@turbolinux.com.cn >

一 国际化、本地化和中文化

  1. 国际化、本地化和多语言化的概念

  2. 一般来说, "国际化"是指把原来为英文设计的计算机系统或应用软件改写为同时支持多种语言和文化习俗的过程.在软件创作的初期,一般的编程语言,编译,开发都是只支持英文的, 为了适应更广的语言和文化习俗,软件有必要在设计结构和机制上支持多语言的扩展特性, 这一过程称为国际化.国际化仅仅是在软件设计上提供了使用多语 言的可能.

    "本地化"是指把计算机系统或者应用软件转变为使用并兼容某种 特定语言的过程.比如,把原来为英文设计软件制作为支持中文的软 件就是本地化的一种.它主要包括翻译文本信息,界面信息,重新设计图标等等.

    语言和文化习俗因地域不同而差别很大.对某一特定的地域的 语言环境称为"locale".它不仅包括语言和货币单位,而且还包括数字标示格式, 日期和时间格式.国际化了的软件含有一个"locale" 的"参量",使用该"locale"参量便可以设置某一区域所用的语言环境.

    在国际化部分中只处理语言的部分叫"多语言化".比如, 一个 "多语言化"的软件可以同时管理诸如英语,法语,中日韩文,阿拉伯语等.

    在英文中, 国际化(Internationalization)被缩写为I18N, 即只 取首尾两个字母,中间字母为18个.同样地, 本地化(Localization) 缩写为L10N, 多语言化(Multilingualization)缩写为M17N.

    在今天, Internet把世界各地的计算机联接了起来, 共享信息和 技术是必然的趋势和需要.因此各地的计算机系统可以互相交流变得越来越重要.在Linux系统向桌面普及的过程中, Linux软件也需要国 际化和本地化.

  3. 中文化 
  4. "中文化"是一个很模糊的概念.在Linux上的"中文化"它既包含使 软件或系统国际化,又包含使软件本地化.也就是说, "中文化"不仅仅 是只把软件本地化这么简单的事情, 更重要的是因为Linux直接支持中文的软件太少, 做"中文化"必须先做"国际化".

    由于历史的原因, 现阶段使用的中文又有简体中文和繁体中文之 分.所使用的编码也不同.支持中文的软件应该同时支持简体中文和繁体中文, 这对软件的国际化提出了更高的要求.

    1999年是中国Linux发展和普及过程中最重要的一年, 其中涌现了许多制作中文Linux发布版本的公司.中文Linux的技术都是采取了中文化的捷径----中文平台.尽管都是中文平台, 但是具体实现的技术特点各不相同.充分展示了中文平台在Linux中文化过程中的魅力.中文平台在短期内发挥了巨大的作用, 加速Linux的中文化过程并推动Linux在中国的普及.

    中文平台的主要技术特点是不用修改西文应用软件, 便可以显示和 输入中文(有的情况下会失效).具体地说,就是利用自己的规范去修改 X系统的底层函数.从修改的层次上分为(1)修改函数库libX11.so,这种 方式是动态修改,又称外挂方式.外挂方式的实现可以是直接修改X11库 或使用LD_PRELOAD载入动态库修改.(2)修改X Server部分, 又称内嵌方式,它的实现也分为两种, 直接修改X Server部分和建立虚拟Display(X传输协议的部分代理).

  5. X11 国际化的历史和级别 
  6. 早期的X11R4版本中, 仅仅含有支持单字节和双字节字体的函数, 所以它不能算是国际化的函数库.此后,一个叫做"mltalk"的X协会成立并着手研究X窗口系统的国际化问题.众多的X窗口系统供应商也参与了该组织.因为对国际化的研究刚刚开始, 所以mltalk提出的了一个基本问题:什么是X窗口系统的国际化? 对它的解释也各不相同. 实际上, 即使是现在,人们对国际化的定义仍然存在分歧, 分歧的焦点主要集中于对软件或系统怎样程度的国际化才算是真正的国际化.

    按国际化的级别来分, 下列几种情况都属于国际化:

    1. 语言可以切换.在系统启动时可以设置某种语言
    2. 使用不同语言的软件可以同时使用, 在应用软件启动时可以 设置某种语言
    3. 使用不同语言的软件可以同时使用, 而且应用软件的语言可 以动态切换
    4. 使用不同语言的软件可以同时使用, 而且在应用软件中可以 同时使用不同语言
    显然,第(4)种国际化方式是最完善的方式, 其次是第(3)种,第(2)种 和第(1)种.mltalk 最终决定使用第(3)种,原因是需要支持第(4)种的 X窗口系统供应商是少数的.从目前Linux上的国际化情况看,支持第(2), (3)种的国际化软件是最常见的,但是第(4)种软件比较少见,而且应用的 意义不是很大.

    基于上述观点, X11R5 的目的是, 创建支持不用重新编译源代码 就可以适应于语言环境的应用软件开发平台.确切地说,就是国际化 的结构是基于标准C函数setlocale的.X11R5 确立了以下规范:

    1. 切换语言的机制
    2. 与语言无关的输出接口
    3. 与语言无关的输入接口
    4. 资源文件的国际化
    5. X工具(Xt)的国际化
    此后, 以X11R5 为基础, OSF/Motif 完成了国际化改造, 并且成为被用户广泛接受的高层图形软件库,直到今天, 一些大型的软件仍然使用 Motif 作为基础库使用, 如Java, Netscape等.X11R5的规范在制定的同时,为了检测规范的实用性, 开发了两套样本应用, 即 Xsi 和 Ximp.两套应用在输入协议上和对locale的支持上都不同,从而为开发商带来了不便.

    X11R6 解决了X11R5中存在的问题, 主要的变化有,

    1. 定义了标准的输入协议
    2. Locale数据格式定义
    3. 只采用了一种国际化工具的样本应用模块
    在输出上, X11R6增加了从右到左的的书写方式, 以支持阿拉伯语和 希伯来语等,增加了从上到下的书写方式, 以支持中文和日文等的书写.
  7. 国际化标准组织 
  8. 这里所说的国际化标准是国际化标准组织或一些相关组织制定的一些标准, 而且这些标准也会随时间不同而经常更新.国际化标准涉及到字符集,编码,字体处理,打印,文本绘制, 用户界面, 语言输入方法, 数据交换, 文化习俗,等方方面面.

    下面列出一些制定国际化标准的组织:

    • Li18nux(Linux I18n)
    • ANSI(American National Standards Institute)
    • POSIX(Portable Operating System Interface for Computer Environments)
    • ISO(International Standards Organization)
    • IEEE(Institute of Electrical and Electronics Engineers)
    • Unicode Consortium
    • Open Group(X Consortium and OSF)
    • X/Open and XPG
    其中, ANSI/ISO 制定了使用C编程语言编写国际化软件的通用接口.ISO 制定了字符集标准和其它影响locale名字的标准.IEEE提供了一些国际化的通用库函数和设置管理不同locale的用户命令. Open Group是Unix和X窗口 系统的国际化标准设立组织.Li18nux 是一个专门从事Linux上的软件国际化 规范制定的组织.
  9. 国际化的意义 
  10. 国际化,特别是国际化中制定的标准,是当今开发国际化软件所必须 的.它也是软件开发的必然趋势.遵循国际化标准,可以更高效地开发和调试软件和移植软件, 降低软件的开发费用, 使用户更方便地使用软件.从国际环境来看, 新开发的基本的库函数都会支持国际化标准, 基于这些函数库所开发的应用软件理所当然地支持国际化标准,同时有大批的Linux 爱好者把以前不符合国际化标准的软件进行了改造,使它们在一定程度上符合国际化标准.使用国际化标准的软件, 淘汰非国际化标准的软件已成为 一种趋势.

    从国际化的发展历史看, 其中许多标准都有日本的商业机构参与, 支持 日文的软件变得越来越多,而从日语软件移植为中文软件相对于直接移植西文软件相当容易, 有时甚至不用改动,这样就节省了许多不必要的劳动. 反过来, 符合国际化标准的中文软件又影响日语和韩语软件,成滚雪球之势向前发展.其次, 软件商的开发比较看好亚洲市场中的日本市场,在 Unix/Linux上的日语软件或操作系统一般是符合国际化标准的, 所以兼容这一标准是十分必要的.当然,目前的国际化标准也存在不足之处, 特别是对中文这一特殊语言(因为含有GB和Big5两种不能共存的编码)的处理上,应该由中国人在原来的基础上作相应的扩展.

    对中文Linux来说, 遵循国际化也是必然的趋势.在以中文平台为基础 的中文Linux上,软件移植已成为必须解决的问题,这个问题的最终解决 方法就是遵循同一标准,就目前来说遵循国际化标准是唯一的方法.鉴于目前中文Linux上的中文平台的混乱状态,国际化标准是从无序到有序过渡 的必然途径.

    软件的国际标准化也为最终用户带来极大的好处, 如同时支持简体中文 和繁体中文,中文操作为双字节操作, 中文输入能够在更大的程度上使用 标准输入接口带来的好处,如输入服务器的定位等交互式操作.

    国际化的另一个特点是工作在应用软件级别, 所以国际化不会给X窗口 系统带来不稳定性.

  11. 参考资料:
    • Linux I18N: http://www.li18nux.org/

二 Locale

  1. Locale 的概念

  2. Locale 是ANSI C语言中最基本的支持国际化的标志, 对中文Linux来说, 如果它支持国际化,那么支持中文Locale是最基本的要求.

    Locale 是软件在运行时的语言环境, 它包括语言(Language), 地域(Territory)和字符集(Codeset).其格式为: 语言[_地域[.字符集]]. 如对中文GBK字符集, locale的格式是:zh_CN.GBK. 目前Linux上的中文 Locale还不完善, glibc2.1.x中的许多涉及Locale的C函数还不正确.如果用户需要安装中文GBK Locale, 可以直接使用TLC6.0中的:

    • glibc-2.1.2(含有GBK模块)
    • localedata-zh-0.07
    • /usr/X11R6/lib/X11/locale/zh_CN.GBK/XLC_LOCALE(X 下的 GBK Locale)
    Locale 包含了以下分类:
    1. LC_COLLATE, 用于比较和排序.排序对中文来说也比较重要, 但是现在的glibc中的locale对中文支持有些问题.汉字排序的的方式有许多种, 按照发音(汉语拼音)或者汉字笔画来排序 是比较容易被接受的.
    2. LC_CTYPE, 用于字符分类
    3. LC_MONETORY, 用于货币单位
    4. LC_NUMERIC, 用于数字显示格式.下面是不同国家的在货币符号 和数字格式上的不同:
      • 中国大陆: 1,234.56RMB
      • 美国: $1,234.56
      • 德国: 1.234,56DM
    5. LC_TIME, 用于时间和日期.时间可以用12小时或者24小时的 格式来计算.在小时和分钟之间可以用逗点或者冒号隔开.下面是一些Locale设置的时间和日期的格式:
      • 中国: 14点20分 2000年三月十四号
      • 英国: 02:20pm 14/03/2000
      • 美国: 02:20pm 03/14/2000
      • 芬兰: 14.20 14.03.2000
    6. LC_MESSAGES, 用于国际化信息, 主要是提示信息,错误信息, 状态信息, 标题,标签, 按钮和菜单等.
    Locale 通过ANSI C 函数setlocale(分类, locale)来初始化locale 数据.当locale设置为空时, locale的值便从系统的环境变量中取得.为了 方便应用软件, 设置所有的分类,可以采用下述方式:
    setlocale(LC_ALL, ""); 

    如果不成功, 该函数返回NULL.函数应该回落到setlocale(LC_ALL,"C").

  3. 在X中使用Locale 
  4. 在X的客户程序中使用Locale的机制和在标准C函数中使用Locale的方式一样,除此之外, 在X库中还定义了另外两个函数来判断X的locale支持和设置locale 的修饰(XModifier),在X中使用Locale和libX11的基本步骤如下:

    • setlocale(): 设置当前的locale
    • XSupportLocale(): 用来判断X是否支持目前设置的locale.
    • XSetLocaleModifier(): 它用来指定一系列的locale修正值. 它的参量的格式是@分类=赋值.目前唯一可用的是输入服务器的名称"im".如果参量为空, 则根据系统的环境 变量XMODIFIERS查找.比如在系统上设置了环境变量: 
    • % setenv XMODIFIERS @im=Chinput (csh) 或
      % export XMODIFIERS=im=Chinput (bash)

      则客户程序将查找到输入服务器Chinput, "Chinput"是 输入服务器所设置的名称.  

  5. 文化习俗的差别 
  6. 下面是在国际化和本地化过程中常常遇到的并且应当注意的地方, 对国际化软件的开发, 应该充分注意到各个地域的文化和习惯, 开发出通用的软件, 对于本地化过程,则应选择与本地域相符的习惯.

    • 姓名,地址等特殊信息

    • 姓名中的"姓"和"名"的先后次序, 地址书写的先后次序 电话号码的长度等等
    • 图标的通用性

    • 图标是易于接受的用户界面, 设计时应考虑到地域习惯, 而且图标上不能有图形文字,否则需要重新设计本地图标, 并翻译图标上的文字.
    • 声音使用

    • 不适当的声音或提示可能会引起人的反感.另外, 声音 的性别对某些国家是敏感的.
    • 颜色使用

    • 颜色和色调与民俗有关, 比如红色在美国表示危险, 在中国 表示喜庆.
    • 纸张尺寸

    • 打印纸的尺寸因地域而不同, 在选择缺省尺寸时应注意.
    • 键盘差别

    • 在键盘上的键可能因国家而异, 键的个数也可能不一样.
    • 政治因素

    • 在产品设计上, 尽量不要有政治敏感性部分.
  7. 参考资料:
    • Linux 上的Locale

    • http://www.ping.be/linux/locales/index.shtml
    • GBK Locale

    • ftp://ftp.turbolinux.com.cn/pub/turbolinux/TurboLinuxC-6.0/SRPMS/SRPMS/localedata-zh-0.07-1.src.rpm

三 X 窗口系统的国际化

在 X 窗口系统上的国际化, 特别是中文化, 主要体现在显示,输入和打印三个方面.
  1. 显示的国际化
    1. 字符集和编码 
    2. 在Linux上经常使用的字符集是ISO 8859系列的字符集.它包含了10个 多语言的单字节编码字符集.它们分别是,

      字符集 涵盖语言
      ISO 8859-1(Latin1) 拉丁一字符集, 包含绝大多数的欧洲语言, 例如French(fr), Spanish (es), Catalan (ca), Basque (eu), Portuguese (pt), Italian (it), Albanian (sq), Rhaeto-Romanic (rm), Dutch (nl), German (de), Danish (da), Swedish (sv), Norwegian (no), Finnish (fi), Faroese (fo), Icelandic (is), Irish (ga), Scottish (gd), English (en), Afrikaans (af) 和 Swahili (sw).影响了美洲, 澳洲和非洲. 
      ISO 8859-2(Latin2) 拉丁二字符集, 包含了中欧和东欧的语言:Czech (cs), Hungarian (hu), Polish (pl), Romanian (ro), Croatian (hr), Slovak (sk), Slovenian (sl), Sorbian. 
      ISO 8859-3(Latin3) 拉丁三字符集, 包括: Esperanto (eo) and Maltese (mt)
      ISO 8859-4(Latin4) 拉丁四字符集, 包括: Estonian (et), 巴尔地克 Latvian (lv) 和 Lithuanian (lt), Greenlandic (kl) , Lappish. 
      ISO 8859-5(西里尔语) Bulgarian (bg), Byelorussian (be), Macedonian (mk), Russian (ru), Serbian (sr) 
      ISO 8859-6(阿拉伯语) 阿拉伯语(ar)
      ISO 8859-7(希腊语) 希腊语(el)
      ISO 8859-8(希伯来语) Hebrew (iw) 和Yiddish (ji)
      ISO 8859-9(Latin5) 重排了Latin1, 用土耳其语的几个字母做了替换
      ISO 8859-9(Latin6) 重排了Latin4, 去掉了某些符号, 增加了Inuit等
      ISO 8859-11(泰国语) 泰国语(th)
      ISO 8859-12 Celtic
      ISO 8859-13(Latin7) Baltic Rim 和 Lativian(lv)
      ISO 8859-14(Latin8) Gaelic 和 Welsh (cy)
      ISO 8859-15(Latin9) Latin1的变种, 修改了某些字母

      双字节字符集主要包含中文,日文和韩文.它由前导字节(Lead Byte) 和尾部字节(Trail Byte)构成,由于一个字符采用了两个字节, 在软件的 国际化方面又增加了一些麻烦,比如在显示上, 光标的位置不能位于汉字 之间,删除和移动时必须是整字操作等,在输入上, 一般需要预编辑服务器 才能输入汉字. 下表列出了中日韩语言编码的有关信息:

      语言 字符集 代码页 前导字节范围 尾部字节范围
      简体中文 GB2312-1980 CP936 0xA1-0xF7 0xA1-0xFE
      GBK 0x81-0xFE 0x40-0x7E, 0x80-0xFE
      中文繁体 BIG-5 CP950 0x81-0xFE 0x40-0x7E, 0xA1-0xFE
      日文 Shift-JIS CP932 0x81-0x9F, 0xE0-0xFC 0x40-0xFC(0x7F除外)
      韩文 KSC-5601-1987 CP949 0x81-0xFE 0x41-0x5A,0x61-0x7A,0x81-0xFE
      KSC-5601-1992 CP1361 0x84-0xD3
      0xD8
      0xD90-0xDE
      0xE0-0xF9
      0x41,0xFE
      0x41-0x7E
      0x81-0xFE
      0x31-0x7E

      最近, 信息产业部和国家质量技术监督局联合发布了两项新的中文信息处理基础性国家标准,为解决偏、生汉字的输入提供了方案。其中GB18030- 2000《信息技术和信息交换用汉字编码字符集、基本集的扩充》,为强制性国家标准.它收录了2.7万多个汉字,总编码空间超过150万个码位,为彻底解决邮政、户政、金融、 地理信息系统等迫切需要的人名、地名用字问题提供了解决方案,也为汉字研究、古籍整理等领域提供了统一的信息平台基础。这项标准还同时收录了藏文、蒙文、维吾尔文等主要的少数民族文字.字符集编码范围是:

      字节数 编码空间 码位数目
      单字节 0x00-0x80 129
      双字节 第一字节:0x81-0xFE
      第二字节:0x40-0x7E,0x80-0xFE
      23940
      四字节 四字节范围分别是:
      0x80-0xFE,0x30-0x39,0x81-0xFE,0x30-0x39
      1587600

      香港特别行政区也对Big5编码提出了"香港增补字符集", 其目的,是收纳香港特区政府及市民在中文电子通讯中有需要使用的字符,来补充目前大五码和ISO10646编码标准内并未包含的字符,以作为一个通用的中文界面,方便大家能准确地以中文进行电子通讯。香港增补字符集有两套编码方案,一套适用於大五码系统,另一套适用於ISO10646平台。香港增补字符集的大五码版本,实际上是政府通用字库的增订版。ISO10646国际编码标准目前并未包含香港增补字符集内的所有字符。目前尚未收纳在ISO10646内的香港增 补字符集字符,均已提交国际标准化组织管辖下的表意文字小组,以考虑是否纳入ISO10646日后的新增版本内.

      上述标准和草案应该是以后的中文Linux所应该遵循的.

    3. 多字节字符(Multibyte)和宽字符(WideChar)的使用 
    4. 我们平时见到的以文本方式存在的字符都是多字节字符, 它主要用于文件存储和网络上的以流(Stream)的方式传输.一个GB编码的汉字需要两个字节.多字节字符的缺点是在中文处理上不方便,比如汉字的删除和光标的 移动都会有半汉字问题.为了文本处理的方便,在内部操作上通常是把汉字 与英文的混和字符串先转换成等宽度的字符串,即宽字符,为软件的内部处理 提供方便.

      glibc2.1.x中多字节字符串和宽字符串的转换有时有问题.在X下还可以 使用另外一种方式完成转换,即使用XmbTextListToTextProperty()和 XwcTextPropertyToTextList() 联合完成转换.

    5. Unicode 
    6. 目前所使用的Unicode 是一种16位字宽的字符编码, 它由非赢利的计算机组织Unicode研讨会维护和改进.它起源于Xerox和Apple之间的合作研究.几个公司组成了一个非正式的论坛, 接着IBM, Microsoft等公司迅速加入. Unicode研讨会在1990年发表了Unicode标准版本1,同时国际标准化组织完成了一种类似的编码----ISO 10646.因为没有必要存在两套标准,所以Unicode 研讨会和国际标准化组织在1991到1992合二为一. 1994年, 中国和日本开始了基于ISO10646上的国家标准进行工作.现在, Unicode 开始用在许多产品中.

      Unicode包含了当今计算机领域中广泛使用的所由字符, 如世界上大部分 的书面语言,印刷字符, 数字和技术符号,地理图形和标点符号.由于Unicode 的一致性,它在大多数情况下都可能简化软件的国际化过程.它取消了处理多种代码页的必要,并且由于是16位编码, 因此由双字节字符集所引起的额外 处理也不必要了.

      但是, Unicode作为一种编码也有它的缺陷, 比如编码的位置与排序无关,所以使软件支持Unicode仅仅是国际化的第一步, 实际情况中还需要与语言相关的信息和规则.所以Unicode一般作为程序的内部处理编码, 必须提供与其它 编码的双向转换表.

      最后需要说明的是, 虽然使用Unicode会使普通的英文文本大两倍, 但是使用Unicode的整个系统却不会增加太大,因为系统存放的文件大部分是二进制 文件格式, 同时,使用针对Unicode的压缩方式,可以把文件压缩成和使用对应 的8位正文一样大小.

    7. 字体(Font)和字体集(FontSet) 
    8. 在X窗口系统下使用的字体都必须在X服务器中注册X逻辑字体描述(X Logical Font Description)名.它包括了字体的许多信息, 例如以下为西文字体和中文字体的两个例子.

      1. -adobe-times-medium-r-normal--14-140-75-75-p-74-iso8859-1
      2. -tlc-song-medium-r-normal--24-240-75-75-c-240-gbk-0
      为了方便使用, 用户还可以给每一个字体加一个或多个别名, 别名文件 fonts.alias 放在字体目录下, 可以手工编辑.当字体目录变更或别名变更 后, 必须使用命令 "xset fp rehash"或重新启动X才起作用.

      X 字体也可以通过字体服务器(Font Server)加载.这对于本地不放字体 的系统或X终端特别有用.加载的协议可以是TCP或DECNET.

      X 窗口系统的字体在X Server中之存在一份, 当所由软件都不使用它时, 字体的内存自动施放.

      字体中包含了制造商名, 字体类型, 权重, 字体大小, 字符集等信息.它们也可以缩写, 省去的部分用星号代替, 比如对上面的中文字体, 可以缩写为:

      -*-song-*-24-*-gbk-0

      在实际应用中, 字符串往往是中文和英文的混和字符串, 所以必须使用两种字体来绘出该字符串, 这种指定两种或两种以上的字体的描述就是字体集.字体集一般的格式是把多种字体用逗号隔开, 比如, 指定下列字体集:

      "-adobe-helvetica-medium-r-normal--14-*-*-*-*-*-iso8859-*,\
      -tlc-song-medium-r-normal--14-*-*-*-*-*-gbk-0" 

      令人遗憾的是, 中文的GB编码和Big5编码有重叠区域, 不能区分开来, 所以字体集并不能同时指定GB和Big5的字体.

      字体集的具体载入受到Locale的影响.

      在许多已经国际化的软件和图形库中, 一般通过资源文件让用户指定字体集,比如gtk的简体中文资源文件为/etc/gtk/gtkrc.zh_CN, qt-1.44(国际化的)的资源文件是 ~/.qti18nrc 等等.  

  2. 信息的国际化

  3. 信息(Message)国际化是软件国际化中比较重要的一环, 如果使软件可以 支持多种语言,在设计时就应当考虑到信息的国际化问题.现在的绝大多数 软件使用GNU的gettext作为基本工具.信息国际化的基本步骤是:

    • 在软件初始化时设置使用setlocale()设置Locale
    • 使用gettext宏定义, 使程序看上去比较方便:
    • 指定信息的位置:
    • 指定翻译信息: _("Some Strings");
    • 在软件完成后,使用 xgettext 提取信息并翻译
    • 使用msgfmt把信息文件转换为.mo文件, 安装到locale目录下
            /* file this_app.c */
            #include <locale.h>
            #include <libintl.h>
            #define _(String)  gettext(String)
            #define N_(String)  gettext(String)
            #define __(String) (String)

            int main(){
                    //由环境变量决定locale
                    setlocale(LC_ALL, "");               

                    //设置message的位置和文件名
                    bindtextdomain("this_app", "/usr/share/locale");
                    textdomain("this_app");
                    
                    printf(_("Some String"));
            }
            

         至此, 本程序的国际化过程已完成.编译并联接成可执行文件this_app.
    gcc -o this_app this_app.c

     下面是本地化的过程. 

    • 提取要翻译的信息: xgettext -a -o this_app.po this_app.c
    • 翻译信息 
    •  在文件this_app.po 中含有"Some String": 

      msgid "Some String"
      msgstr ""

       翻译成: 

      msgid "Some String"
      msgstr "一些字符串"
       
    • 格式化信息文件: msgfmt -o this_app.mo this_app.po
    • 拷贝信息文件到locale的目录下, 比如对于中文zh_CN, cp this_app.mo /usr/share/locale/zh_CN/LC_MESSAGES
    • 执行文件: LC_ALL=zh_CN ./this_app
  • 输入的国际化

  • 在X窗口系统下输入主要有三种方式:

    1. 单次击键输入单字符
    2. 两个或多个组合键输入单字符
    3. 除键输入外, 还需要转换服务器
    其中前两种用于输入西文字符, 比如对于欧洲语言的特殊字符的输入, 通常采用重映射键盘的方法.或者使用"加速键"的方法输入,加速键是键盘 上的特殊键, 按下后不会使光标向后移动.

    在Linux下, 使用软件xkeycaps可以把键盘重新映射并且保存整个键盘 在映射后的对照表,使用命令xmodmap可以加载映射表.

    对于中文输入, 主要使用第三种输入方式.针对各种语言的综合考虑, X 窗口系统在输入上定义了下列区域:

    1. 预编辑区域(Preedit Area), 用于显示输入的过程, 当用户输入 字符时, 应立即显示在该区域
    2. 状态区域(Status Area), 用于显示输入状态, 对中文来说, 用于显示输入方法,全角/半角状态, 中文/西文标点符号状态.
    3. 辅助区域(Auxiliary Area), 显示可供选择的列表, 又称选择 区域, 它由输入服务器控制.
    根据预编辑区域和状态区域的不同组合, X 窗口系统共定义了四种输入 的风格(Input Style):
    1. Root风格: 预编辑区域和选择区域都在应用软件之外, 它们都是 由输入服务器完成的,输入服务器所显示的界面是根窗口的子 窗口.如类似"中文之星"的独立的输入条模式.
    2. OffTheSpot风格: 预编辑区域和选择区域在应用软件之内, 通常 是在窗口下方的某个固定区域内.如XEmacs的缺省输入模式.
    3. OverTheSpot风格: 预编辑区域在当前的输入位置, 状态区域 在应用程序的某一固定区域.它通常又称为光标跟随模式,类似 于Windows下的智能ABC输入方法
    4. OnTheSpot风格: 预编辑区域和选择区域都在应用软件之内, 内容是由输入服务器发送的,应用程序负责显示.
    对中文输入来说, 最好的风格是(3),(4),(1).对大部分中文输入方法,必须弹出辅助区域, 供用户选择, 只有少数的中文输入方法, 如五笔字型,比较适合(4).对于状态区域,中文输入多数选用在Root风格的窗口的某个 位置或使用专用的控制条.在MS Windows下比较常用的光标跟随模式,可以 用(3),(4)来实现.鉴于Linux下有的用户把X Window设置成为虚屏模式,选择上述的任何一种模式都不尽满意.

    对应用软件来说, 最简单的输入接口是Root风格, 它把显示部分交给输入服务器去做.编写软件时所用的代码量少,是对软件初步使用国际化 标准的最佳选择.从方便用户的角度来看, 应用软件,特别是高层的库函数应该同时支持四种输入风格.令人遗憾的是, 一般软件仅支持两到三种输入风格.所以在现在的输入服务器(IM Server)也很少支持四种风格,这似乎 成了鸡和蛋的问题.

    下面列出几种常用软件和图形库的XIM支持情况:

    Netscape Root,OffTheSpot,OverTheSpot
    Java  Root,OnTheSpot
    Qt  Root,OverTheSpot
    gtk+  Root,OverTheSpot
    rxvt  Root,OffTheSpot,OverTheSpot

    中文输入需要客户软件和服务器软件的的密切配合, 它们之间是通过 XIM(X Input Method)协议来通讯的.输入服务器首先起动,在X Server里 注册自己,服务器的名字也被注册.当客户程序起动时, 到X Server里查寻有没有符合自己locale类型的输入服务器(如果用XMODIFIERS指定服务器名,则同时用locale和名字区分).找到后,根据输入服务器提供的风格种类 选择一个最适合自己的风格.然后客户程序为每一个需要输入的窗口都建立一个自己的标示IC(Input Context), 里面含有客户程序的信息, 以后的通讯则一直使用该标示.

    下面是直接使用X Lib和服务器联接的过程, 在高层函数库中, 把这一 过程隐藏了起来:

                 XIM im;
                 XIC ic;
                 ...
                 if( (im = XOpenIM(display, NULL, NULL, NULL)) == NULL ) {
                         printf("Error : XOpenIM !\n");
                         exit(0);
                 }

                 //指定预编辑的类型等...
                 if( (ic = XCreateIC(im, 
                         XNInputStyle,   XIMPreeditPosition | XIMStatusNothing,
                         XNClientWindow, window, 
                         NULL)) == NULL ) {
                         printf("Error : XCreateIC() ! \n");
                         XCloseIM(im);
                         exit(0);
                 }
                 ...

                 for(;;) {
                         XNextEvent(display, &event);

                         //如果输入服务器接收并处理...继续
                         if (XFilterEvent(&event, None) == True)
                                 continue;
                         switch(event.type) {
                                 case Expose:
                                         XmbDrawString(...);
                                 case KeyPress:
                                         count = XmbLookupString(ic, 
                                                 (XKeyPressedEvent *) &event,
                                                 string, len, &keysym, &status);
                                 ...
                         }
                 }
            

    目前使用比较广泛的XIM输入服务器有Chinput(简体中文, 同时支持繁体), xcin(繁体中文), kinput2(日文) 和 hanIM/ami(韩文).

    中文输入服务器Chinput 选择了OverTheSpot风格作为缺省的输入模式,它与标准的输入风格略有不同,即把预编辑区域偏离输入位置, 使输入区 域同时作为状态区域,在很大程度满足了用户的输入习惯.同时它还使用辅助工具条显示和改变输入状态.Chinput还解决了同时使用GB和Big5编码的问题,被动输入(Passive Input)问题等.对于普通用户, 除了使用键盘 输入外,还可以使用手写识别输入和语音识别输入方式.目前的输入架构基本能够满足它们的要求.笔者在手写识别输入方面做了一些尝试, 发现对绝大部分软件是能够适合被动输入的.

  • 打印的国际化

  • 在X窗口系统下的打印是一个很难解决的问题, 所以到目前为止没有形成 一个统一的打印标准.其原因之一就是X窗口系统在设计上把显示和打印完全分开了.

    在Linux最常见的需要打印的文件格式是普通文本文件和PostScript文件.对于中文的普通文本文件的打印一般需要先转换为PostScript文件再打印.对于PostScript文件,如果应用软件在生成时含有中文字体信息, 则打印 比较容易实现,反之, 则很难实现甚至不可能打印.

    目前中文文本文件常用的打印方法通常是,使用gb2ps/bg2ps/cnprint 等软件转换成PS文件打印,转换过程使用了中文的点阵字体.对已经形成的PS 文件的打印, 如果不包含中文字体,直接打印就会输出乱码,通常使用的方法 是将这一类PS文件过滤一下, 改为使用中文字体,然后再打印.如陈向阳先生的过滤软件ps2cps可以打印Netscape的存储文件.这种打印的缺点是有时输出的PS中汉字字符串和英文字符串对不齐.最好的方法是在 PostScript一级实现 中文打印,陈向阳先生对ghostscript进行了中文化, 可以直接使用TTF轻松打 印Netscape, Qt/KDE, lyx等软件输出的PS文件.这种从底层实现打印的方法 也是日文和韩文所采用的方法.

    使用CID(adobe)字体打印的方法也在尝试之中.

    总之, 目前的中文打印缺乏统一标准, 应用软件在输出打印PS文件时多数 不考虑双字节语言的问题,使打印变得更加复杂化, 所以当前的中文Linux发 布版本多数不支持中文打印,

  • 客户程序间通讯的国际化

  • 客户程序间通讯(Interclient Communications Conventions,简称ICCC)是客户程序之间共享资源的手段之一.最常见的应用是文本的拷贝和粘贴和与窗口管理器通讯.但是如果两个应用程序之间所使用的字符集不同,粘贴就会出现问题, 甚至粘贴的内容会丢失.所以客户程序之间必须国际化了的通讯协议.

    应用程序和窗口管理器之间的通讯也属于客户程序间通讯.

    如果客户程序之间使用的字符集相同, 但是编码不同, 则不会丢失数据, 这时应该使用复合文本(COMPOUND TEXT)传输.X内部定义了COMPOUND_TEXT 的原子(Atom)用于传输中英文混和的字符串.对7字节编码, ASCII或者其它 ISO8859-1字符集, 客户程序通讯可以不用转换而直接使用XA_STRING原子传输.

    四 开发符合国际化标准的软件

    在X窗口系统下开发软件, 应尽量符合国际化标准.它包括, 设置合适的locale(见前面讲述的在X下使用locale),注意选择字符集和字体集, 本地化文本的处理,输入方法等等.这里推荐用户尽量使用在国际化方面已经比较完善的高层图形库, 如Qt, gtk+, Java等, 这样可以避免考虑以上问题.选择Motif时需要考虑资源的国际化问题和FontList等.
    1. 开发国际化软件 
    2. 使用已经支持国际化的高层图形库开发支持国际化的软件基本上可以不用考虑国际化问题.特别是输入问题,在标准的输入区内(单行输入和多行输入), 都可以自动输入汉字.在字体处理上,注意使用字体集.许多软件需要在资源文件中指定字体和字体集, 所以开发的软件应提供一个缺省支持字体集的资源文件.

      下面所介绍的开发国际化的软件是基于libX11的开发方法.除了前面所说的 在软件初始化时调用一些Locale的函数外,在实际编程时, 还应注意以下问题:

      1. 字体载入: 在处理字符串时, 使用FontSet, 而不是Font: 
      2. XCreateFontSet() - 建立字体集
        XFreeFontSet() - 释放字体集内存
        XFontsOfFontSet() - 返回XFontStruct和字体名
        XBaseFontNameListOfFontSet() - 返回字体集的名称
        XLocaleOfFontSet() - 返回XFontSet的locale名
        XExtentsOfFontSet() - 获得FontSet的最大Extents

      3. 计算字符串的屏幕尺寸并画字符串:

      4. Xmb/XwcDrawString() - 只画字型(glyphs)的前景
        Xmb/XwcDrawImageString() - 画前景和背景
        Xmb/XwcDrawText() - 复杂的间隔和字体集
        Xmb/XwcTextEscapement() - X 方向像素
        Xmb/XwcTextExtents() - 字符串轮廓

      5. 客户程序间通讯: 
      6. Xmb/wcTextListToTextProperty() - 根据locale的文本转换
        Xmb/wcTextPropertyToTextList() - 根据locale的文本转换
        XFreeStringList()
        Xmb/wcFreeStringList() - 释放StringList
        XSetWMProperties() - 设置窗口管理器属性
        XSetWMName() - 设置窗口窗口名
        XSetWMIconName() - 设置窗口图标名

      7. 输入: 
      8. XOpenIM()/XCloseIM() - 打开/关闭输入服务器
        XDisplayOfIM()/XLocaleOfIM()
        XSetIMValues()/XGetIMValues() - 设置/获取输入服务器属性
        XCreateIC()/XDestroyIC() - 建立/释放IC
        XIMOfIC()
        XSetICValues()/XGetICValues() - 设置/获取IC的值
        XSetICFocus()/XUnsetICFocus() - 聚焦/取消聚焦
        XmbResetIC()/XwcResetIC() - 重设IC
        XFilterEvent() - 过滤事件
        Xmb/wcLookupString() - 查找字符串
        XRegister/UnregisterIMInstantiateCallback() - 注册/取消回调 

    3. 使非国际化软件国际化 
    4. 修改已经存在的非国际化软件, 应根据具体情况采用不同的补丁.需要 注意的是修改后的软件应与原来的软件兼容,不会对软件以前在西文和其它 语言的支持造成影响.Locale应该是软件的语言切换中心点.下面是笔者在修改软件的过程中一些经验, 仅供参考.

      • 在软件初始化时设置Locale.
      • 定义gettext的宏, 并且把它与信息文件绑定.
      • 对所有静态信息使用gettext
      • 对文本绘制使用字体集代替字体
      • 绘制函数使用X下的多字节或宽字符函数
      • 初始化和XIM服务器的联接
      • 在事件循环中用XFilterEvent()过滤事件到XIM服务器
      • 使用Xmb/wcLookupString()查找字符串

    五 目前中文化中存在的问题

    现有的国际化标准中存在许多问题, 问题的原因主要出自目前的 国际化架构.对于中文化来说,这些问题显得更加突出.
    1. 编码动态切换的问题 
    2. 对中文软件来说, 同时支持多内码(GB和Big5)是比较完善的中文软件, 但是动态切换内码,特别是切换软件界面(如菜单项)的内码,是受到信息 (Message)国际化中 gettext 的限制的.一般来说, 一旦软件载入, 所有 文本信息便被初始化,而且在整个过程中不会再重新装载信息.退一步说,即使重新装载了信息, 由于所装载信息的长度发生了变化, 软件界面调整 布局也是十分困难的.

      所以现有软件的动态编码切换仅仅是在部分区域实现, 例如Netscape. 遗憾的是, Netscape的编码切换并不彻底,它切换的仅仅是显示部分, 输入 部分仍然有问题.比如在zh_CN.GBK的环境下启动Netscape,当切换到有 输入条的繁体中文页面时,如果采用输入软件自动识别Input Context的编码的方式, 仍然会认为Netscape是GB编码, 输入结果不正确.如果输入 Big5编码,必须缩定输出的编码为Big5.Chinput在这方面做了一些尝试, 结论是可以输入Big5编码,但是在输入条中的显示不正确.

      一般来说, 使用中文平台来动态切换编码更容易实现.在中文Linux 的发布版本中,有几个是可以使用中文平台来实现动态切换编码的, 其原理十分简单, 只要在应用程序或X服务器把某个窗口的编码状态记住就行了,以后的文本显示和输入都以此编码为标准.这种方法的缺点是, 应用程序初始界面上的中文由于转化了编码变成了乱码.

    3. 中文编码自动识别问题 
    4. 在文本浏览,网页浏览或网页翻译时, 通常需要自动识别汉字的内码, 但是中文的GB编码和Big5编码有重叠区域,所以很难区分开.目前公开 源代码的识别软件很少, 识别结果不能令人满意,远没有达到目前商业软件 的识别水平.

    5. Linux上的中文平台到国际化的过渡 
    6. 但是从长远的角度看, 因为中文在对中文显示和输入上与国际化标准 存在很大差异,所以亟需一种从中文平台到国际化标准的过渡性方案.在 过渡的过程中, 中文平台可能会和国际化标准共同存在一段时间.

      以CLE和TurboLinux为例, 它们在早期的版本中都采用了中文平台来 支持中文的显示和输入,随着支持国际化标准的软件的增多,逐步采用了 中文平台和国际化标准共同存在的版本作为过渡性版本.到目前为止,已经在缺省情况下放弃中文平台的使用.中文平台只是作为残留物包含在发布 版本中.

    7. Linux 文档中文化 
    8. Linux文档, 主要是指Linux上的一些命令帮助文档(man文件), 软件 手册和说明,软件本身的Message文件(po).目前在这方面的工作还缺乏 统一的管理和广大Linux爱好者的参与.

    参考资料
    • Unicode: http://www.unicode.org/
    • 香港增补字符集: http://www.digital21.gov.hk/chi/hkscs/introduction.html
    • CJK 有关信息: ftp://ftp.ora.com/pub/examples/nutshell/ujip/doc/cjk.inf
    • Linux国际化资料: http://i18n.linux.org.tw/
    • Linux国际化标准: http://www.li18nux.org/
    • MicroSoft 国际化: http://www.microsoft.com/globaldev/

    六 附录

    1. 宽字符处理函数函数与普通函数对照表 
    2. 字符分类:
      宽字符函数 普通C函数 描述
      iswalnum() isalnum() 测试字符是否为数字或字母
      iswalpha() isalpha() 测试字符是否是字母
      iswcntrl() iscntrl() 测试字符是否是控制符
      iswdigit() isdigit() 测试字符是否为数字
      iswgraph() isgraph() 测试字符是否是可见字符
      iswlower() islower() 测试字符是否是小写字符
      iswprint() isprint() 测试字符是否是可打印字符
      iswpunct() ispunct() 测试字符是否是标点符号
      iswspace() isspace() 测试字符是否是空白符号
      iswupper() isupper() 测试字符是否是大写字符
      iswxdigit() isxdigit() 测试字符是否是十六进制的数字

      大小写转换:
      宽字符函数 普通C函数 描述
      towlower() tolower() 把字符转换为小写
      towupper() toupper() 把字符转换为大写

      字符比较:
      宽字符函数 普通C函数 描述
      wcscoll() strcoll() 比较字符串

      日期和时间转换:
      宽字符函数 描述
      strftime() 根据指定的字符串格式和locale设置格式化日期和时间
      wcsftime() 根据指定的字符串格式和locale设置格式化日期和时间, 并返回宽字符串
      strptime() 根据指定格式把字符串转换为时间值, 是strftime的反过程

      打印和扫描字符串:
      宽字符函数 描述
      fprintf()/fwprintf() 使用vararg参量的格式化输出
      fscanf()/fwscanf() 格式化读入
      printf() 使用vararg参量的格式化输出到标准输出
      scanf() 从标准输入的格式化读入
      sprintf()/swprintf() 根据vararg参量表格式化成字符串
      sscanf() 以字符串作格式化读入
      vfprintf()/vfwprintf() 使用stdarg参量表格式化输出到文件
      vprintf() 使用stdarg参量表格式化输出到标准输出
      vsprintf()/vswprintf() 格式化stdarg参量表并写到字符串

      数字转换:
      宽字符函数 普通C函数 描述
      wcstod() strtod() 把宽字符的初始部分转换为双精度浮点数
      wcstol() strtol() 把宽字符的初始部分转换为长整数
      wcstoul() strtoul() 把宽字符的初始部分转换为无符号长整数

      多字节字符和宽字符转换及操作:
      宽字符函数 描述
      mblen() 根据locale的设置确定字符的字节数
      mbstowcs() 把多字节字符串转换为宽字符串
      mbtowc()/btowc() 把多字节字符转换为宽字符
      wcstombs() 把宽字符串转换为多字节字符串
      wctomb()/wctob() 把宽字符转换为多字节字符
      输入和输出:
      宽字符函数 普通C函数 描述
      fgetwc() fgetc() 从流中读入一个字符并转换为宽字符
      fgetws() fgets() 从流中读入一个字符串并转换为宽字符串
      fputwc() fputc() 把宽字符转换为多字节字符并且输出到标准输出
      fputws() fputs() 把宽字符串转换为多字节字符并且输出到标准输出串
      getwc() getc() 从标准输入中读取字符, 并且转换为宽字符
      getwchar() getchar() 从标准输入中读取字符, 并且转换为宽字符
      None gets() 使用fgetws()
      putwc() putc() 把宽字符转换成多字节字符并且写到标准输出
      putwchar() getchar() 把宽字符转换成多字节字符并且写到标准输出
      None puts() 使用fputws()
      ungetwc() ungetc() 把一个宽字符放回到输入流中

      字符串操作:
      宽字符函数 普通C函数 描述
      wcscat() strcat() 把一个字符串接到另一个字符串的尾部
      wcsncat() strncat() 类似于wcscat(), 而且指定粘接字符串的粘接长度.
      wcschr() strchr() 查找子字符串的第一个位置
      wcsrchr() strrchr() 从尾部开始查找子字符串出现的第一个位置
      wcspbrk() strpbrk() 从一字符字符串中查找另一字符串中任何一个字符第一次出现的位置
      wcswcs()/wcsstr() strchr() 在一字符串中查找另一字符串第一次出现的位置
      wcscspn() strcspn() 返回不包含第二个字符串的的初始数目
      wcsspn() strspn() 返回包含第二个字符串的初始数目
      wcscpy() strcpy() 拷贝字符串
      wcsncpy() strncpy() 类似于wcscpy(), 同时指定拷贝的数目
      wcscmp() strcmp() 比较两个宽字符串
      wcsncmp() strncmp() 类似于wcscmp(), 还要指定比较字符字符串的数目
      wcslen() strlen() 获得宽字符串的数目
      wcstok() strtok() 根据标示符把宽字符串分解成一系列字符串
      wcswidth() None 获得宽字符串的宽度
      wcwidth() None 获得宽字符的宽度

      另外还有对应于memory操作的 wmemcpy(), wmemchr(), wmemcmp(), wmemmove(), wmemset().

    3. X 窗口系统下支持中文的函数
    4. 支持西文的函数 支持中文的函数 描述
      XLoadFont XCreateFontSet 载入字体集
      XTextExtents(16) Xmb/wcTextExtents
      Xmb/wcTextPerCharExtents
      返回文本的限制框
      XDrawString Xmb/wcDrawString 在窗口中画字符串, 背景填充
      XDrawImageString Xmb/wcDrawImageString 在窗口中画字符串
      XDrawText Xmb/wcDrawText 在窗口中画字符串
      XLookupString Xmb/wcLookupString 查找字符串

    5. 支持国际化的高层库
      • OSF/Motif
      • Qt/kdelib
      • gtk+/gnome-lib
      • Perl
      • Java
    6. 支持多语言的典型软件
      • 浏览器 Netscape
      • 编辑器 XEmacs
      • 编辑器 Mule
      • 编辑器 vim
      • 终端 rxvt
      • 排版软件 LaTeX/lyx
      • PostScript/PDF: gs/acroread
      • 图像处理: gimp
      • 幻灯片制作 mgp
      • 即将完成: StarOffice, KOffice
    7. 支持Unicode的软件
      • 高级图形库函数 Qt 2.x
      • Java 语言开发工具 JDK
      • 编辑器 yudit
      • 专用的支持Unicode的 X 终端
      • 基于GTK+的文本处理器 GScript

    posted @ 2005-11-15 11:39 幽灵狼 阅读(534) | 评论 (0)编辑 收藏

     

      如何在程序中加入并使用 Unicode 以实现外语支持

    Author:    Thomas W. Burger


    作为一个计算机的多位字符表示系统,Unicode 支持世界上所有语言的编码和转换。这篇文章说明了 Linux 应用程序中的国际语言支持的重要性,以及规划 Unicode 支持并将之结合到 Linux 应用程序中去的思想。

    Unicode 并不只是一个编程工具,它还是一个政治的、经济的工具。没有结合世界的语言支持的应用程序通常只能被那些能读写 ASCII 所支持语言的个人使用。这使得建立在 ASCII 基础之上的计算机技术脱离了世界上大部分人。Unicode 允许程序使用世界上任何一种字符集,因此它支持所有语言。

    Unicode 让程序员为普通人提供用他们本国语言就能使用的软件。这样就不用再学一门外语了,而且更容易实现计算机技术社会和财政上的利益。很容易设想,如果用户必须为使用因特网浏览器而学习乌尔都语的话,您就难以看到计算机在美国的使用。Web 就更不会出现了。

    Linux 承担了对 Unicode 很大程度上的支持。Unicode 支持被嵌入到内核和代码开发库中。在很大程度上,使用程序中几句简单的命令就能将它们自动的结合到代码中。

    所有现代字符集的基础都是在 1968 年以 ANSIX3.4 版本出版的美国信息交换标准码(American Standard Code for Information Interchange,ASCII)。一个值得注意的例外是在 ASCII 之前定义的 IBM 的扩充的二进制编码的十进制交换码(Extended Binary Coded Decimal Information Code,EBCDIC)。ASCII 是一个编码字符集(coded character set,CCS),换句话说,它是整数到字符表示的映射。ASCII 编码字符集允许用一个八位(基于二进制的,用值 0 或 1 表示的)字段或字节(2^8 =256)表示 256 个字符。这是一个高度受限的编码字符集,它不能表示许多不同语言的所有字符(如中文和日文),不能表示科学符号,更不能表示古代文字(神秘符号和象形文字)和音乐符号。通过更改一个字节的长度而使更大的字符集得以被编码,这似乎有效但完全不切实际。所有的计算机都基于八位字节。解决方法是一种字符编码方案(Character encoding scheme,CES)― 用定长或变长的多字节序列能够表示比 256 大的数.这些数值接着通过编码字符集被映射到它们表示的字符。
     

    Unicode 的定义
    Unicode 通常用作涉及双字节字符编码方案的通用术语。Unicode CCS 3.1 的官方称谓是 ISO10646-1 通用多八字节编码字符集(Universal Multiple Octet Coded Character Set,UCS)。Unicode 3.1 版本添加了 44,946 个新的编码字符。算上 Unicode 3.0 版本已经存在的 49,194 个字符,共计 94,140 个。

    Unicode 编码字符集利用了一个由 128 个三维的组构成的四维编码空间。其中每个组包含 256 个二维平面。每个平面由 256 个一维的行组成,并且每个行有 256 个单元。每个单元在这个编码空间内对一个字符编码,或者被声明为未经使用。这种编码概念被称为 UCS-4;四个八位元用来表示指定组、平面、行和单元的每个字符。

    第一个平面(第 00 组的第 00 平面)是基本多语言平面(Basic Multilingual Plane,BMP)。BMP 按字母、音节、表意符号和各种符号及数字定义了常规使用的字符。后续的平面用于附加字符或其它还没有发明的编码实体。我们需要这完整的范围去处理世界上的所有语言;特别是拥有将近 64,000 个字符的一些东亚语言。

    BMP 被用作双字节的编码字符集,这种编码字符集确定为 ISO 10646 UCS-2 格式。ISO 10646 UCS-2 就是指 Unicode(并且两者相同)。BMP,像所有 UCS 平面那样,包含了 256 行,其中每行包含 256 个单元,字符仅仅按照 BMP 中的行和单元的八位元在单元中被编码。 这就允许 16 位编码字符能够被用来书写大多数商业上最重要的语言。UCS-2 不需要代码页切换、代码扩展或代码状态。UCS-2 是一种将 Unicode 结合到软件中的简单方法,但它只限于支持 Unicode BMP。

    若要用 8 位字节表示一个多于 2^8 =256 个字符的字符编码系统(character coding system,CCS),就需要一种字符编码方案(character-encoding scheme,CES)。

    Unicode 转换
    在 UNIX 中,使用得最多的字符编码方案是 UTF-8。 它考虑到了对整个 Unicode 全部页和平面的全面支持,而且它仍能正确的识别 ASCII。除了 UTF-8 的其他选择还有:UCS-4、UTF-16、UTF-7.5、UTF-7、SCSU、HTML 和 JAVA。

    Unicode 转换格式(Unicode Transformation Formats,UTFs)是一种通过映射多字节编码中的值来支持 Unicode 的字符编码方案。本文将分析最流行的格式 ― UTF-8 字符编码系统。

    UTF-8
    UTF-8 转换格式正逐步成为一种占主导地位的交换国际文本信息的方法,因为它可以支持世界上所有的语言,而且它还与 ASCII 兼容。UTF-8 使用变长编码。从 0 到 0x7f(127)的字符把自身编码成单字节,而将值更大的字符编码成 2 到 6 个字节。

    表 1. UTF-8 编码
    0x00000000 - 0x0000007F:
    0 xxxxxxx
    0x00000080 - 0x000007FF:
    110 xxxxx10 xxxxxx
    0x00000800 - 0x0000FFFF:
    1110 xxxx10 xxxxxx10 xxxxxx
    0x00010000 - 0x001FFFFF:
    11110 xxx10 xxxxxx10 xxxxxx 10 xxxxxx
    0x00200000 - 0x03FFFFFF:
    111110 xx10 xxxxxx10 xxxxxx10 xxxxxx 10 xxxxxx
    0x04000000 - 0x7FFFFFFF:
    1111110 x10 xxxxxx10 xxxxxx10 xxxxxx 10 xxxxxx10 xxxxxx

    字节 10 xxxxxx是一个扩展字节,它的 xxxxxx 位位置被以二进制表示的字符代码号的位所填充。这是能够代表被使用代码的最短的可能的多字节序列。

    UTF-8 编码示例
    Unicode 字符版权标记字符 0xA9 = 1010 1001 用 UTF-8 编码如下所示:

    11000010 10101001 = 0xC2 0xA9

    “不等于”符号字符 0x2260 = 0010 0010 0110 0000 编码如下所示:

    11100010 10001001 10100000 = 0xE2 0x89 0xA0

    通过获取 continuation byte 的值可以看到原始数据:

    [1110]0010 [10]001001 [10]100000
    0010 001001 100000
    0010 0010 0110 0000 = 0x2260

    第一个字节定义后面紧跟的八位元数,如果是 7F 或更小,这就是等价的 ASCII 值。每个八位字节以 10 xxxxxx 开头,确保字节不与 ASCII 的值混淆。

    UTF 支持
    在 Linux 平台上使用 UTF-8 之前,请确信分发包里有 glibc 2.2 和 XFree86 4.0 或更新的版本。早先的版本缺少 UTF-8 语言环境支持和 ISO10646-1 X11 字体。

    在 UTF-8 发布之前,Linux 用户使用各种不同特定语言的扩展 ASCII,像欧洲用户用 ISO 8859-1 或 ISO 8859-2,希腊用户使用 ISO 8859-7,俄罗斯用户使用 KOI-8 / ISO 8859-5/CP1251(西里尔字母)。这使得数据交换出现了很多问题,并且需要为这些编码之间的差异编写应用软件。这种语言支持是不完善的,而且数据交换没有经过测试。Linux 主要的发行商和应用程序开发者正致力于让主要以 UTF-8 格式表示的 Unicode 成为 Linux 中的标准。

    为了识别 Unicode 文件,Microsoft 建议所有的 Unicode 文件应该以 ZERO WIDTH NOBREAK SPACE(U+FEFF)字符开头。这作为一个“特征符”或“字节顺序标记(byte-order mark,BOM)”来识别文件中使用的编码和字节顺序。但是,Linux/UNIX 并没有使用 BOM,因为它会破坏现有的 ASCII 文件的语法约定。在 POSIX 系统中,选中的语言环境识别了在一个过程中的所有输入输出文件期望的编码形式。

    有两种方法可以将 UTF-8 支持添加到 Linux 应用程序中。第一种方法,数据都以 UTF-8 形式存放在各处,这样软件改动很少(被动的)。另一种方法,被读取的 UTF-8 数据用标准的 C 语言库函数转变成为宽字符数组(转换的)。在输出时,用函数 wcsrtombs() 使字符串被转变回 UTF-8:

    清单 1. wcsrtombs()
    #include <wchar.h> 
    size_t wcsrtombs (char *dest, const wchar_t **src, size_t len, mbstate_t *ps);

    方法的选择取决于应用程序的性质。大多数应用程序可以使用被动的方法操作。这就是在 UNIX 平台上使用 UTF-8 会如此流行的原因。像 catecho 那样的程序就不需要修改。字节流仍只是字节流,并没有对它进行任何处理。ASCII 字符和控制代码在 UTF-8 语言环境中不改变。

    通过字节计数对字符进行计数的程序需要一些小小的改动。在 UTF-8 中应用程序不对任何扩展的字节进行计数。如果选择了 UTF-8 语言环境,C 语言库的 strlen(s) 函数需要用 mbstowcs() 函数来代替:

    清单 2. mbstowcs() 函数
    #include <stdlib.h>
    size_t mbstowcs(wchar_t *pwcs, const char *s, size_t n);

    strlen 的一种常见用法是估算显示宽度。中文和其它表意符号将占用两列位置。 wcwidth() 函数用来测试每个字符的显示宽度:

    清单 3. wcwidth() 函数
    #include <
    wchar.h>
    int wcwidth(wchar_t wc);

    Unicode 的 C 语言支持
    在正式情况下,从 GNU glibc 2.2 开始,wchar_t 类型只为 32 位的 ISO 10646 格式数值所特定使用,与当前使用的语言环境无关。通过 ISO C99 所要求的 __STDC_ISO_10646__ 宏的定义作为信号通知应用程序。 __STDC_ISO_10646__ 的定义用来指出 wchar_t 是 Unicode。精确的值是一个十进制的 yyyymmL 格式的常数。例如,使用:

    清单 4. 指出 wchar_t 是 Unicode
    #define __STDC_ISO_10646__ 200104L

    是为指出 wchar_t 类型的值是由 ISO/IEC 10646 和到指定的年月为止的所有修正与技术勘误定义的字符编码表示。

    对 wchar_t 的利用如这个示例所示,使用宏确定在 ISO C99 可移植代码中写双引号的方法。

    清单 5. 确定写双引号的方法
    #if __STDC_ISO_10646__  
    printf("%lc", 0x201c);
    #else
    putchar('"');
    #fi

    语言环境
    激活 UTF-8 的恰当的办法是 POSIX 语言环境机制。语言环境是一种包含有关软件行为特定文化约定的配置设定。它包含了字符编码、日期/时间符号、分类规则以及度量系统。语言环境的名称通常由 ISO 639-1 语言、ISO 3166-1 国家或地区代码以及可选的编码名称和其它限定符组成。您可以用命令 locale -a 获取所有安装在系统上的语言环境列表(通常在 /usr/lib/locale/)。

    如果没有预安装 UTF-8 语言环境,你可以用 localedef 命令生成它。若要为某个特定用户生成并激活一个德语的 UTF-8 语言环境,请使用如下语句:

    清单 6. 为特定用户生成语言环境
    localedef -v -c -i de_DE -f UTF-8 $HOME/local/locale/de_DE.UTF-8
    export LOCPATH=$HOME/local/locale
    export LANG=de_DE.UTF-8

    有时候为所有用户添加 UTF-8 语言环境会很有用。root 用户使用如下指令就可以完成:

    清单 7. 为每个用户生成语言环境
    localedef -v -c -i de_DE -f UTF-8 /usr/share/locale/de_DE.UTF-8

    若要为每个用户将这个语言环境设为缺省值,可以将以下行添加到 /etc/profile 文件中:

    清单 8. 为所有用户设置缺省的语言环境
    export LANG=de_DE.UTF-8

    处理多字节字符代码序列的函数行为依赖于当前语言环境的 LC_CTYPE 类别;它确定了依赖语言环境的多字节编码。值 LANG=de_DE(德语)会导致输出按 ISO 8859-1 被格式化。值 LANG=de_DE.UTF-8 会把输出格式化成 UTF-8。语言环境设置会导致 printf 中的 %ls 格式说明符调用 wcsrtombs() 函数以便于将宽字符的参数字符串转换成依赖语言环境的多字节编码。语言环境中的国家或地区标识符如:LC_CTYPE= en_GB (英国英语)和 LC_CTYPE= en_AU(澳大利亚英语),它们之间的差异只在 LC_MONETARY 类别中,原因在于货币的名称和打印货币数量的规则不同。

    请给您首选的语言环境设置环境变量 LANG。当一个 C 程序执行 setlocale() 函数时:

    清单 9. setlocale() 函数
    #include <stdio.h>
    #include <locale.h>
    //char *setlocale(int category, const char *locale);
    int main()
    {
    if (!setlocale(LC_CTYPE, ""))
    {
    fprintf(stderr, "Locale not specified. Check LANG, LC_CTYPE, LC_ALL.
    ");
    return 1;
    }

    C 语言库将会依次测试环境变量 LC_ALL、LC_CTYPE 和 LANG。其中第一个含值的环境变量将决定为 LC_CTYPE 类别装入哪种语言环境数据。语言环境数据分裂成独立的类别。值 LC_CTYPE 定义了字符编码,而 LC_COLLATE 定义了排序顺序。我们用 LANG 环境变量为所有类别设置缺省语言环境,但 LC_* 变量可以用来覆盖单个类别。

    您可以用命令 locale charmap 查询当前语言环境中字符编码的名称。如果您从 LC_CTYPE 类别中成功选取了 UTF-8 语言环境,会输出 UTF-8。命令 locale -m 提供一张已安装的所有字符编码名称的列表。

    如果您使用专门的 C 语言库的多字节函数来完成所有外部字符编码和内部使用的 wchar_t 编码之间的转换,那么 C 语言库将承担责任,根据 LC_CTYPE 使用正确的编码方式。这甚至不需要程序被明确的编码成当前的多字节编码。

    如果需要一个应用程序能明确的支持 UTF-8(或其它编码)转换方法而不用 libc 多字节函数,则应用程序必须确定是否需要激活 UTF-8 模式。带有 <langinfo.h> 库头文件的与 X/Open 兼容系统可以用如下代码:

    清单 10. 检测当前的语言环境是否使用了 UTF-8 编码
    BOOL utf8_mode = FALSE;

    if( ! strcmp(nl_langinfo(CODESET), "UTF-8")
    utf8_mode = TRUE;

    为检测当前语言环境是否使用了 UTF-8 编码。首先必须调用 setlocale(LC_CTYPE, "") 函数,依据环境变量设置语言环境。nl_langinfo(CODESET) 函数也是由 locale charmap 命令调用,从而查找当前语言环境指定的编码名称。

    另一种可以使用的方法是查询语言环境变量:

    清单 11. 查询语言环境变量
    char *s;
    BOOL utf8_mode = FALSE;

    if ((s = getenv("LC_ALL")) || (s = getenv("LC_CTYPE")) || (s = getenv ("LANG")))

    {
    if (strstr(s, "UTF-8"))
    utf8_mode = TRUE;
    }

    这项测试假设 UTF-8 语言环境名称中有值“UTF-8”,但实际情况并不总是如此,所以应该使用 nl_langinfo() 方法。

    总结
    为支持世界上的所有语言,需要一种具有八位字节字符编码策略的字符编码系统,它的字符应多于 ASCII(一种使用无符号字节的扩展版本)的 2^8 = 256 个字符。Unicode 就是这样一种字符编码系统,它具有由 128 个三维组(带有由大量字符编码方案的方法支持的 94,140 个定义好的字符值)组成的四维编码空间,在 Linux 中更流行的字符编码方案是 Unicode 转换格式 UTF-8。

    参考资料

    关于作者
    TW Burger 从 1979 年起曾经做过编程、讲授中等计算机课程以及撰写有关计算机技术方面的书。他正在经营一个信息技术咨询公司。您可以通过 twburger@bigfoot.com 与他联系。

    posted @ 2005-11-15 11:39 幽灵狼 阅读(910) | 评论 (0)编辑 收藏

     

    /* $NetBSD: style,v 1.36 2005/08/25 17:51:58 briggs Exp $ */

    /*
     * The revision control tag appears first, with a blank line after it.
     * Copyright text appears after the revision control tag.
     */

    /*
     * The NetBSD source code style guide.
     * (Previously known as KNF - Kernel Normal Form).
     *
     * from: @(#)style 1.12 (Berkeley) 3/18/94
     */
    /*
     * An indent(1) profile approximating the style outlined in
     * this document lives in /usr/share/misc/indent.pro.  It is a
     * useful tool to assist in converting code to KNF, but indent(1)
     * output generated using this profile must not be considered to
     * be an authoritative reference.
     */

    /*
     * Source code revision control identifiers appear after any copyright
     * text.  Use the appropriate macros from <sys/cdefs.h>.  Usually only one
     * source file per program contains a __COPYRIGHT() section.
     * Historic Berkeley code may also have an __SCCSID() section.
     * Only one instance of each of these macros can occur in each file.
     */
    #include <sys/cdefs.h>
    __COPYRIGHT("@(#) Copyright (c) 2000\n\
     The NetBSD Foundation, inc. All rights reserved.\n");
    __RCSID("$NetBSD: style,v 1.36 2005/08/25 17:51:58 briggs Exp $");

    /*
     * VERY important single-line comments look like this.
     */

    /* Most single-line comments look like this. */

    /*
     * Multi-line comments look like this.  Make them real sentences.  Fill
     * them so they look like real paragraphs.
     */

    /*
     * Attempt to wrap lines longer than 80 characters appropriately.
     * Refer to the examples below for more information.
     */

    /*
     * EXAMPLE HEADER FILE:
     *
     * A header file should protect itself against multiple inclusion.
     * E.g, <sys/socket.h> would contain something like:
     */
    #ifndef _SYS_SOCKET_H_
    #define _SYS_SOCKET_H_
    /*
     * Contents of #include file go between the #ifndef and the #endif at the end.
     */
    #endif /* !_SYS_SOCKET_H_ */
    /*
     * END OF EXAMPLE HEADER FILE.
     */

    /*
     * Kernel include files come first.
     */
    #include <sys/types.h>  /* Non-local includes in brackets. */

    /*
     * If it's a network program, put the network include files next.
     * Group the includes files by subdirectory.
     */
    #include <net/if.h>
    #include <net/if_dl.h>
    #include <net/route.h>
    #include <netinet/in.h>
    #include <protocols/rwhod.h>

    /*
     * Then there's a blank line, followed by the /usr include files.
     * The /usr include files should be sorted!
     */
    #include <assert.h>
    #include <errno.h>
    #include <inttypes.h>
    #include <stdio.h>
    #include <stdlib.h>

    /*
     * Global pathnames are defined in /usr/include/paths.h.  Pathnames local
     * to the program go in pathnames.h in the local directory.
     */
    #include <paths.h>

    /* Then, there's a blank line, and the user include files. */
    #include "pathnames.h"  /* Local includes in double quotes. */

    /*
     * ANSI function declarations for private functions (i.e. functions not used
     * elsewhere) and the main() function go at the top of the source module.
     * Don't associate a name with the types.  I.e. use:
     * void function(int);
     * Use your discretion on indenting between the return type and the name, and
     * how to wrap a prototype too long for a single line.  In the latter case,
     * lining up under the initial left parenthesis may be more readable.
     * In any case, consistency is important!
     */
    static char *function(int, int, float, int);
    static int dirinfo(const char *, struct stat *, struct dirent *,
         struct statfs *, int *, char **[]);
    static void usage(void);
    int main(int, char *[]);

    /*
     * Macros are capitalized, parenthesized, and should avoid side-effects.
     * Spacing before and after the macro name may be any whitespace, though
     * use of TABs should be consistent through a file.
     * If they are an inline expansion of a function, the function is defined
     * all in lowercase, the macro has the same name all in uppercase.
     * If the macro is an expression, wrap the expression in parenthesis.
     * If the macro is more than a single statement, use ``do { ... } while (0)'',
     * so that a trailing semicolon works.  Right-justify the backslashes; it
     * makes it easier to read. The CONSTCOND comment is to satisfy lint(1).
     */
    #define MACRO(v, w, x, y)      \
    do {         \
     v = (x) + (y);       \
     w = (y) + 2;       \
    } while (/* CONSTCOND */ 0)

    #define DOUBLE(x) ((x) * 2)

    /* Enum types are capitalized.  No comma on the last element. */
    enum enumtype {
     ONE,
     TWO
    } et;

    /*
     * When declaring variables in structures, declare them organized by use in
     * a manner to attempt to minimize memory wastage because of compiler alignment
     * issues, then by size, and then by alphabetical order. E.g, don't use
     * ``int a; char *b; int c; char *d''; use ``int a; int b; char *c; char *d''.
     * Each variable gets its own type and line, although an exception can be made
     * when declaring bitfields (to clarify that it's part of the one bitfield).
     * Note that the use of bitfields in general is discouraged.
     *
     * Major structures should be declared at the top of the file in which they
     * are used, or in separate header files, if they are used in multiple
     * source files.  Use of the structures should be by separate declarations
     * and should be "extern" if they are declared in a header file.
     *
     * It may be useful to use a meaningful prefix for each member name.
     * E.g, for ``struct softc'' the prefix could be ``sc_''.
     */
    struct foo {
     struct foo *next; /* List of active foo */
     struct mumble amumble; /* Comment for mumble */
     int bar;
     unsigned int baz:1, /* Bitfield; line up entries if desired */
           fuz:5,
           zap:2;
     uint8_t flag;
    };
    struct foo *foohead;  /* Head of global foo list */

    /* Make the structure name match the typedef. */
    typedef struct BAR {
     int level;
    } BAR;

    /* C99 uintN_t is preferred over u_intN_t. */
    uint32_t zero;

    /*
     * All major routines should have a comment briefly describing what
     * they do.  The comment before the "main" routine should describe
     * what the program does.
     */
    int
    main(int argc, char *argv[])
    {
     long num;
     int ch;
     char *ep;

     /*
      * At the start of main(), call setprogname() to set the program
      * name.  This does nothing on NetBSD, but increases portability
      * to other systems.
      */
     setprogname(argv[0]);

     /*
      * For consistency, getopt should be used to parse options.  Options
      * should be sorted in the getopt call and the switch statement, unless
      * parts of the switch cascade.  Elements in a switch statement that
      * cascade should have a FALLTHROUGH comment.  Numerical arguments
      * should be checked for accuracy.  Code that cannot be reached should
      * have a NOTREACHED comment.
      */
     while ((ch = getopt(argc, argv, "abn")) != -1) {
      switch (ch) {  /* Indent the switch. */
      case 'a':  /* Don't indent the case. */
       aflag = 1;
       /* FALLTHROUGH */
      case 'b':
       bflag = 1;
       break;
      case 'n':
       errno = 0;
       num = strtol(optarg, &ep, 10);
       if (num <= 0 || *ep != '\0' || (errno == ERANGE &&
           (num == LONG_MAX || num == LONG_MIN)) )
        errx(1, "illegal number -- %s", optarg);
       break;
      case '?':
      default:
       usage();
       /* NOTREACHED */
      }
     }
     argc -= optind;
     argv += optind;

     /*
      * Space after keywords (while, for, return, switch).  No braces are
      * used for control statements with zero or only a single statement,
      * unless it's a long statement.
      *
      * Forever loops are done with for's, not while's.
      */
     for (p = buf; *p != '\0'; ++p)
      continue;  /* Explicit no-op */
     for (;;)
      stmt;

     /*
      * Parts of a for loop may be left empty.  Don't put declarations
      * inside blocks unless the routine is unusually complicated.
      */
     for (; cnt < 15; cnt++) {
      stmt1;
      stmt2;
     }

     /* Second level indents are four spaces. */
     while (cnt < 20)
      z = a + really + long + statement + that + needs + two lines +
          gets + indented + four + spaces + on + the + second +
          and + subsequent + lines;

     /*
      * Closing and opening braces go on the same line as the else.
      * Don't add braces that aren't necessary except in cases where
      * there are ambiguity or readability issues.
      */
     if (test) {
      /*
       * I have a long comment here.
       */
    #ifdef zorro
      z = 1;
    #else
      b = 3;
    #endif
     } else if (bar) {
      stmt;
      stmt;
     } else
      stmt;

     /* No spaces after function names. */
     if ((result = function(a1, a2, a3, a4)) == NULL)
      exit(1);

     /*
      * Unary operators don't require spaces, binary operators do.
      * Don't excessively use parenthesis, but they should be used if
      * statement is really confusing without them, such as:
      * a = b->c[0] + ~d == (e || f) || g && h ? i : j >> 1;
      */
     a = ((b->c[0] + ~d == (e || f)) || (g && h)) ? i : (j >> 1);
     k = !(l & FLAGS);

     /*
      * Exits should be EXIT_SUCCESS on success, and EXIT_FAILURE on
      * failure.  Don't denote all the possible exit points, using the
      * integers 1 through 127.  Avoid obvious comments such as "Exit
      * 0 on success.". Since main is a function that returns an int,
      * prefer returning from it, than calling exit.
      */
     return EXIT_SUCCESS;
    }

    /*
     * The function type must be declared on a line by itself
     * preceding the function.
     */
    static char *
    function(int a1, int a2, float fl, int a4)
    {
     /*
      * When declaring variables in functions declare them sorted by size,
      * then in alphabetical order; multiple ones per line are okay.
      * Function prototypes should go in the include file "extern.h".
      * If a line overflows reuse the type keyword.
      *
      * DO NOT initialize variables in the declarations.
      */
     extern u_char one;
     extern char two;
     struct foo three, *four;
     double five;
     int *six, seven;
     char *eight, *nine, ten, eleven, twelve, thirteen;
     char fourteen, fifteen, sixteen;

     /*
      * Casts and sizeof's are not followed by a space.  NULL is any
      * pointer type, and doesn't need to be cast, so use NULL instead
      * of (struct foo *)0 or (struct foo *)NULL.  Also, test pointers
      * against NULL.  I.e. use:
      *
      * (p = f()) == NULL
      * not:
      * !(p = f())
      *
      * Don't use `!' for tests unless it's a boolean.
      * E.g. use "if (*p == '\0')", not "if (!*p)".
      *
      * Routines returning ``void *'' should not have their return
      * values cast to more specific pointer types.
      *
      * Use err/warn(3), don't roll your own!
      */
     if ((four = malloc(sizeof(struct foo))) == NULL)
      err(1, NULL);
     if ((six = (int *)overflow()) == NULL)
      errx(1, "Number overflowed.");

     /* No parentheses are needed around the return value. */
     return eight;
    }

    /*
     * Use ANSI function declarations.  ANSI function braces look like
     * old-style (K&R) function braces.
     * As per the wrapped prototypes, use your discretion on how to format
     * the subsequent lines.
     */
    static int
    dirinfo(const char *p, struct stat *sb, struct dirent *de, struct statfs *sf,
     int *rargc, char **rargv[])
    { /* Insert an empty line if the function has no local variables. */

     /*
      * In system libraries, catch obviously invalid function arguments
      * using _DIAGASSERT(3).
      */
     _DIAGASSERT(p != NULL);
     _DIAGASSERT(filedesc != -1);

     if (stat(p, sb) < 0)
      err(1, "Unable to stat %s", p);

     /*
      * To printf quantities that might be larger that "long", include
      * <inttypes.h>, cast quantities to intmax_t or uintmax_t and use
      * PRI?MAX constants, which may be found in <machine/int_fmtio.h>.
      */
     (void)printf("The size of %s is %" PRIdMAX " (%#" PRIxMAX ")\n", p,
         (intmax_t)sb->st_size, (uintmax_t)sb->st_size);

     /*
      * To printf quantities of known bit-width, use the corresponding
      * defines (generally only done within NetBSD for quantities that
      * exceed 32-bits).
      */
     (void)printf("%s uses %" PRId64 " blocks and has flags %#" PRIx32 "\n",
         p, sb->st_blocks, sb->st_flags);

     /*
      * There are similar constants that should be used with the *scanf(3)
      * family of functions: SCN?MAX, SCN?64, etc.
      */
    }

    /*
     * Functions that support variable numbers of arguments should look like this.
     * (With the #include <stdarg.h> appearing at the top of the file with the
     * other include files).
     */
    #include <stdarg.h>

    void
    vaf(const char *fmt, ...)
    {
     va_list ap;

     va_start(ap, fmt);
     STUFF;
     va_end(ap); 
        /* No return needed for void functions. */
    }

    static void
    usage(void)
    {

     /*
      * Use printf(3), not fputs/puts/putchar/whatever, it's faster and
      * usually cleaner, not to mention avoiding stupid bugs.
      * Use snprintf(3) or strlcpy(3)/strlcat(3) instead of sprintf(3);
      * again to avoid stupid bugs.
      *
      * Usage statements should look like the manual pages.  Options w/o
      * operands come first, in alphabetical order inside a single set of
      * braces.  Followed by options with operands, in alphabetical order,
      * each in braces.  Followed by required arguments in the order they
      * are specified, followed by optional arguments in the order they
      * are specified.  A bar (`|') separates either/or options/arguments,
      * and multiple options/arguments which are specified together are
      * placed in a single set of braces.
      *
      * Use getprogname() instead of hardcoding the program name.
      *
      * "usage: f [-ade] [-b b_arg] [-m m_arg] req1 req2 [opt1 [opt2]]\n"
      * "usage: f [-a | -b] [-c [-de] [-n number]]\n"
      */
     (void)fprintf(stderr, "usage: %s [-ab]\n", getprogname());
     exit(EXIT_FAILURE);
    }

    posted @ 2005-11-15 11:38 幽灵狼 阅读(369) | 评论 (0)编辑 收藏

     本书是一本介绍通信安全的书籍,如果你想保障你的通信安全,本书能给你一个很好的解决
    方案。本书从ssh协议介绍起,到具体的开源实现和商业实现。但本书同时介绍开源实现和
    商业实现,给人感觉比较乱。

    注意:由于openssh是开源软件,各版间的配置方法和设置参数可能会不同,所以设置时要
    以最新版的手册为准,不要硬套书本的设置。

    第一章 SSH简介
    ssh(secure shell)是一种通用,功能强大的基于软件的网络安全解决方案,计算机每次向网络
    发送数据时,SSH都会自动对其进行加密。数据到达目的地时,SSH自动对加密数据进行
    解密。整个过程都是透明的。它使用了现代的安全加密算法,足以胜任大型公司的任务繁重
    的应用程序的要求。

    SSH协议内容涉及认证AUTHENTICATION,加密ENCRYPTION,和网络上传输数据的完整
    性INTEGRITY。

    SSH特性概述
    1、远程登录
    $ ssh -l root host.example.com
    2、安全文件传输
    $ scp myfile metoo@secondacount.com
    3、安全执行远程命令,能确保传输的数据安全。
    4、密钥和代理
    基于密钥的认证方法不用记住多个帐号密码。
    5、访问控制,能授权别人访问自已帐号。
    6、端口转发
    $ ssh -L 3002:localhost:119 xxx.xxx.com

    相关安全技术
    rsh命令族,rsh,rlogin and rcp。连接不加密,认证模型十分脆弱。
    PGP加密程序。它是基于文件的。
    Kerberos认证系统,用于网络可能被监视,而且计算机不是中心控制的环境。基于麻省理工
    学院的Athena项目。它SSH不是,SSH是轻量级的,容易部署。Kerberos使用前必须构建
    一些重要基础。
    IPSEC,Internet安全协议。
    SRP,安全远程密码协议,是Stanford大学开发的。是一种专用的认证协议。
    SSL,安全套接字。
    stunnel,是一种SSL工具,它为UNIX环境现有的基于TCP的服务(POP,IMAP等)增加
    SSL保护,而不用修改服务器源程序。

    第二章 SSH客户端的基本用法
    最常用功能,1、经由安全连接登录到远程计算机。2、通过安全连接在计算机间拷贝文件。

    当你第一次连接SSH服务器时,出现问答时要回答“yes”,把已知名主机的密钥的公共部
    分拷贝一份存在本地。之后你每次连接这台服务器,就用这个公钥来验证远程主机。最好是
    能在首次连接前就能获得这个公钥,否则第一次连接服务器时你可能已受到中间人攻击。

    使用密钥进行认证,SSH支持公钥认证,可以使用加密密钥,密钥比密码更安全。
    SSH证书使用一对密钥,一个私钥,一个公钥,私钥只保存你独有的一些秘密信息。SSH
    用其向服务器证明自已的身份。公钥是公开的,可以随便将其放入SSH服务器上自已的帐
    号中,在认证时,进行私钥和公钥协商,如果匹配,那么身份就得以证明,认证就成功。

    在使用公钥认证以前,首先要进行一些设置:
    1、需要一对密钥,还需要使用一个口令来保护自已的私钥。
    使用ssh-keygen程序生成一对密钥。如果不存在SSH目录,程序为自动创建本地SSH目录
    ~/.ssh,并将所生成的密钥分成两个文件存储,公有部份identity.pub,私有部分identity,或
    id_dsa_1024_a,id_dsa_1024_a.pub(ssh2)。
    2、需要在SSH服务器上安装自已的公钥。
    通过配置SSH目录中的一个文件实现,对于SSH1 AND OPENSSH来说该文件是
    ~/.ssh/authorized_keys。对SSH2来说是~/.ssh2/authorization。OPENSSH中的SSH-2连接自
    3.0版本起也一同使用authorized_keys文件。3.0版本前的使用authorized_keys2。把用户本
    地机器生成identity.pub文件内容加入其中。对SSH2来说,用户需编辑两个文件,一个客
    户端一个在服务器端,
    在客户端,要创建或编辑文件~/.ssh2/identification并在其中插入一行,说明自已的私钥文件
    名: IdKey id_dsa_1024_a.
    在服务器端,要创建或编辑文件~/.ssh2/authorization,该文件包含有公钥信息,每行一个,
    但和SSH1的authorized_keys文件不同(authorized_keys中包含有公钥的拷贝),authorization
    中只给出公钥文件名:Key id_dsa_1024_a.pub。最后,把这个文件从本地机器上拷贝到服务
    器~/.ssh2中。为安全起见,要确保ssh目录的安全,只有所有者才有权写入。如果远程用户
    的SSH配置文件的权限设置不当,服务器可能会拒绝进行认证。

    公钥认证比密码认证更安全,因为:
    1、 公钥认证需要两个加密部份(磁盘上的identify文件和用户头脑中的口令),入侵都必须
    2、 具备两种条件才行。密码认证只需要一个部份,那就是密码,它可能更容易被窃取。
    3、 在公钥认证中,口令和密钥都不用发给远程主机,只要把前面讨论的认证者发给远程主
    4、 机就可以了,因此,并没有秘密信息传出客户端。
    3、机器生成的密钥是不可能猜测出来的,而人生成的密码容易受到字典攻击。
    通过禁用密码认证并只允许使用密钥认证能极大提高主机的安全性。

    如果要修改密钥
    如果已经生成一个密钥对,并把公钥拷贝到多个SSH服务器上了,用户有一天决定修改自
    已的身份,因为再运行ssh-keygen。这样,就会覆盖identify and identify.pub文件,用户之
    前的公钥就没用了,必须把新公钥再次拷贝到各个服务器上。这是很头疼的,所以建议:
    1、 不能局限于仅仅使用一个密钥对,可随意生一此密钥对,将其保存在不同的文件中,并
    2、 将其用作不同的用途。
    3、 如果只是想修改口令,就不必重新生成一个密钥对,ssh-keygen有一个命令行选项可以
    4、 替换现有的密钥口令。ssh1 and openssh是-p,对于ssh2是-e。这样,因为私钥没变,所以
    5、 公钥依然不效,中需使用新口令对私钥进行解密就可以了。

    ssh代理
    它可以把私钥保存在内存中,为认证提供服务,不用重复输入密码。直到用户退出为止。代
    理程序是ssh-agent。可手工运行也可编辑~/.login 或~/.xsession来自动运行。
    $ ssh-agent $SHELL 其中SHELL是用户登录shell的环境变量。运行该命令后,打开另外
    一个shell,在这个shell中可以访问代理。
    接着用ssh-add命令装入私钥。这样,使用ssh and scp命令就不用再提醒输入口令了。口令
    装入内存中。如果用户正运行x window系统,并设置了DISPLAY环境变量,而标准输入
    不是终端,那么ssh-add就使用一个图形化X程序ssh-askpass来读取口令。要强制ssh-add
    使用X来读取口令,请在命令行中输入ssh-add < /dev/null。
    -l 参数显示内存中的密钥
    -d 参数从代理中删除密钥 $ ssh-add -d ~/.ssh/id_xxx.pub
    -D 是删除所有密钥
    -t 对加载的密钥设置超时时间,超时代理将自动卸载密钥。
    -L -U 对代理进行加锁和解锁,当你离开计算机而不想退出登录时有用。


    代理转发
    可能通过代理转发功能,可以用SCP把文件从远程SSH服务器上拷贝到第三方SSH主机上。
    条件是你在第三方SSH主机上必须有一个帐号。具体操作是这样的:
    1、 在本地主机上运行命令:# scp pat@shell.isp.com:print-me
    2、 psmith@other.host.net:other-print-me
    2、这个scp进程与本地代理进行联系,并让用户和shell.isp.com进行认证。
    3、自动在shell.isp.com上执行第二个scp,用来把文件拷贝到other.host.net主机上。
    3、 由于启用了代理转发(SSH1 AND SSH2默认是打开的,openssh默认是关闭的),因此
    4、 shell.isp.com上的SSH服务器就充当一个代理。
    5、第二个scp进程通过联系shell.isp.com上的代理试图让用户和other.host.net进行认证。
    5、 shell.isp.net上ssh服务器秘密与用户的本地代理进行通信,从而构建出一个认证者来提
    6、 供用户的证书并将其传回服务器。
    7、服务器为第二个scp进程验证用户的身份,other.host.net上的认证获得成功。
    8、开始拷贝文件。
    由于代理转发不会把私钥发送到远程主机上,而是把认证返回第一台机进行处理,因此密钥
    是安全的。

    不用密码或口令进行连接方式
    1、使用代理的公钥认证。
    2、可信主机认证。
    3、Kerberos认证。
    在后文中将会讨论这些方式的优缺点。

    sftp
    它是在SSH上的一个独立文件传输工具,操作与ftp类似,可以在一个会话中调用多个命令
    进行文件拷贝和处理,而scp每次调用时都要打开一个会话。sftp不区分ascii and binary传
    输模式,只使用二进制模式,因此,如果使用它在windows and unix之间拷贝ascii文件,
    那么就不能正确转换行结束符。

    第三章 SSH内幕
    SSH协议的主要特性和优点:
    1、 使用强加密技术来保证数据的私密性。端到端通信用随机密钥进行加密,随机密钥为会
    话进行安全协商,会话结束后被丢弃。支持的算法有ARCFOUR,Blowfish,DES,IDEA,3DES等。
    2、通信完整性,确保通信不会被修改。SSH-2基于MD5 AND SHA-1的加密hash算法。
    3、认证,即发送者和接收者的身份证明。客户机和服务器双向认证。
    4、授权,即对账号进行访问控制。
    5、使用转发或隧道技术对其它基于tcp/ip的会话进行加密。支持三种转发,tcp端口转发,
    X转发,代理转发。

    SSH可以防止的攻击
    1、网络窃听,SSH通信是加密的,即使截获会话内容,也不能将其解密。
    2、名字服务和IP伪装,SSH通过加密验证服务器主机身份可避免这类风险。
    3、连接劫持,SSH的完整性检测负责确定会话在传输过程是否被修改,如果被修改过,就
    关闭连接。
    4、 中间人攻击,SSH利用两种方法防止这种攻击,第一种是服务器主机认证。除非攻击者
    已经成功攻击了服务器主机,获得服务器的私有主机密钥。第二种是限制使用容易受到
    这种攻击的认证方法,密码认证容易受到中间人攻击,而公钥和基于主机的/RhostsRSA
    则对中间人攻击可以免疫。
    5、插入攻击,这种攻击可以客户和服务器之间发送的正文数据流之间插入任意数据。ssh1
    1.2.25后和openssh的所有版本都专门进行了设计,来检测并防止这种攻击。这种检测程序
    增大了插入攻击的难度,但是并不能完全防止。ssh2使用强加密完整性检测手段来防止这个
    问题。可以用3DES算法来防止这种攻击。

    SSH不能防止的攻击
    1、 密码崩溃,密码认证是一种脆弱的认证形式,尽量使用公钥认证方式。如果必须要密码
    认证,可考虑使用S/Key之类的一次性密码机制。
    2、 IP AND TCP攻击,由于SSH是在TCP之上进行操作的,因此容易受到针对TCP和IP
    缺陷而发起的攻击。SYN flood,TCP不同步和TCP劫持等。只能通过更低层的防护措施
    来保护。
    3、流量分析。
    4、隐秘通道。
    5、粗心大意。安全是一个过程,而不是一个产品,不要认为装上SSH就安全了。

    第四章 SSH的安装和编译时配置

    第五章 服务器范围的配置
    sshd可以在三个层次上进行配置,第一层次是上面的安装和编译时配置;第二层次是本章的
    服务器范围配置;第三层次是每账号配置(第八章),前者是服务器编译时就指定了包含哪
    些特定功能,不包含哪些功能,后者则是由终端用户来修改自已账号所使用的服务器的行为。

    以普通用户身份运行SSH服务器
    1、得到管理员许可。
    2、生成一个主机密钥。
    $ ssh-keygen -N '' -b 1024 -f ~/myserver/hostkey 生成hostkey and hostkey.pub两个文件
    3、选择端口号。 要选择大于或等1024的端口,因为只有超级用户才有权使用小于
    1024的端口 。
    4、创建服务器配置文件(可选) 可创建自已的配置文件,否则,服务就使用内建的特性或使
    用服务器范围的配置文件。
    启动服务器方式:$ sshd -h ~/myserver/hostkey -p 2345 -f ~/myserver/config
    由普通用户运行的服务器有一些缺点:
    1、由于不是由root的uid下运行,因此只能连接到用户自已的账号上。
    2、它需手工调用,不能自启动。
    3、 日志用户没权看到,因为服务器把它写到syslog日志系统中,但可用调试模式运行服务
    4、 器,这样信息就显示在终端机上。

    服务器配置文件
    SSH1 AND OPENSSH的配置文件通常是/etc/sshd_config,而SSH2的配置文件通常是
    /etc/ssh2/sshd2_config。

    以非缺省的配置文件来调用sshd,可以使用命令 -f 选项。$ sshd -f /usr/local/ssh/my_config。

    以*号作为标号的语名都会被sshd忽略。

    修改完配置后,修改不会马上影响到服务器,可重启服务器或发送SIGHUP信号。$ kill -HUP
    `cat /etc/sshd.pid`

    如果在命令行改动了配置,用SIGHUP信号重启服务器不能覆盖命令行的配置,它的优先
    级高。

    主机密钥,sshd主机密钥向SSH客户端唯一地标识SSH服务器。主机密钥保存在一对文件
    中,一个文件包含私钥,一个文件包含公钥。对于SSH1 AND OPENSSH,它是
    /etc/ssh_host_key。文件位置可用HostKey关键字修改 HostKey /usr/local/ssh/key。服务器的
    公钥保存在.pub文件中。
    OPENSSH服务器有一个SSH-2的主机密钥,缺省是在/etc/ssh_host_dsa_key。其位置可用
    HostDsaKey /usr/local/openssh/key2修改。

    对于SSH2,如果服务器是由超级用户运行,缺省私钥文件是/etc/ssh2/hostkey。如果是其它
    用户运行,则在~/.ssh2/hostkey。可用HostKeyFile /etc/local/ssh/key修改。公钥是hostkey.pub
    文件,可用publicHostKeyFile关键字修改。

    可以用命令行选项指定私钥文件:$ sshd -h /usr/local/ssh/key。

    随机数种子文件
    如果用户的系统中有一个随机位源,如/dev/urandom,那么OPENSSH就不能创建随机数种
    子文件。

    服务器配置文件
    通常是/etc/sshd_config /etc/ssh2/ssh2_config,可以用-f 选项重新指定其配置文件。可用于一
    台机器运行多个sshd的情况。

    每账号认证文件。~/.ssh/authorized_keys 。


    文件权限
    由于配置文件的权限设置错误,会降低系统的安全性,所以可以设置StrictModes YES/NO
    关键字,对sshd的重要文件和目录的权限进行检查,如果检查失败,服务器就拒绝对该用
    户的SSH连接。

    在多宿主主机上,使用ListenAddress xxx.xxx.xxx.xxx来限制SSH只监听一个网络接口。

    空闲连接时间,IdleTimeout xx 如果是0代表什么都不做,保持连接。否则,超时就断开连
    接,可以用s,m,h,d,w表示。

    KeepAlive YES/NO 可以断开失效的连接,比如客户端崩溃。

    失败的登录
    LogingGraceTime 60 限定用户必须在60秒内成功进行认证。 0值表禁用。命令行选项用
    -g

    PasswordGuesses 5 如果连接请求使用密码认证,那么sshd2就只允许客户端尝试五次。
    (SSH2)

    限制并发连接
    MaxConnections 32 最大32个连接(SSH2)

    逆向IP映射
    SSH2服务器可以根据客户端地址进行逆向DNS查询,以确保客户端的地址就是这个地址。
    如果检查失败,连接拒绝。
    RequireReverseMapping yes (ssh2)

    转发
    AllowTcp-Forwarding yes
    X11Forwarding yes

    服务器密钥生成
    该密钥用来对客户端/服务器之间的通信进行保护。是临时的,永远不会保存在磁盘上。服
    务器在启动时生成这个密钥。并以固定的周期重新生成。缺省长度是768位,最小为512,
    可以ServerKeyBits 2048 指定长度。用KeyRegenerationInterval 1200指定周期。 命令行选
    项:-k

    加密算法
    Ciphers any 允许所有支持算法。其它算法包括
    3des-cbc,blowfish-cbc,twofish-cbc,arcfour,none

    mac算法
    MAC关键字可以让用户选择sshd2进行完整性检测所使用的算法,称为消息认证代码。用
    于sshd2的有hmac-sha1,hmac-md5,hmac-md5-96。

    在OPENSSH中,用户可以用Protocol关键字选择支持SSH-1 AND SSH-2,1 代表SSH-1,2 代
    表SSH-2, 1,2 代表都支持。

    允许用户登录:认证和访问控制
    1、认证负责对发起连接请求的用户的身份进行验证。
    密码认证
    PasswordAuthentication yes AllowedAuthentications password (ssh2)
    公钥认证
    RSAAuthentication yes (ssh1,openssh/1)
    AllowedAuthentications publickey (ssh2)
    DEAAuthentication yes (openssh/2)
    Rhosts认证,可信主机认证通过检查远程主机名和相关用户名来实现对客户端的身份认证。
    RhostsAuthentication yes (ssh1,openssh)
    IgnoreRhosts yes (ssh1,ssh2,openssh)不使用系统的hosts.equiv and ~/.rhosts,使用SSH专用
    的/etc/shosts.equiv and ~/.shosts
    强可信主机认证。
    RhostsRSAAuthentication yes ssh1,openssh
    AllowedAuthentications hostbased ssh2
    提取已知名主机的公钥
    UserKnownHosts no ssh2
    IgnoreUserKnownHosts yes openssh
    PGP认证
    Kerberos认证
    S/key认证
    SecurID认证
    PAM认证

    2、访问控制负责允许或禁止来自特定用户、机器在或INTERNET域的SSH连接到服务器
    上。
    通常,只要设置正确,任何账号都可以接收SSH连接,这种访问权限可以使用服务器关键
    字AllowUsers and DenyUsers覆盖。
    AllowUsers smith
    如果配置文件中单独出现一个AllowUsers,后面没有任何内容,就表示禁止所有没提到的用
    户连接,如果没有AllowUsers这个关键字,则所有用户都可连接。DenyUsers表示禁止连接。
    可用通配符,

    可以用组访问控制AllowGroups DenyGroups

    主机名访问控制
    AllowHosts hostname
    DenyHosts hostname

    超级用户的访问控制
    sshd对超级用户专门使用一种特殊的访问机制,PermiRootLogin来允许或禁止使用SSH来
    访问root账号。

    显示用户的欢迎信息
    PrintMotd yes/no default is yes

    显示邮件信息
    CheckMail yes/no default is yes

    空密码
    PermitEmptyPasswords yes/no 如果使用密码认证,并且有个账号没有设定密码,那么服务
    器就可以拒绝访问这个账号

    如果系统中存在/etc/nologin,那么sshd就只允许root用户登录,其它都不能登录。因此,touch
    /etc/nologin是把访问权只授给系统管理员的一种快速方法。这样并不需要重新配置ssh。也
    不需要重启ssh。

    子系统
    定义和调用远程命令的一个抽象层,用户可以通过在客户端命令行中给出命令来调用远程命
    令,如:ssh server.examply.com /bin/tar c /home 这个命令调用tar,远程把/home拷贝到磁带上。
    子系统是服务器机器上预定义的一组远程命令,这样就可以方便地执行。在服务器配置文档
    中定义:subsystem backups /bin/tar c /home,要在服务器上运行该命令,可以使用 -s 选项。
    ssh -s backups server.example.com。缺省情况下,sshd_config中定义了一个子系统,subsystem
    sftp 。不要删除这个子系统,这是scp2和sftp必须的。

    日志
    Fascisl Logging mode 把调试信息打印到系统日志文件中,可以使用FascistLogging关键字
    启用。
    调试模式 可以使用-d命令选项启用
    安静模式 只能输出严重错误,而不能输出 普通日志,可以使用QuietMode关键字或-q
    命令行启用。
    openssh中的日志配置关键字是SyslogFacility and LogLevel。SyslogFacility设置syslog的
    facility(KERN,DAEMON,USER,AUTH,MAIL等),LogLevel记录日志提供的详细程度,该
    值从低到高顺序是:QUIET,FATAL,ERROR,INFO,VERBOSE,DEBUG,使用DEBUG会侵犯用
    户的隐私权,这个级别只能用于诊断,而不能用于普通操作。


    第六章 密钥管理与代理
    一个身份标识由两部份组成,分别称为私钥(Private Key)和公钥(Public Key),合称一个
    密钥对。

    SSH1,SSH2 AND OPENSSH身份标识文件的格式各不相同。
    SSH1缺省设置中,私钥存储在文件identity中,公钥存储在文件identity.pub中。这个密钥
    对存放在~/.ssh目录下,在使用前,把公钥拷贝到服务器上的一个认证文件里,如SSH1 AND
    OPENSSH中的~/.ssh/authorized_keys,此后,当客户请求连接到你的服务器上的帐号时,就
    会用一个私钥作为证明身份的标识,服务器则在authorized_keys文件中寻找与之匹配的公
    钥。

    SSH2密钥对文件的命名通常是根据该密钥使用的加密算法的性质来起的,例如一个用DSA
    加密的1024位密钥生成时其缺省文件名是id_dsa_1024_a and id_dsa_1024_a.pub。用户必须
    把私钥放在identification文件中,缺省是~/.ssh2/目录,一个私钥在这个文件中占一行,在公
    钥认证中,每一行的开头都有一个关键字IdKey,后跟一个私钥文件名。如:
    IdKey id_dsa_1024_a
    IdKey my-other-ssh2-key
    在服务器端的认证文件~/.ssh2/authorization中,SSH2不包含公钥的实际拷贝,只是把公钥
    文件列出来,前面用关键字kEY标识。如:
    Key id_dsa_1024_a.pub
    Key something-else.pub
    这样维护起来更容易,更方便。

    OPENSSH对SSH-1连接使用的标识和授权文件与SSH1完全相同,对于SSH-2连接,缺省
    的密钥则存储在~/.ssh/id_dsa(private key)和~/.ssh/id_dsa.pub(public key)中,服务器上的授权
    文件是~/.ssh/authorized_keys。

    创建身份标识用ssh-keygen命令。

    OPENSSH的ssh-keygen可以支持SSH1中相应程序的所有功能和选项,它还新增了为SSH-2
    连接生成DSA密钥的能力。
    $ ssh-keygen -t dsa -b 1024
    -e -x 选项可把OPENSSH格式的密钥存储格式转换成SSH2格式 (直接回车,按提示输入转
    换文件名)
    -i -X 选项把SSH2格式的密钥转换成OPENSSH格式。这样可用SSH2客户端连接
    OPENSSH服务器。(直接回车,按提示输入转换文件名)
    -y 如果不小心删掉了OPENSSH的公钥,可用-y恢复。
    -l 可计算出公钥的指纹,指纹是鉴别位置不同的两个密钥是否相同的常用的一种密码学技
    术。这项技术用于不可能逐位对比两个密钥的情况。OPENSSH AND SSH2都能计算指纹。
    它是根据密钥计算出来一个长度较短的值,它是原理与校验和类似,用于验证一串信息(在
    我们的例子中是密钥)的不可替换性。

    启动代理
    1、单shell方式,使用当前登录的shell. $ eval `ssh-agent`
    2、子shell方式,派生出一个子shell,并继承父shell的某些环境变量。 $ ssh-agent $SHELL
    不要想当然运行 $ ssh-agent,这样客户端是无法有代理联系的。删除代理用kill命令就可以
    了。

    SSH-1 与 SSH-2代理的兼容性
    SSH-1的代理不能处理SSH-2的代理,SSH-2的代理却可以处理SSH-1的代理请求。

    第七章 客户端的高级用法
    $ ssh -a -p 220 -c blowfish -l sally -i myself server.example.com 可通过配置文件简化命令
    输入

    Host myserver
    ForwardAgent no
    Port 220
    Cipher blowfish
    User sally
    IdentifyFile myself
    HostName server.example.com
    配置了该文件后,就可以在客户端简单地输入
    $ ssh myserver

    全局文件和本地文件
    全局文件通常是由管理员创建的,用来维护整台计算机上的客户行为。该文件通常位于
    /etc/ssh_config or /etc/ssh2/ssh2_config。每个客户也可以在自已账号中创建本地客户配置文
    件,通常是~/.ssh/config or ~/.ssh2/ssh2_config。本地配置文件优先级高于全局配置文件。命
    令行选项的优先级又高于本地配置文件。

    scp有关命令参数
    -r 递归拷贝目录
    -p 保持文件权限和时间戳
    -u 拷贝完成后删除源文件
    -d 防止覆盖文件
    -n 描述操作
    -q 不显示统计信息


    第八章 每账号服务器配置
    这种配置可以让SSH服务器区分每个服务器上的各个用户。利用服务器目标账号的认证文
    件(authorized_keys)配置。局限有两点,它不能覆盖编译时配置和服务器范围配置所采用
    的安全措施,第二,如果使用公钥认证,每账号配置是十分灵活的,如果采用可信主机和密
    码认证,提供的选择范围就很小。

    基于公钥的配置
    1、认证文件的完全格式 依次包含三项内容,一些选项,公钥和注释。多个选项用逗号分
    开。
    2、用于限制客户端可以在服务器上调用的程序的强制命令。如客户端请求执行/bin/ls命令,
    而服务器端强制命令却运行/bin/who命令,它十分有用,可用于加强安全性,了为授权提供
    方便。如要让你的助手每次连接上来都运行email命令程序pine,则可以这样:
    command= "/usr/local/bin/pine" ...key...。最多可给每个密钥关联一个强制命令,要关联多个命
    令可把这些命令放入远程主机的一个脚本中,并将该脚本作为强制命令运行。如果强制命令
    有shell出口,那会存在安全问题,等于没有强制,客户可以运行任何程序。以下规则可以
    用来判断一个程序是否适合用作强制命令。
    a、 避免使用具有shell出口的程序(如:文件编辑器vi,Emacs; 分页程序 more,less;调用分
    b、 页的man,新闻阅读程序rn,邮件阅读程序pine以及调试程序adb,非交互的程序find,xargs
    c、 等)。
    b、避免使用编译器,解释器或其它可以让用户生成并运行任意执行代码的程序。
    c、可创建或删除文件的程序,如cp,mv,rm,scp,ftp等。
    d、避免使用setuid or setgid的程序,特别是setuid 是root的程序。
    d、 如果使用脚本作为强制命令,就要遵循编写安全脚本的传统规则,在一个脚本之内,要
    限制使用相对路径作为搜索路径,应该使用绝对路径来调用所有的程序;不要盲目地把
    用户提供的字符串作为命令来执行;不要让脚本执行任何setuid的工作。不要调用具有
    shell出口的程序。
    e、考虑使用受限shell。
    f. 为一个单独的、专用的SSH密钥(不要用你登录的那个密钥)关联一个强制命令。这样
    不会影响你的登录能力就可以方便地禁用该密钥。
    g、禁用不必要的SSH特性。如no-port-forwarding,no-agent-forwarding,no-pty(禁用tty分配)。
    几个常用的强制命令介绍:
    使用定制消息拒绝连接:command="/bin/echo Sorry,buddy,but you've terminated!" ...key... 千万
    不要用more and less之类的分页程序
    显示命令菜单:利用脚本
    检查客户端的原始程序:command="/bin/echo you tried to invoke
    $SSH_ORIGINAL_COMMAND" ...key... $SSH_ORIGINAL_COMMAND环境变量保存着
    客户连接时运行的原始命令。
    限制客户端的原始命令,创建一个脚本,该脚本根据$SSH_ORIGINAL_COMMAND内容选
    择不同的操作。
    把客户端的原始命令记录在日志中:也是根据$SSH_ORIGINAL_COMMAND变量来做的一
    个脚本。脚本内容如一:
    #!/bin/sh
    if [ -n "$SSH_ORIGINAL_COMMAND" ]
    then
    echo "`/bin/date`: $SSH_ORIGINAL_COMMAND" >> $HOME/ssh-command-log
    exec $SSH_ORIGINAL_COMMAND
    fi

    3、限制来自特定主机的连接。由from选项完成。from="client.example.com" ...key...。强制
    连接必须来自client.example.com。否则断开。from="!client.example.com" ...key...表示拒绝该
    地址的连接。支持通配符。SSH2不支持该功能。但可以通过$SSH2_CLIENT变量提取客户
    ip,编写强制命令脚本达到同样效果。
    4、为远程程序设置环境变量。environment="EDITOR=emacs" ...key...,为每个连接修改默认的
    环境变量。
    5、设置空闲超时时间,这样如果客户端用户不再发送数据就强制将其断开。idle-timeout=5m,
    该选项会覆盖服务器范围配置。
    6、对到达的SSH连接禁用某些特性,例如端口转发和tty分配。禁用tty分配会使客户端没
    有交互会话的能力。$SSH_TTY变量可显示tty情况。

    用户的rc文件
    ssh服务器会在每个连接到达时调用shell脚本/etc/sshrc,用户可把一些登录后想运行的脚本
    写到这个文件中。用户可以在自已的目录下定义类似的脚本,如果有自定义的~/.ssh/rc则
    /etc/sshrc则不会执行。

    第九章 端口转发与X转发
    使用SSH对其它应用程序在别的TCP端口上建立的TCP/IP传输进行加密和解密,这一过
    程称为端口转发,其绝大多数操作都是透明的,功能非常强大。TELNET,SMTP,NNTP,IMAP
    和一些基于TCP的不安全协议都可变得安全,只要将其连接通过SSH转发即可。端口转发
    有时又叫做隧道传输。
    例子:一个运行IMAP的服务器S,在家里的主机H上运行一个email程序,现在想用ssh
    保护IMAP连接。
    $ ssh -L2001:localhost:143 S
    -L 表明是本地转发,,上面这命令可完成登录到S的功能,现在的这个SSH会话同时将H
    的2001端口转发到S的143端口,在退出会话之前一直有效。并告知email程序使用被转
    发的端口,通常邮件程序连接服务器的143端口,即套接字 (S,143)。现在要令其连接
    本地主机H自已的2001端口,也就是套接字(localhost,2001)。创建本地转发时可以不用-L
    选项,而在客户端配置文件中用LocalForward关键字。
    LocalForward 2001 localhost:143 ssh1 openssh
    LocalForward "2001:localhost:143" ssh2

    -g 选项和GatewayPorts yes/no关键字可以配置除本地主机外的机器是否能使用本地的端口
    转发功能。出于安全问题,该禁止这个功能。

    远程转发端口与本地转发几乎完全相同,只是方向相反。此时服务器在本地,转发连接由远
    程主机发起。假设你已登录进服务器S。则
    $ ssh -R2001:localhost:143 H
    -R代表远程转发。命令执行后,一条从远程主机H的2001端口到服务器S的143端口的安
    全隧道就建立起来了。H上的任何程序都可以通过连接(localhost,2001)来使用此安全隧道。
    而在客户端配置文件中用RemoteForward关键字.
    RemoteForward 2001 S:143 ssh openssh
    RemoteForward "2001:S:143" ssh2

    $ ssh -o ClearAllForwardings=yes server.example.com 阻止第二条命令建立隧道

    本地转发与远程转发
    在本地转发中,应用程序客户端与监听端同SSH客户端在一起,应用程序服务器与连接端
    同SSH服务器在一起。
    在远程转发中,应用程序客户端与监听端同SSH服务器在一起,应用程序服务器与连接端
    同SSH客户端在一起。

    无远程登录的端口转发,连接时带-f参数。一次性转发用-fo,ssh1与openssh不支持这个功
    能,但可用以下语句实现:
    $ ssh -f -L2001:localhost:143 server sleep 10

    终止
    如果一个SSH会话现在还在活动当中,终止会出错。在SSH2中,如果退出有活动转发连
    接的会话,该会话会依然打开,但会转到后台运行。直到转发连接终止。ssh1 and openssh
    与此相反,如果要断开还在活动的会话,会出现警告,仍然在前台运行。

    TIME_WAIT问题。在某些情况下,TCP连接断连时,其一端的套接字在很短一段时间内变
    得不可用,所以在断连过程结束前不能把该端口用于TCP转发。






    第十章 推荐配置
    服务器范围配置
    1、禁用其它访问方式。
    关掉r-命令,方法如下:删除/etc/hosts.equiv文件,或改为只读空文件。禁用rshd,rlogind and
    rexecd,通过修改inetd.conf文件。
    2、/etc/sshd_config配置
    HostKey /etc/ssh_host_key
    PidFile /etc/sshd.pid
    RandomSeed /etc/ssh_random_seed

    StrictModes yes 要求用户保护其与SSH有关的文件及目录
    Umask 0077 保证所有SSHD1创建是文件和目录都只能由其所有者(SSHD 运行的
    UID)读取

    port 22
    ListenAddress 0.0.0.0
    IdleTimeout 15m 15分钟空闲超时
    KeepAlive yes 客户机死机时连接将会终止,而不会长期挂起。

    LoginGraceTime 30 登录时成功认证的时限为30秒。

    ServerKeyBits 768 服务器密钥长度
    KeyRegenerationInterval 3600 服务器密钥一小时重新生成一次

    PasswordAuthentication no 禁用密码认证
    RhostsAuthentication no 禁用可信主机认证
    RhostsRSAAuthentication no 禁用增强可信主机认证
    RSAAuthentication yes 启用公钥认证

    IgnoreRhosts yes 完全禁止SSHD使用.rhosts文件
    IgnoreRootRhosts yes

    UseLogin no 禁用UseLogin,防止万一使用了其它登录程序

    AllowHosts xxx 根据需要设置
    SilentDeny yes 任何被DenyHosts拒绝的连接都不会向用户返回消息,不必告诉攻击
    者发生了什么,可以增加了排错的难度。

    PermitRootLogin nopwd 允许超级用户通过SSH连接,但不能用密码认证

    FascistLogging no 禁用FascistLogging日志方式,因为它会在日志中记录用户特定信息,对
    攻击者有用。
    QuietMode no 禁用QuietMode日志方式,使用日志更详细,敏感度更低

    AllowTcpForwarding yes 允许tcp端口转发和X转发,保护其它的tcp连接
    X11Forwarding yes

    3、/etc/ssh2/sshd2_config配置
    HostKeyFile /etc/ssh2/hostkey
    PublicHostKeyFile /etc/ssh2/hostkey.pub
    RandmoSeedFile /etc/ssh2/random_seed

    UserConfigDirectory
    IdentityFile
    AuthorizstionFile

    StrictModes yes

    port 22
    listenAddress 0.0.0.0
    KeepAlive yes
    RequireReverseMapping no

    LoginGraceTime 30

    由于sshd2没有设置服务器密钥的位数的关键字,用户得在启动时使用 -b 选项 $ sshd2 -b
    1024 ....

    AllowedAuthentications publickey
    RequiredAuthentications publickey

    IgnoreRhosts yes
    UserKnownHosts no 禁用该项可防止用户给未知主机提供信任权限。

    PermitRootLogin nopwd


    Ciphers any 不能选none


    QuietMode no
    VerboseMode yes

    Ssh1Compatibility no 禁用SSH-1兼容模式
    #Ssh1Path /usr/local/ssh1/sshd1 出于实用原因,也可以启用此模式,之前要指明ssh1服
    务器可执行文件位置

    4、每账号配置
    对于SSH1 AND OPENSSH,~/.ssh/authorized_keys中的每一个密钥都必须用适当的选项进
    行限制,from选项限制只能从特定的主机访问特定的密钥。例如,假设文件中包含你家那
    台pc(myhome.isp.net)的公钥,而其它机器根本不可能用那个密钥来认证,我们就可以明确
    限定这一关系:from = "myhome.isp.net" ...key...。还要对适当的密钥设置空闲超时时间:from
    = "myhome.isp.net" ,idle-timeout=5m ...key...。
    最后,考虑每一个密钥是否需要对到达的连接使用端口转发,代理转发以及分配tty等,如
    果不需要,就可以分别用no-port-forwarding,no-agent-forwarding and no-pty禁用这些特性。

    5、密钥管理
    至少创建1024位长的用户密钥,并用好的口令对密钥进行保护。

    6、客户端配置
    离开正在运行的ssh客户端时,一定要用密码保护。
    在客户端配置文件中启用某些安全功能,并将其设置为最强
    Host *
    FallBackToRsh no 禁止使用不安全的r-命令(ssh2)没有这个问题。
    UseRsh no
    GatewayPorts no 禁止远程客户端连接本地的转发端口
    StrictHostKeyChecking ask 在主机密钥发生变化时提醒你。请求你的处理意见。
    配置“/etc/ssh/ssh_config”文件 
    “/etc/ssh/ssh_config”文件是OpenSSH系统范围的配置文件,允许你通过设置不同的选项
    来改变客户端程序的运行方式。这个文件的每一行包含“关键词-值”的匹配,其中“关键
    词”是忽略大小写的。下面列出来的是最重要的关键词,用man命令查看帮助页(ssh (1))
    可以得到详细的列表。 

    编辑“ssh_config”文件(vi /etc/ssh/ssh_config),添加或改变下面的参数: 

    # Site-wide defaults for various options 
    Host * 
    ForwardAgent no 
    ForwardX11 no 
    RhostsAuthentication no 
    RhostsRSAAuthentication no 
    RSAAuthentication yes 
    PasswordAuthentication yes 
    FallBackToRsh no 
    UseRsh no 
    BatchMode no 
    CheckHostIP yes 
    StrictHostKeyChecking no 
    IdentityFile ~/.ssh/identity 
    Port 22 
    Cipher blowfish 
    EscapeChar ~ 

    下面逐行说明上面的选项设置: 

    Host * 
    选项“Host”只对能够匹配后面字串的计算机有效。“*”表示所有的计算机。 

    ForwardAgent no 
    “ForwardAgent”设置连接是否经过验证代理(如果存在)转发给远程计算机。 

    ForwardX11 no 
    “ForwardX11”设置X11连接是否被自动重定向到安全的通道和显示集(DISPLAY set)。 

    RhostsAuthentication no 
    “RhostsAuthentication”设置是否使用基于rhosts的安全验证。 

    RhostsRSAAuthentication no 
    “RhostsRSAAuthentication”设置是否使用用RSA算法的基于rhosts的安全验证。 

    RSAAuthentication yes 
    “RSAAuthentication”设置是否使用RSA算法进行安全验证。 

    PasswordAuthentication yes 
    “PasswordAuthentication”设置是否使用口令验证。 

    FallBackToRsh no 
    “FallBackToRsh”设置如果用ssh连接出现错误是否自动使用rsh。 

    UseRsh no 
    “UseRsh”设置是否在这台计算机上使用“rlogin/rsh”。 

    BatchMode no 
    “BatchMode”如果设为“yes”,passphrase/password(交互式输入口令)的提示将被禁止。
    当不能交互式输入口令的时候,这个选项对脚本文件和批处理任务十分有用。 

    CheckHostIP yes 

    “CheckHostIP”设置ssh是否查看连接到服务器的主机的IP地址以防止DNS欺骗。建议设
    置为“yes”。 

    StrictHostKeyChecking no 
    “StrictHostKeyChecking”如果设置成“yes”,ssh就不会自动把计算机的密匙加入
    “$HOME/.ssh/known_hosts”文件,并且一旦计算机的密匙发生了变化,就拒绝连接。 

    IdentityFile ~/.ssh/identity 
    “IdentityFile”设置从哪个文件读取用户的RSA安全验证标识。 

    Port 22 
    “Port”设置连接到远程主机的端口。 

    Cipher blowfish 
    “Cipher”设置加密用的密码。 

    EscapeChar ~ 
    “EscapeChar”设置escape字符。 

    配置“/etc/ssh/sshd_config”文件 
    “/etc/ssh/sshd_config”是OpenSSH的配置文件,允许设置选项改变这个daemon的运行。
    这个文件的每一行包含“关键词-值”的匹配,其中“关键词”是忽略大小写的。下面列出
    来的是最重要的关键词,用man命令查看帮助页(sshd (8))可以得到详细的列表。 

    编辑“sshd_config”文件(vi /etc/ssh/sshd_config),加入或改变下面的参数: 

    # This is ssh server systemwide configuration file. 
    Port 22 
    ListenAddress 192.168.1.1 
    HostKey /etc/ssh/ssh_host_key 
    ServerKeyBits 1024 
    LoginGraceTime 600 
    KeyRegenerationInterval 3600 
    PermitRootLogin no 
    IgnoreRhosts yes 
    IgnoreUserKnownHosts yes 
    StrictModes yes 
    X11Forwarding no 
    PrintMotd yes 
    SyslogFacility AUTH 
    LogLevel INFO 
    RhostsAuthentication no 
    RhostsRSAAuthentication no 
    RSAAuthentication yes 
    PasswordAuthentication yes 
    PermitEmptyPasswords no 
    AllowUsers admin 

    下面逐行说明上面的选项设置: 

    Port 22 
    “Port”设置sshd监听的端口号。 

    ListenAddress 192.168.1.1 
    “ListenAddress”设置sshd服务器绑定的IP地址。 

    HostKey /etc/ssh/ssh_host_key 

    “HostKey”设置包含计算机私人密匙的文件。 

    ServerKeyBits 1024 
    “ServerKeyBits”定义服务器密匙的位数。 

    LoginGraceTime 600 
    “LoginGraceTime”设置如果用户不能成功登录,在切断连接之前服务器需要等待的时间(以
    秒为单位)。 

    KeyRegenerationInterval 3600 
    “KeyRegenerationInterval”设置在多少秒之后自动重新生成服务器的密匙(如果使用密匙)。
    重新生成密匙是为了防止用盗用的密匙解密被截获的信息。 

    PermitRootLogin no 
    “PermitRootLogin”设置root能不能用ssh登录。这个选项一定不要设成“yes”。 

    IgnoreRhosts yes 
    “IgnoreRhosts”设置验证的时候是否使用“rhosts”和“shosts”文件。 

    IgnoreUserKnownHosts yes 
    “IgnoreUserKnownHosts”设置ssh daemon是否在进行RhostsRSAAuthentication安全验证
    的时候忽略用户的“$HOME/.ssh/known_hosts” 

    StrictModes yes 
    “StrictModes”设置ssh在接收登录请求之前是否检查用户家目录和rhosts文件的权限和所
    有权。这通常是必要的,因为新手经常会把自己的目录和文件设成任何人都有写权限。 

    X11Forwarding no 
    “X11Forwarding”设置是否允许X11转发。 

    PrintMotd yes 
    “PrintMotd”设置sshd是否在用户登录的时候显示“/etc/motd”中的信息。 

    SyslogFacility AUTH 
    “SyslogFacility”设置在记录来自sshd的消息的时候,是否给出“facility code”。 

    LogLevel INFO 
    “LogLevel”设置记录sshd日志消息的层次。INFO是一个好的选择。查看sshd的man帮
    助页,已获取更多的信息。 

    RhostsAuthentication no 
    “RhostsAuthentication”设置只用rhosts或“/etc/hosts.equiv”进行安全验证是否已经足够了。 

    RhostsRSAAuthentication no 
    “RhostsRSA”设置是否允许用rhosts或“/etc/hosts.equiv”加上RSA进行安全验证。 

    RSAAuthentication yes 
    “RSAAuthentication”设置是否允许只有RSA安全验证。 

    PasswordAuthentication yes 
    “PasswordAuthentication”设置是否允许口令验证。 

    PermitEmptyPasswords no 
    “PermitEmptyPasswords”设置是否允许用口令为空的帐号登录。 

    AllowUsers admin 
    “AllowUsers”的后面可以跟着任意的数量的用户名的匹配串(patterns)或user@host这样
    的匹配串,这些字符串用空格隔开。主机名可以是DNS名或IP地址。 

       

    posted @ 2005-11-15 11:37 幽灵狼 阅读(367) | 评论 (0)编辑 收藏

     

    ANSI Escape Sequence

    Clear Display

    Function ESC Sequence Description 
    Clear Screen ESC[2J Clear the whole screen and position the cursor to the top left corner. 
    Clear Line ESC[K Clear line, from cursor position to the right most position of line. 

    Cursor Movement

    Function ESC Sequence Description 
    Move Up ESC[numA Move the cursor up num positions 
    Move Down ESC[numB Move the cursor down num positions 
    Move Right ESC[numC Move the cursor right num positions 
    Move Left ESC[numD Move the cursor left num positions 
    Move to Position ESC[row;colH Move the cursor to the (col, row) position. Note that the row comes before column; that is, y comes before x. Either col or row can be omitted. Row and column both start with "1," not zero. (1, 1) corresponds to the top-left corner of the screen. 
    Move to Position ESC[row;colf Same as above. 

    Save and Restore Cursor Position

    Function ESC Sequence Description 
    Save Cursor Positon ESC[s Save the cursor position for later restoration. 
    Restore Cursor Positon ESC[u Restore the cursor position previously saved. 

    Character Mode

    Function ESC Sequence Description 
    Change Character Mode ESC[attrm Change the character mode with attribute attr. The attributes are numbers listed below. 
    Change Character Mode ESC[attr;...;attrm Change the character mode with attributes attr;...;attr. The attributes are numbers listed below. 
    All Off 0 All attributes turned off. (Except for foreground and background color). 
    High Intensity 1 Bold. 
    Low Intensity 2 Normal. 
    Italic 3 Work only on some systems. 
    Underline 4 Underline font. 
    Blink 5 Blinking font. 
    Rapid Blink 6 Works only on some systems. 
    Reverse Video 7 Swapping the foreground color and the background color. 
    Invisible 8 Do not display characters. 
    Foreground Color 30 Black. 
    Foreground Color 31 Red. 
    Foreground Color 32 Green. 
    Foreground Color 33 Yellow. 
    Foreground Color 34 Blue. 
    Foreground Color 35 Magenta. 
    Foreground Color 36 Cyan. 
    Foreground Color 37 White. 
    Background Color 40 Black. 
    Background Color 41 Red. 
    Background Color 42 Green. 
    Background Color 43 Yellow. 
    Background Color 44 Blue. 
    Background Color 45 Magenta. 
    Background Color 46 Cyan. 
    Background Color 47 White. 

    thanks to Kenneth Kin Lum.

    posted @ 2005-11-15 11:37 幽灵狼 阅读(551) | 评论 (0)编辑 收藏

    仅列出标题
    共4页: 1 2 3 4