Mark's profileMark's spacePhotosBlogLists Tools Help

Mark

西塘  
Photo 1 of 14
June 12

linux进程管理及作业控制(一)  

进程管理及作业控制(一)  

Linux是一个多任务的操作系统,系统上同时运行着多个进程,正在执行的一个或多个相关进程称为一个作业。使用作业控制,用户可以同时运行多个作业,并在需要时在作业之间进行切换。本章详细介绍进程管理及作业控制的命令,包括启动进程、查看进程、调度作业的命令。

进程及作业的概念

Linux是一个多用户多任务的操作系统。多用户是指多个用户可以在同一时间使用计算机系统;多任务是指Linux可以同时执行几个任务,它可以在还未执行完一个任务时又执行另一项任务。

操作系统管理多个用户的请求和多个任务。大多数系统都只有一个CPU和一个主存,但一个系统可能有多个二级存储磁盘和多个输入/输出设备。操作系统管理这些资源并在多个用户间共享资源,当您提出一个请求时,给您造成一种假象,好象系统只被您独自占用。而实际上操作系统监控着一个等待执行的任务队列,这些任务包括用户作业、操作系统任务、邮件和打印作业等。操作系统根据每个任务的优先级为每个任务分配合适的时间片,每个时间片大约都有零点几秒,虽然看起来很短,但实际上已经足够计算机完成成千上万的指令集。每个任务都会被系统运行一段时间,然后挂起,系统转而处理其他任务;过一段时间以后再回来处理这个任务,直到某个任务完成,从任务队列中去除。

Linux系统上所有运行的东西都可以称之为一个进程。每个用户任务、每个系统管理守护进程,都可以称之为进程。Linux用分时管理方法使所有的任务共同分享系统资源。我们讨论进程的时候,不会去关心这些进程究竟是如何分配的,或者是内核如何管理分配时间片的,我们所关心的是如何去控制这些进程,让它们能够很好地为用户服务。

进程的一个比较正式的定义是:在自身的虚拟地址空间运行的一个单独的程序。进程与程序是有区别的,进程不是程序,虽然它由程序产生。程序只是一个静态的指令集合,不占系统的运行资源;而进程是一个随时都可能发生变化的、动态的、使用系统运行资源的程序。而且一个程序可以启动多个进程。

Linux操作系统包括三种不同类型的进程,每种进程都有自己的特点和属性。

 

*

交互进程——由一个shell启动的进程。交互进程既可以在前台运行,也可以在后台运行。
*

批处理进程——这种进程和终端没有联系,是一个进程序列。
*

监控进程(也称守护进程)——Linux系统启动时启动的进程,并在后台运行。

上述三种进程各有各的作用,使用场合也有所不同。

进程和作业的概念也有区别。一个正在执行的进程称为一个作业,而且作业可以包含一个或多个进程,尤其是当使用了管道和重定向命令。例如“nroff -man ps.1|grep kill|more”这个作业就同时启动了三个进程。

作业控制指的是控制正在运行的进程的行为。比如,用户可以挂起一个进程,等一会儿再继续执行该进程。shell将记录所有启动的进程情况,在每个进程过程中,用户可以任意地挂起进程或重新启动进程。作业控制是许多shell(包括bash和tcsh)的一个特性,使用户能在多个独立作业间进行切换。

一般而言,进程与作业控制相关联时,才被称为作业。

在大多数情况下,用户在同一时间只运行一个作业,即它们最后向shell键入的命令。但是使用作业控制,用户可以同时运行多个作业,并在需要时在这些作业间进行切换。这会有什么用途呢?例如,当用户编辑一个文本文件,并需要中止编辑做其他事情时,利用作业控制,用户可以让编辑器暂时挂起,返回shell提示符开始做其他的事情。其他事情做完以后,用户可以重新启动挂起的编辑器,返回到刚才中止的地方,就象用户从来没有离开编辑器一样。这只是一个例子,作业控制还有许多其他实际的用途。

启动进程

键入需要运行的程序的程序名,执行一个程序,其实也就是启动了一个进程。在Linux系统中每个进程都具有一个进程号,用于系统识别和调度进程。启动一个进程有两个主要途径:手工启动和调度启动,后者是事先进行设置,根据用户要求自行启动。

手工启动

由用户输入命令,直接启动一个进程便是手工启动进程。但手工启动进程又可以分为很多种,根据启动的进程类型不同、性质不同,实际结果也不一样,下面分别介绍。

1. 前台启动

这或许是手工启动一个进程的最常用的方式。一般地,用户键入一个命令“ls –l”,这就已经启动了一个进程,而且是一个前台的进程。这时候系统其实已经处于一个多进程状态。或许有些用户会疑惑:我只启动了一个进程而已。但实际上有许多运行在后台的、系统启动时就已经自动启动的进程正在悄悄运行着。还有的用户在键入“ls –l”命令以后赶紧使用“ps –x”查看,却没有看到ls进程,也觉得很奇怪。其实这是因为ls这个进程结束太快,使用ps查看时该进程已经执行结束了。如果启动一个比较耗时的进程:

