<?xml version="1.0" encoding="GB2312"?>
<rss version="2.0">
<channel>
<title><![CDATA[中国元素]]></title>
<link>http://blog.edu.cn/user2/35840/index.shtml</link>
<description><![CDATA[中国元素]]></description>
<item>
<title><![CDATA[LINUX 命令集合]]></title>
<link>http://blog.edu.cn/user2/35840/archives/2008/2178373.shtml</link>
<description><![CDATA[<P>更改telnet登录慢的问题: <BR>&nbsp;cd /etc <BR>&nbsp;vi resolv.conf <BR>&nbsp;将里面内容清空 </P>
<P><BR>更改root用户不能直接远程登录问题: <BR>cd /etc <BR>cd pam.d <BR>vi login <BR>注释掉这行 <BR>#auth required pam_securetty.so //该行注释掉 </P>
<P>挂接USB移动硬盘 <BR>将移动硬盘挂上. <BR>#df 查看Linux下硬盘盘符 <BR>mount /dev/sda1 /mnt/usb (举例) </P>
<P>Linux时区同步问题(安装ntp软件过程) <BR>首先在<A href="http://www.meinberg.de/english/sw/index.htm">http://www.meinberg.de/english/sw/index.htm</A> <BR>下载了一个windows的NTP服务程序：ntp4171.zip <BR>windows 192.168.1.32 <BR>1.安装是提示设置服务器地址，我设置的本机widows机器的IP <BR>2.ntpd的控制在： <BR>控制面板-&gt;管理工具-&gt;组件服务-NetworkTimeProtocol <BR>3.可以启动ntpd守护进程保持时间同步 <BR>4.在C:\WINNT目录下有个ntp的配置文件ntp.conf <BR>设置为： <BR>server 127.127.1.0 prefer <BR>fudge 127.127.1.0 stratum 10 <BR>5.确定ntp是否工作: ntpq -p <BR>linux和Windows同步，我用的是RedHat 9.0 <BR>执行命令：ntpdate 192.168.1.32 <BR>你就会发现你的时间变化了，和192.168.1.32的时间一样 <BR>如果执行命令出现一下错误 <BR>1.提示：7 Dec 19:24:55 ntpdate[2120]: the NTP socket is in use, exiting <BR>这个是你linux机器上已经存在这个进程，输入：ps -ef | grep ntpd <BR>Kill掉ntp的进程 <BR>2.提示：No Server suitable for synchronization found <BR>这个是最容易出现的问题，比较常见的是配置好服务器并启动服务器进程后，马上 <BR>启动客户进程，那么客户进程就会报错。解决方法是，在大约3-5分钟以后启动进程就行 <BR>我想每10分钟就和Windows服务同步时间 <BR>1.创建自己的一个crontab文件，随便建立一个文件date.cron，首先可以使用任何文本 <BR>编辑器建立一个新文件，然后向其中写入需要运行的命令和要定期执行的时间。 <BR>vi date.cron加入下面要运行的命令和要定期执行的时间 <BR>*/10 * * * * /usr/sbin/ntpdate 192.168.1.32 <BR>然后存盘退出 <BR>2.使用crontab命令来安装这个文件，使之成为该用户的crontab文件。键入： <BR>crontab date.cron <BR>这个文件已经建立好了 <BR>3.使用命令： <BR>crontab -l (查看安排的作业序列）可以看到刚才的作业 <BR>如： <BR>[root@NXD-TEST root]# crontab -l <BR># DO NOT EDIT THIS FILE - edit the master and reinstall. <BR># (date.cron installed on Tue Dec 7 18:22:42 2004) <BR># (Cron version -- $Id: crontab.c,v 2.13 1994/01/17 03:20:37 vixie Exp $) <BR>*/10 * * * * /usr/sbin/ntpdate 192.168.1.32 <BR>现在就OK了，每10分钟Linux就和服务端同步一次。 </P>
<P>更改Linux启动时用图形界面还是字符界面 <BR>cd /etc <BR>vi inittab <BR>将id:5:initdefault: 其中5表示默认图形界面 <BR>改id:3: initdefault: 3表示字符界面 </P>
<P>重新启动xinetd) <BR>/etc/init.d/xinetd restart </P>
<P>重启smb服务 <BR>/etc/init.d/smb restart </P>
<P>配置smb可以被哪些IP所用. <BR>cd /etc/samba <BR>Vi smb.conf <BR>找到hosts allow = 192.168.1. 192.168.2. 127. <BR>修改其为哪些机器所用,注意IP之间用逗号分开 <BR>举例: <BR>hosts allow =192.168.1.110,192.168.1.120 </P>
<P>禁止在后台使用CTRL-ALT-DELETE重起机器 <BR>cd /etc/inittab <BR>vi inittab 在文件找到下面一行 <BR># Trap CTRL-ALT-DELETE <BR>ca::ctrlaltdel:/sbin/shutdown -t3 -r now （注释掉这一行） <BR>如： # Trap CTRL-ALT-DELETE <BR>#ca::ctrlaltdel:/sbin/shutdown -t3 -r now </P>
<P>修改主机名 <BR>vi /etc/sysconfig/network <BR>修改HOSTNAME一行为HOSTNAME=主机名 </P>
<P>重新启动FTP服务 <BR>/sbin/service vsftpd restart </P>
<P>查看开机检测的硬件 <BR>dmesg | more </P>
<P>查看硬盘使用情况 <BR>df –m </P>
<P>查看目录的大小 <BR>du –sh dirname </P>
<P>忘记了root密码 <BR>一. lilo <BR>1. 在出现lilo菜单的时候按“ctrl+x”或者“Tab"，然后输入：linux single <BR>或者用光盘 <BR>在出现 lilo: 提示时键入 linux single <BR>画面显示 lilo: linux single <BR>2. 回车可直接进入linux命令行 <BR>3. #vi /etc/shadow <BR>将第一行，即以root开头的一行中root:后和下一个:前的内容删除， <BR>第一行将类似于 <BR>root::...... <BR>保存 <BR>4. #reboot重启，root密码为空 </P>
<P>二.grub <BR>1.出现grub画面时，用上下键选启动Linux的哪一项，按e键 <BR>2.上下键选择 kernel /boot/……… 然后按e键 <BR>3.修改现在见到的命令好，加入single 结果： <BR>kernel /boot/vmlinuz-2.4.20-8 single ro root=LABEL= <BR>4.回车返回，按b键启动，直接进入linux命令行 <BR>直接执行: passwd root <BR>修改密码，你的密码就搞定 <BR>5.也可以修改/etc/shadow中 <BR>将第一行，即以root开头的一行中root:后和下一个:前的内容删除， <BR>第一行将类似于 <BR>root::...... <BR>保存 <BR>reboot重启，root密码为空 </P>
<P>显示系统运行了多长时间 <BR>uptime </P>
<P>重新启动网络 <BR>/etc/init.d/network restart </P>
<P>查看端口 <BR>netstat –an <BR>netstat -anp </P>
<P>端口的详细列表 <BR>/etc/services </P>
<P>查看物理信息 <BR>lspci </P>
<P>安装图形界面不能出现，使用解析进行安装 <BR>Linux lowres (使用的是640X480分辨率) </P>
<P>屏蔽主机的ping 命令，是被别人无法ping你的机器 <BR>echo 1 &gt; /proc/sys/net/ipv4/icmp_echo_ignore_all </P>
<P>彻底删除Oracle安装的程序,删除一下几个目录 <BR>/etc/oraInst.loc /tmp/ /etc/oratab $ORACLE_BASE/* </P>
<P><BR>RPM包 <BR>1.卸载 RPM –e <BR>2.查询 rpm –q <BR>-a 查询所有已安装的软件包 <BR>-f 查询包含文件的软件的包 <BR>-i 显示软件包信息 <BR>-l 显示软件包的文件列表 <BR>3.验证 rpm –v <BR>rpm –Va 验证整个文件丢失了哪些文件 <BR>碰到不认识的文件使用 <BR>rpm –qf <BR>4.一个rpm包安装到哪里去了（已经安装的包） <BR>rpm –qi 包名(这里不包括.rpm后缀的软件名称，也就是说只能用mysql或者mysql-3.23.54a而不是mysql-3.23.54a.rpm) <BR>5.一个rpm包中包含哪些文件 <BR>一个没有安装过的软件包：使用rpm –qip ***.rpm <BR>一个已经安装过的软件包: 使用rpm –qi ***.rpm </P>
<P>看已经安装的字符集 <BR>locale –a </P>
<P>抓包命令tcpdump <BR>例：抓获192.168.1.32 的主机收到和发出的所有的数据包 <BR>tcpdump host 192.168.1.32 <BR>截获特定的端口 <BR>tcpdump tcp port 21 host 192.168.1.32 </P>
<P>文本截面的中文支持 <BR>RH 9.0自带安装包 zhcon_0.2.3_1.rh9.i386.rpm <BR>安装完成后，执行: zhcon 就可以支持中文了 </P>
<P><BR>查看端口现在运行什么程序 <BR>lsof –i:8001 </P>
<P>察看实时的日志 <BR>tail –f /var/log/messages </P>
<P>当mount出现死的现象 <BR>1.fuser –m /mnt/share 查出该程序的进程，然后Kill掉 <BR>2.再umount /mnt/share </P>
<P>linux 控制 windows <BR>1.用RH9.0自己带rdesktop,版本是1.2.0 <BR>命令：rdesktop –u user –f 192.168.1.70 色默认的是8位 <BR>2要达到16色，就要下载新版本1.3.0 <BR>rdesktop –a 16 –u lichuanhua –g 800*600 192.168.1.70 </P>
<P>Linux挂载Windows分区 <BR>mount ntfs分区 <BR>一.单机挂windows的NTFS分区 <BR>1. 上<A href="http://www.google.com">www.google.com</A>搜索并下载 kernel-ntfs-2.4.18-14.i686.rpm <BR>2. rpm -ivh kernel-ntfs-2.4.18-14.i686.rpm <BR>3. mkdir /mnt/share <BR>4. mount -t ntfs /dev/hda1 /mnt/share <BR>要挂载Windows分区，首先新建一个目录/mnt/share，修改/etc/fstab，在最末尾添上（假设Windows安装在硬盘的第1个分区） <BR>/dev/hda1 /mnt/share ntfs defaults 0 0 <BR>二.网络上一台windows和linux机器，linux机器挂载windows上的共享文件 <BR>windows IP:192.168.1.1 <BR>1.linux挂载192.168.1.1(windows)上共享文件dbf,挂在linux的/mnt/share目录下,在/mnt下建立share目录 <BR>mount -t smbfs -o username=massky,password=massky //192.168. <BR>1.1/dbf /mnt/share <BR>2.机器重启自动挂载，vi /etc/fstab最后加入： <BR>//192.168.1.1/dbf /mnt/share smbfs defaults,auto,username=m <BR>assky,password=massky 0 0 </P>
<P>Oracle9i在Linux9.0上的安装 <BR>1.确保RPM开发包，使用下面命令查看是否已安装这些包 <BR>rpm -q gcc cpp compat-libstdc++ glibc-devel glibc-kernheaders binutils <BR>2.进行解压 <BR>zcat Linux9i_Disk1.cpio.gz | cpio -idmv <BR>zcat Linux9i_Disk2.cpio.gz | cpio -idmv <BR>zcat Linux9i_Disk3.cpio.gz | cpio -idmv <BR>3.设置内核参数 <BR>vi /etc/sysctl.conf,加入下面参数 <BR>kernel.shmmax=4294967295 内存512M <BR>计算方法为：kernel:shmmax=1024*1024*RAM(M)/2 <BR>执行sysctl -p生效 <BR>4.建立数据目录和用户 <BR>groupadd dba <BR>groupadd oinstall <BR>useradd –g oinstall –G dba oracle <BR>passwd oracle </P>
<P>mkdir /opt/oracle <BR>mkdir /opt/oracle/product <BR>mkdir /opt/oracle/product/9.2.0 <BR>chown –R oracle.oinstall /opt/oracle <BR>mkdir /var/opt/oracle <BR>chown oracle.dba /var/opt/oracle <BR>chmod 755 /var/opt/oracle <BR>5.vi .bash_profile 设置变量 <BR>export LD_ASSUME_KERNEL=2.4.1 <BR>export ORACLE_BASE=/opt/oracle <BR>export ORACLE_HOME=/opt/oracle/product/9.2.0 <BR>export ORACLE_SID=ora9i <BR>export ORACLE_TERM=xterm <BR>export TNS_ADMIN=$ORACLE_HOME/network/admin <BR>export NLS_LANG=AMERICAN_AMERICA.ZHS16GBK <BR>export ORA_NLS33=$ORACLE_HOME/ocommon/nls/admin/data <BR>LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib <BR>LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib <BR>export LD_LIBRARY_PATH </P>
<P>export PATH=$PATH:$ORACLE_HOME/bin <BR>CLASSPATH=$ORACLE_HOME/JRE:$ORACLE_HOME/jlib:$ORACLE_HOME/rdbms/jlib <BR>CLASSPATH=$CLASSPATH:$ORACLE_HOME/network/jlib <BR>export CLASSPATH </P>
<P><BR>网卡的激活与停止 <BR>超级用户; <BR>ifconfig eth0 down 停止 <BR>ifconfig eth0 up 启动 </P>
<P>Linux下cvs的安装配置 <BR>1.安装CVS软件包. <BR>2.groupadd cvs <BR>3.useradd -g cvs cvsroot <BR>4.chmod 777 -R /home/cvsroot <BR>5.cd /etc <BR>6.vi profile <BR>新增以下二行: <BR>CVSROOT=/home/cvsroot export CVSROOT <BR>CVSEDIT=vi export CVSEDIT <BR>7.查看/etc/services文件中cvspserver 所在行的注释状态(有则把注释去掉) <BR>8.进入 /etc /xinetd.d, vi cvspserver该文件不存在,内容如下: <BR>service cvspserver <BR>{ <BR>disable = no <BR>socket_type =stream <BR>wait =no <BR>user =root <BR>env =HOME= <BR>server =/usr/bin/cvs <BR>server_args =--allow-root=/home/cvsroot pserver <BR>log_on_failure +=USERID <BR>} <BR>9.vi /etc/xinetd.conf 内容如下,每次开机自动启动服务: <BR>service cvspserver <BR>{ <BR>port = 2401 <BR>socket_type = stream <BR>wait = no <BR>user = root <BR>server = /usr/bin/cvs <BR>server_args = -f --allow-root=/home/cvsroot pserver <BR>bind = 168.168.1.110 <BR>} <BR>重新登录 换cvsroot用户 <BR>10./etc/init.d/xinetd restart <BR>11.cvs init（初始化：CVS版本库的初始化） <BR>12.cvs -d :pserver:cvsroot@192.168.1.110:/home/cvsroot login(用户登录）没有任何提示信息就成功。 <BR>13.首先要导入库,假设项目名称为LinuxISQuote. <BR>步骤： <BR>　　1、进入LinuxISQuote. <BR>2、一个项目的首次导入 <BR>cvs import LinuxISQuote lch V_0_0_1 <BR>此时到$CVSROOT目录下，可以看到多了一个LinuxISQuote的目录。 </P>
<P>命令绝对路径 <BR>.如果不是绝对路径的话，你可以这样输入 <BR>(1)[root@RedHat linux]# whereis adduser <BR>adduser: /usr/sbin/adduser /usr/share/man/man8/adduser.8.gz <BR>你这样输入就可以了 /usr/sbin/adduser xxx <BR>(2) 或者改vi /etc/profile,加入一句：PATH=$PATH:/usr/sbin:. export PATH， <BR>就可以直接输入adduser </P>
<P>修改用户的权限 <BR>.改用户权限的话，你可以改vi /etc/passwd <BR>如：我想lll变成和root用户一样，就改： lll:x:508:508::/home/lll:/bin/bash <BR>改后面的 508 为和root后面的数据一样的就可以了！ <BR>改为：lll:x:508:0::/home/lll:/bin/bash <BR>lll就拥有root的权限了。 </P>
<P>修改grub启动时的背景图片 <BR>1　将一图片转化成640*480,14色的XPM文件： <BR>　　　#convert abc.jpg -colors 14 -geometry 640x480! abc.xpm <BR>2 压缩生成的xpm文件，使用gzip <BR>#gzip -9 abc.xpm <BR>3 将abc.xpm.gz拷到/boot/grub下 <BR>4　修改/boot/grub/menu.lst <BR>splashimage=(hd0,0)/boot/grub/abc.xpm.gz </P>
<P>VNC for Linux的安装 <BR>1.第一步在linux上安装VNCserver <BR>tar zxvf vnc-X.tgz <BR>cd X <BR>cp *vnc* /usr/local/bin/ <BR>没有vnc 目录，就建vnc目录 <BR>mkdir /usr/local/vnc <BR>cp -r classes/ /usr/local/vnc/ <BR>2.设置vnc server的访问密码 <BR>vncpasswd <BR>3.linux版vnc server的改进.首先执行vncserver <BR>修改/root/.vnc/xstartup里的 twm $ 为gnome-session &amp; <BR>4.启动vnc server <BR>vncserver <BR>注意New 'X' desktop is KILl:3 记住3是客户端要用到的端口 <BR>5.客户端启动vncviewer,输入：如192.168.1.110:3 <BR>OK,你就看到了。。哈。。 <BR>如果在Windows客户机中安装了IE或NETSCAPE,还可以启动IE或netscape <BR>然后在地址栏输入(如果是1的话) <BR><A href="http://192.168.1.64:5801">http://192.168.1.64:5801</A> </P>
<P><BR>改变或关闭Oracle XDB的ftp和http端口 <BR>Oracle 9i开始，创建数据库时默认包含了XDB特性。一旦启动了数据库和Listener，Oracle XDB的http服务就占用8080端口，刚好和JBoss、Tomcat等默认端口冲突。因此，必须有一个做出更改。改Tomcat等容易，只是一时不知道怎么改XDB的配置。 <BR>在Google上搜索一下，找到了答案。原来Oracle XDB的端口设置不在配置文件中，而是在数据库里。修改XDB的http和ftp服务端口的方法有3种： <BR>1。使用sys登录Oracle，利用dbms_xdb修改端口设置 <BR>SQL&gt; -- Change the HTTP/WEBDAV port from 8080 to 8081 <BR>SQL&gt; call dbms_xdb.cfg_update(updateXML( <BR>2 dbms_xdb.cfg_get() <BR>3 , '/xdbconfig/sysconfig/protocolconfig/httpconfig/http-port/text()' <BR>4 , 8081)) <BR>5 / <BR>Call completed. <BR>SQL&gt; -- Change the FTP port from 2100 to 2111 <BR>SQL&gt; call dbms_xdb.cfg_update(updateXML( <BR>2 dbms_xdb.cfg_get() <BR>3 , '/xdbconfig/sysconfig/protocolconfig/ftpconfig/ftp-port/text()' <BR>4 , 2111)) <BR>5 / <BR>Call completed. <BR>SQL&gt; COMMIT; <BR>Commit complete. <BR>SQL&gt; EXEC dbms_xdb.cfg_refresh; <BR>PL/SQL procedure successfully completed. <BR>2。使用OEM console，选择数据库，XML Database，Configuration。更改XDB的有关设置。 <BR>3。去掉数据库的初始化参数： dispatchers='(PROTOCOL=TCP) (SERVICE=XDB)'，将会禁止XDB的http和ftp服务。 </P>
<P>XML for linux的安装 <BR>我下载了两个文件：libxml2-2.6.13.tar.gz和xml4c5_4_0-redhat_80-gcc_32.tar.gz <BR>加入环境： <BR>export XERCESCROOT=/home/lch/xml <BR>export PATH=$PATH:/home/lch/xml/bin <BR>export XERCESC_NLS_HOME=$XERCESCROOT/msg <BR>export LD_LIBRARY_PATH=$XERCESCROOT/lib:$LD_LIBRARY_PATH (on Solaris, Linux) <BR>进入xml4c5_4_0-redhat_80-gcc_32.tar.gz解压后的目录 <BR>runConfigure -plinux -cgcc -xg++ -rpthread <BR>./configure <BR>gmake </P>
<P>ace for linux的安装 <BR>由于安装说明文件“ACE-INSTALL.html”中提及的linux安装过程极少，其主要针对Unix、Windows，手动配置较多，加上本人安装后感觉“ACE-INSTALL.html”文件有些影响视听，因为主要的动作都可以由ACE包中的安装脚本ACE-install.sh自动完成，我们主要的工作就可以直接对这个安装脚本来处理即可。 <BR>1、安装环境： <BR>lRedHat 9.0 <BR>ACE安装包ACE+TAO+CIAO.tar.gz， <BR><A href="http://deuce.doc.wustl.edu/Download.html">http://deuce.doc.wustl.edu/Download.html</A> ， "Latest Beta Kit"，beta版既是ACE的最新版。 <BR>2、安装过程： <BR>第一步 <BR>先设置ACE_ROOT环境，命令： <BR>“vi /etc/profile” <BR>在其中加入4行 <BR>ACE_ROOT=/opt/ACE <BR>export ACE_ROOT <BR>LD_LIBRARY_PATH=$ACE_ROOT/ace:$LD_LIBRARY_PATH <BR>export LD_LIBRARY_PATH <BR>我是加在“export PATH USER….”后的。完成后将/etc/profile执行一次，命令： <BR>“chmod 555 /etc/profile” <BR>“/etc/profile” <BR>这样我们的ACE_ROOT就设置好了，可以用如下命令查看ACE_ROOT是否设置好了： <BR>“echo $ACE_ROOT” <BR>这个时候最好reboot启动一次linux。 <BR>第二步 <BR>不要自己手工将ACE+TAO+CIAO.tar.gz包完全解开，特别强调不要完全解开，后面可以看到安装脚本会给我们解开它的；如果你手工解开全部，安装脚本将会将你的解压缩目录删除的！我们要做的事就只是将ACE+TAO+CIAO.tar.gz包中的ACE-install.sh安装脚本单独解出来，并对其修改。我们只要这一个文件就可以。 <BR>用mkdir建目录，如/home/my/ACE，然后将你的ACE+TAO+CIAO.tar.gz放在此目录下（用cp命令拷贝或mv命令移动到此目录）。注意这个目录将是你的一个存放ACE+TAO+CIAO.tar.gz的目录，安装脚本会来这个目录找这个文件的，这个目录和ACE_ROOT是不一样的，且ACE-install.sh也提示不要将这两个目录设置成同一个目录。ACE_ROOT将是我们的安装目标目录。 <BR>从ACE+TAO+CIAO.tar.gz解压出单个文件ACE-install.sh： <BR>“tar –zxvf ACE+TAO+CIAO.tar.gz ACE_wrappers/ACE-install.sh” <BR>解好后，会出来一个新的子目录“ACE_wrappers”。此时可以先将ACE-install.sh移到外面的目录来： <BR>“mv /ACE_wrappers/ACE-install.sh .” <BR>“.”代表当前目录。当然ACE-install.sh在什么路径下是没什么影响的，因为我们要对ACE-install.sh的内容进行修改的，里面有很多路径要修改。 好，现在在/home/my/ACE就有了ACE-install.sh，我们现在用vi对其进行修改，修改前自己可以先备份一个。命令： <BR>“cp ACE-install.sh ACE-install.sh.bak” <BR>“vi ACE-install.sh” <BR>我们可以看到缺省的，这个文件是用来在UNIX下做安装的。所以我们要将其中的有关UNIX的部分换成linux即可。 <BR>先找到“MY_ACEDIR=${HOME}/aceconfig”，将其改成“MY_ACEDIR=/home/my/ACE”，就是改成我们自己建的、放有ACE+TAO+CIAO.tar.gz文件的目录，之后去掉前面的注释“#”号。 <BR>接着在下面一点，找到“MY_ACE_CONFIG=config-sunos5.4-sunc++-4.x.h”，将其修改成“MY_ACE_CONFIG=config-linux.h”，即改成linux下的配置文件。 继续改，找到“MY_ACE_GNU_MACROS=platform_sunos5_sunc++.GNU”，将其改成“MY_ACE_GNU_MACROS=platform_linux.GNU”。这个是各种操作系统平台下的GNU宏文件设置。 <BR>好了，文件修改完毕，保存退出“:wq”。 <BR>第三步 <BR>我们的重点到了，现在就可以安装ACE了。 <BR>此时应该是在/home/my/ACE目录下，我们执行： <BR>./ACE-install.sh </P>
<P><BR>删除了 /etc/inittab <BR>修复办法如下！ <BR>1.首先进去linux的rescue的模式！ <BR>2.然后使用如下的命令： <BR>rpm -qf --root /mnt/sysimage /etc/inittab <BR>查出该文件属于哪个RPM包！ <BR>3.然后重新安装这个rpm包！ <BR>rpm -ivh --force --root /mnt/sysimage /mnt/source/Redhat/RPMS/packagename <BR>4.sync (将cache中的内容写入磁盘) <BR>5.exit </P>
<P>开启后台talk会话功能 <BR>开启talk功能： chkconfig talk on <BR>交谈 : talk massky(用户) </P>
<P>不让显示器休眠 <BR>setterm –blank 0 </P>
<P>定制用户登录时显示的信息 <BR>编辑 /etc/motd 加入登录时要显示的信息 </P>
<P>查看路由信息 <BR>netstat –rn <BR>route –n </P>
<P>显示硬件信息 <BR>lsdev </P>
<P><BR>&nbsp;显示当前加载的核心模块 <BR>lsmod </P>
<P>列出系统内核所有可用的模块 <BR>modprobe –l </P>
<P>根据进程名显示进程号 <BR>pidof vsftpd </P>
<P>将内容倒序读出 <BR>rev file.name </P>
<P>定制用户登录时显示的信息 <BR>编辑/etc/motd 加入登录时要显示的信息 </P>
<P>查看密码过期信息 <BR>change –l longinname </P>
<P>显示最后一个登录到系统的用户 <BR>last </P>
<P>显示最后一个登录不成功的登录尝试（lastb命令） <BR>如果在系统上不能工作，就需要你建立一个文件：touch /var/log/btmp,然后在执行 lastb命令就可以查看到最后一个不成功的登录尝试， </P>
<P>以3秒钟执行一个ls命令 <BR>watch –n 3 ls </P>
<P>命令显示当前系统中每个用户和他运行的进程信息 <BR>w </P>
<P>Oracle安装界面出现乱码情况 <BR>使用oracle用户登录，执行命令： <BR>export LANG=en </P>
<P>非正常关机的自动磁盘修复 <BR>/etc/sysconfig里增加一个文件autofsck.加入内容： <BR>AUTOFSCK_DEF_CHECK=yes <BR>PROMPT=yes </P>
<P>Oracle9i在RedHat7.1/7.2上的安装配置 <BR>1创建Oracle用户帐号和安装目录 <BR>在shell下,作为root <BR>groupadd dba <BR>groupadd oinstall <BR>useradd –g oinstall –G dba oracle <BR>passwd oracle <BR>mkdir /opt/oracle <BR>mkdir /opt/oracle/product <BR>mkdir /opt/oracle/product/9.2.0 <BR>chown –R oracle.oinstall /opt/oracle <BR>mkdir /var/opt/oracle <BR>chown oracle.dba /var/opt/oracle <BR>chmod 755 /var/opt/oracle <BR>2设置环境变量 <BR>编辑/home/oracle/.bash_profile文件，添加下列行 <BR>export ORACLE_BASE=/opt/oracle <BR>export ORACLE_HOME=/opt/oracle/product/9.2.0 <BR>export ORACLE_SID=lichuanhua <BR>export ORACLE_TERM=xterm <BR>export NLS_LANG=AMERICAN_AMERICA.ZHS16GBK <BR>export NLS_DATE_FORMAT=YYYY-MM-DD <BR>export ORA_NLS33=$ORACLE_HOME/ocommon/nls/admin/data <BR>LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib <BR>export LD_LIBRARY_PATH </P>
<P>export PATH=$PATH:$ORACLE_HOME/bin </P>
<P>CLASSPATH=$ORACLE_HOME/JRE:$ORACLE_HOME/jlib:$ORACLE_HOME/rdbms/jlib <BR>CLASSPATH=$CLASSPATH:$ORACLE_HOME/network/jlib <BR>export CLASSPATH <BR>export DISPLAY=192.168.1.88:0.0 </P>
<P>编译内核的步骤 <BR>1.源码 /usr/src/linux-2.4 <BR>2. make mrproper (清除从前编译内核时残留的.o 文件和不必要的关联) <BR>3. make menuconfig (字符界面内核配置菜单中正确设置个内核选项) <BR>make xconfig (图形界面内核配置菜单中正确设置个内核选项) <BR>4. make dep (设置关联文件 ) <BR>5.make bzImage (对于大内核,如需要SCSI支持的编译) <BR>make zImage (对于小内核的编译) <BR>6.make modules (编译模块) <BR>7. make modules_install (安装模块 ) <BR>8.make install ((针对grub启动，自动装载到grub.conf上，直接重新启动就OK） </P>
<P>VMWare上linux图形界面的安装 <BR>如果你是使用VMware，那么你可以这样 <BR>首先在vmWare的VM-&gt;Install VMware tools选择install <BR>在执行 <BR>1.mount /dev/cdrom /mnt/cdrom <BR>2.cd /mnt/cdrom 有一个文件vmware-linux*.tar.gz <BR>3.cp vmware-linux*.tar.gz /tmp <BR>4.cd /tmp <BR>5.tar zxvf vmware-linux*.tar.gz <BR>6.进入解压目录 cd vmware-tools-distrib <BR>7.进入解压后的目录运行安装命令./vmware-install.pl 就ok了 <BR>8.等待Vmware-insall运行完成后,重启Linux，我们就可以看到漂亮的Linux图形界面了 </P>
<P>Oracle 字符集的问题(ora9i) <BR>sqlplus直接进去,输入命令： <BR>select value$ from props$ where name=' NLS_CHARACTERSET'; <BR>显示不是ZHS16GBK,就更改，默认的是：WE8ISO8859p1 <BR>更改命令： <BR>update props$ set value$='ZHS16GBK' where name='NLS_CHARACTERSET'; <BR>重启生效 </P>
<P>查询一个系统最近何时被引导过 <BR>who -b </P>
<P>查系统硬件类型 <BR>uname -m </P>
<P>查系统的CPU类型 <BR>uname -p </P>
<P>74． 查系统OS版本号 <BR>uname -r </P>
<P>Qt/e的安装 <BR>我是在rh9.0下面安装的 <BR>一.安装qt-x11-free-3.3.2.tar.gz <BR>1. 我把qt-x11-free-3.3.2.tar.gz拷贝到/usr/local/qt目录下 <BR>cd /usr/local/qt <BR>tar zxvf qt-x11-free-3.3.2.tar.gz <BR>mv qt-x11-free-3.3.2 qt </P>
<P>2. vi /etc/profile ，添加环境 <BR>export QTDIR=/usr/local/qt <BR>export PATH=$QTDIR/bin:$PATH <BR>export MANPATH=$QTDIR/doc/man:$MANPATH <BR>export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH <BR>3.检查一下环境是否存在 <BR>#echo $QTDIR <BR>应该返回 /usr/local/qt <BR>4.#./configure <BR>5.# make <BR>6.qt的启动，/usr/local/qt/bin目录下面执行 <BR>#./designer <BR>你就可以看到qt的界面了！ </P>
<P>如果在make时候报错： <BR>In file included from kernel/qtaddons_x11.cpp:25: <BR>kernel/qt_x11_p.h:66:22: X11/Xlib.h: 没有那个文件或目录 <BR>kernel/qt_x11_p.h:71:23: X11 til.h: 没有那个文件或目录 <BR>kernel/qt_x11_p.h:72:21: X11/Xos.h: 没有那个文件或目录 <BR>kernel/qt_x11_p.h:73:23: X11/Xatom.h: 没有那个文件或目录 <BR>make[2]: *** [.obj/release-shared/qtaddons_x11.o] Error 1 <BR>make[2]: Leaving directory `/usr/local/qt/src' <BR>make[1]: *** [sub-src] Error 2 <BR>make[1]: Leaving directory `/usr/local/qt' <BR>make: *** [init] Error 2 <BR>这个问题我搞了半天，最后才知道 <BR>这个错是因为没有安装X11的开发包，在添加和删除里面添加上X11开发包 </P>
<P>二.安装qt-embedded-free-3.3.2.tar.gz <BR>1.解压qt-embedded-free-3.3.2.tar.gz <BR>我放在/root/qt下面 <BR>#tar zxvf qt-embedded-free-3.3.2.tar.gz <BR>#cd qt-embedded-free-3.3.2 <BR>#export QTDIR=/root/qt/qt-embedded-free-3.3.2 <BR>#export LD_LIBRARY_PATH=/root/qt/qt-embedded-free-3.3.2/lib:$LD_LIBRARY_PATH <BR>#./configure <BR># make <BR>然后就是一个漫长的过程 </P>
<P>修改ping 的TTL值(rh9) <BR>修改文件 /proc/sys/net/ipv4/ip_default_ttl的值（默认为64) <BR>如：我把ttl修改为128 <BR># echo 128 &gt; /proc/sys/net/ipv4/ip_default_ttl </P>
<P>使用多达23个的虚拟控制台 <BR>假设现在有6个，仿照/etc/inittab种的文件，加入 <BR>8:2345:respawn:/sbin/mingetty tty8 <BR>10:2345:respawn:/sbin/mingetty tty10 <BR>24:2345:respawn:/sbin/mingetty tty24 <BR>要跳过VT7，因为X使用这个终端。然后telinit q以重新加载配置文件。使用左Alt+Fn在1-6和8-12件切换，使用右Alt+Fn键在13-24之间切换 </P>
<P>Xmanager2的配置 <BR>不使用图形界面也可以使用Xmanager2登陆进行图形控制 <BR>#vi /etc/X11/xdm/xdm-config <BR>在最后一行： DisplayManager.requestPort: 0 前面加！号注释掉此行。 <BR>#vi /etc/X11/xdm/Xservers <BR>在最后一行：:0 local /usr/X11R6/bin/X 前面加#号注释掉这一行。 <BR>#vi /etc/X11/xdm/Xaccess <BR>找到#* #any host can get a login window <BR>把这一行前面的#号去掉，变成： <BR>* #any host can get a login window <BR>最后运行#xdm。这样使用xmanager等工具就可以连接Linux了！ </P>
<P>如果使用ssh从windows远程登录到linux <BR>的 ssh 必须开了 X forwarding 的选项。 <BR>1.vi /etc/ssh/sshd_config 里 X11Forwarding 要为 yes <BR>2.vi /etc/ssh/ssh_config 也是的 ForwardX11 yes </P>
<P>更改控制台的分辨率(grub) <BR>vi /boot/grub/grub.conf <BR>在kernel /vmlinuz-2.4.20-8smp ro root=LABEL=/ 一行后面添加参数vga=792成为 <BR>kernel /vmlinuz-2.4.20-8smp ro root=LABEL=/ vga=792 <BR>最后的vga=792表示1024x768，16色 <BR>具体参数为： <BR>depth 640x480 800x600 1024x768 1280x1024 <BR>8bit 769 771 773 775 <BR>15bit 784 787 790 793 <BR>16bit 785 788 791 794 <BR>24bit 786 789 792 795 <BR></P>]]></description>
<author>fuhj02</author>
<pubDate>2008-11-30 11:41:00</pubDate>
</item>
<item>
<title><![CDATA[浏览器中的内存泄露]]></title>
<link>http://blog.edu.cn/user2/35840/archives/2008/2176399.shtml</link>
<description><![CDATA[<H3><SPAN style="FONT-FAMILY: 宋体">什么是内存泄露</SPAN></H3>
<P><SPAN style="FONT-FAMILY: 宋体">内存泄露是指一块被分配的内存既不能使用，又不能回收，直到浏览器进程结束。在</SPAN>C++<SPAN style="FONT-FAMILY: 宋体">中，因为是手动管理内存，内存泄露是经常出现的事情。而现在流行的</SPAN>C#<SPAN style="FONT-FAMILY: 宋体">和</SPAN>Java<SPAN style="FONT-FAMILY: 宋体">等语言采用了自动垃圾回收方法管理内存，正常使用的情况下几乎不会发生内存泄露。浏览器中也是采用自动垃圾回收方法管理内存，但由于浏览器垃圾回收方法有</SPAN>bug<SPAN style="FONT-FAMILY: 宋体">，会产生内存泄露。</SPAN></P>
<H3><SPAN style="FONT-FAMILY: 宋体">内存泄露</SPAN>Quick View</H3>
<P><SPAN style="FONT-FAMILY: 宋体">不同的浏览器中存在各种内存泄露方式，目前发现的主要是这样几种：</SPAN></P>
<H4 class=MsoListParagraph style="MARGIN-LEFT: 18pt; TEXT-INDENT: -18pt">1.<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="FONT-FAMILY: 宋体">循环引用</SPAN></H4>
<P><SPAN style="FONT-FAMILY: 宋体">已经确认存在泄漏的浏览器：</SPAN>IE6.0 FF2.0</P>
<P><SPAN style="FONT-FAMILY: 宋体">含有</SPAN>DOM<SPAN style="FONT-FAMILY: 宋体">对象的循环引用将导致大部分当前主流浏览器内存泄露</SPAN> <SPAN style="FONT-FAMILY: 宋体">这里有两个简单的概念</SPAN></P>
<P><SPAN style="FONT-FAMILY: 宋体">引用：</SPAN>a.<SPAN style="FONT-FAMILY: 宋体">属性</SPAN>=b<SPAN style="FONT-FAMILY: 宋体">，</SPAN>a<SPAN style="FONT-FAMILY: 宋体">就引用了</SPAN>b</P>
<P><SPAN style="FONT-FAMILY: 宋体">循环引用：简单来说假如</SPAN>a<SPAN style="FONT-FAMILY: 宋体">引用了</SPAN>b,b<SPAN style="FONT-FAMILY: 宋体">又引用了</SPAN>a,a<SPAN style="FONT-FAMILY: 宋体">和</SPAN>b<SPAN style="FONT-FAMILY: 宋体">就构成了循环引用。</SPAN></P>
<P>a<SPAN style="FONT-FAMILY: 宋体">和</SPAN>b<SPAN style="FONT-FAMILY: 宋体">循环引用：</SPAN></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><SPAN style="FONT-FAMILY: Times New Roman"><IMG style="FONT-FAMILY: " alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><SPAN style="http://blog.edu.cn/COLOR: #0000ff; FONT-FAMILY: "><SPAN style="FONT-FAMILY: 宋体"><SPAN style="FONT-FAMILY: "><SPAN style="COLOR: #0000ff; FONT-FAMILY: ">var</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">&nbsp;a</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">=</SPAN><SPAN style="COLOR: #0000ff; FONT-FAMILY: ">new</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">&nbsp;Object;<BR style="FONT-FAMILY: "><IMG style="FONT-FAMILY: " alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="http://blog.edu.cn/COLOR: #0000ff; FONT-FAMILY: ">var</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">&nbsp;b</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">=</SPAN><SPAN style="COLOR: #0000ff; FONT-FAMILY: ">new</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">&nbsp;Object;<BR style="FONT-FAMILY: "><IMG style="FONT-FAMILY: " alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>a.r</SPAN><SPAN style="http://blog.edu.cn/COLOR: #000000; FONT-FAMILY: ">=</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">b;<BR style="FONT-FAMILY: "><IMG style="FONT-FAMILY: " alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>b.r</SPAN><SPAN style="http://blog.edu.cn/COLOR: #000000; FONT-FAMILY: ">=</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">a;</SPAN></SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: "><BR style="FONT-FAMILY: "></SPAN></SPAN></SPAN></SPAN><SPAN style="COLOR: #000000"><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></SPAN></DIV>
<P>a<SPAN style="FONT-FAMILY: 宋体">循环引用自己：</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><SPAN style="http://blog.edu.cn/COLOR: #0000ff">var</SPAN><SPAN style="COLOR: #000000">&nbsp;a</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;Object;<BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>a.r</SPAN><SPAN style="http://blog.edu.cn/COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">a;<BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></SPAN></DIV>
<P></SPAN><SPAN style="FONT-FAMILY: 宋体">循环引用很常见且大部分情况下是无害的，但当参与循环引用的对象中有</SPAN><FONT face=Verdana>DOM</FONT><SPAN style="FONT-FAMILY: 宋体">对象或者</SPAN><FONT face=Verdana>ActiveX</FONT><SPAN style="FONT-FAMILY: 宋体">对象时，循环引用将导致内存泄露。我们把例子中的任何一个</SPAN><FONT face=Verdana>new Object</FONT><SPAN style="FONT-FAMILY: 宋体">替换成</SPAN><FONT face=Verdana>document.getElementById</FONT><SPAN style="FONT-FAMILY: 宋体">或者</SPAN><FONT face=Verdana>document.createElement</FONT><SPAN style="FONT-FAMILY: 宋体">就会发生内存泄露了。<BR><SPAN style="FONT-FAMILY: 宋体">尽管这看起来非常容易理解，但是因为有closure的参与而使事情变得复杂，有些closure导致的循环引用很难被察觉。</SPAN>下面是一个非常常见的动态绑定事件：<BR></P>
<DIV class=cnblogs_code><SPAN style="COLOR: #0000ff">function</SPAN><SPAN style="COLOR: #000000">&nbsp;bindEvent()<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">var</SPAN><SPAN style="COLOR: #000000">&nbsp;obj</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">document.createElement(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">XXX</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">);<BR>&nbsp;&nbsp;&nbsp;&nbsp;obj.onclick</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #0000ff">function</SPAN><SPAN style="COLOR: #000000">(){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">Even&nbsp;if&nbsp;it's&nbsp;a&nbsp;empty&nbsp;function</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<BR>}</SPAN></DIV>
<P></SPAN><FONT face=Verdana>这个bindEvent执行时100%会发生内存泄露，Someone 可能会问，哪里出现了循环引用? 关于closure和scope chain参与的循环引用比较复杂，此处暂不深入讨论。有一个简单的判断方式：函数将间接引用所有它能访问的对象。obj.onclick这个函数中 可以访问外部的变量obj 所以他引用了obj,而obj又引用了它，因此这个事件绑定将会造成内存泄露。在</FONT><A href="http://www.ibm.com/developerworks/web/library/wa-memleak/?S_TACT=105AGX52&amp;S_CMP=cn-a-wa"><FONT face=Verdana color=#000000>IBM的文章</FONT></A><FONT face=Verdana>中介绍了2种方式解决类似的问题一个是obj=null，另一个是把onclick的函数写在bindEvent外，重复人家的我就不说了。简单贴下代码：</FONT></P>
<DIV class=cnblogs_code><SPAN style="COLOR: #0000ff">function</SPAN><SPAN style="COLOR: #000000">&nbsp;bindEvent()<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">var</SPAN><SPAN style="COLOR: #000000">&nbsp;obj</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">document.createElement(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">XXX</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">);<BR>&nbsp;&nbsp;&nbsp;&nbsp;obj.onclick</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">onclickHandler;<BR>}<BR></SPAN><SPAN style="COLOR: #0000ff">function</SPAN><SPAN style="COLOR: #000000">&nbsp;onclickHandler(){<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">do&nbsp;something</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">}</SPAN></DIV>
<P>&nbsp;</P>
<DIV class=cnblogs_code><SPAN style="COLOR: #0000ff">function</SPAN><SPAN style="COLOR: #000000">&nbsp;bindEvent()<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">var</SPAN><SPAN style="COLOR: #000000">&nbsp;obj</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">document.createElement(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">XXX</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">);<BR>&nbsp;&nbsp;&nbsp;&nbsp;obj.onclick</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #0000ff">function</SPAN><SPAN style="COLOR: #000000">(){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">Even&nbsp;if&nbsp;it's&nbsp;a&nbsp;empty&nbsp;function</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;obj</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #0000ff">null</SPAN><SPAN style="COLOR: #000000">;<BR>}</SPAN></DIV>
<P><BR>这两个方法都打断了循环引用，可以解决问题，但是似乎对代码表达能力造成了一定破坏，假设有这么一个问题：</P>
<DIV class=cnblogs_code style="FONT-FAMILY: 宋体"><SPAN style="COLOR: #0000ff">function</SPAN><SPAN style="COLOR: #000000">&nbsp;bindEvent()<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">var</SPAN><SPAN style="COLOR: #000000">&nbsp;obj</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">document.createElement(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">XXX</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">);<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">var</SPAN><SPAN style="COLOR: #000000">&nbsp;var0</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">OOXX</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">Here&nbsp;is&nbsp;a&nbsp;variable</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;obj.onclick</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #0000ff">function</SPAN><SPAN style="COLOR: #000000">(){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(var0);</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">I&nbsp;want&nbsp;to&nbsp;visit&nbsp;var2&nbsp;here!</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000">&nbsp;obj;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">bindEvent&nbsp;must&nbsp;return&nbsp;obj!</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">}</SPAN></DIV>
<P>好了 这下两种办法都不行了，假如我把函数写外面去，var0肯定访问不了，假如我把obj弄成null，还怎么return它呢？这并不是空想的需要，这实际上是一个用JS定制DOM控件的简单抽象：创建DOM元素、设置私有属性、绑定事件。所以，我们必须update一下两个方法。首先，方法1，为了让函数能访问某些变量，我们可以通过一个Builder函数来订制onclick的外部闭包：</P>
<DIV class=cnblogs_code><SPAN style="COLOR: #0000ff"><SPAN style="FONT-FAMILY: 宋体"><SPAN style="COLOR: #0000ff; FONT-FAMILY: ">function</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">&nbsp;bindEvent()<BR style="FONT-FAMILY: ">{<BR style="FONT-FAMILY: ">&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff; FONT-FAMILY: ">var</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">&nbsp;obj</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">=</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">document.createElement(</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">"</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">XXX</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">"</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">);<BR style="FONT-FAMILY: ">&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff; FONT-FAMILY: ">var</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">&nbsp;var0</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">=</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">"</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">OOXX</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">"</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">;</SPAN><SPAN style="COLOR: #008000; FONT-FAMILY: ">//</SPAN><SPAN style="COLOR: #008000; FONT-FAMILY: ">Here&nbsp;is&nbsp;a&nbsp;variable</SPAN><SPAN style="COLOR: #008000; FONT-FAMILY: "><BR style="FONT-FAMILY: "></SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">&nbsp;&nbsp;&nbsp;&nbsp;obj.onclick</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">=</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">&nbsp;onclickBuilder(var0);</SPAN><SPAN style="COLOR: #008000; FONT-FAMILY: ">//</SPAN><SPAN style="COLOR: #008000; FONT-FAMILY: ">想访问谁就把谁传进去！！</SPAN><SPAN style="COLOR: #008000; FONT-FAMILY: "><BR style="FONT-FAMILY: "></SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff; FONT-FAMILY: ">return</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">&nbsp;obj;</SPAN><SPAN style="COLOR: #008000; FONT-FAMILY: ">//</SPAN><SPAN style="COLOR: #008000; FONT-FAMILY: ">bindEvent&nbsp;must&nbsp;return&nbsp;obj!</SPAN><SPAN style="COLOR: #008000; FONT-FAMILY: "><BR style="FONT-FAMILY: "></SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">}<BR style="FONT-FAMILY: "></SPAN><SPAN style="COLOR: #0000ff; FONT-FAMILY: ">function</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">&nbsp;onclickBuilder(var0)</SPAN><SPAN style="COLOR: #008000; FONT-FAMILY: ">//</SPAN><SPAN style="COLOR: #008000; FONT-FAMILY: ">这里跟上面对应上就行了&nbsp;最好参数名字也对应上</SPAN><SPAN style="COLOR: #008000; FONT-FAMILY: "><BR style="FONT-FAMILY: "></SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">{<BR style="FONT-FAMILY: ">&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff; FONT-FAMILY: ">return</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">&nbsp;</SPAN><SPAN style="COLOR: #0000ff; FONT-FAMILY: ">function</SPAN><SPAN style="COLOR: #000000; FONT-FAMILY: ">(){<BR style="FONT-FAMILY: ">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(var0);<BR style="FONT-FAMILY: ">&nbsp;&nbsp;&nbsp;&nbsp;}<BR style="FONT-FAMILY: ">}</SPAN></SPAN></SPAN><SPAN style="COLOR: #000000"><BR></SPAN></DIV><BR>
<P>第二个办法，这个来自51js的chpn同学，让obj=null在return 之后执行！！</P>
<DIV class=cnblogs_code style="FONT-FAMILY: 宋体"><SPAN style="COLOR: #0000ff">function</SPAN><SPAN style="COLOR: #000000">&nbsp;bindEvent()<BR>{<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">try</SPAN><SPAN style="COLOR: #000000">{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">var</SPAN><SPAN style="COLOR: #000000">&nbsp;obj</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">document.createElement(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">XXX</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">var</SPAN><SPAN style="COLOR: #000000">&nbsp;var0</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">OOXX</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">Here&nbsp;is&nbsp;a&nbsp;variable</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj.onclick</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #0000ff">function</SPAN><SPAN style="COLOR: #000000">(){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(var0);</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">I&nbsp;want&nbsp;to&nbsp;visit&nbsp;var2&nbsp;here!</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000">&nbsp;obj;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">bindEvent&nbsp;must&nbsp;return&nbsp;obj!</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</SPAN><SPAN style="COLOR: #0000ff">finally</SPAN><SPAN style="COLOR: #000000">&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;obj</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #0000ff">null</SPAN><SPAN style="COLOR: #000000">;<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>}</SPAN></DIV>
<P>&nbsp;</P>
<H4 class=MsoListParagraph style="MARGIN-LEFT: 18pt; TEXT-INDENT: -18pt">2.<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="FONT-FAMILY: 宋体">某些</SPAN>DOM<SPAN style="FONT-FAMILY: 宋体">操作</SPAN></H4>
<P><SPAN style="FONT-FAMILY: 宋体">这是</SPAN>IE<SPAN style="FONT-FAMILY: 宋体">系列的特有问题</SPAN> <SPAN style="FONT-FAMILY: 宋体">简单的来说就是在向不在</SPAN>DOM<SPAN style="FONT-FAMILY: 宋体">树上的</SPAN>DOM<SPAN style="FONT-FAMILY: 宋体">元素</SPAN>appendChild<SPAN style="FONT-FAMILY: 宋体">，可能会发生内存泄露（只是可能，具体原因不明，似乎十分复杂，下面例子中去掉</SPAN>onClick<SPAN style="FONT-FAMILY: 宋体">也可以避免泄露）。所以</SPAN>appendChild<SPAN style="FONT-FAMILY: 宋体">的顺序可能影响内存泄露，来自微软的例子：<BR></P>
<DIV class=cnblogs_code><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top><SPAN style="http://blog.edu.cn/COLOR: #0000ff">&lt;/</SPAN><SPAN style="COLOR: #800000">html</SPAN><SPAN style="COLOR: #0000ff">&gt;</SPAN><SPAN style="COLOR: #000000"><BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #0000ff">&lt;</SPAN><SPAN style="COLOR: #800000">head</SPAN><SPAN style="COLOR: #0000ff">&gt;</SPAN><SPAN style="COLOR: #000000"><BR><IMG id=Codehighlighter1_54_1699_Open_Image onclick="this.style.display='none'; document.getElementById('Codehighlighter1_54_1699_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_54_1699_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_54_1699_Closed_Text').style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_54_1699_Closed_Image style="http://blog.edu.cn/DISPLAY: none" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_54_1699_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_54_1699_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_54_1699_Open_Text').style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #0000ff">&lt;</SPAN><SPAN style="COLOR: #800000">script&nbsp;</SPAN><SPAN style="COLOR: #ff0000">language</SPAN><SPAN style="COLOR: #0000ff">="JScript"</SPAN><SPAN style="COLOR: #0000ff">&gt;</SPAN><SPAN id=Codehighlighter1_54_1699_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG alt="" src="http://www.cnblogs.com/Images/dot.gif"></SPAN><SPAN id=Codehighlighter1_54_1699_Open_Text><SPAN style="http://blog.edu.cn/COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"><BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5">function</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;LeakMemory()<BR><IMG id=Codehighlighter1_93_864_Open_Image onclick="this.style.display='none'; document.getElementById('Codehighlighter1_93_864_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_93_864_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_93_864_Closed_Text').style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><IMG id=Codehighlighter1_93_864_Closed_Image style="http://blog.edu.cn/DISPLAY: none" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_93_864_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_93_864_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_93_864_Open_Text').style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN id=Codehighlighter1_93_864_Closed_Text style="http://blog.edu.cn/BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG alt="" src="http://www.cnblogs.com/Images/dot.gif"></SPAN><SPAN id=Codehighlighter1_93_864_Open_Text><SPAN style="http://blog.edu.cn/COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">{<BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5">var</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;hostElement&nbsp;</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">=</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;document.getElementById(</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">"</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">hostElement</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">"</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">);<BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #008000; BACKGROUND-COLOR: #f5f5f5">//</SPAN><SPAN style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5">&nbsp;Do&nbsp;it&nbsp;a&nbsp;lot,&nbsp;look&nbsp;at&nbsp;Task&nbsp;Manager&nbsp;for&nbsp;memory&nbsp;response</SPAN><SPAN style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5"><BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top></SPAN><SPAN style="http://blog.edu.cn/COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5">for</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">(i&nbsp;</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">=</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">0</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">;&nbsp;i&nbsp;</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&lt;</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">5000</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">;&nbsp;i</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">++</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">)<BR><IMG id=Codehighlighter1_284_822_Open_Image onclick="this.style.display='none'; document.getElementById('Codehighlighter1_284_822_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_284_822_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_284_822_Closed_Text').style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><IMG id=Codehighlighter1_284_822_Closed_Image style="http://blog.edu.cn/DISPLAY: none" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_284_822_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_284_822_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_284_822_Open_Text').style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN id=Codehighlighter1_284_822_Closed_Text style="http://blog.edu.cn/BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG alt="" src="http://www.cnblogs.com/Images/dot.gif"></SPAN><SPAN id=Codehighlighter1_284_822_Open_Text><SPAN style="http://blog.edu.cn/COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">{<BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5">var</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;parentDiv&nbsp;</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">=</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"><BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.createElement(</SPAN><SPAN style="http://blog.edu.cn/COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">"</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&lt;div&nbsp;onClick='foo()'&gt;</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">"</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">);<BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5">var</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;childDiv&nbsp;</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">=</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"><BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.createElement(</SPAN><SPAN style="http://blog.edu.cn/COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">"</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&lt;div&nbsp;onClick='foo()'&gt;</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">"</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">);<BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #008000; BACKGROUND-COLOR: #f5f5f5">//</SPAN><SPAN style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5">&nbsp;This&nbsp;will&nbsp;leak&nbsp;a&nbsp;temporary&nbsp;object</SPAN><SPAN style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5"><BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top></SPAN><SPAN style="http://blog.edu.cn/COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parentDiv.appendChild(childDiv);<BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hostElement.appendChild(parentDiv);<BR><IMG alt="http://blog.edu.cn/" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hostElement.removeChild(parentDiv);<BR><IMG alt="http://blog.edu.cn/" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parentDiv.removeChild(childDiv);<BR><IMG alt="http://blog.edu.cn/" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parentDiv&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">=</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;</SPAN><SPAN style="COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5">null</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">;<BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;childDiv&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">=</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;</SPAN><SPAN style="COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5">null</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">;<BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</SPAN></SPAN><SPAN style="http://blog.edu.cn/COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"><BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hostElement&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">=</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;</SPAN><SPAN style="COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5">null</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">;<BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</SPAN></SPAN><SPAN style="http://blog.edu.cn/COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"><BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top><BR><IMG alt="http://blog.edu.cn/" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5">function</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;CleanMemory()<BR><IMG id=Codehighlighter1_905_1690_Open_Image onclick="this.style.display='none'; document.getElementById('Codehighlighter1_905_1690_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_905_1690_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_905_1690_Closed_Text').style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><IMG id=Codehighlighter1_905_1690_Closed_Image style="http://blog.edu.cn/DISPLAY: none" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_905_1690_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_905_1690_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_905_1690_Open_Text').style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN id=Codehighlighter1_905_1690_Closed_Text style="http://blog.edu.cn/BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG alt="" src="http://www.cnblogs.com/Images/dot.gif"></SPAN><SPAN id=Codehighlighter1_905_1690_Open_Text><SPAN style="http://blog.edu.cn/COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">{<BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5">var</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;hostElement&nbsp;</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">=</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;document.getElementById(</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">"</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">hostElement</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">"</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">);<BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #008000; BACKGROUND-COLOR: #f5f5f5">//</SPAN><SPAN style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5">&nbsp;Do&nbsp;it&nbsp;a&nbsp;lot,&nbsp;look&nbsp;at&nbsp;Task&nbsp;Manager&nbsp;for&nbsp;memory&nbsp;response</SPAN><SPAN style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5"><BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top></SPAN><SPAN style="http://blog.edu.cn/COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5">for</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">(i&nbsp;</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">=</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">0</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">;&nbsp;i&nbsp;</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&lt;</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">5000</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">;&nbsp;i</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">++</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">)<BR><IMG id=Codehighlighter1_1096_1648_Open_Image onclick="this.style.display='none'; document.getElementById('Codehighlighter1_1096_1648_Open_Text').style.display='none'; document.getElementById('Codehighlighter1_1096_1648_Closed_Image').style.display='inline'; document.getElementById('Codehighlighter1_1096_1648_Closed_Text').style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><IMG id=Codehighlighter1_1096_1648_Closed_Image style="http://blog.edu.cn/DISPLAY: none" onclick="this.style.display='none'; document.getElementById('Codehighlighter1_1096_1648_Closed_Text').style.display='none'; document.getElementById('Codehighlighter1_1096_1648_Open_Image').style.display='inline'; document.getElementById('Codehighlighter1_1096_1648_Open_Text').style.display='inline';" alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN id=Codehighlighter1_1096_1648_Closed_Text style="http://blog.edu.cn/BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG alt="" src="http://www.cnblogs.com/Images/dot.gif"></SPAN><SPAN id=Codehighlighter1_1096_1648_Open_Text><SPAN style="http://blog.edu.cn/COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">{<BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5">var</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;parentDiv&nbsp;</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">=</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"><BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.createElement(</SPAN><SPAN style="http://blog.edu.cn/COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">"</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&lt;div&nbsp;onClick='foo()'&gt;</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">"</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">);<BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5">var</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;childDiv&nbsp;</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">=</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"><BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.createElement(</SPAN><SPAN style="http://blog.edu.cn/COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">"</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&lt;div&nbsp;onClick='foo()'&gt;</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">"</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">);<BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #008000; BACKGROUND-COLOR: #f5f5f5">//</SPAN><SPAN style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5">&nbsp;Changing&nbsp;the&nbsp;order&nbsp;is&nbsp;important,&nbsp;this&nbsp;won't&nbsp;leak</SPAN><SPAN style="COLOR: #008000; BACKGROUND-COLOR: #f5f5f5"><BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top></SPAN><SPAN style="http://blog.edu.cn/COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hostElement.appendChild(parentDiv);<BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parentDiv.appendChild(childDiv);<BR><IMG alt="http://blog.edu.cn/" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hostElement.removeChild(parentDiv);<BR><IMG alt="http://blog.edu.cn/" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parentDiv.removeChild(childDiv);<BR><IMG alt="http://blog.edu.cn/" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parentDiv&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">=</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;</SPAN><SPAN style="COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5">null</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">;<BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;childDiv&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">=</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;</SPAN><SPAN style="COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5">null</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">;<BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</SPAN></SPAN><SPAN style="http://blog.edu.cn/COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"><BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hostElement&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">=</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">&nbsp;</SPAN><SPAN style="COLOR: #0000ff; BACKGROUND-COLOR: #f5f5f5">null</SPAN><SPAN style="COLOR: #000000; BACKGROUND-COLOR: #f5f5f5">;<BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</SPAN></SPAN><SPAN style="http://blog.edu.cn/COLOR: #000000; BACKGROUND-COLOR: #f5f5f5"><BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN></SPAN><SPAN style="http://blog.edu.cn/COLOR: #0000ff">&lt;/</SPAN><SPAN style="COLOR: #800000">script</SPAN><SPAN style="COLOR: #0000ff">&gt;</SPAN><SPAN style="COLOR: #000000"><BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #0000ff">&lt;/</SPAN><SPAN style="COLOR: #800000">head</SPAN><SPAN style="COLOR: #0000ff">&gt;</SPAN><SPAN style="COLOR: #000000"><BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #0000ff">&lt;</SPAN><SPAN style="COLOR: #800000">body</SPAN><SPAN style="COLOR: #0000ff">&gt;</SPAN><SPAN style="COLOR: #000000"><BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #0000ff">&lt;</SPAN><SPAN style="COLOR: #800000">button&nbsp;</SPAN><SPAN style="COLOR: #ff0000">onclick</SPAN><SPAN style="COLOR: #0000ff">="LeakMemory()"</SPAN><SPAN style="COLOR: #0000ff">&gt;</SPAN><SPAN style="COLOR: #000000">Memory&nbsp;Leaking&nbsp;Insert</SPAN><SPAN style="COLOR: #0000ff">&lt;/</SPAN><SPAN style="COLOR: #800000">button</SPAN><SPAN style="COLOR: #0000ff">&gt;</SPAN><SPAN style="COLOR: #000000"><BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #0000ff">&lt;</SPAN><SPAN style="COLOR: #800000">button&nbsp;</SPAN><SPAN style="COLOR: #ff0000">onclick</SPAN><SPAN style="COLOR: #0000ff">="CleanMemory()"</SPAN><SPAN style="COLOR: #0000ff">&gt;</SPAN><SPAN style="COLOR: #000000">Clean&nbsp;Insert</SPAN><SPAN style="COLOR: #0000ff">&lt;/</SPAN><SPAN style="COLOR: #800000">button</SPAN><SPAN style="COLOR: #0000ff">&gt;</SPAN><SPAN style="COLOR: #000000"><BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #0000ff">&lt;</SPAN><SPAN style="COLOR: #800000">div&nbsp;</SPAN><SPAN style="COLOR: #ff0000">id</SPAN><SPAN style="COLOR: #0000ff">="hostElement"</SPAN><SPAN style="COLOR: #0000ff">&gt;&lt;/</SPAN><SPAN style="COLOR: #800000">div</SPAN><SPAN style="COLOR: #0000ff">&gt;</SPAN><SPAN style="COLOR: #000000"><BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="http://blog.edu.cn/COLOR: #0000ff">&lt;/</SPAN><SPAN style="COLOR: #800000">body</SPAN><SPAN style="COLOR: #0000ff">&gt;</SPAN><SPAN style="COLOR: #000000"><BR><IMG alt="" src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="http://blog.edu.cn/COLOR: #0000ff">&lt;/</SPAN><SPAN style="COLOR: #800000">html</SPAN><SPAN style="COLOR: #0000ff">&gt;</SPAN></DIV>
<P><BR></P>而在IE7中，貌似为了改善内存泄露，IE7采用了极端的解决方案：离开页面时回收所有DOM树上的元素，其它一概不管。但是这不仅没起到任何作用，反而使问题变得更加复杂。对这类问题，除了自觉一点绕开这些恶心的东西，多用innerHTML这种无用的建议之外。我想可以通过覆盖document.createElement来略为改善：<BR>首先我们定义一个看不见的元素当作垃圾箱，所有新创建的元素都扔进垃圾箱里，这样保证了所有DOM元素都在DOM树上，IE7就可以正确回收了，另一方面也能避免所谓的"appendChild顺序不对导致内存泄露"。 
<DIV class=cnblogs_code><SPAN style="COLOR: #0000ff">function</SPAN><SPAN style="COLOR: #000000">&nbsp;MemoryFix(){<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">var</SPAN><SPAN style="COLOR: #000000">&nbsp;garbageBox</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">document.createElement(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">div</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">);<BR>&nbsp;&nbsp;&nbsp;&nbsp;garbageBox.style.display</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">none</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">;<BR>&nbsp;&nbsp;&nbsp;&nbsp;document.body.appendChild(garbageBox);<BR>&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">var</SPAN><SPAN style="COLOR: #000000">&nbsp;createElement</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">document.createElement;<BR>&nbsp;&nbsp;&nbsp;&nbsp;document.createElement</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #0000ff">function</SPAN><SPAN style="COLOR: #000000">(){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">var</SPAN><SPAN style="COLOR: #000000">&nbsp;obj</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">Function.prototype.apply.apply(createElement,[document,arguments]);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;garbageBox.appendChild(obj);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000">&nbsp;obj;<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>}</SPAN></DIV><BR>
<H4></SPAN>&nbsp;</H4>
<H4>3.<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="FONT-FAMILY: 宋体">自动类型装箱转换</SPAN></H4>
<P><SPAN style="FONT-FAMILY: 宋体">别不相信，下面的代码在</SPAN>ie<SPAN style="FONT-FAMILY: 宋体">系列中会导致内存泄露</SPAN></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; FONT-FAMILY: 宋体; BACKGROUND-COLOR: #eeeeee"><SPAN style="COLOR: #0000ff">var</SPAN><SPAN style="COLOR: #000000">&nbsp;s</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">”lalala”;<BR>alert(s.length);</SPAN></DIV>
<P>s<SPAN style="FONT-FAMILY: 宋体">本身是一个</SPAN>string<SPAN style="FONT-FAMILY: 宋体">而非</SPAN>object<SPAN style="FONT-FAMILY: 宋体">，它没有</SPAN>length<SPAN style="FONT-FAMILY: 宋体">属性，所以当访问</SPAN>length<SPAN style="FONT-FAMILY: 宋体">时，</SPAN>JS<SPAN style="FONT-FAMILY: 宋体">引擎会自动创建一个临时</SPAN>String<SPAN style="FONT-FAMILY: 宋体">对象封装</SPAN>s<SPAN style="FONT-FAMILY: 宋体">，而这个对象一定会泄露。<BR>这个bug匪夷所思，所幸解决起来相当容易，记得所有值类型做.运算之前先显式转换一下：<BR></P>
<DIV class=cnblogs_code><SPAN style="COLOR: #0000ff">var</SPAN><SPAN style="COLOR: #000000">&nbsp;s</SPAN><SPAN style="COLOR: #000000">="</SPAN><SPAN style="COLOR: #000000">lalala";<BR>alert(</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;String(s).length);</SPAN></DIV>
<P><BR><BR></P>
<H3 class=MsoListParagraph style="MARGIN-LEFT: 18pt; TEXT-INDENT: -18pt">参考</H3>
<P><BR><SPAN style="FONT-FAMILY: 宋体"><A href="http://msdn2.microsoft.com/en-us/library/bb250448.aspx"><FONT color=#000000>Understanding and Solving Internet Explorer Leak Patterns</FONT></A>(<A href="http://birdshome.cnblogs.com/archive/2006/05/28/IE_MemoryLeak.html"><FONT color=#000000>中文版</FONT></A>)<BR><A href="http://www.ibm.com/developerworks/web/library/wa-memleak/?S_TACT=105AGX52&amp;S_CMP=cn-a-wa"><FONT color=#000000>Memory leak patterns in JavaScript</FONT></A>(<A href="http://www.ibm.com/developerworks/cn/web/wa-memleak/index.html?S_TACT=105AGX52&amp;S_CMP=techcsdn"><FONT color=#000000>中文版</FONT></A>) </SPAN></P></SPAN>]]></description>
<author>fuhj02</author>
<pubDate>2008-11-14 22:30:00</pubDate>
</item>
<item>
<title><![CDATA[跨浏览器开发工具集]]></title>
<link>http://blog.edu.cn/user2/35840/archives/2008/2176398.shtml</link>
<description><![CDATA[<P>整理了一些Web前端开发的资源，包括有浏览器开发工具，Microformats，电子书资源等，如果你有更好的资源给我邮件。</P>
<H2>浏览器及相关开发工具</H2>
<TABLE summary=浏览器开发工具清单 border=0>
<THEAD>
<TR>
<TH>浏览器</TH>
<TH>相关开发工具</TH></TR></THEAD>
<TBODY>
<TR>
<TD><A href="http://www.mozilla.com/en-US/firefox/">Firefox</A>, <A href="http://flock.com/">Flock</A></TD>
<TD>
<UL>
<LI><A href="http://chrispederick.com/work/web-developer/">Web Developer Toolbar</A> (various) 
<LI><A href="http://www.getfirebug.com/">Firebug</A> (DOM, CSS, JavaScript, Traffic) 
<UL>
<LI><A href="http://developer.yahoo.com/yslow/">YSlow</A> 
<LI><A href="http://www.pixelperfectplugin.com/">Pixel Perfect</A> </LI></UL>
<LI><A href="http://modifyheaders.mozdev.org/">Modify Headers</A> (Ajax) 
<LI><A href="http://code.google.com/p/poster-extension/">Poster</A> (Ajax) 
<LI><A href="http://www.westciv.com/xray/index.html">XRAY</A>, <A href="http://www.westciv.com/mri/">MRI</A> (CSS) 
<LI><A href="http://firefox.cita.uiuc.edu/">Firefox Accessibility Extension</A> 
<LI><A href="http://livehttpheaders.mozdev.org/">LiveHTTPHeaders</A> </LI></UL></TD></TR>
<TR class=odd>
<TD><A href="http://www.microsoft.com/windows/ie/ie6/downloads/default.mspx">IE6</A>, <A href="http://www.microsoft.com/china/windows/products/winfamily/ie/default.mspx">IE7</A>, <A href="http://www.microsoft.com/windows/products/winfamily/ie/ie8/default.mspx">IE8beta</A></TD>
<TD>
<UL>
<LI><A href="http://www.microsoft.com/downloads/details.aspx?familyid=e59c3964-672d-4511-bb3e-2d5e1db91038&amp;displaylang=en">IE Developer Toolbar</A> (DOM, CSS) 
<LI><A href="http://httpwatch.com/">HttpWatch</A> (HTTP viewer) 
<LI><A href="http://www.visionaustralia.org.au/ais/toolbar/">Web Accessibility Toolbar</A> (Accessibility and more) 
<LI><A href="http://www.westciv.com/xray/index.html">XRAY</A>, <A href="http://www.westciv.com/mri/">MRI</A> (CSS) 
<LI><A href="http://www.microsoft.com/express/vwd/Default.aspx">Visual Web Developer Express Edition</A> (JavaScript) 
<LI><A href="http://www.microsoft.com/downloads/details.aspx?FamilyID=2f465be0-94fd-4569-b3c4-dffdf19ccd99&amp;displaylang=en">Microsoft Script Debugger</A> (JavaScript) </LI></UL></TD></TR>
<TR>
<TD><A href="http://www.opera.com/">Opera</A>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<P></P>
<P><A title="Opera 蜻蜓（Dragonfly）是 Opera 软件公司提供的开发工具" href="http://dragonfly.opera.com/">Dragonfly</A></P></TD>
<TD>
<UL>
<LI><A href="http://dev.opera.com/tools/">Opera developer tools</A> (DOM, CSS, JavaScript) 
<LI><A href="http://www.klauskomenda.com/archives/2008/02/16/collection-of-web-developer-tools-per-browser/#opera-ec">Opera Error Console</A> (HTML, CSS, JavaScript) 
<LI><A href="http://www.paciellogroup.com/resources/wat-about.html">Web Accessibility Toolbar</A> (Accessibility and more) </LI></UL></TD></TR>
<TR class=odd>
<TD><A href="http://www.apple.com.cn/safari/download/">Safari</A> <A href="http://nightly.webkit.org/">WebKit</A></TD>
<TD>
<UL>
<LI><A href="http://www.westciv.com/xray/index.html">XRAY</A>, <A href="http://www.westciv.com/mri/">MRI</A> (CSS) 
<LI>偏好设置》高级》在菜单栏中显示开发菜单 </LI></UL></TD></TR></TBODY></TABLE>
<P>相关开发工具，来自<A title="Collection of Web Developer Tools, per Browser" href="http://www.klauskomenda.com/archives/2008/02/16/collection-of-web-developer-tools-per-browser/">klauskomenda.com</A><BR><STRONG>关于浏览器多版本并存问题</STRONG></P>
<UL>
<LI>Firefox装3.0的，再装个Flock1.1(内核为firefox2)的，就可以并存两个版本，某些插件不支持新版可装<A href="https://addons.mozilla.org/zh-CN/firefox/addon/6543">Nightly Tester Tools</A>来解决 
<LI>IE多个版本并存可选择<A title="Multiple IE" href="http://tredosoft.com/Multiple_IE" target=_blank>Multiple IE</A>或者<A title="http://blog.edu.cn/IETester " href="http://www.my-debugbar.com/wiki/IETester/HomePage" target=_blank>IETester</A> </LI></UL>
<H2>一些在线用的小东东</H2>
<P><STRONG>Accessibility</STRONG></P>
<UL>
<LI><STRONG>&nbsp;<A href="http://www.wave.webaim.org/wave/index.jsp"><SPAN>WAVE 3.0 Web Accessibility Tool</SPAN></A></STRONG>&nbsp;高度可定制的工具，它采用了图形化模型展示网站兼容性问题（ WCAG 1.0 and section 508 ）。 
<LI><STRONG><A href="http://www.tawdis.net/taw3/cms/en"><SPAN>TAW Web Accessibility Test</SPAN></A></STRONG>&nbsp;测试网页是否存在冲突（ WCAG 1.0 兼容性 ），通过图形模式生成一份依据 wcag 优先模式为基础的网站修改建议。 
<LI><STRONG><A href="http://www.cynthiasays.com/"><SPAN>HiSoftware CynthiaSays portal</SPAN></A></STRONG>&nbsp;采用了非常严格的规则来测试网页（ 根据 section 508 和 WCAG 1.0 规则 ），生成的报告也极为详细。 
<LI><STRONG><A href="http://www.sidar.org/hera/index.php.en"><SPAN>HERA Accessibility testing with Style</SPAN></A></STRONG>&nbsp;使用一种极为复杂但容易理解方式指出网页的 wcag1.0 兼容性问题。 </LI></UL>
<DIV><STRONG>浏览器模拟工具</STRONG></DIV>
<DIV>
<UL>
<LI><STRONG><A href="http://browsershots.org/">Browsershots</A></STRONG>&nbsp;能给出你的网站在不同浏览器下显示效果的截图，包括：Firefox 和 Internet Explorer （ Windows ）、Firefox 和 Safari （ Mac OS X ）、Iceweasal 和 Konqueror （ Linux ），但是结果要在 1 - 3 小时后才能出来。 
<LI><A href="http://www.browsrcamp.com/">Browsrcamp</A>&nbsp;没有Mac的同学可以来这里。。实时生成Safari滴，速度很快。 
<LI><STRONG><A href="http://ipinfo.info/netrenderer/"><SPAN>IE NetRenderer</SPAN></A></STRONG>&nbsp;没有Win的同学可以来这里。。实时生成你的网站在 Internet Explorer 5.5 、6.0 和 7.0 下的截图。 
<LI><STRONG><A href="http://ready.mobi/launch.jsp?locale=en_EN">MobiReady Report</A></STRONG>&nbsp;分析使用手机访问网页的兼容性问题，会生成一份详细的报告，并提供了在两种不同类型的手机浏览器上你得网站可能显示的样子。 </LI></UL></DIV>
<H2>一些软件</H2>
<H3>Mac</H3>
<UL>
<LI><A href="http://www.panic.com/coda/">Coda</A>：华丽的软件设计，最大的优点就是同步方便 
<LI><A href="http://macromates.com/">TextMate</A>：实用软件，最大的缺点就是中文支持不好，而且不支持存GBK的 </LI></UL>
<H2><A title=Microformats官方 href="http://microformats.org/">Microformats</A><SUP><A href="http://suda.co.uk/projects/microformats/cheatsheet/">Cheat Sheet</A> <A href="http://www.ilovejackdaniels.com/cheat-sheets/microformats-cheat-sheet/">另一份</A></SUP></H2>
<UL>
<LI><A href="http://tools.microformatic.com/">http://tools.microformatic.com/</A> 
<LI>Firefox Add-ons :<A href="https://addons.mozilla.org/zh-CN/firefox/addon/2240">Tails Export </A>(<A href="http://www.aoao.org.cn/blog/2006/11/microformats/">说明</A>), <A href="https://addons.mozilla.org/zh-CN/firefox/addon/4106">Operator</A> 
<LI><A href="http://zappatic.net/safarimicroformats">Safari Microformats plugin</A> </LI></UL>
<H2>一些参考资料</H2>
<UL>
<LI>Web开发人员的百科全书：<A href="http://code.google.com/doctype/">Google Doctype</A>,包括Web安全、JavaScript、DOM控制、 CSS技巧和窍门等。 
<LI>HTML<SUP><A href="http://www.ilovejackdaniels.com/cheat-sheets/html-cheat-sheet/">Cheat Sheet</A></SUP>: <A href="http://reference.sitepoint.com/html">SitePoint HTML Reference (beta)</A> <A title="http://blog.edu.cn/HTML Playground, html, css reference by example" href="http://htmlplayground.com/">HTML Playground</A> 
<LI>CSS<SUP><A href="http://www.ilovejackdaniels.com/cheat-sheets/css-cheat-sheet/">Cheat Sheet</A></SUP>：<A href="http://www.aoao.org.cn/blog/2007/08/css2-translate-chm/">W3C CSS2中文翻译（有CHM）</A>，<A href="http://52css.com/css/">CSS2在线参考手册</A>，<A href="http://reference.sitepoint.com/css"> SitePoint CSS Reference</A>,&nbsp;<A title=CSS_Reference:Mozilla_Extensions href="http://developer.mozilla.org/en/docs/CSS_Reference:Mozilla_Extensions">Mozilla_私有属性</A><SUP><A title="http://blog.edu.cn/Firefox CSS私有属性备忘记录" href="http://www.aoao.org.cn/blog/2006/10/firefox-css-extensions/">部分翻译</A></SUP> </LI></UL>]]></description>
<author>fuhj02</author>
<pubDate>2008-11-14 22:27:00</pubDate>
</item>
<item>
<title><![CDATA[CVSNT用户管理方案]]></title>
<link>http://blog.edu.cn/user2/35840/archives/2008/2172666.shtml</link>
<description><![CDATA[&nbsp;所有这些操作基于的环境和软件版本：WINDOWS2000 Pro、CVSNT2.0.4、WinCVS1.3.9.1Beta9 在前面的介绍CVSNT配合WinCVS进行用户管理的文章中，已经对CVSNT的用户管理，权限分配进行了比较详细的叙述，但是还有一些概念没有交待清楚，在这里，我会根据项目的实际需要，以及自己的一些经验给出一套用户管理、权限管理方案，在看这篇文章之前你最好已经阅读了前面的一篇文章，对用户的增加删除，权限的修改，等等这些操作能够了解，否则，会有一点困难。<BR><STRONG>&nbsp;&nbsp;1、 CVSNT的用户验证方式<BR></STRONG>&nbsp;&nbsp;我们这里所讨论的是工作在pserver方式下。<BR>&nbsp;&nbsp;在CVSNT的文档中给出了两种验证方式，我总结了一下，可以这样称呼：Window和CVSNT混合验证方式，CVSNT独立验证方式。在前面的文章中，我们没有详细的给出这两种方式的内容，所讲述的启示就是混合验证方式。<BR>&nbsp;&nbsp;决定CVSNT工作于何种验证方式是由CVS的管理文件来决定的，这些管理文件处在库的目录下的CVSROOT目录中，这里可以得出结论，对于不同的库，可以给不同的验证方式。所以，在每个库建立的时候要首先设定好这些前提。<BR>&nbsp;&nbsp;下面的操作如果没有特殊指出则都是在客户端来进行管理的，下面首先是对一些控制原理和相关的文件做一些说明，如果你正在进行相关的模拟操作，请停下来暂时停止你的操作，因为这些操作的步骤是有先后的，如果你顺序不对，那么你可能就权限失效，进行不了下面的操作了。<BR><STRONG>&nbsp;&nbsp;1．1 config文件<BR></STRONG>&nbsp;&nbsp;在库建立好了以后，你还没有对控制文件进行修改之前，CVSNT是工作在混合验证方式之下的，这个时候，CVS服务器的管理员就是CVSNT的管理员，你以一个管理员身份登陆，检出你要操作的库的CVSROOT模块，看一下文件列表，控制CVSNT的验证工作方式的是config文件，你可以在文件列表中找到它，双击看看其中的内容，这里对我们最重要的就是第一个设置内容，你会看到下面的内容：<BR>&nbsp;&nbsp;# Set this to `no' if pserver shouldn't check system users/passwords<BR>&nbsp;&nbsp;#SystemAuth=yes<BR>&nbsp;&nbsp;第二行就是我们要修改的内容，默认状态是被注释掉的，SystemAuth有两个值yes和no<BR>yes：pserver将使用系统用户数据库和passwd文件（这个文件后面会详细讲述）来共同验证（若passwd文件不存在或者文件中没有相应的资料，则用系统用户来进行验证）默认为yes<BR>&nbsp;&nbsp;no：所有的用户必须在passwd中存在，根据passwd的内容来进行用户的验证。<BR>&nbsp;&nbsp;我这里所阐述的方案就是工作在no的下面的，修改完之后提交到服务器，提交完毕服务器就处在CVSNT的独立验证模式下了。在这个工作方式下，NT本地的用户和CVSNT用户没有任何本质的联系和影响（仅仅是要建立一个别名）。<BR><STRONG>&nbsp;&nbsp;1．2 passwd文件<BR></STRONG>&nbsp;&nbsp;在讲述上面的时候提到了这个文件，在服务器工作在CVSNT验证模式下的时候，这个文件就可以称之为CVSNT的用户数据库，这个里面存储着用户列表，用户的密码，以及别名的一些信息。默认状态下这个文件是不存在的，所以，如果我们要在CVSNT验证模式下工作，必须建立这个文件。注意：这个文件是不能够在客户端进行修改的。这个文件的内容是相当简单的，就像下面：<BR>&nbsp;&nbsp;bach:ULtgRLXo7NRxs<BR>&nbsp;&nbsp;spwang:1sOp854gDF3DY<BR>&nbsp;&nbsp;melissa:tGX1fS8sun6rY:pubcvs<BR>&nbsp;&nbsp;qproj:XR4EZcEs0szik:pubcvs<BR>&nbsp;&nbsp;这里分别拿第一个用户bach和第三个用户melissa来进行说明，每一行代表一个用户，总共有三部分信息，用户名、密码、本地用户三部分之间使用冒号“:”来进行分割。<BR>&nbsp;&nbsp;用户名：就是登陆CVS的用户名<BR>&nbsp;&nbsp;密 码：用户的密码，这里是经过加密的，如果为空，那么就是空密码<BR>&nbsp;&nbsp;本地用户：CVS用户这个别名对应的本地用户，（跟本地用户没有任何其他关系，仅仅是别名的关系）<BR>&nbsp;&nbsp;如果在本地系统中存在一个用户名bash，那么要在CVS建立一个bach这样的用户就不需要在后面指出对应的系统用户，melissa后面的pubcvs就是系统用户，在本地系统上面存在的用户。对于要用命令增加这两种用户的格式如下：<BR>&nbsp;&nbsp;cvs passwd –a bach<BR>&nbsp;&nbsp;cvs passwd –r pubcvs –a melissa<BR>&nbsp;&nbsp;在库建立的时候可以在服务器上建立一个简单的passwd初始化文件，加一行<BR>&nbsp;&nbsp;cvsadmin:<BR>&nbsp;&nbsp;这样，就给出了一个cvsadmin这个空密码用户（本地系统中有这样的用户，就可以不加到后面去），然后在客户端来进行修改和以后的用户增加工作。注意：在客户端进行其他之前请先首先修改这个密码，以防止别人进行破坏。<BR>&nbsp;&nbsp;在服务器端建立了这个文件以后，就不用再手动进行修改了，当你在客户端进行密码或者用户的增加删除的时候，系统会自动进行这个文件的更新。这个文件是管理着CVSNT系统中的所有的用户，所以，要特别重视，不了解这个文件格式的，不要去随便修改，更加不要尝试在客户端进行修改！<BR><STRONG>&nbsp;&nbsp;1．3 admin文件<BR></STRONG>&nbsp;&nbsp;这个文件是指定CVSNT的管理员列表的文件，CVSNT会根据这个文件中的内容来判断一个用户是否是管理员。这个文件的内容很简单，是一个用户列表。类似下面<BR>&nbsp;&nbsp;user1<BR>&nbsp;&nbsp;user2<BR>&nbsp;&nbsp;user3<BR>&nbsp;&nbsp;这些代表user1,user2,user3都是管理员，当然，这些用户必须要存在才能够正确登陆系统来执行管理。<BR>&nbsp;&nbsp;这个文件默认状态下是没有的，但是，可以在客户端进行添加，在你的客户端进行新建这个文件然后add上去再commit一下，这个文件就可以上传到服务器，但是这个时候还没有生效，请修改checkoutlist这个文件，加入admin这一行，checkoutlist也可以在客户端进行修改再提交，这个时候admin就可以被系统自动的build了。<BR>&nbsp;&nbsp;Checkoutlist是维护的一个文件列表，可以放入系统自动build的用户自定义的系统文件列表，注意：对passwd没有用！！<BR><STRONG>&nbsp;&nbsp;1．4 group文件<BR></STRONG>&nbsp;&nbsp;这个文件是定义系统的组，我们可以将同样性质的用户归入一个组，然后用给用户赋权限的方式给组赋权限，这样，一个组的用户就会具有同样的权限。Group的内容如下：<BR>&nbsp;&nbsp;group1:user1 user2 user3<BR>&nbsp;&nbsp;group2:me you he<BR>&nbsp;&nbsp;group3:tom honey<BR>&nbsp;&nbsp;有上面可以看出来，这个文件的内容也是相当的简单，首先是组的名称然后是冒号，接着是用户名，多个用户名之间用空格来进行分割。<BR>&nbsp;&nbsp;Group文件可以在客户端进行新建和修改，不用修改checkoutlist这个文件，系统会自动build这个文件并且使之生效。<BR>&nbsp;&nbsp;作为组里面的特定成员还可以赋给特定的权限，权限分为两类c,w,r和n，否定权限是有高的优先级的。<BR>&nbsp;&nbsp;好，上面已经介绍了本方案所涉及到的几个重要的文件以及修改方式。这里再强调一下，passwd只能够再服务器端进行建立和修改，不能够在客户端进行操作！<BR>现在根据上面介绍的内容，可以开始你的操作了，下面给出修改顺序，库刚刚建立起来的时候，使用一个服务器上的本地管理员用户进行登陆检出CVSROOT模块。<BR>&nbsp;&nbsp;1、 现在服务器端加上passwd文件，给一个初始的用户，比如cvsadmin:<BR>&nbsp;&nbsp;2、 在客户端增加admin，将cvsadmin加入admin文件，作为出是管理员，并提交加入到库中。<BR>&nbsp;&nbsp;3、 在修改checkoutlist文件，加入admin，使其能够自动build。<BR>&nbsp;&nbsp;4、 最后修改config文件的SystemAuth=no，在提交之前要确认一下你上面的修改是否正确，如果提交了这个文件，CVSNT验证模式就开始生效了！<BR>&nbsp;&nbsp;5、 好，现在请修改你的参数再重新进行的登陆吧。因为你的系统已经切换了工作模式，你当前的用户已经失效了。<BR>&nbsp;&nbsp;完成了上面的步骤，整个服务器就会有效的工作在CVSNT验证模式下了。而group文件在你需要的任何时候可以加入。<BR>&nbsp;&nbsp;在上面的文章关于CVSNT的用户的管理方案的，在这里做一点补充，在后面的操作中全部是针对在客户端使用WinCVS来进行的（出了增加passwd）文件，其实，在我的实践当中config，passwd，admin，checkoutlist，这些文件的起始修改（初始化）都可以在新建了库以后一起完成，然后再让相应的库的管理员来进行相关的操作。]]></description>
<author>fuhj02</author>
<pubDate>2008-10-8 9:12:00</pubDate>
</item>
<item>
<title><![CDATA[入侵渗透思路]]></title>
<link>http://blog.edu.cn/user2/35840/archives/2008/2165229.shtml</link>
<description><![CDATA[&nbsp; 入侵渗透涉及许多知识和技术，并不是一些人用一两招就可以搞定的。<BR>一，踩点<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>踩点可以了解目标主机和网络的一些基本的安全信息，主要有；<BR>1，管理员联系信息，电话号，传真号；<BR>2，IP地址范围；<BR>3，DNS服务器；<BR>4，邮件服务器。<BR>相关搜索方法：<BR>1，搜索网页。<BR>确定目标信息1，为以后发动字典和木马入侵做准备；寻找网页源代码找注释和隐藏域，寻找隐藏域中的"FORM"标记。例如：<BR><BR>可以发起SQL注入攻击，为以后入侵数据库做准备。<BR>相关工具：UNIX下的Wget,Windows下的Teleport。<BR>2，链接搜索<BR>目标网站所在的服务器可能有其他具有弱点的网站，可以进行迂回入侵，而且可以发现某些隐含的信息。<BR>搜索方法介绍：<BR>通过各种搜索引擎：GOOGLE，[url=http://www.dogpile.com,<A href="http://www.hotbot.com/" target=_self><FONT color=#606060>http://www.hotbot.com</FONT></A>]http://www.dogpile.com,<A href="http://www.hotbot.com/" target=_self><FONT color=#606060>http://www.hotbot.com</FONT></A>[/url]<BR>二，查点<BR>A，确定目标的域名和相关的网络信息。<BR>搜索方法；<BR>Whois查询，通过Whois数据库查询可以得到以下的信息：<BR>1，注册机构：显示相关的注册信息和相关的Whois服务器；<BR>2，机构本身：显示与某个特定机构相关的所有信息；<BR>3，域名：显示与某个特定域名相关的所有信息<BR>4，网络：显示与某个特定网络或单个IP地址相关的所有信息；<BR>5，联系点:显示与某位特定人员相关的所有信息<BR>搜索引擎站：http://www.infobear.com/whois.shtml,<BR>举例：Output of: whois 163.com@whois.internic.net<BR>Registrant: <BR>Netease.com, Inc. <BR>36/F Peace World Plaza, No.362-366 <BR>Huan Shi Dong Road <BR>Guangzhou, Guangdong 510060 <BR>CN <BR><BR>Domain Name: 163.COM <BR><BR>Administrative Contact, Technical Contact: <BR>Netease.com, Inc. <A href="mailto:nsadmin@corp.netease.com" target=_self><FONT color=#606060>nsadmin@corp.netease.com</FONT></A> <BR>36/F Peace World Plaza, No.362-366 <BR>Huan Shi Dong Road <BR>Guangzhou, Guangdong 510060 <BR>CN <BR>+86-20-85525516 fax: +86-20-85525535 <BR><BR>Record expires on 24-Jan-2009. <BR>Record created on 15-Sep-1997. <BR>Database last updated on 10-Feb-2006 03:24:01 EST. <BR><BR>Domain servers in listed order: <BR><BR>NS.NEASE.NET 202.106.185.75 <BR>NS3.NEASE.NET 220.181.28.3 <BR><BR>B，利用ARIN数据库可以查询某个域名所对应的网络地址分配信息。<BR>相关搜索地址：<A href="http://ws.arin.net/cgi-bin/whois.pl" target=_self><FONT color=#606060>http://ws.arin.net/cgi-bin/whois.pl</FONT></A><BR>利用<A href="http://whois.apnic.net/apnic-bin/whois2.pl" target=_self><FONT color=#606060>http://whois.apnic.net/apnic-bin/whois2.pl</FONT></A>进行对IP地址的查询，以搜集有关的网络信息：<BR>举例：163.com-&gt;202.108.9.16<BR>inetnum: 202.108.0.0 - 202.108.255.255<BR>netname: CNCGROUP-BJ<BR>descr: CNCGROUP Beijing province network<BR>descr: China Network Communications Group Corporation<BR>descr: No.156,Fu-Xing-Men-Nei Street,<BR>descr: Beijing 100031<BR>country: CN<BR>admin-c: CH455-AP<BR>tech-c: SY21-AP<BR>mnt-by: APNIC-HM<BR>mnt-lower: MAINT-CNCGROUP-BJ<BR>mnt-routes: MAINT-CNCGROUP-RR<BR>changed: <A href="mailto:hm-changed@apnic.net" target=_self><FONT color=#606060>hm-changed@apnic.net</FONT></A> 20031017<BR>status: ALLOCATED PORTABLE<BR>changed: <A href="mailto:hm-changed@apnic.net" target=_self><FONT color=#606060>hm-changed@apnic.net</FONT></A> 20060124<BR>source: APNIC<BR><BR>role: CNCGroup Hostmaster<BR>e-mail: <A href="mailto:abuse@cnc-noc.net" target=_self><FONT color=#606060>abuse@cnc-noc.net</FONT></A><BR>address: No.156,Fu-Xing-Men-Nei Street,<BR>address: Beijing,100031,P.R.China<BR>nic-hdl: CH455-AP<BR>phone: +86-10-82993155<BR>fax-no: +86-10-82993102<BR>country: CN<BR>admin-c: CH444-AP<BR>tech-c: CH444-AP<BR>changed: <A href="mailto:abuse@cnc-noc.net" target=_self><FONT color=#606060>abuse@cnc-noc.net</FONT></A> 20041119<BR>mnt-by: MAINT-CNCGROUP<BR>source: APNIC<BR><BR>person: sun ying<BR>address: Beijing Telecommunication Administration<BR>address: TaiPingHu DongLi 18, Xicheng District<BR>address: Beijing 100031<BR>country: CN<BR>phone: +86-10-66198941<BR>fax-no: +86-10-68511003<BR>e-mail: <A href="mailto:suny@publicf.bta.net.cn" target=_self><FONT color=#606060>suny@publicf.bta.net.cn</FONT></A><BR>nic-hdl: SY21-AP<BR>mnt-by: MAINT-CHINANET-BJ<BR>changed: <A href="mailto:suny@publicf.bta.net.cn" target=_self><FONT color=#606060>suny@publicf.bta.net.cn</FONT></A> 19980824<BR>source: APNIC<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>知道了目标所在的网络，可以进行迂回渗透，寻找薄弱点，进入目标网络，然后在攻击目标。<BR><BR>C，DNS信息查询<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>域名系统允许把一个DNS命名空间分割成多个区，各个去分别保存一个或多个DNS域的名字信息。<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>区复制和区传送：DNS服务器之间是采用区传送的机制来同步和复制区内数据的。<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>区传送的安全问题不在于所传输的域名信息，而在于其配置是否正确。因为有些域名信息当中包含了不应该公开的内部主机和服务器的域名信息。<BR>相关工具：<BR>1，Windows下，nslookup,SamSpade;<BR>2, UNIX下：nslookup,dig,host,axfr<BR>在Windows下的使用方法：<BR>c:\&gt;nslookup<BR>Default server: 目标的DNS服务器<BR>Address: 目标的IP地址<BR><BR>&gt;set type=ANY//表示接受任何可能的DNS记录<BR>&gt;ls -d 163.com &gt;zone.163.com.txt //获得目标域的相关记录，结果保存在zone.163.com.txt<BR><BR>D，通过Traceroute获得网络的拓扑结构以及网络网络设备的地址。<BR>相关工具；<BR>Windows下：Tracert 支持ICMP协议<BR>UNIX下：Traceroute 支持ICMP和DNS协议，由于多数防火墙已经过滤了ICMP，所以UNIX下的Traceroute是不错的选择，而且使用-p n选项可以自己指定使用的端口。<BR><BR>三，网络扫描<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>面对不同的网络，应该采用不用的扫描方法：<BR>1，对于内部网络，可用类型很多，ICMP协议是普遍要装上的，在内部网广播ICMP数据包可以区分WINDOWS和UNIX系统，发送类型为8的ICMP的ECHO请求，如果可以受到类型为0的ECHO回应，表明对方主机是存活的。<BR>相关工具介绍：<BR>UNIX下的：fping&amp;gping<BR>WINDOWS下：Pinger 特点：速度快，多线程。<BR>2，对于外部网络，可用类型也很多，涉及到的原理也有很多，例如：TCP扫描，UDP扫描，<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>其实我是很不愿意用扫描工具的，很容易使对方感觉到入侵事件的发生，不论是防火墙还是入侵检测系统都会或多或少的留下我们的脚印，如果遇到一个勤快的管理员的话，那么这次入侵很可能以失败告终。<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>但使用与否依各个喜好而定了：），有时候我们在测试网络或者主机的安全性时，就不能忽视他的存在了，首先，安全测试不是入侵，全面的测试对抵御黑客和蠕虫的攻击是必要的，在这里推荐的端口扫描工具是NMAP，因为他带有躲避IDS检测的机制，重组了TCP的三次握手机制，慢扫描机制等等都是其他扫描工具无法比拟的，UDP扫描是很不可靠的，原因有下几点：<BR>这种扫描依靠ICMP端口不可达消息,如果发送端给目标一个感兴趣的端口发送了一个UDP数据包后，没有收到ICMP端口不可打消息，那么我们认为该端口处于打开状态。<BR>不可靠的原因：<BR>1，路由器可能丢弃UDP分组；<BR>2，很多的UDP服务不也不产生响应；<BR>3，防火墙的常规配置是丢弃UDP分组（除DNS外）；<BR>4，休眠状态的UDP端口是不会发送一个ICMP端口不可到达消息。<BR><BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>还有的扫描工具就是弱点扫描工具，这些工具综合各种漏洞信息构造漏洞数据库，去探究存在漏洞没有打补丁的主机,当然也有针对特定漏洞的检测发现工具（脚本小子能用，网络安全人员也弄用--双刃剑-：）<BR>这里详细介绍对目标操作系统类型的检测原理：<BR>Telnet标识和TCP/IP堆栈指纹：<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>1，网上许多的系统可以直接Telnet到目标，大多会返回欢迎信息的，返回的信息包含了该端口所对应的服务软件的版本号，这个对于寻找这个版本的软件的漏洞很重要，如果对方开了Telnet，那么可以直接得到对方的系统类型和版本号，这个对于挖掘系统的漏洞很重要（对于溢出来说，不同版本的系统和语言版本的系统来说，RET地址，JMP ESP，地址是不同的）。<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>2，如今越来越多的管理员懂的了关闭功能标志，甚至提供伪造的欢迎信息。那么TCP/IP堆栈指纹是区分不同系统的好方法。<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>1，FIN扫描<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>给打开的端口发送FIN包，RFC 793规定不返回任何响应，例外的系统是： MS Windows,BSDI,CISCO,HP/UX,MVS和IRIX都返回一个RESET包。<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>2，TCP初始序列号（ISN）采样<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>这种方法利用了在实现TCP连接时使用不同的ISN模式识别系统，可以分成多种模式：传统的64K增加（旧UNIX OS），随机增加（新版的Solaris,IRIX,FreeBSD,Digital UNIX和Cray等），真正随机（Linux 2.0.*,OpenVMS和新版AIX等），Windows系统使用所谓的“时间依赖性”模型，即ISN的增加同某一个短固定的时间间隔有关系，有些主机始终使用固定的ISN，例如3COM集线器（使用0x803)和AppleLaserWriter打印机（0xC7001）。<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>3，不分片位<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>目前许多系统在他们发送的包中使用IP“不分片”位，这主要是想获得好的运行性能，不过也不是所有的操作系统都有此功能，即使有，其实现的方式可能也不同。因此利用次位或许有利于我们收集更多的有关目标OS的信息。<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>4，TCP初始窗<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>TCP初始窗只是简单地测试返回包的窗口尺寸。Queso和Nmap可以对实际的窗口进行窗口跟踪。在很多操作系统中是一个常数。例如：AIX是唯一使用0x3F25的操作系统。对于完全重新编写代码的NT 5的TCP堆栈，使用0x402E.<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>5,ACK值<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>如果发送一个FIN|PSH|URG，许多操作系统设置ACK等于初始序列号，而Windows和某些打印机将发送seq+1.如果发送一个SYN|FIN|PSH|URG到打开的端口，不同的Windows系统的实现将很不一致，有时返回seq,有时返回seq+1,甚至返回完全随机的数值。<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>6，ICMP错误消息机制<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>某些操作系统按照RFC 1812的建议，限制不同错误消息的发送速率。例如：Linux内核（在net/ipv4/icmp.h中定义）限制目标不可到达消息的产生速率为4秒种内80个，如果超过这个限制将有1/4的惩罚。测试方法是发送一大串包到某些随机选取的高端口，然后计算返回的不可到达包的数目。<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>7，ICMP消息引用（Message Quoting)<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>RFC规定：ICMP错误消息将引用一小部分导致错误消息包的ICMP消息内容。对于端口不可达消息，几乎所有的实现都只发送所需要的IP头+8字节。不过Solaris发送的内容更多，而Linux发送的东西最多。这就是我们识别没有打开任何端口的Linux和Solaris主机。<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>8，ICMP错误消息回射完整性<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>主机对端口不可打错误消息将送回一小部分于是消息的内容。某些机器送回的包中包括的协议头部分已经被改变。例如，AIX和BSDI送回的IP总长度是20字节。而系统BSDI，FreeBSD,OpenBSD,ULTRIX和VAXen则将原样送回你所发送的IP标识符。某些系统（AIX和FreeBSD等）将送回不一致或等于0的校验和。这同样适用于UDP校验和。Nmap对ICMP错误消息包进行九种不同的测试以标识系统之间的微笑差别。<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>9，TCP选项<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>是实现TCP/IP协议时可选的一个部分功能，这跟不同的系统实现有关，这些选项都是挖掘可用信息的好方法。原因是：<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>1，他们都是可选项，不是所有主机都可以实现的；<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>2，如果你所发送的包中对某个选项进行了设置，只要目标支持，那么目标主机就返回此选项；<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>3，可以在包中设置所有的选项进行测试。<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>例如：Nmap在每个探测包中设置所有的选项来进行测试：<BR>Windows Scale=10;NOP;Max Segment Size=265;Timestamp;End of Ops;<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>从返回的的包中查看这些选项，就知道了什么系统支持他们。<BR><BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>还有一种被动操作系统识别方法，就是监控不同系统之间网络包的情况来判断目标的操作系统类型，siphon被用来进行这方面的测试，这个工作原理如下：<BR>签名：<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>主要TCP的四个字段判断：<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>1，TTL：出站的包的存活时间；<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>2，Window size：窗口大小；<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>3，DF：是否设置了不准分片位；<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>4，TOS：是否设置了服务类型。<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>综合这些信息可以大概判断出目标的系统，但不能%100。<BR>四，查点<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>利用查点技术可以得到比前面讲的更多更具体的有用信息，例如：帐户信息等。<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>1，Windows系统查点技术<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>利用NetBIOS规则，首先介绍NetBIOS,NetBOIS位于TCP/IP之上，定义了多个TCP和UDP端口。<BR>----TCP<BR>（1），139：nbsession:NetBOIS会话。<BR>例如：net use \\IP\ipc$ " " /user:" ".<BR>（2），42：WINS：Windows Internet名字系统（UDP端口也是42）。<BR>----UDP<BR>（1）137：nbname:名字查询。<BR>例如：nbtstat -A IP//03中显示的不是计算机名就是用户名<BR>（2）138：nbdatagram:UDP数据报服务<BR>例如：net send /d:domain-name "Hello"<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>得到用户名利用到了IPC$空会话和sid工具。sid工具由两个小工具组成：user2sid和sid2user.user2sid获得用户名或组名的sid;sid2user则是输入一个sid而获得相应用户名的和组名，sid就是在创建用户时而创建的，相当于UNIX系统下的UID,WIN系统权限的检查就是通过对SID的检查的。一个sid是由一长串数字组成的，其中包括两个部分，前一部分用来唯一标识一个域，后一部分唯一标识一个用户名，这部分数字被称作rid，既相对标识符，rid有一定的规律，其取值总是从500开始的，超级管理员的rid总是500，而GUEST用户的rid总是501；而新建立的帐户的rid从1000开始。<BR>具体的步骤：<BR>c:\net use \\IP\ipc$ " " /user:" "<BR>c:\user2sid \\IP guest //得到了SID的前半部分<BR>s-1-5-21-1123561945-1580818891-1957994488-501<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>s是sid的前缀，后面跟的是1表示版本号，5用于标识发放sid的授权实体，5指NT/2000。21-1123561945-1580818891-1957994488唯一地标识域和工作组。不同的用户只是最后的相对标识符不一样。现在用sid2user查询系统的用户名了：<BR>c:\sid2user \\IP 5 21 1123561945 1580818891 1957994488 500<BR>name is cookie<BR>domain is condor<BR>c:\sid2user \\IP 5 21 1123561945 1580818891 1957994488 1001<BR><BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>SNMP查点：通过默认的管理群字符串PUBLIC读取特性，可以得到系统的一些信息，具体有：接口表，路由表及ARP表，TCP表和UDP表，设备表和存储表，进程表和软件表，用户表，共享表。<BR>SNMP工具，snmputil.exe<BR>例如：<BR>1，或者网络接口数目：<BR>c:\snmputil get localhost public .1.3.6.1.2.1.2.1.0<BR>2,显示所有的SNMP变量内容<BR>c:\snmputil walk localhost public .1.3<BR>2UNIX类系统的查点技术<BR>1，$showmount -e <A href="http://www.target.com//" target=_self><FONT color=#606060>www.target.com </FONT></A>//前提2049号端口开着（NFS）<BR>2，$finger @<A href="http://www.target.com///" target=_self><FONT color=#606060>www.target.com//</FONT></A>还有rusers<BR>3, $telnet <A href="http://www.target.com/" target=_self><FONT color=#606060>www.target.com</FONT></A> 25<BR>vrfy root //证实是否有root<BR>expn adm <BR>quit <BR>五，具体的分析漏洞<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>针对特定目标进行了以上分析后，总结出最好的入侵思路，选择入侵工具，做好入侵的准备工作是必须，有时入侵时间的选择也是很重要的，因为会涉及到正常的公司网络的正常通信，甚至会使恶意的网络在你入侵测试就发生了，最直接的漏洞利用方法，我认为是溢出漏洞了，因为他直接就可以得到对方的系统权限，返回一个和在本地一样的SHELL环境，此时无所不能：<BR>溢出攻击的分类有：<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>1，WINDOWS下的和UNIN下的<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>一般原理，就用户提交的参数范围超过了在内存中保存的本地变量的范围，而程序或者系统并没有对输入的参数进行合理的长度检查，导致了被调用函数的返回地址被覆盖，如果用一个跳转到我们提交的shellcode的地方的地址代替，那么我们的shellcode就可以运行，成功得到了目标的系统权限。<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>此外还有格式化串漏洞，导致这个漏洞的原因是在处理用户数据的参数时没有过滤用户提交的，格式化符号，例如%n这个将允许输出的参数的个数保存在内存中，恶意构造此漏洞用户将会向内存的任何位置写SHELLCODE的地址。<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>2,常见漏洞类型<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>UNIX下的本地漏洞很多，挖掘起来也较容易，他主要有以下几种类型：<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>1，环境欺骗<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>一般指PATH环境变量的欺骗，就是说如果一个特权的程序执行了一个外部的命令，那么我们可以简单的构造这个外部命令程序，然后修改PATH使这个特权程序能够去首先执行我们构造的外部命令程序，而这个外部的命令程序是一个去得SHELL的程序例如：<BR>bash$cat &gt;ps #!/bin/sh<BR>&gt;EOF<BR>而这个特权程序是：<BR>bash$cat &gt;test.c int main()<BR>&gt;{<BR>&gt;setuid(0);<BR>&gt;system("ps -ef"); /*程序调用了外部命令，但没有给出这个命令的绝对路径，这个是PATH欺骗的前提*/<BR>&gt;}<BR>&gt;EOF<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>编译后的test文件具有s为，属主是root.这样设置是因为程序test执行时会以root身份运行特权命令，这样在他运行时由于调用的是我们伪造的ps命令程序，所以会产生一个root权限的SHELL环境。<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>2，竞争条件<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>一般指时序竞争，例如：<BR>fp=fopen("test.log","w+");<BR>chown("test.log",getuid(),getgid());<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>原理也很简单，就是如果当前的程序运行时权限是euid=root,uid=当前用户，由于文件test.log在打开会执行将文件的属主改为当前用户，所以我们可以在执行完fopen之后，chown之前删了test.log，而创建了一个到/etc/passwd的符号链接，这样就会将/etc/passwd文件的属主改为当前的用户，当前的用户就可以在passwd文件中将自己的uid改为0，这样就取得了system权限。<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>3，溢出和格式串漏洞<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>导致这些漏洞的数据来源主要是：<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>1，命令行参数<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>2，环境变量<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>3，特定格式文件的读取<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>4，用户交互十的输入<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>缓冲溢出的漏洞是有以下一些函数引起的：<BR>1，strcpy<BR>2, strcat<BR>3, sprintf<BR>4, vsprintf<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>格式化串的漏洞和以下一些函数有关：<BR>1, print/vprintf<BR>2, fprintf/vfprintf<BR>3, sprintf/vsprintf<BR>4, snprintf/vsnprintf<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>利用工具有objdump,elfedump查看目标是否有不安全的以上不安全的函数，如果有可以进行黑盒测试，进而进行返汇编分析程序的上下文和执行流程，利用strings可以静态查找目标的环境变量。<BR>六，攻击WWW<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>现在的入侵事件，攻击WWW居多，原因也很简单，那就是程序员在编写WEB脚本程序时更本不注重安全因素，导致了上传shell,提升权限之类的严重后果，入侵渗透测试主要通过以下几个方面进行测试：<BR>1，搜索SQL注入点；<BR>2，搜索特定目录和文件，例如：上传程序文件，这个利用价值也很大；<BR>3，寻找管理员登陆网页，进行字典或者SQL饶过入侵；<BR>4，寻找WEB程序的源代码，进行漏洞挖掘，主要涉及的漏洞类型有：SQL注入，文件包含漏洞，目录跳转漏洞，以脚本文件格式保存错误日志漏洞，上传漏洞；<BR>5，在代码审核时，不要忘记对程序员犯的逻辑错误进行查看，例如：函数书写错误<BR>6，总是，漏洞的成因归根到底是由于对用户的输入没有进行严格的过滤。<BR>七，其他的入侵<BR>1，针对数据库MSSQL，MYSQL，ORACLE等数据库的入侵；<BR>2，针对路由，防火墙，IDS等网络设备的渗透<BR>3，无线入侵渗透<BR>八，入侵渗透以后<BR><A href="http://bbs.51cto.com/thread-108414-1-16.html" target=_self><FONT color=#606060>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></A>1，在成功得到系统级别的权限以后，就要在目标留下后门方便以后进入，当然清楚日志是最为重要的收尾工作，这些方面也有很多的技术可以讨论，例如：后门的隐藏（WIN下的ADS是一个不错的隐藏程序的东东，日志的有选择删除及其伪造等等，这里就不详谈了。。]]></description>
<author>fuhj02</author>
<pubDate>2008-8-31 16:37:00</pubDate>
</item>
<item>
<title><![CDATA[Server2003 防木马权限配置IIS服务器安全配置]]></title>
<link>http://blog.edu.cn/user2/35840/archives/2008/2165076.shtml</link>
<description><![CDATA[<P>参考了网络上很多关于WIN2003的安全配置连同自己动手做了一些实践，综合了这些安全配置文章整理而成，希望对大家有所帮助，另外里面有不足之处还请大家多多指点，然后给补上，谢谢！ <BR></P>
<P align=left><B>一、系统的安装</B></P>
<P align=left>１、按照Windows2003安装光盘的提示安装，默认情况下2003没有把IIS6.0安装在系统里面。 </P>
<P align=left>２、IIS6.0的安装 </P>
<P align=left>　　开始菜单—&gt;控制面板—&gt;添加或删除程序—&gt;添加/删除Windows组件 </P>
<P align=left>　　应用程序 ———ASP.NET（可选） </P>
<P align=left>　　　　　　　|——启用网络 COM+ 访问（必选） </P>
<P align=left>　　　　　　　|——Internet 信息服务(IIS)———Internet 信息服务管理器（必选）　　　　　　　　　　　　　　　　 |——公用文档（必选） </P>
<P align=left>　　　　　　　　　　　　　　　 |——万维网服务———Active Server pages（必选）　　　　　　　　　　　　　　　 　 　　　　　|——Internet 数据连接器（可选） </P>
<P align=left>　　　　　　　　　　　　　　　　　　　　　　 |——WebDAV 发布（可选） </P>
<P align=left>　　　　　　　　　　　　　　　　　　　　　　 |——万维网服务（必选） </P>
<P align=left>　　　　　　　　　　　　 　　　　　　　　　 |——在服务器端的包含文档（可选） </P>
<P align=left>　　然后点击确定—&gt;下一步安装。（具体见本文附件1） </P>
<P align=left>３、系统补丁的更新 </P>
<P align=left>　　点击开始菜单—&gt;任何程序—&gt;Windows Update </P>
<P align=left>　　按照提示进行补丁的安装。 </P>
<P align=left>４、备份系统 </P>
<P align=left>　　用GHOST备份系统。 </P>
<P align=left>５、安装常用的软件 </P>
<P align=left>　　例如：杀毒软件、解压缩软件等；安装完毕后,配置杀毒软件,扫描系统漏洞,安装之后用GHOST再次备份系统。 </P>
<P align=left>6、先关闭无需的端口 开启防火墙 导入IPSEC策略 </P>
<P align=left>在”网络连接”里，把无需的协议和服务都删掉，这里只安装了基本的Internet协议（TCP/IP），由于要控制带宽流量服务，额外安装了Qos数据包计划程序。在高级tcp/ip配置里--"NetBIOS"配置"禁用tcp/IP上的NetBIOS（S）"。在高级选项里，使用"Internet连接防火墙"，这是windows 2003 自带的防火墙，在2000系统里没有的功能，虽然没什么功能，但能够屏蔽端口，这样已基本达到了一个IPSec的功能。 </P>
<P align=left>修改3389远程连接端口 </P>
<P align=left>修改注册表. </P>
<P align=left>开始--运行--regedit </P>
<P align=left>依次展开 HKEY_LOCAL_MACHINE/SYSTEM/CURRENTCONTROLSET/CONTROL/ </P>
<P align=left>TERMINAL SERVER/WDS/RDPWD/TDS/TCP </P>
<P align=left>右边键值中 PortNumber 改为您想用的端口号.注意使用十进制(例 10000 ) </P>
<P align=left>HKEY_LOCAL_MACHINE/SYSTEM/CURRENTCONTROLSET/CONTROL/TERMINAL SERVER/ </P>
<P align=left>WINSTATIONS/RDP-TCP/ </P>
<P align=left>右边键值中 PortNumber 改为您想用的端口号.注意使用十进制(例 10000 ) </P>
<P align=left>注意：别忘了在WINDOWS2003自带的防火墙给+上10000端口 </P>
<P align=left>修改完毕.重新启动服务器.配置生效. </P>
<P align=left><B>二、用户安全配置</B></P>
<P align=left>1、禁用Guest账号 </P>
<P align=left>在电脑管理的用户里面把Guest账号禁用。为了保险起见，最好给Guest加一个复杂的密码。您能够打开记事本，在里面输入一串包含特别字符、数字、字母的长字符串，然后把他作为Guest用户的密码拷进去。 </P>
<P align=left>2、限制不必要的用户 </P>
<P align=left>去掉任何的Duplicate User用户、测试用户、共享用户等等。用户组策略配置相应权限，并且经常检查系统的用户，删除已不再使用的用户。这些用户很多时候都是黑客们入侵系统的突破口。 </P>
<P align=left>3、把系统Administrator账号改名 </P>
<P align=left>大家都知道，Windows 2003 的Administrator用户是不能被停用的，这意味着别人能够一遍又一遍地尝试这个用户的密码。尽量把他伪装成普通用户，比如改成Guesycludx。 </P>
<P align=left>4、创建一个陷阱用户 www_bitscn_com </P>
<P align=left>什么是陷阱用户?即创建一个名为“Administrator”的本地用户，把他的权限配置成最低，什么事也干不了的那种，并且加上一个超过10位的终极复杂密码。这样能够让那些 Hacker们忙上一段时间，借此发现他们的入侵企图。 </P>
<P align=left>5、把共享文档的权限从Everyone组改成授权用户 </P>
<P align=left>任何时候都不要把共享文档的用户配置成“Everyone”组，包括打印共享，默认的属性就是“Everyone”组的，一定不要忘了改。 </P>
<P align=left>6、开启用户策略 </P>
<P align=left>使用用户策略，分别配置复位用户锁定计数器时间为20分钟，用户锁定时间为20分钟，用户锁定阈值为3次。 （该项为可选） </P>
<P align=left>7、不让系统显示上次登录的用户名 </P>
<P align=left>默认情况下，登录对话框中会显示上次登录的用户名。这使得别人能够很容易地得到系统的一些用户名，进而做密码猜测。修改注册表能够不让对话框里显示上次登录的用户名。方法为：打开注册表编辑器并找到注册表“HKLM\Software\Microsoft\Windows T\CurrentVersion\Winlogon\Dont-DisplayLastUserName”，把REG_SZ的键值改成1。 </P>
<P align=left>密码安全配置 </P>
<P align=left>1、使用安全密码 </P>
<P align=left>一些公司的管理员创建账号的时候往往用公司名、电脑名做用户名，然后又把这些用户的密码配置得太简单，比如“welcome”等等。因此，要注意密码的复杂性，还要记住经常改密码。 </P>
<P align=left>2、配置屏幕保护密码 </P>
<P align=left>这是个很简单也很有必要的操作。配置屏幕保护密码也是防止内部人员破坏服务器的一个屏障。 </P>
<P align=left>3、开启密码策略 </P>
<P align=left>注意应用密码策略，如启用密码复杂性需要，配置密码长度最小值为6位 ，配置强制密码历史为5次，时间为42天。 </P>
<P align=left>4、考虑使用智能卡来代替密码 </P>
<P align=left>对于密码，总是使安全管理员进退两难，密码配置简单容易受到黑客的攻击，密码配置复杂又容易忘记。假如条件允许，用智能卡来代替复杂的密码是个很好的解决方法。 </P>
<P align=left><B>三、系统权限的配置</B></P>
<P align=left><B>１、磁盘权限 </B></P>
<P align=left>　　系统盘及任何磁盘只给 Administrators 组和 SYSTEM 的完全控制权限 </P>
<P align=left>　　系统盘\Documents and Settings 目录只给 Administrators 组和 SYSTEM 的完全控制权限 </P>
<P align=left>　　系统盘\Documents and Settings\All Users 目录只给 Administrators 组和 SYSTEM 的完全控制权限 </P>
<P align=left>　　系统盘\Windows\System32\cacls.exe、cmd.exe、net.exe、net1.exe、ftp.exe、tftp.exe、telnet.exe 、 netstat.exe、regedit.exe、at.exe、attrib.exe、format.com、del文档只给 Administrators 组和SYSTEM 的完全 控制权限 </P>
<P align=left>另将&lt;systemroot&gt;\System32\cmd.exe、format.com、ftp.exe转移到其他目录或更名 BBS.biDocuments and Settings下任何些目录都配置只给adinistrators权限。并且要一个一个目录查看，包括下面的任何子目录。 </P>
<P align=left>删除c:\inetpub目录 </P>
<P align=left><B>２、本地安全策略配置 </B></P>
<P align=left>　　开始菜单—&gt;管理工具—&gt;本地安全策略 </P>
<P align=left>　　A、本地策略——&gt;审核策略 </P>
<P align=left>　　审核策略更改　　　成功　失败　　 </P>
<P align=left>　　审核登录事件　　　成功　失败 </P>
<P align=left>　　审核对象访问　　　　　　失败 </P>
<P align=left>　　审核过程跟踪　　　无审核 </P>
<P align=left>　　审核目录服务访问　　　　失败 </P>
<P align=left>　　审核特权使用　　　　　　失败 </P>
<P align=left>　　审核系统事件　　　成功　失败 </P>
<P align=left>　　审核账户登录事件　成功　失败 </P>
<P align=left>　　审核账户管理　　　成功　失败 </P>
<P align=left>　　B、本地策略——&gt;用户权限分配 </P>
<P align=left>　　关闭系统：只有Administrators组、其他全部删除。 </P>
<P align=left>　　通过终端服务允许登陆：只加入Administrators,Remote Desktop Users组，其他全部删除 </P>
<P align=left>　　C、本地策略——&gt;安全选项 </P>
<P align=left>　　交互式登陆：不显示上次的用户名　　　　　　　启用 </P>
<P align=left>　　网络访问：不允许SAM帐户和共享的匿名枚举　 启用 </P>
<P align=left>　　网络访问：不允许为网络身份验证储存凭证　　　启用 </P>
<P align=left>　　网络访问：可匿名访问的共享　　　　　　　　　全部删除 </P>
<P align=left>　　网络访问：可匿名访问的命　　　　　　　　　　全部删除 </P>
<P align=left>　　网络访问：可远程访问的注册表路径　　　　　　全部删除 </P>
<P align=left>　　网络访问：可远程访问的注册表路径和子路径　　全部删除 </P>
<P align=left>　　帐户：重命名来宾帐户　　　　　　　　　　　　重命名一个帐户 </P>
<P align=left>　　帐户：重命名系统管理员帐户　　　　　　　　　重命名一个帐户 </P>
<P align=left><B>３、禁用不必要的服务</B> </P>
<P align=left>开始-运行-services.msc </P>
<P align=left>TCP/IPNetBIOS Helper提供 TCP/IP 服务上的 NetBIOS 和网络上客户端的 NetBIOS 名称解析的支持而使用户能够共享 </P>
<P align=left>文档、打印和登录到网络 </P>
<P align=left>Server支持此电脑通过网络的文档、打印、和命名管道共享 </P>
<P align=left>　　Computer Browser 维护网络上电脑的最新列表连同提供这个列表 </P>
<P align=left>Task scheduler 允许程序在指定时间运行 </P>
<P align=left>Messenger 传输客户端和服务器之间的 NET SEND 和 警报器服务消息 </P>
<P align=left>　　Distributed File System: 局域网管理共享文档，无需可禁用 </P>
<P align=left>　　Distributed linktracking client：用于局域网更新连接信息，无需可禁用 </P>
<P align=left>　　Error reporting service：禁止发送错误报告 </P>
<P align=left>　　Microsoft Serch：提供快速的单词搜索，无需可禁用 </P>
<P align=left>　　NTLMSecuritysupportprovide：telnet服务和Microsoft Serch用的，无需可禁用 </P>
<P align=left>　　PrintSpooler：假如没有打印机可禁用 </P>
<P align=left>　　Remote Registry：禁止远程修改注册表 </P>
<P align=left>　　Remote Desktop Help Session Manager：禁止远程协助 </P>
<P align=left>Workstation 关闭的话远程NET命令列不出用户组 </P>
<P align=left>　　以上是在Windows Server 2003 系统上面默认启动的服务中禁用的，默认禁用的服务如没特别需要的话不要启动。 </P>
<P align=left><B>４、修改注册表 </B></P>
<P align=left>修改注册表，让系统更强壮 </P>
<P align=left>（1）、隐藏重要文档/目录能够修改注册表实现完全隐藏 </P>
<P align=left>HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\ Current-Version\Explorer\Advanced\Folder\Hi-dden\SHOWALL”，鼠标右击 “CheckedValue”，选择修改，把数值由1改为0 </P>
<P align=left>（2）、防止SYN洪水攻击 </P>
<P align=left>HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters </P>
<P align=left>新建DWORD值，名为SynAttackProtect，值为2 </P>
<P align=left>新建EnablePMTUDiscovery REG_DWORD 0 </P>
<P align=left>新建NoNameReleaseOnDemand REG_DWORD 1 </P>
<P align=left>新建EnableDeadGWDetect REG_DWORD 0 中国网管论坛 </P>
<P align=left>新建KeepAliveTime REG_DWORD 300,000 </P>
<P align=left>新建PerformRouterDiscovery REG_DWORD 0 </P>
<P align=left>新建EnableICMPRedirects REG_DWORD 0 </P>
<P align=left>（3）、 禁止响应ICMP路由通告报文 </P>
<P align=left>HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\interface </P>
<P align=left>新建DWORD值，名为PerformRouterDiscovery 值为0 </P>
<P align=left>（4） 、防止ICMP重定向报文的攻击 </P>
<P align=left>HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters </P>
<P align=left>将EnableICMPRedirects 值设为0 </P>
<P align=left>（5）、不支持IGMP协议 </P>
<P align=left>HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters </P>
<P align=left>新建DWORD值，名为IGMPLevel 值为0 </P>
<P align=left>（6）、禁止IPC空连接： </P>
<P align=left>cracker能够利用net use命令建立空连接，进而入侵，更有net view，nbtstat这些都是基于空连接的，禁止空连接就好了。 </P>
<P align=left>Local_Machine\System\CurrentControlSet\Control\LSA-RestrictAnonymous 把这个值改成”1”即可。 </P>
<P align=left>（7）、更改TTL值 </P>
<P align=left>cracker能够根据ping回的TTL值来大致判断您的操作系统，如： </P>
<P align=left>TTL=107(WINNT); </P>
<P align=left>TTL=108(win2000); </P>
<P align=left>TTL=127或128(win9x); 中国.网管联盟 </P>
<P align=left>TTL=240或241(linux); </P>
<P align=left>TTL=252(solaris); </P>
<P align=left>TTL=240(Irix); </P>
<P align=left>实际上您能够自己改的：HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters：DefaultTTL REG_DWORD 0-0xff(0-255 十进制,默认值128)改成一个莫名其妙的数字如258，起码让那些小菜鸟晕上半天，就此放弃入侵您也不一定哦 </P>
<P align=left>（8）、 删除默认共享 </P>
<P align=left>有人问过我一开机就共享任何盘，改回来以后，重启又变成了共享是怎么回事，这是2K为管理而配置的默认共享，HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters：AutoShareServer类型是REG_DWORD把值改为0即可 </P>
<P align=left>（9）、 禁止建立空连接 </P>
<P align=left>默认情况下，任何用户通过通过空连接连上服务器，进而枚举出帐号，猜测密码。我们能够通过修改注册表来禁止建立空连接： </P>
<P align=left>Local_Machine\System\CurrentControlSet\Control\LSA-RestrictAnonymous 的值改成”1”即可。 </P>
<P align=left>（10）、建立一个记事本，填上以下代码。保存为*.bat并加到启动项目中 </P>
<P align=left>net share c$ /del </P>
<P align=left>net share d$ /del </P>
<P align=left>net share e$ /del </P>
<P align=left>net share f$ /del </P>
<P align=left>net share ipc$ /del </P>
<P align=left>net share admin$ /del </P>
<P align=left><B>5</B><B>、IIS站点配置： </B></P>
<P align=left>（1）、将IIS目录＆数据和系统磁盘分开，保存在专用磁盘空间内。 </P>
<P align=left>（2）、启用父级路径 </P>
<P align=left>（3）、在IIS管理器中删除必须之外的任何没有用到的映射（保留asp等必要映射即可） </P>
<P align=left>（4）、在IIS中将HTTP404 Object Not Found出错页面通过URL重定向到一个定制HTM文档</P>
<P align=left>（5）、Web站点权限设定（建议） </P>
<P align=left>读 允许 </P>
<P align=left>写 不允许 </P>
<P align=left>脚本源访问 不允许 </P>
<P align=left>目录浏览 建议关闭 </P>
<P align=left>日志访问 建议关闭 </P>
<P align=left>索引资源 建议关闭 </P>
<P align=left>执行 推荐选择 “仅限于脚本” </P>
<P align=left>（6）、建议使用W3C扩充日志文档格式，每天记录客户IP地址，用户名，服务器端口，方法，URI字根，HTTP状态，用户代理，而且每天均要审查日志。（最好不要使用缺省的目录，建议更换一个记日志的路径，同时配置日志的访问权限，只允许管理员和system为Full Control）。 </P>
<P align=left>（7）、程序安全: </P>
<P align=left>1) 涉及用户名和口令的程序最好封装在服务器端，尽量少的在ASP文档里出现，涉及到和数据库连接地用户名和口令应给予最小的权限; </P>
<P align=left>2) 需要经过验证的ASP页面，可跟踪上一个页面的文档名，只有从上一页面转进来的会话才能读取这个页面。 </P>
<P align=left>3) 防止ASP主页.inc文档泄露问题; </P>
<P align=left>4) 防止UE等编辑器生成some.asp.bak文档泄露问题。 </P>
<P align=left><B>6</B><B>、IIS权限配置的思路 </B></P>
<P align=left>要为每个单独的要保护的个体（比如一个网站或一个虚拟目录）创建一个系统用户，让这个站点在系统中具备惟一的能够配置权限的身份。 </P>
<P align=left>在IIS的【站点属性或虚拟目录属性→目录安全性→匿名访问和验证控制→编辑→匿名访问→编辑】填写刚刚创建的那个用户名。 </P>
<P align=left>配置任何的分区禁止这个用户访问，而刚才这个站点的主目录对应的那个文档夹配置允许这个用户访问（要去掉继承父权限，并且要加上超管组和SYSTEM组）。 </P>
<P align=left><B>7</B><B>、卸载最不安全的组件 </B></P>
<P align=left>最简单的办法是直接卸载后删除相应的程序文档。将下面的代码保存为一个.BAT文档，( 以下均以 WIN2000 为例，假如使用2003，则系统文档夹应该是 C:\WINDOWS\ ) </P>
<P align=left>regsvr32/u C:\WINDOWS\System32\wshom.ocx </P>
<P align=left>del C:\WINDOWS\System32\wshom.ocx </P>
<P align=left>regsvr32/u C:\WINDOWS\system32\shell32.dll </P>
<P align=left>del C:\WINNT\WINDOWS\shell32.dll </P>
<P align=left>然后运行一下，WScript.Shell, Shell.application, WScript.Network就会被卸载了。可能会提示无法删除文档，不用管他，重启一下服务器，您会发现这三个都提示“×安全”了。</P>]]></description>
<author>fuhj02</author>
<pubDate>2008-8-30 11:22:00</pubDate>
</item>
<item>
<title><![CDATA[软件项目版本号的命名规则及格式]]></title>
<link>http://blog.edu.cn/user2/35840/archives/2008/2164973.shtml</link>
<description><![CDATA[<P>版本控制比较普遍的 3 种命名格式 :<BR><BR><STRONG>一、GNU 风格的版本号命名格式 :</STRONG><BR>主版本号 . 子版本号 [. 修正版本号 [. 编译版本号 ]]<BR>Major_Version_Number.Minor_Version_Number[.Revision_Number[.Build_Number]]<BR>示例 : 1.2.1, 2.0, 5.0.0 build-13124<BR><BR><STRONG>二、Windows 风格的版本号命名格式 :</STRONG><BR>主版本号 . 子版本号 [ 修正版本号 [. 编译版本号 ]]<BR>Major_Version_Number.Minor_Version_Number[Revision_Number[.Build_Number]]<BR>示例: 1.21, 2.0<BR><BR><STRONG>三、.Net Framework 风格的版本号命名格式:</STRONG><BR>主版本号.子版本号[.编译版本号[.修正版本号]]<BR>Major_Version_Number.Minor_Version_Number[.Build_Number[.Revision_Number]]<BR>版本号由二至四个部分组成：主版本号、次版本号、内部版本号和修订号。主版本号和次版本号是必选的；内部版本号和修订号是可选的，但是如果定义了修订号部分，则内部版本号就是必选的。所有定义的部分都必须是大于或等于 0 的整数。<BR><BR><STRONG>应根据下面的约定使用这些部分：</STRONG><BR><BR>Major ：具有相同名称但不同主版本号的程序集不可互换。例如，这适用于对产品的大量重写，这些重写使得无法实现向后兼容性。<BR><BR>Minor ：如果两个程序集的名称和主版本号相同，而次版本号不同，这指示显著增强，但照顾到了向后兼容性。例如，这适用于产品的修正版或完全向后兼容的新版本。<BR><BR>Build ：内部版本号的不同表示对相同源所作的重新编译。这适合于更改处理器、平台或编译器的情况。<BR><BR>Revision ：名称、主版本号和次版本号都相同但修订号不同的程序集应是完全可互换的。这适用于修复以前发布的程序集中的安全漏洞。<BR><BR>程序集的只有内部版本号或修订号不同的后续版本被认为是先前版本的修补程序 (Hotfix) 更新。<BR><BR><STRONG>版本号管理策略</STRONG><BR><BR><STRONG>一、GNU 风格的版本号管理策略：</STRONG><BR><BR>1．项目初版本时，版本号可以为 0.1 或 0.1.0, 也可以为 1.0 或 1.0.0，如果你为人很低调，我想你会选择那个主版本号为 0 的方式；<BR>2．当项目在进行了局部修改或 bug 修正时，主版本号和子版本号都不变，修正版本号加 1；<BR>3. 当项目在原有的基础上增加了部分功能时，主版本号不变，子版本号加 1，修正版本号复位为 0，因而可以被忽略掉；<BR>4．当项目在进行了重大修改或局部修正累积较多，而导致项目整体发生全局变化时，主版本号加 1；<BR>5．另外，编译版本号一般是编译器在编译过程中自动生成的，我们只定义其格式，并不进行人为控制。<BR><BR><STRONG>二、Window 下的版本号管理策略：</STRONG><BR>1．项目初版时，版本号为 1.0 或 1.00；<BR>2. 当项目在进行了局部修改或 bug 修正时，主版本号和子版本号都不变，修正版本号加 1；<BR>3. 当项目在原有的基础上增加了部分功能时，主版本号不变，子版本号加 1，修正版本号复位为 0，因而可以被忽略掉；<BR>4. 当项目在进行了重大修改或局部修正累积较多，而导致项目整体发生全局变化时，主版本号加 1；<BR>5. 另外 , 编译版本号一般是编译器在编译过程中自动生成的，我们只定义其格式，并不进行人为控制。<BR><BR>另外，还可以在版本号后面加入 Alpha、Beta、Gamma、Current、RC (Release Candidate)、Release、Stable 等后缀，在这些后缀后面还可以加入 1 位数字的版本号。<BR><BR>对于用户来说，如果某个软件的主版本号进行了升级，用户还想继续那个软件，则发行软件的公司一般要对用户收取升级费用；而如果子版本号或修正版本号发生了升级，一般来说是免费的。<BR><BR>=====附录软件版本名称=====<BR><BR><STRONG>α（alphal） 内部测试版</STRONG><BR>α版，此版本表示该软件仅仅是一个初步完成品，通常只在软件开发者内部交流，也有很少一部分发布给专业测试人员。一般而言，该版本软件的 bug 较多，普通用户最好不要安装。<BR><BR><STRONG>β（beta）外部测试版</STRONG><BR>该版本相对于α版已有了很大的改进，消除了严重的错误，但还是存在着一些缺陷，需要经过大规模的发布测试来进一步消除。这一版本通常由软件公司免费发布，用户可从相关的站点下载。通过一些专业爱好者的测试，将结果反馈给开发者，开发者们再进行有针对性的修改。该版本也不适合一般用户安装。<BR><BR><STRONG>γ（gamma）版</STRONG><BR>该版本已经相当成熟了，与即将发行的正式版相差无几，如果用户实在等不及了，尽可以装上一试。<BR><BR><STRONG>trial（试用版）</STRONG><BR>试用版软件在最近的几年里颇为流行，主要是得益于互联网的迅速发展。该版本软件通常都有时间限制，过期之后用户如果希望继续使用，一般得交纳一定的费用进行注册或购买。有些试用版软件还在功能上做了一定的限制。<BR><BR><STRONG>unregistered（未注册版）</STRONG><BR>未注册版与试用版极其类似，只是未注册版通常没有时间限制，在功能上相对于正式版做了一定的限制，例如绝大多数网络电话软件的注册版和未注册版，两者之间在通话质量上有很大差距。还有些虽然在使用上与正式版毫无二致，但是动不动就会弹出一个恼人的消息框来提醒你注册，如看图软件acdsee、智能陈桥汉字输入软件等。<BR><BR><STRONG>demo 演示版</STRONG><BR>在非正式版软件中，该版本的知名度最大。demo版仅仅集成了正式版中的几个功能，颇有点像 unregistered。不同的是，demo版一般不能通过升级或注册的方法变为正式版。<BR><BR>以上是软件正式版本推出之前的几个版本，α、β、γ可以称为测试版，大凡成熟软件总会有多个测试版，如 windows 98 的β版，前前后后将近有10个。这么多的测试版一方面为了最终产品尽可能地满足用户的需要，另一方面也尽量减少了软件中的bug 。而 trial 、unregistered 、demo有时统称为演示版，这一类版本的广告色彩较浓，颇有点先尝后买的味道，对于普通用户而言自然是可以免费尝鲜了。<BR><BR><STRONG>正式版，不同类型的软件的正式版本通常也有区别。</STRONG><BR><BR><STRONG>release 最终释放版</STRONG><BR>该版本意味“最终释放版”，在出了一系列的测试版之后，终归会有一个正式版本，对于用户而言，购买该版本的软件绝对不会错。该版本有时也称为标准版。一般情况下，release不会以单词形式出现在软件封面上，取而代之的是符号 (r) ，如 windows nt(r) 4.0、ms-dos(r) 6.22 等。<BR><BR><STRONG>registered 注册版</STRONG><BR>很显然，该版本是与 unregistered 相对的注册版。注册版、release和下面所讲的standard版一样，都是软件的正式版本，只是注册版软件的前身有很大一部分是从网上下载的。<BR><BR><STRONG>standard 标准版</STRONG><BR>这是最常见的标准版，不论是什么软件，标准版一定存在。标准版中包含了该软件的基本组件及一些常用功能，可以满足一般用户的需求。其价格相对高一级版本而言还是“平易近人”的。<BR><BR><STRONG>deluxe 豪华版</STRONG><BR>顾名思义即为“豪华版”。豪华版通常是相对于标准版而言的，主要区别是多了几项功能，价格当然会高出一大块，不推荐一般用户购买。此版本通常是为那些追求“完美”的专业用户所准备的。<BR><BR><STRONG>reference</STRONG><BR>该版本型号常见于百科全书中，比较有名的是微软的encarta系列。 reference是最高级别，其包含的主题、图像、影片剪辑等相对于standard和deluxe版均有大幅增加，容量由一张光盘猛增至三张光盘，并且加入了很强的交互功能，当然价格也不菲。可以这么说，这一版本的百科全书才能算是真正的百科全书，也是发烧友们收藏的首选。<BR><BR><STRONG>professional（专业版）</STRONG><BR>专业版是针对某些特定的开发工具软件而言的。专业版中有许多内容是标准版中所没有的，这些内容对于一个专业的软件开发人员来说是极为重要的。如微软的visual foxpro标准版并不具备编译成可执行文件的功能，这对于一个完整的开发项目而言显然是无法忍受的，若客户机上没有foxpro将不能使用。如果用专业版就没有这个问题了。<BR><BR><STRONG>enterprise（企业版）</STRONG><BR>企业版是开发类软件中的极品（相当于百科全书中的reference版）。拥有一套这种版本的软件可以毫无障碍地开发任何级别的应用软件。如著名的visual c++的企业版相对于专业版来说增加了几个附加的特性，如sql调试、扩展的存储过程向导、支持as/400对ole db的访问等。而这一版本的价格也是普通用户无法接受的。如微软的visual studios 6.0 enterprise 中文版的价格为 23000 元。<BR><BR><STRONG>其他版本，除了以上介绍的一些版本外，还有一些专有版本名称。</STRONG><BR><BR><STRONG>update（升级版）</STRONG><BR>升级版的软件是不能独立使用的，该版本的软件在安装过程中会搜索原有的正式版，如果不存在，则拒绝执行下一步。如microsoft office 2000升级版、windows 9x升级版等等。<BR><BR><STRONG>oem版</STRONG><BR>oem 版通常是捆绑在硬件中而不单独销售的版本。将自己的产品交给别的公司去卖，保留自己的著作权，双方互惠互利，一举两得。<BR><BR><STRONG>单机（网络）版</STRONG><BR>网络版在功能、结构上远比单机版复杂，如果留心一下软件的报价，你就会发现某些软件单机版和网络版的价格相差非常大，有些网络版甚至多一个客户端口就要加不少钱。<BR><BR><STRONG>普及版</STRONG><BR>该版本有时也会被称为共享版，其特点是价格便宜（有些甚至完全免费）、功能单一、针对性强（当然也有占领市场、打击盗版等因素）。与试用版不同的是，该版本的软件一般不会有时间上的限制。当然，如果用户想升级，最好还是去购买正式版。<BR><BR>Enhance 增强版或者加强版 属于正式版<BR>Free 自由版<BR>Full version 完全版 属于正式版<BR>shareware 共享版<BR>Release 发行版 有时间限制<BR>Upgrade 升级版<BR>Retail 零售版<BR>Cardware 属共享软件的一种，只要给作者回复一封电邮或明信片即可。（有的作者并由此提供注册码等），目前这种形式已不多见。<BR>Plus 属增强版，不过这种大部分是在程序界面及多媒体功能上增强。<BR>Preview 预览版<BR>Corporation &amp; Enterprise 企业版<BR>Standard 标准版<BR>Mini 迷你版也叫精简版只有最基本的功能<BR>Premium -- 贵价版<BR>Professional -- 专业版<BR>Express -- 特别版<BR>Deluxe -- 豪华版<BR>Regged -- 已注册版<BR>CN -- 简体中文版<BR>CHT -- 繁体中文版<BR>EN -- 英文版<BR>Multilanguage -- 多语言版</P>]]></description>
<author>fuhj02</author>
<pubDate>2008-8-29 19:23:00</pubDate>
</item>
<item>
<title><![CDATA[Linux下C开发工具介绍]]></title>
<link>http://blog.edu.cn/user2/35840/archives/2008/2164971.shtml</link>
<description><![CDATA[Linux的发行版中包含了很多软件开发工具. 它们中的很多是用于 C 和 C++应用程序开发的. 本文介绍了在 Linux 下能用于 C 应用程序开发和调试的工具. 本文的主旨是介绍如何在 Linux 下使用 C 编译器和其他 C 编程工具, 而非 C 语言编程的教程. <BR><BR><BR>GNU C 编译器 <BR>GNU C 编译器(GCC)是一个全功能的 ANSI C 兼容编译器. 如果你熟悉其他操作系统或硬件平台上的一种 C 编译器, 你将能很快地掌握 GCC. 本节将介绍如何使用 GCC 和一些 GCC 编译器最常用的选项. <BR><BR>使用 GCC <BR>通常后跟一些选项和文件名来使用 GCC 编译器. gcc 命令的基本用法如下: <BR><BR>gcc [options] [filenames] <BR>命令行选项指定的操作将在命令行上每个给出的文件上执行. 下一小节将叙述一些你会最常用到的选项. <BR><BR><BR>GCC 选项 <BR>GCC 有超过100个的编译选项可用. 这些选项中的许多你可能永远都不会用到, 但一些主要的选项将会频繁用到. 很多的 GCC 选项包括一个以上的字符. 因此你必须为每个选项指定各自的连字符, 并且就象大多数 Linux 命令一样你不能在一个单独的连字符后跟一组选项. 例如, 下面的两个命令是不同的: <BR><BR>gcc -p -g test.c <BR><BR>gcc -pg test.c <BR>第一条命令告诉 GCC 编译 test.c 时为 prof 命令建立剖析(profile)信息并且把调试信息加入到可执行的文件里. 第二条命令只告诉 GCC 为 gprof 命令建立剖析信息. <BR><BR>当你不用任何选项编译一个程序时, GCC 将会建立(假定编译成功)一个名为 a.out 的可执行文件. 例如, 下面的命令将在当前目录下产生一个叫 a.out 的文件: <BR><BR>gcc test.c <BR>你能用 -o 编译选项来为将产生的可执行文件指定一个文件名来代替 a.out. 例如, 将一个叫 count.c 的 C 程序编译为名叫 count 的可执行文件, 你将输入下面的命令: <BR><BR>gcc -o count count.c <BR><BR>-------------------------------------------------------------------------------- <BR><BR>注意: 当你使用 -o 选项时, -o 后面必须跟一个文件名. <BR><BR><BR>-------------------------------------------------------------------------------- <BR><BR>GCC 同样有指定编译器处理多少的编译选项. -c 选项告诉 GCC 仅把源代码编译为目标代码而跳过汇编和连接的步骤. 这个选项使用的非常频繁因为它使得编译多个 C 程序时速度更快并且更易于管理. 缺省时 GCC 建立的目标代码文件有一个 .o 的扩展名. <BR><BR>-S 编译选项告诉 GCC 在为 C 代码产生了汇编语言文件后停止编译. GCC 产生的汇编语言文件的缺省扩展名是 .s . -E 选项指示编译器仅对输入文件进行预处理. 当这个选项被使用时, 预处理器的输出被送到标准输出而不是储存在文件里. <BR><BR>优 化 选 项 <BR>当 你用 GCC 编译 C 代码时, 它会试着用最少的时间完成编译并且使编译后的代码易于调试. 易于调试意味着编译后的代码与源代码有同样的执行次序, 编译后的代码没有经过优化. 有很多选项可用于告诉 GCC 在耗费更多编译时间和牺牲易调试性的基础上产生更小更快的可执行文件. 这些选项中最典型的是-O 和 -O2 选项. <BR><BR>-O 选项告诉 GCC 对源代码进行基本优化. 这些优化在大多数情况下都会使程序执行的更快. -O2 选项告诉 GCC 产生尽可能小和尽可能快的代码. -O2 选项将使编译的速度比使用 -O 时慢. 但通常产生的代码执行速度会更快. <BR><BR>除 了 -O 和 -O2 优化选项外, 还有一些低级选项用于产生更快的代码. 这些选项非常的特殊, 而且最好只有当你完全理解这些选项将会对编译后的代码产生什么样的效果时再去使用. 这些选项的详细描述, 请参考 GCC 的指南页, 在命令行上键入 man gcc . <BR><BR>调试和剖析选项 <BR>GCC 支持数种调试和剖析选项. 在这些选项里你会最常用到的是 -g 和 -pg 选项. <BR>-g 选项告诉 GCC 产生能被 GNU 调试器使用的调试信息以便调试你的程序. GCC 提供了一个很多其他 C 编译器里没有的特性, 在 GCC 里你能使 -g 和 -O (产生优化代码)联用. 这一点非常有用因为你能在与最终产品尽可能相近的情况下调试你的代码. 在你同时使用这两个选项时你必须清楚你所写的某些代码已经在优化时被 GCC 作了改动. 关于调试 C 程序的更多信息请看下一节"用 gdb 调试 C 程序" . <BR>-pg 选项告诉 GCC 在你的程序里加入额外的代码, 执行时, 产生 gprof 用的剖析信息以显示你的程序的耗时情况. 关于 gprof 的更多信息请参考 "gprof" 一节. <BR><BR><BR>用 gdb 调试 GCC 程序 <BR>Linux 包含了一个叫 gdb 的 GNU 调试程序. gdb 是一个用来调试 C 和 C++ 程序的强力调试器. 它使你能在程序运行时观察程序的内部结构和内存的使用情况. 以下是 gdb 所提供的一些功能: <BR><BR>它使你能监视你程序中变量的值. <BR>它使你能设置断点以使程序在指定的代码行上停止执行. <BR>它使你能一行行的执行你的代码. <BR><BR><BR>在命令行上键入 gdb 并按回车键就可以运行 gdb 了, 如果一切正常的话, gdb 将被启动并且你将在屏幕上看到类似的内容: <BR><BR>GNU gdb 5.0 <BR>Copyright 2000 Free Software Foundation, Inc. <BR>GDB is free software, covered by the GNU General Public License, and you are <BR>welcome to change it and/or distribute copies of it under certain conditions. <BR>Type "show copying" to see the conditions. <BR>There is absolutely no warranty for GDB. Type "show warranty" for details. <BR>This GDB was configured as "i386-redhat-linux". <BR>(gdb) <BR>当你启动 gdb 后, 你能在命令行上指定很多的选项. 你也可以以下面的方式来运行 gdb : <BR><BR>gdb <BR>当 你用这种方式运行 gdb , 你能直接指定想要调试的程序. 这将告诉gdb 装入名为 fname 的可执行文件. 你也可以用 gdb 去检查一个因程序异常终止而产生的 core 文件, 或者与一个正在运行的程序相连. 你可以参考 gdb 指南页或在命令行上键入 gdb -h 得到一个有关这些选项的说明的简单列表. <BR><BR><BR>为调试编译代码(Compiling Code for Debugging) <BR>为了使 gdb 正常工作, 你必须使你的程序在编译时包含调试信息. 调试信息包含你程序里的每个变量的类型和在可执行文件里的地址映射以及源代码的行号. gdb 利用这些信息使源代码和机器码相关联. <BR><BR>在编译时用 -g 选项打开调试选项. <BR><BR><BR>gdb 基本命令 <BR>gdb 支持很多的命令使你能实现不同的功能. 这些命令从简单的文件装入到允许你检查所调用的堆栈内容的复杂命令, 表27.1列出了你在用 gdb 调试时会用到的一些命令. 想了解 gdb 的详细使用请参考 gdb 的指南页. <BR><BR>基本 gdb 命令. <BR><BR>命 令 描 述 <BR>file 装入想要调试的可执行文件. <BR>kill 终止正在调试的程序. <BR>list 列出产生执行文件的源代码的一部分. <BR>next 执行一行源代码但不进入函数内部. <BR>step 执行一行源代码而且进入函数内部. <BR>run 执行当前被调试的程序 <BR>quit 终止 gdb <BR>watch 使你能监视一个变量的值而不管它何时被改变. <BR>print 显示表达式的值 <BR>break 在代码里设置断点, 这将使程序执行到这里时被挂起. <BR>make 使你能不退出 gdb 就可以重新产生可执行文件. <BR>shell 使你能不离开 gdb 就执行 UNIX shell 命令. <BR><BR><BR><BR><BR>gdb 支持很多与 UNIX shell 程序一样的命令编辑特征. 你能象在 bash 或 tcsh里那样按 Tab 键让 gdb 帮你补齐一个唯一的命令, 如果不唯一的话 gdb 会列出所有匹配的命令. 你也能用光标键上下翻动历史命令. <BR><BR>gdb 应用举例 <BR>本节用一个实例教你一步步的用 gdb 调试程序. 被调试的程序相当的简单, 但它展示了 gdb 的典型应用. <BR><BR>下面列出了将被调试的程序. 这个程序被称为 hello , 它显示一个简单的问候, 再用反序将它列出. <BR><BR>#include <BR><BR>static void my_print (char *); <BR>static void my_print2 (char *); <BR><BR>main () <BR>{ <BR>char my_string[] = "hello world!"; <BR>my_print (my_string); <BR>my_print2 (my_string); <BR>} <BR><BR>void my_print (char *string) <BR>{ <BR>printf ("The string is %s ", string); <BR>} <BR><BR>void my_print2 (char *string) <BR>{ <BR>char *string2; <BR>int size, i; <BR><BR>size = strlen (string); <BR>string2 = (char *) malloc (size + 1); <BR>for (i = 0; i &lt; size; i++) <BR>string2[size - i] = string[i]; <BR>string2[size+1] = ; <BR><BR>printf ("The string printed backward is %s ", string2); <BR>} <BR>用下面的命令编译它: <BR><BR><BR>gcc -g -o hello hello.c <BR>这个程序执行时显示如下结果: <BR>./hello <BR>The string is hello world! <BR><BR>The string printed backward is <BR>输出的第一行是正确的, 但第二行打印出的东西并不是我们所期望的. 我们所设想的输出应该是: <BR><BR>The string printed backward is !dlrow olleh <BR>由于某些原因, my_print2 函数没有正常工作. 让我们用 gdb 看看问题究竟出在哪儿, 先键入如下命令: <BR><BR><BR>gdb hello <BR><BR>-------------------------------------------------------------------------------- <BR><BR>注意: 记得在编译 hello 程序时把调试选项打开. <BR><BR><BR>-------------------------------------------------------------------------------- <BR><BR>如果你在输入命令时忘了把要调试的程序作为参数传给 gdb , 你可以在 gdb 提示符下用 file 命令来载入它: <BR><BR><BR>(gdb) file hello <BR>这个命令将载入 hello 可执行文件就象你在 gdb 命令行里装入它一样. <BR><BR>这时你能用 gdb 的 run 命令来运行 hello 了. 当它在 gdb 里被运行后结果大约会象这样: <BR><BR>(gdb) run <BR><BR>Starting program: /root/hello <BR><BR>The string is hello world! <BR><BR>The string printed backward is <BR><BR>Program exited with code 040 <BR>这个输出和在 gdb 外面运行的结果一样. 问题是, 为什么反序打印没有工作? 为了找出症结所在, 我们可以在 my_print2 函数的 for 语句后设一个断点, 具体的做法是在 gdb 提示符下键入 list 命令三次, 列出源代码: <BR><BR>(gdb) list <BR><BR>(gdb) list <BR><BR>(gdb) list <BR><BR>-------------------------------------------------------------------------------- <BR><BR>技巧: 在 gdb 提示符下按回车健将重复上一个命令. <BR><BR><BR>-------------------------------------------------------------------------------- <BR><BR>第一次键入 list 命令的输出如下: <BR><BR><BR>1 #include <BR>2 <BR>3 static void my_print (char *); <BR>4 static void my_print2 (char *); <BR>5 <BR>6 main () <BR>7 { <BR>8 char my_string[] = "hello world!"; <BR>9 my_print (my_string); <BR>10 my_print2 (my_string); <BR><BR><BR>如果按下回车, gdb 将再执行一次 list 命令, 给出下列输出: <BR><BR><BR>11 } <BR>12 <BR>13 void my_print (char *string) <BR>14 { <BR>15 printf ("The string is %s ", string); <BR>16 } <BR>17 <BR>18 void my_print2 (char *string) <BR>19 { <BR>20 char *string2; <BR>再按一次回车将列出 hello 程序的剩余部分: <BR><BR>21 int size, i; <BR>22 <BR>23 size = strlen (string); <BR>24 string2 = (char *) malloc (size + 1); <BR>25 for (i = 0; i &lt; size; i++) <BR>26 string2[size - i] = string[i]; <BR>27 string2[size+1] = ; <BR>28 <BR>29 printf ("The string printed backward is %s ", string2); <BR>30 } <BR>根据列出的源程序, 你能看到要设断点的地方在第26行, 在 gdb 命令行提示符下键入如下命令设置断点: <BR><BR>(gdb) break 26 <BR>gdb 将作出如下的响应: <BR><BR>Breakpoint 1 at 0x804857c: file hello.c, line 26. <BR><BR>(gdb) <BR><BR>现在再键入 run 命令, 将产生如下的输出: <BR><BR><BR>Starting program: /root/hello <BR><BR>The string is hello world! <BR><BR>Breakpoint 1, my_print2 (string=0xbffffab0 "hello world!") at hello.c:26 <BR>26 string2[size - i] = string[i]; <BR>你能通过设置一个观察 string2[size - i] 变量的值的观察点来看出错误是怎样产生的, 做法是键入: <BR><BR>(gdb) watch string2[size - i] <BR>gdb 将作出如下回应: <BR><BR>Hardware watchpoint 2: string2[size - i] <BR>现在可以用 next 命令来一步步的执行 for 循环了: <BR><BR><BR>(gdb) next <BR>经过第一次循环后, gdb 告诉我们 string2[size - i] 的值是 `h`. gdb 用如下的显示来告诉你这个信息: <BR><BR><BR>Hardware watchpoint 2: string2[size - i] <BR><BR>Old value = 0 0 <BR>New value = 104 h <BR>my_print2 (string=0xbffffab0 "hello world!") at hello.c:25 <BR>25 for (i = 0; i &lt; size; i++) <BR>这个值正是期望的. 后来的数次循环的结果都是正确的. 当 i=11 时, 表达式 string2[size - i] 的值等于 `!`, size - i 的值等于 1, 最后一个字符已经拷到新串里了. <BR><BR>如 果你再把循环执行下去, 你会看到已经没有值分配给 string2[0] 了, 而它是新串的第一个字符, 因为 malloc 函数在分配内存时把它们初始化为空(null)字符. 所以 string2 的第一个字符是空字符. 这解释了为什么在打印 string2 时没有任何输出了. <BR><BR>现在找出了问题出在哪里, 修正这个错误是很容易的. 你得把代码里写入 string2 的第一个字符的的偏移量改为 size - 1 而不是 size. 这是因为 string2 的大小为 12, 但起始偏移量是 0, 串内的字符从偏移量 0 到 偏移量 10, 偏移量 11 为空字符保留. <BR><BR>改正方法非常简单. 这是这种解决办法的代码: <BR><BR>#include <BR><BR>static void my_print (char *); <BR>static void my_print2 (char *); <BR><BR>main () <BR>{ <BR>char my_string[] = "hello world!"; <BR>my_print (my_string); <BR>my_print2 (my_string); <BR>} <BR><BR>void my_print (char *string) <BR>{ <BR>printf ("The string is %s ", string); <BR>} <BR><BR>void my_print2 (char *string) <BR>{ <BR>char *string2; <BR>int size, i; <BR><BR>size = strlen (string); <BR>string2 = (char *) malloc (size + 1); <BR>for (i = 0; i &lt; size; i++) <BR>string2[size -1 - i] = string[i]; <BR>string2[size] = ; <BR><BR>printf ("The string printed backward is %s ", string2); <BR>} <BR>如 果程序产生了core文件，可以用gdb hello core命令来查看程序在何处出错。如在函数my_print2()中，如果忘记了给string2分配内存 string2 = (char *) malloc (size + 1);，很可能就会core dump. <BR><BR><BR>另外的 C 编程工具 <BR><BR>xxgdb <BR>xxgdb 是 gdb 的一个基于 X Window 系统的图形界面. xxgdb 包括了命令行版的 gdb 上的所有特性. xxgdb 使你能通过按按钮来执行常用的命令. 设置了断点的地方也用图形来显示. <BR><BR>你能在一个 Xterm 窗口里键入下面的命令来运行它: <BR><BR>xxgdb <BR>你能用 gdb 里任何有效的命令行选项来初始化 xxgdb . 此外 xxgdb 也有一些特有的命令行选项, 表 27.2 列出了这些选项. <BR><BR>表 27.2. xxgdb 命令行选项. <BR><BR>选 项 描 述 <BR>db_name 指定所用调试器的名字, 缺省是 gdb. <BR>db_prompt 指定调试器提示符, 缺省为 gdb. <BR>gdbinit 指定初始化 gdb 的命令文件的文件名, 缺省为 .gdbinit. <BR><BR>nx 告诉 xxgdb 不执行 .gdbinit 文件. <BR>bigicon 使用大图标. <BR><BR><BR>calls <BR>你可以在 sunsite.unc.edu FTP 站点用下面的路径: <BR>/pub/Linux/devel/lang/c/calls.tar.Z <BR>来 取得 calls , 一些旧版本的 Linux CD-ROM 发行版里也附带有. 因为它是一个有用的工具, 我们在这里也介绍一下. 如果你觉得有用的话, 从 BBS, FTP, 或另一张CD-ROM 上弄一个拷贝. calls 调用 GCC 的预处理器来处理给出的源程序文件, 然后输出这些文件的里的函数调用树图. <BR><BR><BR>注意: 在你的系统上安装 calls , 以超级用户身份登录后执行下面的步骤: 1. 解压和 untar 文件. 2. cd 进入 calls untar 后建立的子目录. 3. 把名叫 calls 的文件移动到 /usr/bin 目录. 4. 把名叫 calls.1 的文件移动到目录 /usr/man/man1 . 5. 删除 /tmp/calls 目录. 这些步骤将把 calls 程序和它的指南页安装载你的系统上. <BR><BR>-------------------------------------------------------------------------------- <BR><BR>当 calls 打印出调用跟踪结果时, 它在函数后面用中括号给出了函数所在文件的文件名: <BR><BR>main [hello.c] <BR>如果函数并不是向 calls 给出的文件里的, calls 不知道所调用的函数来自哪里, 则只显示函数的名字: <BR><BR>printf <BR>calls 不对递归和静态函数输出. 递归函数显示成下面的样子: <BR><BR>fact &lt;&lt;&lt; recursive in factorial.c &gt;&gt;&gt; <BR>静态函数象这样显示: <BR><BR>total [static in calculate.c] <BR>作为一个例子, 假设用 calls 处理下面的程序: <BR><BR>#include <BR><BR>static void my_print (char *); <BR>static void my_print2 (char *); <BR><BR>main () <BR>{ <BR>char my_string[] = "hello world!"; <BR>my_print (my_string); <BR>my_print2 (my_string); <BR>my_print (my_string); <BR>} <BR><BR>void count_sum() <BR>{ <BR>int i,sum=0; <BR>for(i=0; i&lt;1000000; i++) <BR>sum += i; <BR>} <BR><BR>void my_print (char *string) <BR>{ <BR>count_sum(); <BR>printf ("The string is %s ", string); <BR>} <BR><BR>void my_print2 (char *string) <BR>{ <BR>char *string2; <BR>int size, i,sum =0; <BR><BR>count_sum(); <BR>size = strlen (string); <BR>string2 = (char *) malloc (size + 1); <BR>for (i = 0; i &lt; size; i++) string2[size -1 - i] = string[i]; <BR>string2[size] = ; <BR>for(i=0; i&lt;5000000; i++) <BR>sum += i; <BR><BR>printf ("The string printed backward is %s ", string2); <BR>} <BR>将产生如下的输出: <BR><BR>1 __underflow [hello.c] <BR>2 main <BR>3 my_print [hello.c] <BR>4 count_sum [hello.c] <BR>5 printf <BR>6 my_print2 [hello.c] <BR>7 count_sum <BR>8 strlen <BR>9 malloc <BR>10 printf <BR>calls 有很多命令行选项来设置不同的输出格式, 有关这些选项的更多信息请参考 calls 的指南页. 方法是在命令行上键入 calls -h . <BR><BR><BR>calltree <BR>calltree与calls类似，初了输出函数调用树图外，还有其它详细的信息。 <BR>可以从sunsite.unc.edu FTP 站点用下面的路径:/pub/Linux/devel/lang/c/calltree.tar.gz得到calltree. <BR><BR>cproto <BR>cproto 读入 C 源程序文件并自动为每个函数产生原型申明. 用 cproto 可以在写程序时为你节省大量用来定义函数原型的时间. <BR>如果你让 cproto 处理下面的代码(cproto hello.c): <BR><BR>#include <BR><BR>static void my_print (char *); <BR>static void my_print2 (char *); <BR><BR>main () <BR>{ <BR>char my_string[] = "hello world!"; <BR>my_print (my_string); <BR>my_print2 (my_string); <BR>} <BR><BR>void my_print (char *string) <BR>{ <BR>printf ("The string is %s ", string); <BR>} <BR><BR>void my_print2 (char *string) <BR>{ <BR>char *string2; <BR>int size, i; <BR><BR>size = strlen (string); <BR>string2 = (char *) malloc (size + 1); <BR>for (i = 0; i &lt; size; i++) <BR>string2[size -1 - i] = string[i]; <BR>string2[size] = ; <BR><BR>printf ("The string printed backward is %s ", string2); <BR>} <BR>你将得到下面的输出: <BR><BR>/* hello.c */ <BR><BR>int main(void); <BR><BR>int my_print(char *string); <BR><BR>int my_print2(char *string); <BR>这个输出可以重定向到一个定义函数原型的包含文件里. <BR><BR>indent <BR>indent 实用程序是 Linux 里包含的另一个编程实用工具. 这个工具简单的说就为你的代码产生美观的缩进的格式. indent 也有很多选项来指定如何格式化你的源代码.这些选项的更多信息请看indent 的指南页, 在命令行上键入 indent -h . <BR><BR><BR>下面的例子是 indent 的缺省输出: <BR><BR>运行 indent 以前的 C 代码: <BR><BR>#include <BR><BR>static void my_print (char *); <BR>static void my_print2 (char *); <BR><BR>main () <BR>{ <BR>char my_string[] = "hello world!"; <BR>my_print (my_string); <BR>my_print2 (my_string); <BR>} <BR><BR>void my_print (char *string) <BR>{ <BR>printf ("The string is %s ", string); <BR>} <BR><BR>void my_print2 (char *string) <BR>{ <BR>char *string2; int size, i; <BR><BR>size = strlen (string); <BR>string2 = (char *) malloc (size + 1); <BR>for (i = 0; i &lt; size; i++) string2[size -1 - i] = string[i]; <BR>string2[size] = ; <BR><BR>printf ("The string printed backward is %s ", string2); <BR>} <BR>运行 indent 后的 C 代码: <BR><BR>#include <BR>static void my_print (char *); <BR>static void my_print2 (char *); <BR>main () <BR>{ <BR>char my_string[] = "hello world!"; <BR>my_print (my_string); <BR>my_print2 (my_string); <BR>} <BR>void <BR>my_print (char *string) <BR>{ <BR>printf ("The string is %s ", string); <BR>} <BR>void <BR>my_print2 (char *string) <BR>{ <BR>char *string2; <BR>int size, i; <BR>size = strlen (string); <BR>string2 = (char *) malloc (size + 1); <BR>for (i = 0; i &lt; size; i++) <BR>string2[size - 1 - i] = string[i]; <BR>string2[size] = ; <BR>printf ("The string printed backward is %s ", string2); <BR>} <BR>indent 并不改变代码的实质内容, 而只是改变代码的外观. 使它变得更可读, 这永远是一件好事. <BR><BR>gprof <BR>gprof 是安装在你的 Linux 系统的 /usr/bin 目录下的一个程序. 它使你能剖析你的程序从而知道程序的哪一个部分在执行时最费时间. <BR><BR>gprof 将告诉你程序里每个函数被调用的次数和每个函数执行时所占时间的百分比. 你如果想提高你的程序性能的话这些信息非常有用. <BR><BR>为了在你的程序上使用 gprof, 你必须在编译程序时加上 -pg 选项. 这将使程序在每次执行时产生一个叫 gmon.out 的文件. gprof 用这个文件产生剖析信息. <BR><BR>在你运行了你的程序并产生了 gmon.out 文件后你能用下面的命令获得剖析信息: <BR><BR>gprof <BR>参数 program_name 是产生 gmon.out 文件的程序的名字. <BR><BR>为了说明问题，在程序中增加了函数count_sum()以消耗CPU时间，程序如下 <BR>#include <BR><BR>static void my_print (char *); <BR>static void my_print2 (char *); <BR><BR>main () <BR>{ <BR>char my_string[] = "hello world!"; <BR>my_print (my_string); <BR>my_print2 (my_string); <BR>my_print (my_string); <BR>} <BR><BR>void count_sum() <BR>{ <BR>int i,sum=0; <BR>for(i=0; i&lt;1000000; i++) <BR>sum += i; <BR>} <BR><BR>void my_print (char *string) <BR>{ <BR>count_sum(); <BR>printf ("The string is %s ", string); <BR>} <BR><BR>void my_print2 (char *string) <BR>{ <BR>char *string2; <BR>int size, i,sum =0; <BR><BR>count_sum(); <BR>size = strlen (string); <BR>string2 = (char *) malloc (size + 1); <BR>for (i = 0; i &lt; size; i++) string2[size -1 - i] = string[i]; <BR>string2[size] = ; <BR>for(i=0; i&lt;5000000; i++) <BR>sum += i; <BR><BR>printf ("The string printed backward is %s ", string2); <BR>} <BR>$ gcc -pg -o hello hello.c <BR>$ ./hello <BR>$ gprof hello | more <BR>将产生以下的输出 <BR>Flat profile: <BR><BR>Each sample counts as 0.01 seconds. <BR>% cumulative self self total <BR>time seconds seconds calls us/call us/call name <BR>69.23 0.09 0.09 1 90000.00 103333.33 my_print2 <BR>30.77 0.13 0.04 3 13333.33 13333.33 count_sum <BR>0.00 0.13 0.00 2 0.00 13333.33 my_print <BR><BR>% 执行此函数所占用的时间占程序总 <BR>time 执行时间的百分比 <BR><BR>cumulative 累计秒数 执行此函数花费的时间 <BR>seconds （包括此函数调用其它函数花费的时间） <BR><BR>self 执行此函数花费的时间 <BR>seconds （调用其它函数花费的时间不计算在内） <BR><BR>calls 调用次数 <BR><BR>self 每此执行此函数花费的微秒时间 <BR>us/call <BR><BR>total 每此执行此函数加上它调用其它函数 <BR>us/call 花费的微秒时间 <BR><BR>name 函数名 <BR><BR>由以上数据可以看出，执行my_print()函数本身没花费什么时间，但是它又调用了count_sum()函数，所以累计秒数为0.13. <BR><BR>技巧: gprof 产生的剖析数据很大, 如果你想检查这些数据的话最好把输出重定向到一个文件里. <BR>]]></description>
<author>fuhj02</author>
<pubDate>2008-8-29 19:22:00</pubDate>
</item>
<item>
<title><![CDATA[GCC使用手册]]></title>
<link>http://blog.edu.cn/user2/35840/archives/2008/2164970.shtml</link>
<description><![CDATA[1.前言 
<P>&nbsp;&nbsp;&nbsp; GCC编译器的手册(GCC MANUAL)的英文版已经非常全面，并且结构也非常完善了，只是一直都没有中文的版本，我这次阅读了GCC编译器的主要内容，对手册的内容进行了结构性的了解，认为有必要对这次阅读的内容进行整理，为以后的工作做准备。 </P>
<P>&nbsp;&nbsp;&nbsp; 由于我对这个英文手册的阅读也仅仅是结构性的。因此有很多地方并没有看，所以这篇文档的内容我也只能写出部分，对于以后需要详细了解的地方，会再往这篇文档中增添内容，需要增添的内容主要是编译器的各种开关。 </P>
<P>2. GCC功能介绍 </P>
<P>&nbsp;&nbsp;&nbsp; GCC编译器完成从C、C++、objective-C等源文件向运行在特定CPU硬件上的目标代码的转换（这是任何一个编译器需要完成的任务）。 </P>
<P>&nbsp;&nbsp;&nbsp; GCC能够处理的源文件分为C、C++、Objective-C、汇编语言等。对于这些源文件，用他们的后缀名进行标示。GCC能够处理的后缀有： </P>
<P>a. *.c&nbsp; *.C&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (C语言) </P>
<P>b. *.cxx&nbsp;&nbsp; *.cc&nbsp; (C++语言) </P>
<P>c. *.m&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (面向对象的C) </P>
<P>d. *.i&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (预处理后的C语言源文件) </P>
<P>e. *.ii&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (预处理后的C++语言源文件) </P>
<P>f. *.s *.S&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (汇编语言) </P>
<P>h. *.h&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (头文件) </P>
<P>目标文件可以是： </P>
<P>a. *.o&nbsp;&nbsp;&nbsp;&nbsp; 编译连接后的目标文件 </P>
<P>b. *.a&nbsp;&nbsp;&nbsp;&nbsp; 库文件 </P>
<P>编译器把编译生成目标代码的任务分为以下4步： </P>
<P>a.预处理，把预处理命令扫描处理完毕； </P>
<P>b.编译，把预处理后的结果编译成汇编或者目标模块； </P>
<P>c.汇编，把编译出来的结果汇编成具体CPU上的目标代码模块； </P>
<P>d.连接，把多个目标代码模块连接生成一个大的目标模块； </P>
<P>3.&nbsp; GCC开关 </P>
<P>&nbsp;&nbsp;&nbsp; GCC的运行开关共分为11类，这是类开关从11个方面控制着GCC程序的运行，以达到特定的编译目的。 </P>
<P>3.1.&nbsp; 全局开关(OVERALL OPTIONS) </P>
<P>&nbsp;&nbsp;&nbsp; 全局开关用来控制在“GCC功能介绍”中的GCC的4个步骤的运行，在缺省的情况下，这4个步骤都是要执行的，但是当给定一些全局开关后，这些步骤就会在某一步停止执行，这产生中间结果，例如可能你只是需要中间生成的预处理的结果或者是汇编文件(比如拟的目的是为了看某个CPU上的汇编语言怎么写)。 </P>
<P>3.1.1.&nbsp; –x&nbsp; language </P>
<P>&nbsp;&nbsp;&nbsp; 对于源文件是用什么语言编写的，可以通过文件名的后缀来标示，也可以用这开关。指定输入文件是什么语言编写的，language 可以是如下的内容 </P>
<P>a.&nbsp; c </P>
<P>b. objective-c </P>
<P>c. c-header </P>
<P>d. c++ </P>
<P>e.cpp-output </P>
<P>f.assembler </P>
<P>g.assembler-with-cpp </P>
<P>3.1.2.–x none </P>
<P>把上一节介绍的-x开关都给关掉了。 </P>
<P>3.1.3.&nbsp; –c </P>
<P>编译成把源文件目标代码，不做连接的动作。 </P>
<P>3.1.4. –S </P>
<P>把源文件编译成汇编代码，不做汇编和连接的动作。 </P>
<P>3.1.5. –E </P>
<P>只把源文件进行预处理之后的结果输出来。不做编译，汇编，连接的动作。 </P>
<P>3.1.6.&nbsp; –o file </P>
<P>指明输出文件名是file。 </P>
<P>3.1.7. –v </P>
<P>把整个编译过程的输出信息都给打印出来。 </P>
<P>3.1.8.–pipe </P>
<P>由于gcc的工作分为好几步才完成，所以需要在过程中生成临时文件，使用-pipe就是用管道替换临时文件。 </P>
<P>3.2.&nbsp; 语言相关开关(Language Options) </P>
<P>用来处理和语言相关的控制开关。 </P>
<P>3.2.1.–ansi </P>
<P>&nbsp;&nbsp;&nbsp; 这个开关让GCC编译器把所有的gnu的编译器特性都给关掉，让你的程序可以和ansi标准兼容。 </P>
<P>&nbsp;&nbsp;&nbsp; 除了以上的开关外，语言相关开关还有很多，如果在以后的工作学习中遇到了再加不迟！3.3.预处理开关(Preprocessor Options) </P>
<P>用来控制预处理所设置的开关。 </P>
<P>3.3.1. –include file </P>
<P>&nbsp;&nbsp;&nbsp; 在编译之前，把file包含进去，相当于在所有编译的源文件最前面加入了一个#include &lt;file&gt;语句，这样做更“省油”。 </P>
<P>3.3.2. –imacros file </P>
<P>&nbsp;&nbsp;&nbsp; 同-include file 一样。不过这个文件在具体编译的时候只有里面定义的宏才起作用，所以值用来在file文件里面定义宏。 </P>
<P>3.3.3. –nostdinc </P>
<P>&nbsp;&nbsp;&nbsp; 在搜寻include 的文件路径中去掉标准的c语言头文件搜索路径，例如stdio.h文件就是放在标准头文件搜索路径下。 </P>
<P>3.3.4.&nbsp; –nostdinc++ </P>
<P>&nbsp;&nbsp;&nbsp; 同上，只是去掉的是标准C++语言的头文件搜索路径。 </P>
<P>3.3.5. –C </P>
<P>&nbsp;&nbsp;&nbsp; 同-E参数配合使用。让预处理后的结果，把注释保留，让人能够比较好读它。 </P>
<P>3.3.6. –Dmacro </P>
<P>&nbsp;&nbsp;&nbsp; 把macro定义为字符串’1’。 </P>
<P>3.3.7. –Dmacro = defn </P>
<P>&nbsp;&nbsp;&nbsp; 把macro定义为defn。 </P>
<P>3.3.8.&nbsp; –Umacro </P>
<P>&nbsp;&nbsp;&nbsp; 把对macro的定义取消。 </P>
<P>&nbsp;&nbsp;&nbsp; 除了以上的开关外，预处理相关开关还有很多，如果在以后的工作学习中遇到了再加不迟！ </P>
<P>3.4.&nbsp;&nbsp; 汇编开关(Assembler Option) </P>
<P>&nbsp;&nbsp;&nbsp; 用来控制汇编行为的开关。 </P>
<P>3.4.1.&nbsp; –Wa , option </P>
<P>&nbsp;&nbsp;&nbsp; 把option作为开关送给汇编程序。如果option里面有逗号，则作为好几行进行处理。 </P>
<P>3.5.连接开关(Linker Options) </P>
<P>&nbsp;&nbsp;&nbsp; 用来控制连接过程的开关选项。 </P>
<P>3.5.1. object-file-name </P>
<P>3.5.2. –llibrary </P>
<P>&nbsp;&nbsp;&nbsp; 连接库文件开关。例如-lugl，则是把程序同libugl.a文件进行连接。 </P>
<P>3.5.3. –lobjc </P>
<P>&nbsp;&nbsp;&nbsp; 这个开关用在面向对象的C语言文件的库文件处理中。 </P>
<P>3.5.4.&nbsp; –nostartfiles </P>
<P>&nbsp;&nbsp;&nbsp; 在连接的时候不把系统相关的启动代码连接进来。 </P>
<P>3.5.5.&nbsp;&nbsp; –nostdlib </P>
<P>&nbsp;&nbsp;&nbsp; 在连接的时候不把系统相关的启动文件和系统相关的库连接进来。 </P>
<P>3.5.6. –static </P>
<P>&nbsp;&nbsp;&nbsp; 在一些系统上支持动态连接，这个开关则不允许动态连接。 </P>
<P>3.5.7. –shared </P>
<P>&nbsp;&nbsp;&nbsp; 生成可共享的被其他程序连接的目标模块。 </P>
<P>&nbsp;&nbsp;&nbsp; 连接相关的开关还有一些，以后需要的时候再补。 </P>
<P>3.6.目录相关开关(Directory Options) </P>
<P>&nbsp;&nbsp;&nbsp; 用于定义与目录操作相关的开关。 </P>
<P>3.6.1. –Idir </P>
<P>&nbsp;&nbsp;&nbsp; 宏include需要搜寻的目录。 </P>
<P>3.6.2.–I- </P>
<P>&nbsp;&nbsp;&nbsp; 与-I开关类似。 </P>
<P>3.6.3.–Ldir </P>
<P>&nbsp;&nbsp;&nbsp; 搜寻库文件(*.a)的路径。 </P>
<P>&nbsp;&nbsp;&nbsp; 和目录相关的开关还有很多，以后需要再加。 </P>
<P>3.7. 警告开关(Warning Options) </P>
<P>&nbsp;&nbsp;&nbsp; 与警告处理相关的开关。 </P>
<P>3.7.1.–fsyntax-only </P>
<P>&nbsp;&nbsp;&nbsp; 只检查代码中的语法错误，但并没有输出。 </P>
<P>3.7.2. –w </P>
<P>&nbsp;&nbsp;&nbsp; 禁止一切警告信息打印出来。 </P>
<P>3.7.3. –Wno-import </P>
<P>&nbsp;&nbsp;&nbsp; 禁止对宏#import提出警告。 </P>
<P>3.7.4. –pedantic </P>
<P>3.7.5.&nbsp; –pedantic-errors </P>
<P>3.7.6.&nbsp; –W </P>
<P>&nbsp;&nbsp; 还有很多与警告处理相关的开关，以后再补。 </P>
<P>3.8. 调试开关(Debugging Options) </P>
<P>3.8.1.–g </P>
<P>&nbsp;&nbsp;&nbsp; 把调试开关打开，让编译的目标文件有调试信息。 </P>
<P>&nbsp;&nbsp;&nbsp; 还有很多与调试处理相关的开关，以后再补。 </P>
<P>3.9. 优化开关(Optimization Options) </P>
<P>&nbsp;&nbsp;&nbsp; -O1 –O2 –O3 –O0，这些开关分别控制优化的强度，-O3最强。 </P>
<P>3.10. 目标机开关(Target Options) </P>
<P>3.10.1. –b machine </P>
<P>&nbsp;&nbsp;&nbsp; 在有的时候，Gcc编译器编译出来的目标代码并不是在运行这个编译动作的机器上运行而是另外一台机器，这种编译叫做交叉编译，用来运行最终目标代码的得机器叫做目标机，machine就是用来指明目标机的类型的。 </P>
<P>3.10.2.&nbsp; –V version </P>
<P>&nbsp;&nbsp;&nbsp; 用来告诉编译器使用它的多少版本的功能，version参数用来表示版本。 </P>
<P>3.11.&nbsp;&nbsp; CPU相关开关(Machine Dependent Options) </P>
<P>&nbsp;&nbsp;&nbsp; 比较多，也是在交叉编译的时候用得着。以后再说。 </P>
<P>3.12. 生成代码开关(Code Generation Options) </P>]]></description>
<author>fuhj02</author>
<pubDate>2008-8-29 19:20:00</pubDate>
</item>
<item>
<title><![CDATA[ARP协议揭密]]></title>
<link>http://blog.edu.cn/user2/35840/archives/2008/2164969.shtml</link>
<description><![CDATA[<P>1 ARP协议概述<BR><BR>IP数据包常通过以太网发送。以太网设备并不识别32位IP地址：它们是以48位以太网地址传输以太网数据包的。因此，IP驱动器必须把IP目的地址转换成以太网网目的地址。在这两种地址之间存在着某种静态的或算法的映射，常常需要查看一张表。地址解析协议(Address Resolution Protocol，ARP)就是用来确定这些映象的协议。<BR><BR>ARP工作时，送出一个含有所希望的IP地址的以太网广播数据包。目的地主机，或另一个代表该主机的系统，以一个含有IP和以太网地址对的数据包作为应答。发送者将这个地址对高速缓存起来，以节约不必要的ARP通信。<BR><BR>如果有一个不被信任的节点对本地网络具有写访问许可权，那么也会有某种风险。这样一台机器可以发布虚假的ARP报文并将所有通信都转向它自己，然后它就可以扮演某些机器，或者顺便对数据流进行简单的修改。ARP机制常常是自动起作用的。在特别安全的网络上， ARP映射可以用固件，并且具有自动抑制协议达到防止干扰的目的。<BR><BR><BR>图1 以太网上的ARP报文格式 <BR><BR>图1是一个用作IP到以太网地址转换的ARP报文的例子。在图中每一行为32位，也就是4个八位组表示，在以后的图中，我们也将遵循这一方式。<BR><BR>硬件类型字段指明了发送方想知道的硬件接口类型，以太网的值为1。协议类型字段指明了发送方提供的高层协议类型，IP为0806（16进制）。硬件地址长度和协议长度指明了硬件地址和高层协议地址的长度，这样ARP报文就可以在任意硬件和任意协议的网络中使用。操作字段用来表示这个报文的目的，ARP请求为1，ARP响应为2，RARP请求为3，RARP响应为4。<BR><BR>当发出ARP请求时，发送方填好发送方首部和发送方IP地址，还要填写目标IP地址。当目标机器收到这个ARP广播包时，就会在响应报文中填上自己的48位主机地址。<BR><BR>2 ARP使用举例<BR><BR>我们先看一下linux下的arp命令(如果开始arp表中的内容为空的话,需要先对某台主机进行一个连接,例如ping一下目标主机来产生一个arp项)：<BR><BR>d2server:/home/kerberos# arp<BR>Address HWtype HWaddress Flags Mask Iface<BR>211.161.17.254 ether 00:04:9A:AD:1C:0A C eth0<BR>Address：主机的IP地址<BR>Hwtype：主机的硬件类型<BR>Hwaddress：主机的硬件地址<BR>Flags Mask：记录标志，"C"表示arp高速缓存中的条目，"M"表示静态的arp条目。<BR><BR>用"arp --a"命令可以显示主机地址与IP地址的对应表，也就是机器中所保存的arp缓存信息。这个高速缓存存放了最近Internet地址到硬件地址之间的映射记录。高速缓存中每一项的生存时间一般为20分钟，起始时间从被创建时开始算起。<BR><BR>d2server:/home/kerberos# arp -a<BR>(211.161.17.254) at 00:04:9A:AD:1C:0A [ether] on eth0<BR>可以看到在缓存中有一条211.161.17.254相对应的arp缓存条目。<BR>d2server:/home/kerberos# telnet 211.161.17.21<BR>Trying 211.161.17.21...<BR>Connected to 211.161.17.21.<BR>Escape character is ^].<BR>^].<BR>telnet&gt;quit<BR>connetion closed.<BR><BR>在执行上面一条telnet命令的同时，用tcpdump进行监听：<BR><BR>d2server:/home/kerberos# tcpdump -e dst host 211.161.17.21<BR>tcpdump: listening on eth0<BR><BR>我们将会听到很多包，我们取与我们arp协议相关的2个包：<BR><BR>1 0.0 00:D0:F8:0A:FB:83 FF:FF:FF:FF:FF:FF arp 60<BR>who has 211.161.17.21 tell d2server<BR>2 0.002344(0.0021) 00:E0:3C:43:0D:24 00:D0:F8:0A:FB:83 arp 60<BR>arp reply 211.161.17.21 is at 00:E0:3C:43:0D:24<BR><BR>在第1行中，源端主机（d2server）的硬件地址是00:D0:F8:0A:FB:83。目的端主机的硬件地址是FF:FF:FF:FF:FF:FF，这是一个以太网广播地址。电缆上的每个以太网接口都要接收这个数据帧并对它进行处理。<BR><BR>第1行中紧接着的一个输出字段是arp，表明帧类型字段的值是0x0806，说明此数据帧是一个ARP请求或回答。<BR><BR>在每行中，单词后面的值60指的是以太网数据帧的长度。由于ARP请求或回答的数据帧长都是42字节（28字节的ARP数据，14字节的以太网帧头），因此，每一帧都必须加入填充字符以达到以太网的最小长度要求：60字节。<BR><BR>第1行中的下一个输出字段arp who-has表示作为ARP请求的这个数据帧中，目的I P地址是211.161.17.21的地址，发送端的I P地址是d2server的地址。tcpdump打印出主机名对应的默认I P地址。<BR><BR>从第2行中可以看到，尽管ARP请求是广播的，但是ARP应答的目的地址却是211.161.17.21(00:E0:3C:43:0D:24)。ARP应答是直接送到请求端主机的，而是广播的。tcpdump打印出arp reply的字样，同时打印出响应者的主机ip和硬件地址。<BR><BR>在每一行中，行号后面的数字表示tcpdump收到分组的时间（以秒为单位）。除第1行外，每行在括号中还包含了与上一行的时间差异（以秒为单位）。<BR><BR>这个时候我们再看看机器中的arp缓存：<BR><BR>d2server:/home/kerberos# arp -a<BR>(211.161.17.254) at 00:04:9A:AD:1C:0A [ether] on eth0<BR>(211.161.17.21) at 00:E0:3C:43:0D:24 [ether] on eth0<BR><BR>arp高速缓存中已经增加了一条有关211.161.17.21的映射。<BR><BR>再看看其他的arp相关的命令：<BR><BR>d2server:/home/kerberos# arp -s 211.161.17.21 00:00:00:00:00:00<BR>d2server:/home/kerberos# arp<BR>Address HWtype HWaddress Flags Mask Iface<BR>211.161.17.254 ether 00:04:9A:AD:1C:0A C eth0<BR>211.161.17.21 ether 00:00:00:00:00:00 CM eth0<BR>d2server:/home/kerberos# arp -a<BR>(211.161.17.254) at 00:04:9A:AD:1C:0A [ether] on eth0<BR>(211.161.17.21) at 00:00:00:00:00:00 [ether] PERM on eth0<BR><BR>可以看到我们用arp -s选项设置了211.161.17.21对应的硬件地址为00:00:00:00:00:00，而且这条映射的标志字段为CM,也就是说我们手工设置的arp选项为静态arp选项，它保持不变没有超时，不像高速缓存中的条目要在一定的时间间隔后更新。<BR><BR>如果想让手工设置的arp选项有超时时间的话，可以加上temp选项<BR><BR>d2server:/home/kerberos# arp -s 211.161.17.21 00:00:00:00:00:00 temp<BR>d2server:/home/kerberos# arp -a<BR>(211.161.17.254) at 00:04:9A:AD:1C:0A [ether] on eth0<BR>(211.161.17.21) at 00:00:00:00:00:00 [ether] on eth0<BR>d2server:/home/kerberos# arp<BR>Address HWtype HWaddress Flags Mask Iface<BR>211.161.17.254 ether 00:04:9A:AD:1C:0A C eth0<BR>211.161.17.21 ether 00:00:00:00:00:00 C eth0<BR><BR>可以看到标志字段的静态arp标志"M"已经去掉了，我们手工加上的是一条动态条目。<BR><BR>请大家注意arp静态条目与动态条目的区别。<BR><BR>在不同的系统中，手工设置的arp静态条目是有区别的。在linux和win2000中，静态条目不会因为伪造的arp响应包而改变，而动态条目会改变。而在win98中，手工设置的静态条目会因为收到伪造的arp响应包而改变。<BR><BR>如果您想删除某个arp条目（包括静态条目），可以用下面的命令：<BR><BR>d2server:/home/kerberos# arp -d 211.161.17.21 <BR>d2server:/home/kerberos# arp -a<BR>(211.161.17.254) at 00:04:9A:AD:1C:0A [ether] on eth0<BR>(211.161.17.21) at &lt;incomplete&gt; on eth0<BR><BR>可以看到211.161.17.21的arp条目已经是不完整的了。<BR><BR>还有一些其他的命令，可以参考linux下的man文档：<BR><BR>d2server:/home/kerberos# man arp<BR><BR>3 ARP欺骗<BR><BR>我们先复习一下上面所讲的ARP协议的原理。在实现TCP/IP协议的网络环境下，一个ip包走到哪里，要怎么走是靠路由表定义，但是，当ip包到达该网络后，哪台机器响应这个ip包却是靠该ip包中所包含的硬件mac地址来识别。也就是说，只有机器的硬件mac地址和该ip包中的硬件mac地址相同的机器才会应答这个ip包，因为在网络中，每一台主机都会有发送ip包的时候，所以，在每台主机的内存中，都有一个 arp--&gt; 硬件mac 的转换表。通常是动态的转换表（该arp表可以手工添加静态条目）。也就是说，该对应表会被主机在一定的时间间隔后刷新。这个时间间隔就是ARP高速缓存的超时时间。<BR><BR>通常主机在发送一个ip包之前，它要到该转换表中寻找和ip包对应的硬件mac地址，如果没有找到，该主机就发送一个ARP广播包，于是，主机刷新自己的ARP缓存。然后发出该ip包。 <BR><BR>了解这些常识后，现在就可以谈在以太网络中如何实现ARP欺骗了，可以看看这样一个例子。<BR><BR>3.1 同一网段的ARP欺骗<BR><BR><BR>图2 同一网段的arp欺骗 <BR><BR>如图2所示，三台主机<BR><BR>A: ip地址 192.168.0.1 硬件地址 AA:AA:AA:AA:AA:AA<BR>B: ip地址 192.168.0.2 硬件地址 BB:BB:BB:BB:BB:BB<BR>C: ip地址 192.168.0.3 硬件地址 CC:CC:CC:CC:CC:CC<BR><BR><BR>一个位于主机B的入侵者想非法进入主机A，可是这台主机上安装有防火墙。通过收集资料他知道这台主机A的防火墙只对主机C有信任关系（开放23端口(telnet)）。而他必须要使用telnet来进入主机A，这个时候他应该如何处理呢？<BR><BR>我们这样考虑，入侵者必须让主机A相信主机B就是主机C，如果主机A和主机C之间的信任关系是建立在ip地址之上的。如果单单把主机B的ip地址改的和主机C的一样，那是不能工作的，至少不能可靠地工作。如果你告诉以太网卡设备驱动程序， 自己IP是192.168.0.3，那么这只是一种纯粹的竞争关系，并不能达到目标。我们可以先研究C这台机器如果我们能让这台机器暂时当掉，竞争关系就可以解除,这个还是有可能实现的。在机器C当掉的同时，将机器B的ip地址改为192.168.0.3,这样就可以成功的通过23端口telnet到机器A上面，而成功的绕过防火墙的限制。<BR><BR>上面的这种想法在下面的情况下是没有作用的，如果主机A和主机C之间的信任关系是建立在硬件地址的基础上。这个时候还需要用ARP欺骗的手段让主机A把自己的ARP缓存中的关于192.168.0.3映射的硬件地址改为主机B的硬件地址。<BR><BR>我们可以人为的制造一个arp_reply的响应包,发送给想要欺骗的主机,这是可以实现的,因为协议并没有规定必须在接收到arp_echo后才可以发送响应包.这样的工具很多,我们也可以直接用snifferpro抓一个arp响应包,然后进行修改。 <BR><BR>你可以人为地制造这个包。可以指定ARP包中的源IP、目标IP、源MAC地址、目标MAC地址。<BR><BR>这样你就可以通过虚假的ARP响应包来修改主机A上的动态ARP缓存达到欺骗的目的。<BR><BR>下面是具体的步骤：<BR><BR>他先研究192.0.0.3这台主机，发现这台主机的漏洞。 <BR>根据发现的漏洞使主机C当掉，暂时停止工作。 <BR>这段时间里，入侵者把自己的ip改成192.0.0.3 <BR>他用工具发一个源ip地址为192.168.0.3源MAC地址为BB:BB:BB:BB:BB:BB的包给主机A，要求主机A更新自己的arp转换表。 <BR>主机更新了arp表中关于主机C的ip--&gt;mac对应关系。 <BR>防火墙失效了，入侵的ip变成合法的mac地址，可以telnet 了。 <BR>上面就是一个ARP的欺骗过程，这是在同网段发生的情况，但是，提醒注意的是，在B和C处于不同网段的时候，上面的方法是不起作用的。<BR><BR>3.2 不同网段的ARP欺骗<BR><BR><BR>图3 不同网段之间的ARP欺骗<BR><BR>如图3所示A、C位于同一网段而主机B位于另一网段，三台机器的ip地址和硬件地址如下：<BR><BR>A: ip地址 192.168.0.1 硬件地址 AA:AA:AA:AA:AA:AA<BR>B: ip地址 192.168.1.2 硬件地址 BB:BB:BB:BB:BB:BB<BR>C: ip地址 192.168.0.3 硬件地址 CC:CC:CC:CC:CC:CC<BR><BR>在现在的情况下，位于192.168.1网段的主机B如何冒充主机C欺骗主机A呢？显然用上面的办法的话，即使欺骗成功，那么由主机B和主机A之间也无法建立telnet会话，因为路由器不会把主机A发给主机B的包向外转发，路由器会发现地址在192.168.0.这个网段之内。<BR><BR>现在就涉及到另外一种欺骗方式―ICMP重定向。把ARP欺骗和ICMP重定向结合在一起就可以基本实现跨网段欺骗的目的。<BR><BR>什么是ICMP重定向呢？<BR><BR>ICMP重定向报文是ICMP控制报文中的一种。在特定的情况下，当路由器检测到一台机器使用非优化路由的时候，它会向该主机发送一个ICMP重定向报文，请求主机改变路由。路由器也会把初始数据报向它的目的地转发。<BR><BR>我们可以利用ICMP重定向报文达到欺骗的目的。<BR><BR>下面是结合ARP欺骗和ICMP重定向进行攻击的步骤：<BR><BR>为了使自己发出的非法ip包能在网络上能够存活长久一点，开始修改ip包的生存时间ttl为下面的过程中可能带来的问题做准备。把ttl改成255. (ttl定义一个ip包如果在网络上到不了主机后，在网络上能存活的时间，改长一点在本例中有利于做充足的广播) <BR>下载一个可以自由制作各种包的工具（例如hping2） <BR>然后和上面一样，寻找主机C的漏洞按照这个漏洞当掉主机C。 <BR>在该网络的主机找不到原来的192.0.0.3后，将更新自己的ARP对应表。于是他发送一个原ip地址为192.168.0.3硬件地址为BB:BB:BB:BB:BB:BB的ARP响应包。 <BR>好了，现在每台主机都知道了，一个新的MAC地址对应192.0.0.3,一个ARP欺骗完成了，但是，每台主机都只会在局域网中找这个地址而根本就不会把发送给192.0.0.3的ip包丢给路由。于是他还得构造一个ICMP的重定向广播。 <BR>自己定制一个ICMP重定向包告诉网络中的主机："到192.0.0.3的路由最短路径不是局域网，而是路由，请主机重定向你们的路由路径，把所有到192.0.0.3的ip包丢给路由。" <BR>主机A接受这个合理的ICMP重定向，于是修改自己的路由路径，把对192.0.0.3的通讯都丢给路由器。 <BR>入侵者终于可以在路由外收到来自路由内的主机的ip包了，他可以开始telnet到主机的23口。 <BR>其实上面的想法只是一种理想话的情况，主机许可接收的ICMP重定向包其实有很多的限制条件，这些条件使ICMP重定向变的非常困难。<BR><BR>TCP/IP协议实现中关于主机接收ICMP重定向报文主要有下面几条限制：<BR><BR>新路由必须是直达的 <BR>重定向包必须来自去往目标的当前路由 <BR>重定向包不能通知主机用自己做路由 <BR>被改变的路由必须是一条间接路由 <BR>由于有这些限制，所以ICMP欺骗实际上很难实现。但是我们也可以主动的根据上面的思维寻找一些其他的方法。更为重要的是我们知道了这些欺骗方法的危害性，我们就可以采取相应的防御办法。<BR><BR>3.3 ARP欺骗的防御<BR><BR>知道了ARP欺骗的方法和危害，我们给出一些初步的防御方法：<BR><BR>不要把你的网络安全信任关系建立在ip地址的基础上或硬件mac地址基础上，（rarp同样存在欺骗的问题），理想的关系应该建立在ip+mac基础上。 <BR>设置静态的mac--&gt;ip对应表，不要让主机刷新你设定好的转换表。 <BR>除非很有必要，否则停止使用ARP，将ARP做为永久条目保存在对应表中。在linux下可以用ifconfig -arp可以使网卡驱动程序停止使用ARP。 <BR>使用代理网关发送外出的通讯。 <BR>修改系统拒收ICMP重定向报文 <BR>在linux下可以通过在防火墙上拒绝ICMP重定向报文或者是修改内核选项重新编译内核来拒绝接收ICMP重定向报文。<BR><BR>在win2000下可以通过防火墙和IP策略拒绝接收ICMP报文。<BR><BR>4 代理ARP的应用<BR><BR>代理ARP有两大应用,一个是有利的就是我们在防火墙实现中常说的透明模式的实现,另一个是有害的就是通过它可以达到在交换环境中进行嗅探的目的.由此可见同样一种技术被应用于不同的目的,效果是不一样的.<BR><BR>我们先来看交换环境中局域网的嗅探.<BR><BR>通常在局域网环境中，我们都是通过交换环境的网关上网的。在交换环境中使用NetXray或者NAI Sniffer一类的嗅探工具除了抓到自己的包以外，是不能看到其他主机的网络通信的。<BR><BR>但是我们可以通过利用ARP欺骗可以实现Sniffer的目的。<BR><BR>ARP协议是将IP地址解析为MAC地址的协议，局域网中的通信都是基于MAC地址的。<BR><BR><BR>图4 交换网络中的ARP欺骗 <BR><BR>如图4所示，三台主机位于一个交换网络的环境中，其中A是网关：<BR><BR>A: ip地址 192.168.0.1 硬件地址 AA:AA:AA:AA:AA<BR>B: ip地址 192.168.0.2 硬件地址 BB:BB:BB:BB:BB<BR>C：ip地址 192.168.0.3 硬件地址 CC:CC:CC:CC:CC<BR><BR>在局域网中192.168.0.2和192.168.0.3都是通过网关192.168.0.1上网的，假定攻击者的系统为192.168.0.2，他希望听到192.168.0.3的通信，那么我们就可以利用ARP欺骗实现。<BR><BR>这种欺骗的中心原则就是arp代理的应用.主机A是局域网中的代理服务器,局域网中每个节点的向外的通信都要通过它.主机B想要听主机C的通信,它需要先使用ARP欺骗,让主机C认为它就是主机A,这个时候它发一个IP地址为192.168.0.1,物理地址为BB:BB:BB:BB:BB:BB的ARP响应包给主机C,这样主机C会把发往主机A的包发往主机B.同理,还要让网关A相信它就是主机C,向网关A发送一个IP地址为192.168.0.3,物理地址为BB:BB:BB:BB:BB:BB的包.<BR><BR>上面这一步的操作和前面的ARP欺骗的原理是一样的,但是还是有问题,过一段时间主机B会发现自己无法上网.所以下面还有一个步骤就是需要在主机B上转发从主机A到主机C的包,并且转发从主机C到主机A的包.现在我们可以看到其实主机B在主机A和主机C的通讯中起到了一个代理的作用,这就是为什么叫做ARP代理的原因.<BR><BR>具体实现要用到两个工具dsniff和fragrouter,dsniff用来实现ARP欺骗,fragroute用来进行包的转发.<BR><BR>首先利用dsniff中的arpspoof来实现ARP欺骗,dsniff软件可以在下面的网址下载:<BR><BR>http://naughty.monkey.org/~dugsong/dsniff<BR><BR>安装这个软件包之前先要下载安装libnet.<BR><BR>欺骗192.168.0.3，告诉这台机器网关192.168.0.1的MAC地址是192.168.0.2的MAC地址. <BR><BR>[root@sound dsniff-2.3]# ./arpspoof -i eth0 -t 192.168.0.3 192.168.0.1<BR>欺骗192.168.0.1，告诉192.168.0.1主机192.168.0.3的MAC地址是192.168.0.2的MAC地址。<BR><BR>[root@sound dsniff-2.3]# ./arpspoof -i eth0 -t 192.168.0.1 192.168.0.3<BR>现在我们已经完成了第一步的欺骗,这个欺骗是通过arpspoof来完成的,当然您也可以使用别的工具甚至自己发包来完成.现在我们可以看到在主机A和主机C的arp列表里面都完成了我们需要的工作.在后面的透明代理中我们将使用另外一种不同的理念.<BR><BR>下面我们先打开linux系统中的转发包的选项:<BR><BR>[root@sound /root]# echo "1" &gt;/proc/sys/net/ipv4/ip_forward<BR>下面我们可以下载大名鼎鼎的dugsong的另外一个工具fragroute,这个工具以前叫做fragrouter(仅有1字的差别)主要用于实现入侵检测系统处理分片的ip和tcp包功能的检测,本身自代包转发的功能.可以到下面的网站下载:<BR><BR>http://monkey.org/~dugsong/fragroute/<BR><BR>安装这个软件包之前先要下载安装libpcap和libevent.<BR><BR>当然我们也可以使用fragrouter来完成:<BR><BR>http://www.packetstormsecurity.org/groups/ w00w00/sectools/fragrouter/ <BR><BR>[root@sound fragrouter-1.6]# ./fragrouter -B1 <BR>fragrouter: base-1: normal IP forwarding<BR><BR>现在就可以实现在交换局域网中嗅探的目标.当然上面这些只是一些原理性的介绍,在真正的使用中会遇到很多的问题,比如如何实现对网关A和主机C的欺骗,以及如何处理可能出现的广播风暴问题,这些可以在实践中学习.还有一个叫arpsniff的工具能够很方便的完成这一功能,很多网站都提供下载,界面比较友好,由于和上面的原理一样,只是工具使用上的不同并且添加了一些附加的功能,所以这里不在进行介绍.<BR><BR>代理ARP的另外一个应用就是防火墙的透明代理的实现.我们都知道早期的防火墙大都是基于路由模式,也就是防火墙要完成一个路由的作用.这种接入方式需要在局域网内的主机上设置防火墙的IP为代理,而且需要在外部路由器的路由表中加入一条指向防火墙的路由.这种方式的缺点在于不透明,需要进行过多的设置,并且破坏了原有的网络拓扑.所以现在几乎全部的防火墙都实现了一种透明接入的功能,用户的路由器和客户端不用做任何修改,用户甚至感觉不到透明接入方式防火墙的存在.这种透明接入的原理就是ARP代理.<BR><BR>我们现在看如何配置一台主机作为透明接入模式的防火墙(透明接入的防火墙不需要IP),<BR><BR><BR>图5 <BR><BR>如图5所示,一台防火墙连接内部网段和DMZ网段到外部路由.我们在这台用作防火墙的主机上使用linux操作系统,这样我们可以方便的使用iptables防火墙.假设三块网卡为eth0,eth1和eth2,eth0和路由器相连,eth1和内网相连.eth2和外网相连.假设DMZ区有2台服务器.<BR><BR>内网地址:192.168.1.0/24<BR>DMZ地址:192.168.1.2---192.168.1.3<BR>路由器的ip地址:192.168.1.1<BR>eth0:AA:AA:AA:AA:AA:AA<BR>eth1:BB:BB:BB:BB:BB:BB<BR>eth2:CC:CC:CC:CC:CC:CC<BR><BR>和前面差不多,第一步需要实现ARP欺骗,这次我们有个简单的实现.我们把路由器的IP地址和防火墙的eth1和eth2的网卡物理地址绑定,将内网和DMZ网段的IP地址和eth0的网卡绑定,在linux系统上我们用arp命令实现:<BR><BR>arp -s 192.168.1.1 BB:BB:BB:BB:BB:BB<BR>arp -s 192.168.1.1 CC:CC:CC:CC:CC:CC <BR>arp -s 192.168.1.0/24 AA:AA:AA:AA:AA:AA<BR><BR>第二部我们需要在基于linux的防火墙上设置路由,把目标地址是外部路由的包转发到eth0,把目标地址为内网的包转发到eth1,把目标地址是DMZ网段服务器的包转发到eth2.在linux下面用route命令实现<BR><BR>route add 192.168.1.1 dev eth0<BR>route add -net 192.168.1.0/24 dev eth1<BR>route add 192.168.1.2 dev eth2<BR>route add 192.168.1.3 dev eth3 <BR><BR>(针对DMZ网段里面的每台服务器都要增加一条单独的路由) 现在我们就已经实现了一个简单的arp代理的透明接入,当然对应于防火墙的iptables部分要另外配置,iptables的配置不在本文范畴之内.<BR><BR>小结<BR><BR>本文介绍了ARP协议以及与其相关的安全问题。一个重要的安全问题就是ARP欺骗，我们讲到了同一网段的ARP欺骗以及跨网段的ARP欺骗和ICMP重定向相结合的方法。由于有这些安全问题的存在，我们给出一些最基本的解决办法。最后谈到了利用代理ARP实现在交换网络中嗅探和防火墙的透明接入。<BR><BR>有关更深入的知识请参考RFC826、RFC814、RFC1029、RFC1166<BR><BR></P>]]></description>
<author>fuhj02</author>
<pubDate>2008-8-29 18:49:00</pubDate>
</item>

</channel>
</rss>
