Coding Poet, Coding Science

Keep Stupid, Keep Hungry


  • 归档

  • 分类

  • 标签

  • 资源

  • 关于

  • 搜索
  • 简体中文
  • English (US)
close
Coding Poet, Coding Science

LaTeX的编程原理

发表于 2013-06-20 | 更新于 2016-12-14 | 分类于 出版 , TeX |

第二节 书籍排版与普通排版

%%% 这部分实际上是介绍tex的输入与词法规则,算是编程基础

当使用计算机排版,我们首先要知道传统排版与使用计算机输入字符的区别。本来计算机上面的字符并不是专门为了排版而设计的。为了使用现有的计算机键盘输入TeX的源文件,我们需要对原来的键盘符号进行一个重新定义。

单引号,双引号

键盘上,左单引号与右单引号是区分开来的。一个是好像重音符号的东西,另一个就是普通的单号号。但是直接键入的时候,TeX将这个符号理解成左单引号。显然我们不能使用ASCII上的双引号排版双此号,因为那样无法区分左右。所以两个连在一起的左单引号代表左双引号,而两个连在一起的右单引号代表右双引号。

阅读全文 »
Coding Poet, Coding Science

TeX与LaTeX的编组

发表于 2013-06-20 | 更新于 2016-12-15 |

编组

编组可以理解成计算机编程中的模块结构。编组发生作用是在编程语言层次上的,也就是每经过一个编组,编译器就回复到编组之前的正常规则。

ex5.1 得到ff不连在一起的shelfful.

方法是输入shelf{ful}.也就是在f中间加上一个编组。

ex5.2 不用转义的空格,怎样在一排中得到三个空格。

使用{ }{ }{ }吧。或者{ } { },注意编组后面的空格不会被自动忽略。

为了使控制序列作用在特定的文本上,我们也使用\centerline{}这样的结构。

虽然编组的功能很强大,但是也容易使文档变得难读。幸好在普通文稿当中不必使用太多的编组。

括号的作用有多个,一个是把多个单词看成一个结构,另一种是提供了一个局部模块结构。不应当认为大括号仅有一个作用。

ex5.3 键入下列内容会得到什么结果?

\centerline{This information should be {centered}.}
\centerline So should this.

它的结果是,第一条命令产生一个居中的文本块,但是第二行将只有一个单词S。第三行变成了一o开头。

注意第二行不是一个单词,因为TeX控制系列默认将后面的一个字母而不是单词视为一个单独的参数。

ex5.5 定义一个控制系列\ital,使得用户键入\ital{text}来代替{\it text\/}.与\it相比它有什么优缺点。

显然使用\def\ital#1{ {\it #1\/} }它的不足只是放在后面,并且总是有一个斜体校正,它的所有的特点都跟它的封装形式有关。

TeX的宏定义与m4差不多,过多的括号里面,只有最外层的被去掉,内层的括号得到了保留。

TeX的参数的处理

与C语言不同,在编组当中改变即使是全局变量,当走出编组的时候全局变量也会恢复成原来的样子(这有一点像是有硬堆栈变量的计算机)。使用\global命令可以做到这一点。比如将计数器加一的操作,显然通过普通方法是不行的,在块里面需要使用

\global\advance\count0 by 1

其中的advance表示对指定的计数器加上特定的值。\count0是TeX内部的一个计数器。

分组

另一个分组的命令是\begingroup{GRPNAME}...\endgroup{GRPNAME}.

这个可以看成是LaTeX环境的基础。如果使组正常工作,那么我们就应当避免Sa,Sb,Ea,Eb这样的情况,方法其实很简单,在Sa的时候定义一个\blockname{}名子与本环境的名子相同,Sb也同样这种做法。这样在Ea的时候,Sb定义的blockname就会消失,在读到Eb的时候检查一下b有没有被定义就可以了。

\def\beginthe#1{\begingroup\def\blockname{ #1}}
\def\endthe#1{\def\test{ #1}%
\ifx\test\blockname\endgroup
\else\errmessage{You should have said
\string\endthe{\blockname}}\fi}

(具名编组的概念,有些像是Pascal语言的end for语句之类的扩展)。

从外壳中键入tex命令,出现双星号提示符,要求输入文件名,这个时候我们可以代之以输入\relax命令,进入到一个星号的状态。之后就进入排版了。

在输入完成内容后,键入\end可以结束会话,TeX会把文件输出到当前目录里面。

在第一篇TeX当中,可能\hskip, \vskip 以及后面的\hrule 我们比较常用吧。

直接的波浪线表示告诉TeX前后两个文本是连在一起的,不要在此处断行。\vfill表示用空白将本页剩下的部分用空白填满,然后用\eject把它送到输出文件。

在出现**提示符的时候,我们可以以&开头表示以特定的宏格式处理文件,比如 &plain \input story表示使用plainTeX的格式处理文件。一般来说,还可以在从外壳调用它的时候使用tex &plain story或tex \relax这样的形式直接跳过双星号提示。

\eject 表示本页处理完毕,不代表所有的页都处理完成了。我们仍然需要使用\end来结束文本的输入。

在TeX中,由\hsize=控制本行的排版宽度(不是页面宽度)。

如果TeX发出警告,那么每段文本后面最后有一个|表示在输出的时候TeX加了一个黑色的方块。以产生警告作用。

在输出文件的时候,TeX总会产生log日志。

TeX通过给定的信息以断词。比如通过\hyphenation{gal-axy},中间的一个-让TeX知道这是一个可以断词的位置。

错误信息与处理

TeX的错误信息是以感叹号!开始的。并提供了错误上下文。上文是读出的内容,下文是要读的内容。并在上文的最左边给出了错误的行号(X.Y中Y表示行号)。

这个时候可以键入回车,表示试图忽略本次错误,或者输入

在TeX当中,这些命令改变了交互的等级。S,R,Q分别对应于\scrollmode,\nonstopmode,\batchmode.使用\errorstopmode转成正常的模式。这些命令是全局作用的,无论它们出现在哪一个组当中。

调用宏的时候产生的错误就像编程语言里面函数调用栈的错误一样,我们可以设置\errorcontextlines设置显示出来的调用栈的深度。

TeX的工作原理

在TeX中有如下约定,一个回车类似于一个空格,一行中的两个连续空格被视为一个,无论出现在哪一个位置,并且使用一个空行表示一段的结束。

TeX的字符所属的类

256个字符被分成16类。数字编号从0到15.TeX在读入文件的时候每次读取一个记号,并对比当前记号所在的类,以决定所产生的行为。这些类及作用为:

类别 意义 默认字符
0 转义符 反斜杠
1 组开始 {
2 组结束 }
3 数学环境 $
4 表格对齐 &
5 换行
6 位置参数 #
7 上标 ^
8 下标 _
9 可忽略字符
10 空格
11 字母 [a-zA-Z]
12 其它字符 无
13 活动符 ~
14 注释符 %
15 无用符

其中每类都可以包含若干个字符。当使用plainTeX格式的时候,$,%,&,#,_要转义使用。此外,一些词在转义时有其它的含义,比如\~得到的是波浪重音。

在TeX工作的时候源文件中所有的部分被分成一个一个的记号,它们或者是指定类代码中的单个字符,或者是一个控制序列。也就是在读内容的时候,TeX先给字符分类,根据分类的情况作进一步的处理:

\hskip 36 pt
\\[1]skip3[12]6[12] [10]p[11]t[11]

TeX有一个叫INITEX的版本。这个版本里面气有的字母都被认为是12,除了字母,回车,空格,delete,注释与反斜杠符号之外。

一个明显的特点是,编组符号是不能使用的。

使用\catcodeSYMBOL=N`来将字符更改到指定的类代码当中。

catcode的作用域是局部的。使用\string命令可以将控制字符分成单个的对象。使用\csnameXXXX\endcsname可以将一个字符记号列表变成一个单独的控制系列。只要它不与TeX的原始控制序列相冲突。这个时候,控制系列的名子完全来自于后面的字符,比如 \csname TeX\endcsname 我们不能使用\csname\TeX\endcsname这样的格式,因为\TeX在被调用的时候会被宏展开成其它的东西。

\string宏可以看成是读取后面的非空白字符并按照原样显示,它可以用在我们的\message{\stringXXX}命令当中,以便正确显示出向用户提示的信息。

注: 当\csname用来第一次定义控制系列的时候,那个控制系列在重新被定义之前等价于\relax命令产生的效果。

使用\let命令可以给一个记号赋值,使用

\ifundefined{TOKEN}<if_true>\else<if_false>\fi

可以完成一个复杂的判断逻辑。比如

\ifundefined{TeX}<true_text>\else<false_text>\fi

表示在\TeX宏未被定义或者为\relax的时候被展开成,否则被展开成.

\let的语法是\let\TOKEN=\VALUE

除了\string用于得到记号外,还可以使用\numberNUM用于得到一个小数,使用\romannumeralNUMBER得到一个用小写罗马数字表示的数(如\romannumeral24得到xxiv)。并且可以使用\numberREG来得到一个内部寄存器里面的数字。

\uppercase{token_list},\lowercase{token_list}用于完成记号的转换。

ex7.8 想一想,\uppercase{a\lowercase{bC}}得到的记号列表是什么

这可能是TeX语法最为特殊的一点了吧。它的展开不是从内到外逐渐展开的,而是从外到内按照记号逐个分析出来的。发生的过程是,首先\uppercase宏看到了它的一系列参数。这些参数被识别成记号的列表,a, \lowercase, {, b, C, },各自都是完整的单位。这个时候,每一个列表被分类。被uppercase宏作用,就变成了A\lowercase{BC}。然后继续向前读入字符并排版,转成Abc.

这个过程可能很特殊吧。仔细想一想,它跟m4宏还是很相像的,不过m4宏把它们都当成字符,而TeX还分类处理这些记号。

ex7.9 TeX有一个内部整数参数叫做year,它等于任务开始时当前年的数字,看看怎样用\year以及\romannumeral和\uppercase对所有运行在2003的任务给出后面的版权表示。

根据前面的介绍\uppercase{\romannumeral\year}显然是不行的,因为uppercase在展开的时候,首先得到它的参数,而它的参数还没有被展开,为了解决这个问题,必须使用\expandafter宏,让里面的宏先展开,让uppercase得到宏展开后的参数。

正确的答案是

\copyright\ \uppercase\expandafter{\romannumeral\year}

TeX的语法的特殊性现在有一点了解了。但是还差很多基础的知识,等看到后面更多的控制系列之后再看它的语法结构吧。

字符输入

很少有键盘能够提供256个字符,而且有的字符已经有其它的用处,所以我们使用下面的char命令得到任意的字符。格式是: \char<NUMBER>得到当前字体的相应字符。注意是当前字体中的字符。

在TeX刚设计的时候,一个字体文件就最多只有256个字符。在TeX内部,字体的代码总是以ASCII格式被调用的。b的内部代码,这样就总是98.

Knuth喜欢使用斜体表示八进制数,使用打字机字体表示十六进制数。个人的习惯不同吧。我觉得都使用正常字体就行了,Knuth的字体使用风格有些复杂。

八进制数使用右单引号引导,而十六进制数使用"引导。比如\char'142与\char"62与\char98是等效的。

定义char还有一个比较方便的方式,这时候不用使用\def<SEQ>{\char<NUM>}这样复杂的形式,而是直接使用\chardef<SEQ>=<NUM>。

有些人的键盘上直接有\(\leq\),\(\geq\)这些字符,它们的生活还真是比较方便啊。

像回车等换行字符的ASCII可以使用^^M这样的形式来表示。^^后面实际上还可以跟两位十六进制数字,用于表示指字代码的ASCII字符。

TeX系统读入的规则

TeX的输入是一系列的“行”,当TeX从里面读入文本的时候,它就处于三个状态中的三歧的一个: 新行N,行中间M,跳过空格S.

在每行的开头它处于状态N,但是大部分的时间它处在状态M,当读入一个控制词或者一个空格之后它进入状态S,这个时候再遇到空格就会被忽略。

出现在行尾的任何空格都会被删除。当TeX在任意的状态读到一个第零类的字符的时候,它就会搜索这个控制序列的名子。如果行中没有其它的字符,那么定义这个序列的名子为空。如果接下来的一个字符不是属于第11类,那么它读入一个字符作为控制系列的名子。如果是属于第十一类,那么继续读,直到读到一个非第11类的字母为止。作为控制序列的一个记号。在读完记号后进入到处理第十类字符的状态S,如果读的记号为空,那么进入状态M当中。

TeX在任意状态遇到第7类字符,并且接下来还是一个第7类字符,也就是遇到了^^,如果后面跟一个小于128的字符,那么^^被去掉,并且从c中加上或减去64.于是^^A就被解释成ASCII为1的字符。但是如果后面跟的是0123456789abcdef,那么读取两位字符,然后使用十六进制代码对应的符号替换^^xx.当替换完成后,TeX返回到原来的位置继续开始。

比如,使用\T65X得到的结果与\TeX结果相同,因为65代表的就是字母e.

在上面的状态下,如果遇到的不是三字符或者四字符,采用另外的处理办法。在读入一个^后,下面的字符如果是1,2,3,4,6,8,11,12,13类中的一个字符,或者第七类的字符,但是不能理解成上面的三字符或者四字符,那么它给字符一个类代码并且进入状态M.

如果遇到的是第5类(行尾字符),那么它就放弃本行剩下的所有的内容但是如果在状态N的时候遇到了行尾字符,那么行尾字符就被转换到控制系列\par.如果处于状态M,那么行尾字符转换成第10类(空白)记号。如果处于状态S的时候遇到了行尾符,那么行尾的字符就被忽略。(同时转到状态N?)

如果遇到第9类字符,那么直接忽跳过它,就好像没有它一样。

遇到第10类字符的处理: N或S时,第10类字符被直接跳过,并且保持当前状态,处在状态M的时候,字符被转换成第10类的记号,并设此记号代码为32.然后进入状态S.空格记号当中,字符代码总是32.

我们不妨看成这就是TeX程序的词法分析。在词法分析的时候它得到了记号的类型与记号的值。

如果TeX遇到了注释符,它就不再读入当前行剩下的内容。

遇到无用符(第15类)的时候,跳过此字符,打印出错误消息,并仍保持当前的状态不发生改变。

如果当前行没有要读入的内容了,就进入下一行并且进入状态S.但是如果是\input文件结束,或者\input的文件给出了\endinput,那么TeX返回到\input文件读取结束后的状态,就好像是从读完input的内容一样。

ex8.2 回答下面简短问题,看看你对TeX的读入规则的理解程度: a.第5类和第14类的不同在什么地方 b.第3类和第4类的不同在什么地方 c.第11类和第12类的不同在什么地方 d.活动符后面的空格要忽略掉么 e.当一行以注释符%结尾的时候,在下一行开头的空格被忽略了么? f.一个可被忽略的字符能出现在控制系列的名子中间吗?

答:a.第5类是换行,第14类是注释,两者都结束了当前行,但是换行会被转成第10类(空白符)的代码或者一个\par控制系列。但是第14类的字符永远不产生任何记号。

b.第3类是数学类,第四类是表格类。它们产生不同类型的代记号。在后续的处理当中它们是完全不同的。

c.类似于b.第11类是字母,第12类是其它符号。但是只有第11类的字母有组成较长的控制系列的能力。

d.不能被忽略掉。活动符是第十三类,读完它后处于状态M,后面的空格不能被忽略。

e.是的,当注释符里面的内容结束后,TeX进入状态N,任何位于行首的空白字符都会被删除的。

f.不可以。控制系列是连续读取在第11类中的单词,遇到其它类就是结束对控制系列名字的读取。从而起到了分割的作用。

ex8.3 再次看看有关\vship的错误信息,当TeX报告说\vship是一个未定义的控制序列的时候,它输出了两行上下文,表明它正在读入文件story的第二行的中间部分,在遇见错误的时候,TeX处于什么状态,它下一个要读入什么字符。

我们可以按照正确的路向分析。它读入一个控制系列后处于状态S,会忽略掉后面的空白的字符(第10类),因此它下一个要读取的是非空白字符。

ex8.4 给定plainTeX格式的类代码后,从输入行$x^2$~ \TeX ^^62^^6得到什么样的记号?

这得好好分析。首先数学模式正常排版,读完$后进入M状态,活动符是有效的,所以波浪线后面的空格不能被忽略。接下来读\TeX,在读完\TeX之后,进入状态S,因此后面的空格都被忽略,接下来读^^62,得到字母b,再接下来读记号^^6,得到字母v.

我们完全可以把这种分析过程理解成词法分析,分析之后形成了记号的类型与值的线性序列。

ex8.5 想想正好有一个三行的输入文件,第一行是Hi!,其它两行都是空的,当TeX读入这个文件的时候,按照plainTeX的类代码将会得到什么记号?

这个时候处理的方式是,处理成[11]H[11]i[12]![10] [0]\[S]par.空格是第一行的回车引起的。

据Knuth自己的表述,类代码写成数值格式主要是为了防止人们过度使用\catcode.

Coding Poet, Coding Science

使用Python下面的enthought和matplotlib绘图

发表于 2013-05-07 | 更新于 2016-12-14 |

关于matplotlib的一些问题

安装模块的问题

一直不了解模块到底是什么东西,它与对象有什么样的区别。到了现在才差不多把模块比成一个可以加载与控制的子程序。在Python这样的动态类型里面相当于扩展功能。相当于在C语言程序里面使用了其它的库。

这么说来,模块的编译原理理论应当是与子程序密不可分的。以前甚少将动态语言里面的模块与C语言这样的传统语言里的程序联系在一起。那仅仅是因为自己觉得C语言这样的程序是连接到二进制的库,而动态语言是导入源代码。而库与源代码是绝对不同的事物。这说明自己还是抱着以前形成的概念,以为在二进制与源代码是绝对分离的。但是在开源世界源代码与二进制通常并不存在异步的现象。两者还是非常相近的。

在开源的世界里淡化了库与源文件在用户与程序员角度上的差别。这个观点应当好好地思考一下。在Shell里面是没有什么模块的,它们使用的都是脚本与函数这样的概念。基本上只是使用另一个编译单元或者运行实体的一部分代码,这部分代码只是一个源文件里面很少的一个成分,基本上我们调用一次函数后就不再用它了。但在Python当中,我们不如认为一个模块可以以解释的方式出现,也可以以编译的方式出现。或者以混合的方式出现。这并不阻止我们使用一个模块。

于是使用模块就好像是在C语言里面加载动态链接库一样。大致来说就是如此。但是模块在脚本文件里面通常有更多的应用。也就是如果我们在文件a里导入一个代码,通常我们在a文件里面大量的功能都是通过库来实现的。但是在C语言里面并不能感受到这一点。

在C语言里面并不怎么关心库是怎样导入的。这大概是因为C是一个系统级的语言。通常而言如果我们要使用C库,需要一个头文件一个库文件就可以了。由于了解C语言的人数是那么地多,所以导入C库的方法就变得几乎不用任何思考了。

但是脚本语言的应用还是没有C那么多。脚本语言里的模块,虽然功能上与C还是那么地相象。但是所用的指导理论至少在形式上与C的差别还是比较大的。类似于C,模块也有自己的命名空间。但是在Python当中,模块是以一个对象的形式存在的。

在C语言里面也没有接触过怎么编译与安装模块,似乎那是不用考虑的,只要我们有头文件与库文件就可以了。但是那只是模块的产品,我们如何根据源代码生成库呢。

还有,Python里面的库是可以有很多的层次的关系的。这一点在C语言里就更没有体现了。CXX里面还有命名空间的概念的。可是以前学习CXX的时候都没有怎样讲命名空间。我想设计CXX时,命名空间那个时候还是为一解决函数调用重复而设置的一个机制,并没有太多其它的意思。但是脚本语言里面,命名空间得到了广泛的应用的同时,可能也有了一个理论的基础。不过,由于模块这个词比较陌生,在理解时用C语言的头文件加上库文件理解就是一个相当必要的方法了。

Python的库的安装

以matplotlib为例吧。安装一个模块的基本过程是:

  1. 检查要安装的模块所需的依赖关系是否满足。我们可以视为当前系统上面是否有相应的头文件与库文件。但是C语言里面还没有见到过。我们就把模块想象成C语言里的动态链接库吧,它不仅是需要一个编译器,还需要其它的库。我们知道C语言里面单独发布一个动态链接库版本是不可想象的。伴随一个动态函数库发布的通常还有其它的依赖的关件。不过造成这一现象可能更多是策略的原因吧。

对于matplotlib来说,检查的主要是numpy模块。要在动态语言里面检查模块是否被安装了,可以在执行解释器的时候导入该库,然后调用该库的 __version__ 函数。因为在Python里面,一个模块可以通过一个对象的方法进行访问。

import numpy
print numpy.__version__

模块与函数库的区别还在于,函数库是脱离编译器运行的。但是模块却是在解释器下源代码被解释器执行的。

在Python里面,对象占据着重要的地位。在导入模块的同时,不如就视为创建了一个模块访问对象。我们通过它访问到模块里面的各种数据结构,还可以通过里面的函数定义一个其它的对象。在Python里面不用声明变量类型。这是很有用的,因为模块里面对象的类型可能是非常长的一个名子。

在WINDOWS下面使用一个安装好的exe文件就可以了。

Python的库有时候需要编译。我们不如假设Python的模块不只是可以被解释,也可以直接先被编译出来,这样可以进一步加快速度。

matplotlib也是如此。如果我们从源代码构建它,可能就需要添加freetype,libpng,tk,pyqt,pygtk,wxpython等组件了。有了这些支持我们最终构建出来模块在被执行时所必需的程序,配置或接口实现等。

matplotlib的具体依赖可以查看INSTALL文档。与unix下面的其它文件基本相同。

  1. 编译模块

matplotlib里面实际上提供了一个Makefile文件。但是make help并没有显示出结果,也就不敢随便用它。按照上面的说明,编译的时候执行命令:

python setup.py build

这是很简单的。因为我们还在没有configure的时候就已经编译出来了,到最后我们应该把文件安装到哪个位置呢。C语言的库来说并不成问题,一来有configure的prefix指出目标目录,并且unix系统搜索C库的位置我们也是知道的。但是Python就不同了。我们可能安装的并不是标准位置。但是先不管它。

  1. 安装模块

安装模块实际上相当于保证主程序,也就是python里面在import命令被执行的时候能够找到相应的模块。一般来说,模块能不能被导入仅仅是取决于它们是否在搜索路径里面。而Python的搜索路径除了当前工作目录外,就是在安装Python的时候的标准的路径了。

不同的系统有不同的定义吧。在我的系统上/usr/lib64/python*里面有python的标准模块。但是仍然没有发现matplotlib被安装在了哪里。

可以通过sys模块的 exec_prefix 与path变量得到关于python解释器的一些信息。模块文件可以是.py, .pyc, .pyo, .pyd, .so. 结果按照这种要求。在/usr/lib64/python2.7/site-packges里面找到了matplotlib. 假设Python安装在了 $PREFIX 下,可执行程序在 $EXEC_PREFIX 。下面,那么一般先找 $PREFIX/lib/pythonX.X 文件夹(Python可以向系统提供自己格式的库文件),找 $PREFIX/lib/pythonX.X.zip

有的时候 $PREFIX/lib/pythonX.X/plat-linux2 也会被设置。动态加载模块的路径放在 $PREFIX/lib/pythonX.X/lib-dynload/ 下面。其它模块的默认安装路径一般是 $PREFIX/lib/pythonX.X/site-packages/ 。整个模块组织成了一颗树的形状。这颗树的根由库的搜索路径合并而成。每遇到一个子文件夹可能这颗树就向下延伸一层。

在sys模块里面的path变量里显示的是模块的ROOT的来源。而sys模块的本来含义并不是操作系统,而是Python解释器里的相关变量。

  1. 检查模块是否可用

这部分通常要运行一些测试脚本来完成。有时候如果没有的话,我们可以尝试导入我们安装的库,看看有没有异常出现。

自动测试应该还是有一些技术可言的。个人觉得应该使用脚本以及高度自动化的工具完成这些任务。说明一下,自己还想到使用m4宏处理器写一个简单的TeX前端,用于包含了复杂选项的TeX变成一些容易设置的选项的集合。

注:unix下面的应用程序都可以这么来看。一个应用程序的目录总是符合unix下面目录的规范的,库安装到 $PREFIX 的lib/下面,诸如这些规定。对于Python来说也是不例外的。因此对于matplotlib包来说,它不必什么都看Python安装在哪里。它可以认为它就是一个库,因此它的库与模块就安装在 $PREFIX/lib/python 下面,它的文档就安装在 /share/doc/$LIBNAME 下面。

关于IPython交互式解释器

matplotlib的pylab在运行show()时有时会不出现结果,那是因为我们当前可能并未关联到图形库。要想显示图片通常在shell里执行

ipython -pylab=qt

之后,使用

run $script_name

然后输出Python相应的代码进行。

使用IPython也算是能够提高工作的效率吧。不过也许只有在IPython里面才可以直接使用run命令了。这对于执行脚本是很有好处的。

在使用pylab的时候,绘图的后端决定了图片在哪里被显示。在ipython里面可以使用debug命令进入调试。

matplotlib的其它问题

其实可以使用setup.cfg对matplotlib的安装进行更详细的配置。我们不用从网上找资料。因为源代码包里的INSTALL等文档就是最好的说明。就连setup.py脚本也有很好的可读性。

也许以后自己应当学会从源码包里面读英文文档了。在网上找资料实在是太麻烦了。而且如果有可能,软件的使用教程也应当从附带的doc里面查找。

matplotlib绘图的基本方法

读过了书里的第5章的文档,觉得matplotlib的确很伟大。但是自己还是觉得不应当手动从无到有地使用pylab绘制图表,而是应当通过其它的科学计算软件调用它。这样绘制出来的图表才有意义。不然就纯粹是为了玩了。

我们不介绍其它的模块了。matplotlib是Python最著名的绘图库。但是pylab能在numpy或者scipy里面集成接口。

调试的方法

几乎每一本书都说Python的调试功能很强大。但是我却觉得Python的错误显示很复杂。大概是我不会使用堆栈吧。在ipython里面调试时,先运行程序。如果出现错误,程序会返回。这个时候调用debug返回到出错的时候的堆栈,使用u命令在堆栈中一直向上,直到出现本层次模块里的错误为止。

其实ipython的错误提示是我见过的最好最详细的提示了。中间有高亮又有各个源代码文件出错的行号。不过相比之下,python里的错误输出可能是最难读的了。可能是堆栈太多的时候必须有一定的提取文件中关键错误的方法吧。

ipython调试的时候显示的高亮什么的特性在Sagemath里也得到了应用。

matplotlib绘图的时候有一种基本的方法就是使用

import matplotlib.pyplot as plt

这样可以直接使用pyplot模块提供的绘图函数功能。

把模块导入成对象,可以这么理解,导入一个对象相当于找到一个能够在运行期间为我们干活的人。这个人可以做相应的输出,我们可以调用它里面的相应方法,或者根据它的功能创建一个工作对象。

另一个则是使用matplotlib的pylab模块。其中包括了许多NumPy与pyplot模块里面的绘图函数,可以方便快捷地进行计算与绘图。pylab可以直接通过

import pylab as pl

进行。

书里面实际上介绍了三种绘图的方法。有pyplot,pylab,这样直接调用模块的方法,也可以是调用pyplot里面的绘图API进行绘图。

pyplot的面向对象的绘图方法与机制

我们不如这样理解pyplot的工作过程。在刚开始的时候创建了一个模块访问对象,也就是在import pyplot as plt里面说明的plt这个名子。通过这个名子我们访问到绘图所需的一切要素。plt里面有自己的成员与数据,它的直接成员与数据通常都是用于调整绘图环境里面的配置的。真正绘图的时候,总是通过具体的绘图对象完成的。

我们不如称做是一个绘图对象关联了一个模块访问对象。我们可以通过plt创建,显示绘图对象,切换当前绘图对象这些操作。

绘图对象里面最基本的就是图表,其次是子图。当我们调用plt的绘图函数plot()的时候,总是在figure与axes对象上面绘制的。

一个模块访问对象plt里可以管理多个绘图对象。一个绘图对象里面也可以有多个子图。在pyplot里面,通过plt.figure(N)的方法访问指定序号的图表。当序号不存在的时候该图表会被自动创建。

如果我们在ipython里面测试,我们就会发现调用plt.figure(1)的时候会出现一个绘图窗口。接下来的绘图就是在这个窗口里面进行,而如果再调用plt.figure(2)就会创建另一个绘图窗口,里面有另一个图表。这时再调用plt.figure(1)并不会出现新的窗口。相当于模块会自动判断当前绘图区存在与否。

一个图表对象的类型是Figure。默认情况下,模块访问对象plt会创建一个图表,并将它作为当前的图表。plt的figure()函数也可以接受其它种类的参数。总而言之,plt的figure()函数完成的工作是创建图表,管理,导出当前绘图模块所属的某个图表对象。以及选择当前的模块访问对象绘图时所在的图表。

使用plt的gcf()函数获得模块的当前图表对象。类型是matplotlib.figure.Figure。无论以前面的哪种方式,返回值都是一个图表对象,我们就是在这个图表对象里绘制图表的。

这样一来,我们就不需要在figure里面绘图,然后再进行显示了。plt里面封装了访问当前figure的方法。调用名称与figure对象里的类似。

一个图表可能会有多个子图。子图用Axes对象来表示。pyplot并不是在一个Figure对象上直接绘图的,而是在一个Axes里面绘制函数的图象。plt模块封装的plot(),xlabel()等方法几乎都是针对于模块访问对象的当前子图而起作用的。

使用plt.gca()得到当前的子图。而使用plt.subplot()函数可以创建子图(实际上是在当前的Figure对象里面创建子图)。subplot的函数调用是subplot(Rows, Cols, Index)。该调用的含义是假设当前Figure对象被分成Rows*Cols的网格。使用编号为Index的区域绘制子图。Index的编号是从左到右,从上到下,编号从1开始。

如果Figure对象判断不同的subplot的区域有重叠,前面的被重叠的子图将会被清除掉以绘制新的子图。否则就继续添加新的图表。

函数subplot()返回它创建的Axes对象。调用gca(Object)可以使这个Axes()对象成为当前的对象。如果子图已经存在,subplot并不会将先前的子图覆盖,而是返回符合那个标号的子图。比如下面的代码:

plt.subplot(111)
plt.subplot(111)

第二个语句并不会清除掉第一条语句里的subplot,而是返回第一条子图创建的对象。

当Figure与Axes对象都决定好之后,真正的绘图就开始了。

绘图的时候坐标系的选择

matplotlib设置了四组坐标系。各个坐标系的大略描述如下:

窗口坐标系: 左下为(0,0),右上为(W,H)。坐标以像素为单位。

图表坐标系: 左下为(0,0),右上为(1,1)。坐标以英寸为单位。

子图坐标系: 左下为(0,0),右上为(1,1)。本身是没有单位的。

数据坐标系: 根据不同的坐标系有不同的表达形式,在笛卡尔坐标系下面通常是\((XMIN, XMAX)\)到\((YMIN, YMAX)\)。本身没有单位。但是我们可以根据物理量来设置。

在屏幕输出的时候才用到窗口坐标系。我们不妨将图表坐标系看成是与平台无关的。决定了对象的实际的大小。

在实际绘图时,一旦终端被确定了,绘图程序的窗口坐标系也就相当于是确定的。于是根据这种关系,一个图表被显示到桌面上,或者是输出到一个文件当中。而单以纯数据表示而论,在运行的时候,所有的图形的位置在图表坐标系里面的安排都是固定的了。

不同坐标之间的变换都同样地依赖于本对象的二维仿射变换矩阵的定义。

假设ax是一个Axes对象。那么它有一个transData用于决定从数据坐标系到窗口坐标系的变换。函数

ax.transData.transform((3, 5))

将返回点(3,5)在变成窗口坐标系后所在的位置。 注: 返回类型是一个ndarray对象。而且这个函数也可以一次调用返回多个点在窗口坐标系里面的位置。

下面我们以Figure下在的tranFigure变换为例了解Python的实现。

在交互式命令行下直接输入f.transFigure()将可以看到它里面的一些对象。其中第一项里面的Bbox描述了这个Figure的物理大小信息。比如\([0,0]--[8,4\),单位是英寸。而在Affine2D里面的就是那个变换矩阵了。经过分析不难发现,对角线上的第一个元素就是所谓的X方向分辨率,第二个元素就是Y方向分辨率。我们也可以通过直接查看 f.transFigure._boxout._transform 得到真正的变换矩阵。

上面的代码实际上还只是一个Affine2D对象。调用它的 get_matrix() 方法才能得到以numpy.ndarray形式表示的矩阵。

而Axes对象在Figure里面的位置可以通过 Axes.get_position() 方法得到。其结果是在图表坐标系里面的位置(注意Figure坐标系从左下角的(0,0)到右上角的(1,1))。如果子图是以2*3行分隔的,那么最后一个子图的坐标通常就是(0.66,0)-(1.0,0.5)。不过实际上子图与图表边缘之间还是有一定间隔的。

根据这一信息我们自己就可以计算出来Axes对象如何转换成窗口坐标系了。就是拿前面的坐标系,乘以Figure的变换函数。这步工作Python是不会每计算一个点就运算一次的。因为Axes提供了 ax.transAxes._boxout 对象,它里面存储了变计算后的结果。

一般来说,一个子图对象里面只有一个数据坐标系。于是我们可以通过Axes对象访问数据坐标系的transData对象。该对象指出了数据坐标系里的点如何进行变换。

transData由transLimits与transScale构成。transLimit描述了该数据坐标系的坐标范围,比如(-5,-5)-(2-3)。而transScale表示transData将数据坐标系转成Axes对象坐标系里面的缩放大小,通常都是1.于是数据坐标系里面的某个点转成一个窗口像素。

使用这些概念主要用于处理不现的坐标系表示方法,以及不同的刻度标准。

关于绘图操作

如何调用label,line,axis等对象这里就不说了,因为它们是一些很繁锁的东西。

matplotlib绘图的背后原理

matplotlib的绘图的三个层次(这种三层次模型也可以用在其它的语言里面)是:

backend_bases.FigureCanvas
backend_bases.Renderer
artist.Artist

Renderer与Canvas知道如何处理底层的绘制操作,比如在QT界面上绘图或者使用PostScript在PDF文件里面作图。Artist对象处理所有的高层的结构,如图表,文字与曲线等绘图元素的绘制与布局。通常我们只是与Artist对象打交道,而不需要关心底层是如何实现绘图的细节的。

Artist对象有简单类型与容器类型两种。有点像是GUI里面的Component.简单类型的Artist对象是标准绘图元件,如Line2D, Rectangle, Text, AxesImage等。但是容器类型则包括了其它的简单对象,如Axis, Axes, Figure等。我们不如把Artist看成是一个桌面绘图管理器。那么以前所学过的Metapost语言便就是用于产生这些复杂对象的绘图原语言。它们能够在更底层的意义上提供编程方法,因而更容易绘制出来其它的对象。

Asymptote与Artist相比,多的只是一种灵活的方式。Artist虽然也是用编程语言实现,但是封装的内容与对象比较繁杂,底层不够清晰。而Asy使用清晰的底层数据结构,让我们可以自由地决定插值等操作。

我们也可以直接使用Artist对象绘图。利用Artist的特性的关键在于我们使用Artist提供的许许多多绘图对象,通过调用它们的方法设置它们的属性,进而描述出图形里面各个元素的关系。

一个Axes对象里面包含了其它的简单的对象,因为Axes是容器类型。使用Axes的lines可以得到在该子图里面的所有曲线列表。我们可以通过该函数返回对于这个曲线的引用以便我们能够单独地调整该line的属性。

Figure对象与Axes对象都有一个patch属性作为它的背景。这向我们说明Figure对象对于绘图的理解是描述性的,只有在调用实际的绘图引擎的时候,才会将背景显示出来。该背景是一个Rectangle对象。通过它我们可以设置背景的背景颜色,透明度等等属性。

Artist的对象有一些通用的属性,比如透明度alpha, label, visible等。所有的属性都可以通过 get_ 方法或 set_ 方法读写。而可以通过任何一个Artist对象的set()函数与get()函数设置一个对象的多个属性。

模块访问对象提供了getp()函数用于返回一个Artist对象的各种属性。比如通过 plt.getp(plt.gcf())我们就可以得到当前图表对象的所有属性名与值。在交互式ipython里面我们可以参考这些输出通过前面说过的set方法加以改变。

在matplotlib里面,Axes是绘图的核心。它包含了许许多多的Artist可显示对象。

matplotlib的配置文件

matplot工作是类似一个应用程序。检查配置文件的顺序是,当前配置文件,用户家目录下的配置文件,应用程序里面的配置文件。配置文件实际上是一系列的变量与值。在依次读取这些配置文件的过程中,如果前面的配置文件已经设定了这个值了,那么后面配置文件里面的值就不再生效。于是配置文件的优先级是当前目录最高的。

配置文件的读取也有一些规律。Bash从/etc里面读取配置,最终也是用户目录里面的配置脚本生效的。不如引入配置文件优先级这个概念。一个应用程序在工作的时候,假设从一列可选的列表里读取每一个配置文件。高优先级的配置文件是说,如果配置项目出现在某一个配置文件里面,而其它配置文件里面有相同的配置项目的时候,前者会对程序起到真正的作用。于是Bash里的配置文件中,系统目录是第一读取的,并具有最低的优先级。matplotlib里面,系统目录是最后读取的,具有最低的优先级。世界真是奇妙。

matplot配置文件可以通过 matplot.get_config_dir 得到当前生效的路径,使用 matplotlib.matplotlib_fname() 得到最优先的那个配置文件。 而 matplotlib.rc_params() 用于读取配置文件里的每一项(默认是返回当前使用的配置文件里面的项目), matplotlib使用rcParams变量保存当前的配置。如果要修改,可以直接令

matplotlib.rcParams[$hash_key] = $value

以让参数成为当前绘图参数。

matplotlib.rc()函数接受一些参数设置并将它写入rcParams变量。如果要恢复默认的配置文件里面的内容,可能需要rcdefaults()选项。

显然matplotlib是不支持直接从matplotlib里面直接修改配置文件里的内容的。因为这些配置文件可能权限比较高,或者干脆就是系统目录下的配置文件,不允许用户修改。

在实际的应用中使用一个库

在python里面导入模块使用import命令。而使用reload(modulename)可以重新加载这个模块(让里面的数据复原)。

中文字体的显示

在matplotlib里面一个是使用Fontmanager选择字体。这对于有些绘图方法特别有用。比如plot()的xlabel()这些函数,都可以接受一个font=可选参数。这个时候选择一个字体属性就可以了。

但是这种方法明显的缺陷是缺乏统一性。如果我们需要绘制多种图,或者需要学习多种图的绘制参数,每一个都要学习就变得代价太高了。所以我们还是用统一的方法吧。

统一的方法是matplotlib的rcParams参数。这些参数让我们选择字体的字族等参数。具体可以通过rcParam.keys()找到。字体大小也可以找得到。如果我们要显示中文。那么我们应当检查以下的做法是否被完成了。

1.虽然Python对于unicode的支持很好。可以直接通过u“”使用unicode字符串。但是这样还是不能够保证直接解析出来多字节编码。尤其是采用unix的magic来运行脚本的时候,编码必须被另外指定。这种方法就是所谓的W3C编码指定方法。

这种方法比较自由,也就是在前面的几行里面出现#-*- coding: utf-8 -*-这样的字符就可以了。下面的编码就会自动被认为是unicode文本并采用了utf-8编码。

2.需要支持中文的字体才能显示出来中文字符。如果没有这样的字体,通常并不是显示乱码,而是是空格或者方框代替。但是一个字体里面总是只包含特定的几个语言里的编码,很少有字体可以包括所有的文本。于是换字体似乎是必然的。不幸的是,Python没有LaTeX那样的复杂的字体种类。同一时间加载的只有一个字体文件。所以我们如果要使用不同字符区域位置的字体,最好还是自己换用字体。

3.系统下使用fontconfig管理字体。大概其它的应用程序也使用了这样的接口,所以可以使用某种字体名,而不需要通过字体文件访问指定的字型。如果我们要改变matplotlib的文件,除了通过fontconfig查询系统字体之外,大概也能够使用fc-list管理字体文件。

4.当将字体嵌入到图表的时候,注意字体的大小。这个是很关键的。对于显示效果有重要的影响。一般而言,如果我们要在图表里面使用字体,一定要确定我们希望图表的输出大小。这个问题在下面的笔记中会讲到。

讲求实际大小在计算机可以自由放缩文本的时候似乎显得有点过时。但是人的眼睛视野大小总是一定的。我们虽然可以放大与缩小图象。但是同一时间内我们的焦点只是集中于图象的某一区域。这个时候采取放大镜的做法也许对我们更好一点。虽然我们可以这么做。但是随意地放大与缩小字体还是缺少一种科学上的价值。我们应该时该记着我们想输出的字体是有多大的。

实际上这些问题大概还是视觉范围的问题。比如我们在看书的时候,因为离得近,虽然很小,但是也能看清楚。可是如果是在屏幕上,那么小的字体就不行了。我们不妨做一个计算。假设我们眼睛离书是30厘米。而字体的大小是11pt。换算成厘米表示,字体的大小就是0.38cm.也就是说,我们平常见到的印刷体也就是0.4cm左右的大小。但是如果是在屏幕上显示,我们的距离变成了80cm.这时的11pt相当于在30cm处看到一个0.15cm大小的块。于是我们可以说,我们的眼睛实际上可以看到小的物体。但是如果我们一直使用较小的字体,对于我们的眼睛也会造成一些压力。大概这就是为什么使用电脑伤害更大吧。

原来自己对于这些东西一直没有什么概念。但是现在才发现问题的所在。那么以后在使用显示屏的时候,就要注意到自己是在多远的距离下看多大的物体。其实距离这么远的话,将屏幕的字体调大一些也是很合理的。

原来的时候自己一直以为在纸上是多大,在显示屏上就应该是多大。这样自己的感觉会好一些。但是今天终于发现,原来显示屏上的内容是不可以相信阅读效果的。但是由于显示屏上照样以11pt的大小显示,那么我也就没有什么办法了。可惜的是,计算机在这么大的时候分辨率不够。

注:业界总是认为高分辨率屏幕没有什么作用。但是它们的确有很大的作用。因为我们通常在显示屏上看到的并不是与看书时文本的大小,所以如果分辨率更高一些,就能够以更华丽的字体显示。而且,图片的大小也可以进行调整。

注:如果我们不使用桌面显示器。那么最终的效果应当是我们每天都在看书。

关于绘制饼状图

也许饼状图在科学计算里面遇到的并不多。但是在人际交流里面用的还是很多的。这些活动包括政治活动,商业活动。反正是在向不是一行的人解释东西的时候很有用。

饼状图调用的是pie()函数,它与plot()函数的作用是类似的。但是pie()函数只给出了一个返回值,而且输出的结果不可进行广泛调整的。比如它就不支持传入font=参数,以致于我们必须得事先设置rcParams.

饼状图在显示比例上是很好的。它的主要参数是一列正则化的数据。是数值类型的。至少可以计算出来一个百分比。一般来说,还需要一列标签文本,以辅助显示。至于阴影线与突出显示,就没有那么重要了。

文档与绘图,是一系列基础的技能。它相当于古代能够写字的人与不会写字的人之间的区别。只有自己能够创造出来这些东西,才相当于有了这样的表达工具,不然就只是一个平平常常,只能从事体力劳动与重复劳动的人。其工作也就不能显示出任何的创造性。

ENTHOUGHT公司的几个科学计算软件

这个公司的软件还是比较难得到的。我们要首先知道git.但是git对于断点续传的支持是很差的,所以我们就要在国内这么差的网络上进行数据的处理了。于是我们就很难得到。但是我们得到以后还得看说明去安装它。为此应当先去构建它。在构建过程中有几个库我们的机器上可能是很难得到的。

现在知道,ETS需要至少需要freeglut,vtk,swig,hg这些软件。但是通常情况下不可能是完备的,于是我们通过逐步测试build的方式解决这一系列的问题。

Cython以及相应的distutils库也是Python所需要的。这些库应当受到足够的重视。

国内的现状大致如此。为了更好地研究一个问题,有时候必须采取一些极端的手段才行。可是这些手段有时候让人追寻了好久好久。最后找到的还是一个不全面的解答。我想自己需要静下来多想一想为什么。

Matplotlib的设置

默认方法仍然是使用.matplotlibrc文件。这样输出的文件比较不错,而且也可以避免在运行脚本的时候花很长时间处理图表参数。

Matplotlib示例

好久没有使用过Matplotlib绘图了,里面的有些东西都忘记了,实在不应该啊。现在是得好好学习的时候了,因为现在及以后会使用很多这样的方法的。

首先是matplotlib的配置问题。这是一个.matplotlibrc文件决定的。配置的方法可以参考matplotlib的官方网站http://matplotlib.org/users/customizing.html。在实际中我们用到的更多的是对于图形的大小的控制。因为我们要输出文件放入到文章当中。其中的选项figure.figsize, figure.dpi, savefig.dpi, savefig.format是在matplotlibrc里面应该指定的。不然每次输出的时候都可能要设置一下,太麻烦了。

折线图

Matplotlib最简单的方法应该是用折线顺次连接起来 \(y\) 轴上的数据了。这个时候 \(x\) 轴对应的坐标就是元素在列表中出现的次序。代码与效果分别如下:

#!/usr/bin/env python
# Plot a list of numbers with pyplot
import sys
import re
import matplotlib.pyplot as plt
plt.plot([1,2,3,4])
plt.ylabel('some numbers')
plt.savefig('../img/'+re.sub('.py$','.pdf',sys.argv[0]))
image

image

散点图

散点图只不过使用了两个数组。另外,还可以接受点的形状作为第三个可选的参数。使用axis选项可以设置坐标轴的显示范围。

#!/usr/bin/env python
import sys; import re
import matplotlib.pyplot as plt
plt.plot([1,2,3,4],[1,4,9,16],'ro')
plt.axis([0,6,0,20])
plt.savefig('../img/'+re.sub('.py$','.pdf',sys.argv[0]))
image

image

代码中的ro代表使用红色圆点来表示。与MATLAB有几分相似。其它的选项还有,r-- 代表红色虚线,bs 代表蓝色方块,而g^代表绿色三角形。

import sys
import re
import numpy as np
import matplotlib.pyplot as plt
# every sampled time at 200 ms intervals
t = np.arange(0., 5., 0.2)
# red dashes, blue squares and green triangles
plt.plot(t,t,'r--', t,t**2,'bs', t,t**3,'g^')
plt.savefig('../img/'+re.sub('.py$','.pdf',sys.argv[0]))
image

image

Coding Poet, Coding Science

JDK与OpenJDK的安装与使用

发表于 2013-05-01 | 更新于 2016-12-14 | 分类于 编程 |

OpenJDK的官网上面的安装手册

在openjdk官网上面的资料http://openjdk.java.net/install/index.html

How to download and install prebuilt OpenJDK packages

JDK 7

Debian, Ubuntu, etc.

On the command line, type:

sudo apt-get install openjdk-7-jre

The openjdk-7-jre package contains just the Java Runtime Environment. If you want to develop Java programs then install the openjdk-7-jdk package.

阅读全文 »
Coding Poet, Coding Science

Linux下DHCP服务器的配置

发表于 2013-04-29 | 更新于 2016-12-14 | 分类于 计算机网络 |

DHCP的主配文件便是/etc/dhcpd.conf.

DHCP服务器搭建流程分为几步,第一是编辑主配文件,指定分配的范围等。第二就是建立租约数据文件,第三就是启动或重启DHCP服务,使配置生效。

DHCP的工作过程是客户端以广播的方式向服务器申请IP地址(通过接口连接)。DHCP服务器通常本身接口已经配置好IP并在这个接口上启动了DHCP服务。于是服务器根据DHCP的相关配置给客户端提供IP,GATEWAY,DNS等信息。并且DHCP服务器将本次分配信息存入租约数据库里面。

DHCP的配置文件一般从安装源目录的一个dhcp.conf.sample文件得来。该文件包含了适用于服务器的配置,本行的#后面的内容被DHCP服务器视为注释并自动忽略。

DHCP主配文件里面分成参数,选项,声明三种类型。

参数一节表明DHCP服务器如何执行任务,是否执行任务,以及要发送给客户的选项。声明一节用于描述网络的布局,提供给用户的IP地址等。选项一节用来配置DHCP可选参数,都以option关键字作为开始。

先说参数一节里面的重要关键字。

default-lease-time 缺省租赁时间的长度,以秒为单位
max-lease-time 最大租赁时间的长度,以秒为单位
hardware 指定网卡接口类型与MAC地址(假设客户端的信息)
server-name 通知给DHCP客户端的服务器名称
fixed-address ip 分配给客户端的IP地址

注意: 在客户端发出分配IP请求的时候,服务器也会根据客户端的信息决定IP的分配。所以在参数一节里面,所提供的hardware相当于筛选出来具有特定特征的客户端,并分配一个指定的IP地址。配置文件是分节的,也有局部选项与全体选项之分。

下面是一些重要的声明:

subnet [network_id] netmask [subnet_mask_id]

: 该区块用于指明一个网络地址资源名称。表示这些将用于DHCP的相关选项

range [start_ip_addr] [end_ip_addr]

: 表明地址池里的动态IP地址范围

host [hostname]

: 对主机名下面的DHCP配置,里面通常有hardware,fixed-address等参数

filename [boot_file_path]

: 从网络启动时的文件的名称

最后是一些选项:

subnet-mask 为客户端设定子网掩码
domain-name 为客户端指定域名
domain-name-servers 为客户端指明DNS的IP地址
host-name 指定客户端的主机名
routers 指定客户端的默认网关
broadcast-address 指定客户端的广播地址
ntp-server 客户端的时间服务器地址
time-offset 客户端与格林威治时间的偏移(时区),以秒为单位

/var/lib/dhcpd/dhcpd.leases里面保存一系列的租约声明(包括有客户端的主机名等等信息)。

启动的时候按照一般的daemon进行就可以了。

1…891011
Istyasna

Istyasna

GO FORTH now and create masterpieces of the publishing art!

55 日志
36 分类
189 标签
RSS
GitHub Aliyun
Creative Commons
Links
  • Homepage
  • Hainan University
  • Qi Qi
© 2016 - 2017 Istyasna
由 Hexo 强力驱动
主题 - NexT.Mist