find / -name fox.jpg

然后再把该进程挂起,使用ps查看,就会看到一个find进程在里面。

 

 

2. 后台启动

直接从后台手工启动一个进程用得比较少一些,除非是该进程甚为耗时,且用户也不急着需要结果的时候。假设用户要启动一个需要长时间运行的格式化文本文件的进程。为了不使整个shell在格式化过程中都处于“瘫痪”状态,从后台启动这个进程是明智的选择。

[例1]

$ troff –me notes > note_form &

[1] 4513

$

由上例可见,从后台启动进程其实就是在命令结尾加上一个&号。键入命令以后,出现一个数字,这个数字就是该进程的编号,也称为PID,然后就出现了提示符。用户可以继续其他工作。

上面介绍了前、后台启动的两种情况。实际上这两种启动方式有个共同的特点,就是新进程都是由当前shell这个进程产生的。也就是说,是shell创建了新进程,于是就称这种关系为进程间的父子关系。这里shell是父进程,而新进程是子进程。一个父进程可以有多个子进程,一般地,子进程结束后才能继续父进程;当然如果是从后台启动,那就不用等待子进程结束了。

一种比较特殊的情况是在使用管道符的时候。例如:

nroff -man ps.1|grep kill|more

这时候实际上是同时启动了三个进程。请注意是同时启动的,所有放在管道两边的进程都将被同时启动,它们都是当前shell的子程序,互相之间可以称为兄弟进程。

以上介绍的是手工启动进程的一些内容,作为一名系统管理员,很多时候都需要把事情安排好以后让其自动运行。因为管理员不是机器,也有离开的时候,所以有些必须要做的工作而恰好管理员不能亲自操作,这时候就需要使用调度启动进程了。

调度启动

有时候需要对系统进行一些比较费时而且占用资源的维护工作,这些工作适合在深夜进行,这时候用户就可以事先进行调度安排,指定任务运行的时间或者场合,到时候系统会自动完成这一切工作。

要使用自动启动进程的功能,就需要掌握以下几个启动命令。

at命令

用户使用at命令在指定时刻执行指定的命令序列。也就是说,该命令至少需要指定一个命令、一个执行时间才可以正常运行。at命令可以只指定时间,也可以时间和日期一起指定。需要注意的是,指定时间有个系统判别问题。比如说:用户现在指定了一个执行时间:凌晨3:20,而发出at命令的时间是头天晚上的20:00,那么究竟是在哪一天执行该命令呢?如果用户在3:20以前仍然在工作,那么该命令将在这个时候完成;如果用户3:20以前就退出了工作状态,那么该命令将在第二天凌晨才得到执行。下面是at命令的语法格式:

at [-V] [-q 队列] [-f 文件名] [-mldbv] 时间

at -c 作业 [作业...]

at允许使用一套相当复杂的指定时间的方法,实际上是将POSIX.2标准扩展了。它可以接受在当天的hh:mm(小时:分钟)式的时间指定。如果该时间已经过去,那么就放在第二天执行。当然也可以使用midnight(深夜),noon(中午),teatime(饮茶时间,一般是下午4点)等比较模糊的词语来指定时间。用户还可以采用12小时计时制,即在时间后面加上AM(上午)或者PM(下午)来说明是上午还是下午。

也可以指定命令执行的具体日期,指定格式为month day(月 日)或者mm/dd/yy(月/日/年)或者dd.mm.yy(日.月.年)。指定的日期必须跟在指定时间的后面。

上面介绍的都是绝对计时法,其实还可以使用相对计时法,这对于安排不久就要执行的命令是很有好处的。指定格式为:now + count time-units ,now就是当前时间,time-units是时间单位,这里可以是 minutes(分钟)、hours(小时)、days(天)、weeks(星期)。count是时间的数量,究竟是几天,还是几小时,等等。

还有一种计时方法就是直接使用today(今天)、tomorrow(明天)来指定完成命令的时间。下面通过一些例子来说明具体用法。

[例2] 指定在今天下午5:30执行某命令。假设现在时间是中午12:30,1999年2月24日,其命令格式如下:

at 5:30pm

at 17:30

at 17:30 today

at now + 5 hours

at now + 300 minutes

at 17:30 24.2.99

at 17:30 2/24/99

at 17:30 Feb 24

 

以上这些命令表达的意义是完全一样的,所以在安排时间的时候完全可以根据个人喜好和具体情况自由选择。一般采用绝对时间的24小时计时法可以避免由于用户自己的疏忽造成计时错误的情况发生,例如上例可以写成:

at 17:30 2/24/99

这样非常清楚,而且别人也看得懂。

对于at命令来说,需要定时执行的命令是从标准输入或者使用-f选项指定的文件中读取并执行的。如果at命令是从一个使用su命令切换到用户shell中执行的,那么当前用户被认为是执行用户,所有的错误和输出结果都会送给这个用户。但是如果有邮件送出的话,收到邮件的将是原来的用户,也就是登录时shell的所有者。

[例3]

$ at -f work 4pm + 3 days

在三天后下午4点执行文件work中的作业。

$ at -f work 10am Jul 31

在7月31日上午10点执行文件work中的作业。

在任何情况下,超级用户都可以使用这个命令。对于其他用户来说,是否可以使用就取决于两个文件:/etc/at.allow和/etc/at.deny。如果/etc/at.allow文件存在的话,那么只有在其中列出的用户才可以使用at命令;如果该文件不存在,那么将检查/etc/at.deny文件是否存在,在这个文件中列出的用户均不能使用该命令。如果两个文件都不存在,那么只有超级用户可以使用该命令;空的/etc/at.deny文件意味着所有的用户都可以使用该命令,这也是默认状态。

下面对命令中的参数进行说明。

-V 将标准版本号打印到标准错误中。

-q queue 使用指定的队列。队列名称是由单个字母组成,合法的队列名可以由a-z或者A-Z。a队列是at命令的默认队列。

-m 作业结束后发送邮件给执行at命令的用户。

-f file 使用该选项将使命令从指定的file读取,而不是从标准输入读取。

-l atq命令的一个别名。该命令用于查看安排的作业序列,它将列出用户排在队列中的作业,如果是超级用户,则列出队列中的所有工作。

命令的语法格式如下:

atq [-V] [-q 队列] [-v]

-d atrm 命令的一个别名。该命令用于删除指定要执行的命令序列,语法格式如下:

atrm [-V] 作业 [作业...]

-c 将命令行上所列的作业送到标准输出。

[例4] 找出系统中所有以txt为后缀名的文件,并且进行打印。打印结束后给用户foxy发出邮件通知取件。指定时间为十二月二十五日凌晨两点。

首先键入:

$ at 2:00 12/25/99

然后系统出现at>提示符,等待用户输入进一步的信息,也就是需要执行的命令序列:

at> find / -name “*.txt”|lpr

at> echo “foxy:All texts have been printed.You can take them over.Good day!River” |mail -s ”job done” foxy

输入完每一行指令然后回车,所有指令序列输入完毕后,使用<Ctrl+d>组合键结束at命令的输入。这时候屏幕将出现如下信息:

warning:command will be executed using /bin/sh.

job 1 at 1999-12-25 02:00

提醒用户将使用哪个shell来执行该命令序列。

实际上如果命令序列较长或者经常被执行的时候,一般都采用将该序列写到一个文件中,然后将文件作为at命令的输入来处理。这样不容易出错。

 

[例5] 上面的例子可以修改如下:

将命令序列写入到文件/tmp/printjob,语句为:

$ at -f /tmp/printjob 2:00 12/25/99

这样一来,at命令将使用文件中的命令序列,屏幕显示如下:

Warning:command will be executed using /bin/sh.

job 2 at 1999-12-25 02:00

当然也可以采用以下命令:

$ at< /tmp/printjob 2:00 12/25/99

来完成同样的任务。也就是使用输入重定向的办法将文件定向为命令输入。

batch命令

batch 用低优先级运行作业,该命令几乎和at命令的功能完全相同,唯一的区别在于,at命令是在指定时间,很精确的时刻执行指定命令;而batch却是在系统负载较低,资源比较空闲的时候执行命令。该命令适合于执行占用资源较多的命令。

batch命令的语法格式也和at命令十分相似,即

batch [-V] [-q 队列] [-f 文件名] [-mv] [时间]

具体的参数解释请参考at命令。一般地说,不用为batch命令指定时间参数,因为batch本身的特点就是由系统决定执行任务的时间,如果用户再指定一个时间,就失去了本来的意义。

[例6] 使用例4,键入:

$ batch

at> find / -name *.txt|lpr

at> echo “foxy:All texts have been printed.You can take them over.Good day!River” |mail -s ”job done” foxy

现在这个命令就会在合适的时间进行了,进行完后会发回一个信息。

仍然使用<Ctrl+d>组合键来结束命令输入。而且batch和at命令都将自动转入后台,所以启动的时候也不需要加上&符号。

cron命令

前面介绍的两条命令都会在一定时间内完成一定任务,但是要注意它们都只能执行一次。也就是说,当指定了运行命令后,系统在指定时间完成任务,一切就结束了。但是在很多时候需要不断重复一些命令,比如:某公司每周一自动向员工报告头一周公司的活动情况,这时候就需要使用cron命令来完成任务了。

实际上,cron命令是不应该手工启动的。cron命令在系统启动时就由一个shell脚本自动启动,进入后台(所以不需要使用&符号)。一般的用户没有运行该命令的权限,虽然超级用户可以手工启动cron,不过还是建议将其放到shell脚本中由系统自行启动。

首先cron命令会搜索/var/spool/cron目录,寻找以/etc/passwd文件中的用户名命名的crontab文件,被找到的这种文件将载入内存。例如一个用户名为foxy的用户,它所对应的crontab文件就应该是/var/spool/cron/foxy。也就是说,以该用户命名的crontab文件存放在/var/spool/cron目录下面。cron命令还将搜索/etc/crontab文件,这个文件是用不同的格式写成的。

cron启动以后,它将首先检查是否有用户设置了crontab文件,如果没有就转入“休眠”状态,释放系统资源。所以该后台进程占用资源极少。它每分钟“醒”过来一次,查看当前是否有需要运行的命令。命令执行结束后,任何输出都将作为邮件发送给crontab的所有者,或者是/etc/crontab文件中MAILTO环境变量中指定的用户。

上面简单介绍了一些cron的工作原理,但是cron命令的执行不需要用户干涉;需要用户修改的是crontab中要执行的命令序列,所以下面介绍crontab命令。

crontab命令

crontab命令用于安装、删除或者列出用于驱动cron后台进程的表格。也就是说,用户把需要执行的命令序列放到crontab文件中以获得执行。每个用户都可以有自己的crontab文件。下面就来看看如何创建一个crontab文件。

在/var/spool/cron下的crontab文件不可以直接创建或者直接修改。crontab文件是通过crontab命令得到的。现在假设有个用户名为foxy,需要创建自己的一个crontab文件。首先可以使用任何文本编辑器建立一个新文件,然后向其中写入需要运行的命令和要定期执行的时间。

然后存盘退出。假设该文件为/tmp/test.cron。再后就是使用crontab命令来安装这个文件,使之成为该用户的crontab文件。键入:

crontab test.cron

这样一个crontab 文件就建立好了。可以转到/var/spool/cron目录下面查看,发现多了一个foxy文件。这个文件就是所需的crontab 文件。用more命令查看该文件的内容可以发现文件头有三行信息:

#DO NOT EDIT THIS FILE -edit the master and reinstall.

#(test.cron installed on Mon Feb 22 14:20:20 1999)

#(cron version --$Id:crontab.c,v 2.13 1994/01/17 03:20:37 vivie Exp $)

大概意思是:

#切勿编辑此文件——如果需要改变请编辑源文件然后重新安装。

#test.cron文件安装时间:14:20:20 02/22/1999

如果需要改变其中的命令内容时,还是需要重新编辑原来的文件,然后再使用crontab命令安装。

可以使用crontab命令的用户是有限制的。如果/etc/cron.allow文件存在,那么只有其中列出的用户才能使用该命令;如果该文件不存在但cron.deny文件存在,那么只有未列在该文件中的用户才能使用crontab命令;如果两个文件都不存在,那就取决于一些参数的设置,可能是只允许超级用户使用该命令,也可能是所有用户都可以使用该命令。

crontab命令的语法格式如下:

crontab [-u user] file

crontab [-u user]{-l|-r|-e}

 

第一种格式用于安装一个新的crontab 文件,安装来源就是file所指的文件,如果使用“-”符号作为文件名,那就意味着使用标准输入作为安装来源。

-u 如果使用该选项,也就是指定了是哪个具体用户的crontab 文件将被修改。如果不指定该选项,crontab 将默认是操作者本人的crontab ,也就是执行该crontab 命令的用户的crontab 文件将被修改。但是请注意,如果使用了su命令再使用crontab 命令很可能就会出现混乱的情况。所以如果是使用了su命令,最好使用-u选项来指定究竟是哪个用户的crontab文件。

-l 在标准输出上显示当前的crontab。

-r 删除当前的crontab文件。

-e 使用VISUAL或者EDITOR环境变量所指的编辑器编辑当前的crontab文件。当结束编辑离开时,编辑后的文件将自动安装。

[例7]

# crontab -l #列出用户目前的crontab。

10 6 * * * date

0 */2 * * * date

0 23-7/2,8 * * * date

#

在crontab文件中如何输入需要执行的命令和时间。该文件中每行都包括六个域,其中前五个域是指定命令被执行的时间,最后一个域是要被执行的命令。每个域之间使用空格或者制表符分隔。格式如下:

minute hour day-of-month month-of-year day-of-week commands

第一项是分钟,第二项是小时,第三项是一个月的第几天,第四项是一年的第几个月,第五项是一周的星期几,第六项是要执行的命令。这些项都不能为空,必须填入。如果用户不需要指定其中的几项,那么可以使用*代替。因为*是统配符,可以代替任何字符,所以就可以认为是任何时间,也就是该项被忽略了。在表4-1中给出了每项的合法范围。

 

表4-1 指定时间的合法范围

时间

合法值

minute

00-59

hour

00-23,其中00点就是晚上12点

day-of-month

01-31

month-of-year

01-12

day-of-week

0-6,其中周日是0

 

这样用户就可以往crontab 文件中写入无限多的行以完成无限多的命令。命令域中可以写入所有可以在命令行写入的命令和符号,其他所有时间域都支持列举,也就是域中可以写入很多的时间值,只要满足这些时间值中的任何一个都执行命令,每两个时间值中间使用逗号分隔。

[例8]

5,15,25,35,45,55 16,17,18 * * * command

这就是表示任意天任意月,其实就是每天的下午4点、5点、6点的5 min、15 min、25 min、35 min、45 min、55 min时执行命令。

[例9] 在每周一,三,五的下午3:00系统进入维护状态,重新启动系统。那么在crontab 文件中就应该写入如下字段:

00 15 * * 1,3,5 shutdown -r +5

然后将该文件存盘为foxy.cron,再键入crontab foxy.cron安装该文件。

[例10] 每小时的10分,40分执行用户目录下的innd/bbslin这个指令:

10,40 * * * * innd/bbslink

[例11] 每小时的1分执行用户目录下的bin/account这个指令:

1 * * * * bin/account

[例12] 每天早晨三点二十分执行用户目录下如下所示的两个指令(每个指令以;分隔):

20 3 * * * (/bin/rm -f expire.ls logins.bad;bin/expire>expire.1st)

[例13] 每年的一月和四月,4号到9号的3点12分和3点55分执行/bin/rm -f expire.1st这个指令,并把结果添加在mm.txt这个文件之后(mm.txt文件位于用户自己的目录位置)。

12,55 3 4-9 1,4 * /bin/rm -f expire.1st>>mm.txt

[例14] 我们来看一个超级用户的crontab文件:

#Run the ‘atrun’ program every minutes

#This runs anything that’s due to run from ‘at’.See man ‘at’ or ‘atrun’.

0,5,10,15,20,25,30,35,40,45,50,55 * * * * /usr/lib/atrun

40 7 * * * updatedb

8,10,22,30,39,46,54,58 * * * * /bin/sync

进程的挂起及恢复命令bg、fg

作业控制允许将进程挂起并可以在需要时恢复进程的运行,被挂起的作业恢复后将从中止处开始继续运行。只要在键盘上按<ctrl+z>,即可挂起当前的前台作业。

[例15]

$ cat > text.file

<ctrl+z>

[1] + stopped cat > text.file

$ jobs

[1]+ stopped cat > text.file

在键盘上按<ctrl+z>后,将挂起当前执行的命令cat。使用jobs命令可以显示shell的作业清单,包括具体的作业、作业号以及作业当前所处的状态。

恢复进程执行时,有两种选择:用fg命令将挂起的作业放回到前台执行;用bg命令将挂起的作业放到后台执行。

[例16] 用户正在使用Emacs,突然需要查看系统进程情况。就首先使用<Ctrl+z>组合键将Emacs进程挂起,然后使用bg命令将其在后台启动,这样就得到了前台的操作控制权,接着键入“ps –x”查看进程情况。查看完毕后,使用fg命令将Emacs带回前台运行即可。其命令格式为:

<Ctrl+z>

$ bg emacs

$ ps –x

$ fg emacs

默认情况下,fg和bg命令对最近停止的作业进行操作。如果希望恢复其他作业的运行,可以在命令中指定要恢复作业的作业号来恢复该作业。例如:

$ fg 1

cat > text.file

灵活使用上述命令,将给自己带来很大的方便。






用java调用linux的操作系统命令

import   java.io.BufferedInputStream;  
  import   java.io.IOException;  
   
  public   class   ExecLs   {  
   
  static   public   void   main(String[]   args)   {  
  String   cmd   =   "ls"  
   
  try   {  
  Process   ps   =   Runtime.getRuntime().exec(cmds);  
  System.out.print(loadStream(ps.getInputStream()));  
  System.err.print(loadStream(ps.getErrorStream()));  
  }   catch(IOException   ioe)   {  
  ioe.printStackTrace();  
  }  
  }  
   
  //   read   an   input-stream   into   a   String  
  static   String   loadStream(InputStream   in)   throws   IOException   {  
  int   ptr   =   0;  
  in   =   new   BufferedInputStream(in);  
  StringBuffer   buffer   =   new   StringBuffer();  
  while(   (ptr   =   in.read())   !=   -1   )   {  
  buffer.append((char)ptr);  
  }  
  return   buffer.toString();  
  }  
   
  }
May 14

有关raw socket的一些知识

有关raw socket的一些知识 众所周知,通过socket编程,我们能够实现机器之间的通信.在TCP/IP协议簇(PF_INET)中,可以建立面向连接的SOCK_STREAM类型的socket,非连接的SOCK_DGRAM类型的socket.事实上,在所有的网络程序中,也是这两种socket用的最为广泛.除此之外,还有一些不常用的socket类型,它们却是在某些网络通信中担当重要的角色.这里要讲的就是这么一种socket,称之为raw socket.raw socket的作用主要在三个方面: 1.通过raw socket来接受发向本机的ICMP,IGMP协议包,或者用来发送这些协议包. 2.接受发向本机的但TCP/IP栈不能够处理的IP包. 3.用来发送一些自己制定源地址特殊作用的IP包(自己写IP头,TCP头等等) 我们知道,平时我们想看一看网络是否通达,就用ping命令测试一些.ping 命令用的是ICMP协议.因此,我们不能够通过建立一个SOCK_STREAM或SOCK_DGRAM来发送这个包,只能够自己亲自来构建ICMP包来发送.这是一种情况.另一种情况是:现在许多操作系统在实现网络部分的时候,通常只实现了常用的几种协议, 如tcp,udp,icmp等,但象其它的如ospf,ggp等协议,操作系统往往没有实现,如果自己有必要编写位于其上的应用,就必须借助raw socket来实现,这是因为操作 系统遇到自己不能够处理的数据包(ip头中的protocol所指定的上层协议不能处理).就将这个包交给raw socket.而最后一种使用raw socket的目的主要是用来构建一些特殊的协议头,比如我们想对某台机器进行denial of service类型的攻击,但是有不想留下痕迹,让别人知道IP包的来源,这时候就可以使用rawsocket来发送这些伪造源地址信息的包,这其实也是这种攻击所采用的主要技术手段.当然了,我说的是HACKER行为,之所以想要处理这些特殊的IP包,通常也是为了诊断网络的目的. raw socket的建立是通过如下方式的: sockfd = socket(PF_INET, SOCK_RAW, protocol); 第一个参数就不必讲了,第二个参数说明建立的是一个raw socket,第三个参数倒是需要详细解说一下.这里分三种情况: 1.参数protocol用来指明所要接收的协议包,如果是象IPPROTO_TCP(6)这种非0,非255的协议,则内核碰到ip头中 protocol域和创建socket所使用参数protocol相同的IP包,就会交给这个rawsocket来处理.因此,一般说来,要想接收什么样的数据包,就应该在参数protocol里来指定相应的协议.当内核向此raw socket交付数据包的时候,是包括整个IP头的,并且已经是重组好的IP包. 如下: --------------------------------------------------------------- |ip header|tcp header(or x header)| data | --------------------------------------------------------------- 用recvfrom收到的数据包括一个IP头,一个相应的协议头,然后是数据(数据也可以为空,就看实际情况了). 但当我们发送IP包的时候,却不用亲自处理IP包头,只需要填充参数protocol所指定的相应的协议头即可.也就是说,用sendto的时候,我们提供给它的缓冲区数据是从IP包头的第一个字节开始,如下,只需要构造这么一个缓冲区就可以了. -------------------------------------------------------------- |tcp header(or udp header or x header)| data | -------------------------------------------------------------- 如果想自己也想亲自处理IP头,则需要IP_HDRINCL的socket选项.如下: int flag = 1; setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &flag, sizeof(int)); 这样,发送时所要提供的缓冲区有成如下形式: --------------------------------------------------------------- |ip header|tcp header(or x header)| data | --------------------------------------------------------------- 但是,即时是这种情况,在我们发送IP包的时候.也不是填充ip头的所有字段,而是应该将ip头的id(identification)字段设置为0,表示让内核来处理这个字段.同时,内核还帮你完成ip头的校验和的计算,并随后填充check字段. 2.如果protocol是IPPROTO_RAW(255),这时候,这个socket只能用来发送IP包,而不能接收任何数据.发送的数据需要自己填充IP包头,并且自己计算校验和. 3.对于protocol为0(IPPROTO_IP)的raw socket. 在linux和sco unix上是不允许建立的.我没有再试过其他操作系统,谁能给我一个答案:) 对于raw socket,只有root权限才能够创建. 这里对raw socket总结一下: 当内核接收到IP包的时候,首先检查ip包的protocol域,当存在与此域匹配的raw socket时,就将包先传给此raw socket,然后交给相应的上层协议处理.交给raw socket的数据是包括IP头并且已经重组完成后的.当使用raw socket发送包的时候,如果raw socket创建时的protocol不是0或255,并且没有设置IP_HDRINCL选项,则发送的数据不包括IP头.如果此选项置位,则需要自己构件IP头.如果创建protocol为255的raw socket,此rawsocket只能用来发送包括IP头,自己构建IP包. 附录: IP头结构: struct iphdr |-------|--------|---------------|-------------------------------| |version| ihl | tos | tot_len | |-------|--------|---------------|-------------------------------| | id | | frag_off | |----------------|---------------|-------------------------------| | ttl | protocol | check | |----------------|---------------|-------------------------------| | saddr | |----------------------------------------------------------------| | daddr | |----------------------------------------------------------------| 参考书籍: Unix Network Programming (Volume 1 SECOND EDITION P655-P702)
April 04

nesC Module

Module 问题
ledi 发表于 2006-5-16 19:29:00

接口PeriodicReaderC:
module PeriodicReaderC {
provides interface StdControl;
uses interface Timer<TMilli>;
uses interface Read<uint16_t>;
}
implementation {
uint16_t lastVal = 0;
command error_t StdControl.start() {
return call Timer.startPeriodic(1024);
}
command error_t StdControl.stop() {
return call Timer.stop();
}
event void Timer.fired() {
call Read.read();
}
event void Read.readDone(error_t err, uint16_t val) {
if (err == SUCCESS) {
lastVal = val;
}
}
}
知识点:在provides中提供的命令与使用的event的必须在implementation中实现。
问题:1 在此接口中command error_t StdControl.start()
        与return call Timer.startPeriodic(1024)的关系是如何确定的?
      2 error_t的数据类型定义的具体含义是什么??

March 20

BNF范式和EBNF范式

BNF范式和EBNF范式

关键字: BNF 范式
1、什么是BNF范式,什么又是EBNF范式?(在学习中经常会碰到用BNF范式描述的规则,老是忘记每个符号确切的作用,现在把他们一一罗列如下,亲手记录的东西应该能记住吧。。。-__-|||)
答:巴科斯范式及其扩展(BNF & Augmented BNF)
1)巴科斯范式:巴科斯范式(BNF: Backus-Naur Form 的缩写)是由 John Backus 和 Peter Naur 首先引入的用来描述计算机语言语法的符号集。现在,几乎每一位新编程语言书籍的作者都使用巴科斯范式来定义编程语言的语法规则。
2)巴科斯范式的内容:
在双引号中的字("word")代表着这些字符本身。而double_quote用来代表双引号。
在双引号外的字(有可能有下划线)代表着语法部分。
< > : 内包含的为必选项。
[ ] : 内包含的为可选项。
{ } : 内包含的为可重复0至无数次的项。
| : 表示在其左右两边任选一项,相当于"OR"的意思。
::= : 是“被定义为”的意思
3)扩展的巴科斯范式(Augmented BNF):RFC2234 定义了扩展的巴科斯范式(ABNF)。近年来在Internet的定义中ABNF被广泛使用。ABNF做了更多的改进,比如说,在ABNF中,尖括号不再需要。
4)EBNF的基本内容:
"..." : 术语符号
[...] : 选项:最多出现一次
{...} : 重复项: 任意次数,包括 0 次
(...) : 分组
| : 并列选项,只能选一个
斜体字: 参数,在其它地方有解释

例子BNF应用较多,以下给出一个简单例子,这是用BNF来定义的Java语言中的For语句的实例:
FOR_STATEMENT ::=
"for" "(" ( variable_declaration |
( expression ";" ) | ";" )
[ expression ] ";"
[ expression ] ";"
")" statement
August 26

java的转义字符

\n 回车(\u000a)
\t 水平制表符(\u0009)
\b 空格(\u0008)
\r 换行(\u000d)
\f 换页(\u000c)
\' 单引号(\u0027)
\" 双引号(\u0022)
\\ 反斜杠(\u005c)
\ddd 三位八进制
\udddd 四位十六进制

上周发现还有其它需要转义的字符,例如

 String sName = "Java转义字符(补遗)";
 sName = sName.replaceFirst("(补遗)","");
 out.println(sName);

 如果你以为会输出“Java转义字符”,那你就错了,事实上输出“Java转义字符()”,我也很奇怪,以为是中英文括号的问题,可是并不是,我不确定是否转义问题,解决方法是

 sName = sName.replaceFirst("\\(补遗\\)",""); 

April 23

MRTG流量监控

MRTG (Multi Router Traffic Grapher)是一款监控网络流量负载的免费软件,目前利用MRTG已经开发出了各式各样的统计系统:
1.系统资源负载统计,例如:磁盘空间、CPU负载、内存用量等等
2.Server流量统计,例如:Mail、DNS、Web、BBS、IRC等等
3.网络设备流量统计,例如:防火墙、路由器、交换机等等
4.另类统计,例如:Modem流量、Login人数、联机游戏人数等等。
MRTG是利用SNMP协议去查询指定有SNMP协议的设备,定时统计其设备的流量或负载,再将统计结果绘成统计图,从统计图上能很容易、直观地就能查出流量或负载。以思科2950为例来说明一下本软件的使用过程:

一、2950端的配置
2950端需要将SNMP功能打开(一般网络设备出厂设置是打开SNMP的),并做相应的设置,具体如下:
telnet 10.10.100.13
123# conf t
\\进入特权配置模式
123(config)# snmp-server community 5haolou RO(此处不是零)
\\设置SNMP的团体名为5haolou
123(config)# snmp-server trap-source FastEthernet0/1
\\以Fa0/1端口为监控源,如果不输,将以设备自身的ROUTER ID作为监控源
123(config)# snmp-server contact
qufeng13_2003@126.com
\\设置管理者的邮箱地址
123(config)# snmp-server host 10.10.100.201 5haolou
\\设置管理机的IP地址为10.10.100.201,并设置团体名5haolou
123(config)# snmp-server enable traps
\\启动监控
123#copy run start
\\保存设置
至此已经完成在2950设备上的所有配置。

二、监控端的配置
需要使用的软件:
1.Perl
2.MRTG
3.微软的工具软件 :INSTSRV.exe
SRVANY.exe
软件安装步骤:
1.Perl的安装
Perl的安装比较简单,目前使用的一般是Active Perl for windows,现在最新的版本是5.8.0,它需要使用者先安装IIS或者APACHE等常用的Web服务器平台。在linux/unix操作系统中Perl是系统自带的。
安装Perl的过程其实很简单的,打开PERL的安装文件,点下一步,然后同意软件使用权的协议,下一个画面会让您确认是否使用PPM3发送个人信息至ASPN,不要选它,直接按下一步。然后就是下一步直通车,直至Perl安装成功,重新启动计算机生效。
注意:本文安装路径选择d:\perl。
安装完毕的检查方法:
我的电脑右键单击——管理——服务和应用程序——Internet信息服务管理(IIS)——网站右键单击——属性——主目录——配置,调出下图,查看有没有.pl,.plx扩展名,如果有就说明perl安装成功了。

2.MRTG的安装
Mrtg在windows下的安装很简单,只需要将mrtg.***直接解压到某个盘就好了,比如解压到:d:\mrtg
同时还要建立一个目录来存放我们要生成的文件,如:d:\mrtgwww,同时将d:\mrtg\images的所有文件复制到d:\wwwmrtg下。
接下来我们就可以做mrtg的配置了。
开始——运行——cmd进入dos窗口进行相关配置。

①、配置文件的生成(由cfgmaker来生成)
首先进入到目录d:\mrtg\bin(mrtg解压后的目录),执行如下命令:
D:\mrtg\bin>perl cfgmaker 5haolou@10.10.100.13 --global “workdir: d:\wwwmrtg” --output mrtg5haolou.cfg

5haolou是SNMP的通信密码,一般是交换机的出厂设置是public,10.10.100.13是被监控设备的IP,生成的文件默认路径为D:\mrtg\bin(一定要注意那些地方有空格,那些地方没有)。
安装完毕的检查方法:
输入以下命令:
D:\mrtg\bin>perl mrtg mrtg.cfg
会出现警告,不用管,连续运行三次就不会出现了。

②、配置文件的修改(mrtg5haolou.cfg)

其中的第4,5行是新加进去的语句,保证能够自动更新(interval后的5表示每5分钟刷新一次,可根据实际情况进行修改,另外,如果不加RunAsDaemon:yes这个参数,PERL执行MRTG后会自然中止,切记)。
将第12行前面的#符号去掉,如果没有此行就加入,使显示以bits为单位
加入language: GB2312,使显示界面为汉语
然后保存关闭即可。(注意:修改之前一定要备份文件,防止出现意外)

③运行如下命令:
D:\mrtg\bin>perl mrtg mrtg5haolou.cfg
如果出现以下语句就表明mrtg工作正常:
Daemoning mrtg…
Do not close this window,or mrtg will die
就是告诉你不要关闭这个窗口,否则mrtg就无法工作.

④添加服务MRTG为一项随机启动服务
由于MRTG是用perl编写的,所以不能直接添加为windows的服务,需要以下两个小程序:Instsrv.exe和srvany.exe,可以用google直接搜索下载到。将Instsrv.exe和srvany.exe放到d:\mrtg\bin目录(为了方便起见),执行如下命令:
d:\mrtg\bin>instsrv MRTG d:\mrtg\bin\srvany.exe
会出现添加服务成功的提示。
接下来需要修改注册表的内容:
HKEY_LOCAL_MACHINE——system——currentcontrolset——service——MRTG
为其新建一个名为parameters的项
在该项下添加以下键值(字符串)
Application 值为: d:\perl\bin\perl.exe(perl的安装目录)
AppDirectory 值为: d:\mrtg\bin
AppParameters 值为: mrtg mrtg5haolou.cfg
添加完以后就可以把MRTG服务启动了。
启动方法:在控制面板\管理工具\服务中,找到MRTG服务,启用服务,MRTG即可全天监视指定设备的网络信息了。

⑤建立MRTG统计网页(使用indexmaker)
d:\mrtg\bin>perl indexmaker mrtg5haolou.cfg >D:\wwwmrtg\index.htm
这样就生成了统计的网页D:\wwwmrtg\index.htm。
可以通过修改mrtg5haolou.cfg中每个端口的Title、PageTop信息来指定每个端口流量信息页面的标题,可以修改mrtg5haolou.cfg中其他的一些信息,也可以修改index.htm文件来改变页面的显示,当然你每次修改之前最好备份一下mrtg5haolou.cfg文件。

3、为了使系统在每次开机后,能自动运行该命令,我们还需要在启动里面加入以下快捷方式。
①在桌面击右键,选择快捷方式。
②输入快捷方式的运行命令行为 start /D d:\mrtg\bin wperl mrtg --logging=mrtg5haolou.log mrtg5haolou.cfg。
③输入一个好记的文件名,如“mrtg流量监控”。
④运行后,查看bin目录中有没有mrtg5haolou.cfg_l文件,如果有就是执行成功了。

至此,如果在IIS中为index.htm添加一个联接,MRTG就可以正常运行了,并且会给我们提供每5分钟流量图,每日流量图,每周流量图,每月流量图,每年流量图。