修改.vimrc文件,让其支持 gb2312就行
"设定文件编码类型,彻底解决中文编码问题
let &termencoding=&encoding
set fileencodings=utf-8,gbk,ucs-bom,cp936
略微查了一下.vimrc中添加内容的含意,这篇文章有相关解释。
http://blog.dawnh.net/comment.php?type=trackback&entry_id=59
内容如下:
vim中编辑不同编码的文件时需要注意的一些地方
此文讲解的是vim编辑多字节编码文档(中文)所要了解的一些基础知识,注意其没有涉及gvim,纯指字符终端下的vim。
vim编码方面的基础知识:
1,存在3个变量:
encoding----该选项使用于缓冲的文本(你正在编辑的文件),寄存器,Vim 脚本文件等等。你可以把 'encoding' 选项当作是对 Vim 内部运行机制的设定。
fileencoding----该选项是vim写入文件时采用的编码类型。
termencoding----该选项代表输出到客户终端(Term)采用的编码类型。
2,此3个变量的默认值:
encoding----与系统当前locale相同,所以编辑文件的时候要考虑当前locale,否则要设置的东西就比较多了。
fileencoding----vim打开文件时自动辨认其编码,fileencoding就为辨认的值。为空则保存文件时采用encoding的编码,如果没有修改encoding,那值就是系统当前locale了。
termencoding----默认空值,也就是输出到终端不进行编码转换。
由此可见,编辑不同编码文件需要注意的地方不仅仅是这3个变量,还有系统当前locale和、文件本身编码以及自动编码识别、客户运行vim的终端所使用的编码类型3个关键点,这3个关键点影响着3个变量的设定。
如果有人问:为什么我用vim打开中文文档的时候出现乱码?
答案是不确定的,原因上面已经讲了,不搞清楚这3个关键点和这3个变量的设定值,出现乱码是正常的,倒是不出现乱码那反倒是凑巧的。
再来看一下常见情况下这三个关键点的值以及在这种情况下这3个变量的值:
1,locale----目前大部分Linux系统已经将utf-8作为默认locale了,不过也有可能不是,例如有些系统使用中文locale
zh_CN.GB18030。在locale为utf-8的情况下,启动vim后encoding将会设置为utf-8,这是兼容性最好的方式,因为内部
处理使用utf-8的话,无论外部存储编码为何都可以进行无缺损转换。locale决定了vim内部处理数据的编码,也就是encoding。
2,文件的编码以及自动编码识别----这方面牵扯到各种编码的规则,就不一一细讲了。但需要明白的是,文件编码类型并不是保存在文件内的,也
就是说没有任何描述性的字段来记录文档是何种编码类型的。因此我们在编辑文档的时候,要么必须知道这文档保存时是以什么编码保存的,要么通过另外的一些手
段来断定编码类型,这另外的手段,就是通过某些编码的码表特征来断定,例如每个字符占用的字节数,每个字符的ascii值是否都大于某个字段来断定这个文
件属于何种编码。这种方式vim也使用了,这就是vim的自动编码识别机制了。但这种机制由于编码各式各样,不可能每种编码都有显著的特征来辨别,所以是
不可能
100%准确的。对于我们GB2312编码,由于其中文是使用了2个acsii值高于127的字符组成汉字字符的,因此不可能把gb2312编码的文件与
latin1编码区分开来,因此自动识别编码的机制对于gb2312是不成功的,它只会将文件辨识为latin1编码。此问题同样出现在gbk,big5
上等。因此我们在编辑此类文档时,需要手工设定encoding和fileencoding。如果文档编码为utf-8时,一般vim都能自动识别正确的
编码。
3,客户运行vim的终端所使用的编码类型----同第二条一样,这也是一个比较难以断定的关键点。第二个关键点决定着从文件读取内容和写入内容
到文件时使用的编码,而此关键点则决定vim输出内容到终端时使用的编码,如果此编码类型和终端认为它收到的数据的编码类型不同,则又会产生乱码问题。在
linux本地X环境下,一般终端都认为其接收的数据的编码类型和系统locale类型相符,因此不需关心此方面是否存在问题。但如果牵涉到远程终端,例
如ssh登录服务器,则问题就有可能出现了。例如从1台locale为GB2310的系统(称作客户机)ssh到locale为utf-8的系统(称作服
务器)并开启vim编辑文档,在不加任何改动的情况下,服务器返回的数据为utf-8的,但客户机认为服务器返回的数据是gb2312的,按照
gb2312来解释数据,则肯定就是乱码了,这时就需要设置termencoding为gb2312来解决这个问题。此问题更多出现在我们的
windows
desktop机远程ssh登录服务器的情况下,这里牵扯到不同系统的编码转换问题。所以又与windows本身以及ssh客户端有很大相关性。在
windows下存在两种编码类型的软件,一种是本身就为unicode编码方式编写的软件,一种是ansi软件,也就是程序处理数据直接采用字节流,不
关心编码。前一种程序可以在任何语言的windows上正确显示多国语言,而后一种则编写在何种语言的系统上则只能在何种语言的系统上显示正确的文字。对
于这两种类型的程序,我们需要区别对待。以ssh客户端为例,我们使用的putty是unicode软件,而secure CRT则是ansi
软件。对于前者,我们要正确处理中文,只要保证vim输出到终端的编码为utf-8即可,就是termencoding=utf-8。但对于后者,一方面
我们要确认我们的windows系统默认代码页为cp936(中文windows默认值),另一方面要确认vim设置的termencoding=
cp936。
最后来看看处理中文文档最典型的几种情况和设置方式:
1,系统locale是utf-8(很多linux系统默认的locale形式),编辑的文档是GB2312或GBK形式的(Windows记事
本默认保存形式,大部分编辑器也默认保存为这个形式,所以最常见),终端类型utf-8(也就是假定客户端是putty类的unicode软件)
则vim打开文档后,encoding=utf-8(locale决定的),fileencoding=latin1(自动编码判断机制不准导致的),termencoding=空(默认无需转换term编码),显示文件为乱码。
解决方案1:首先要修正fileencoding为cp936或者euc-cn(二者一样的,只不过叫法不同),注意修正的方法不是:set
fileencoding=cp936,这只是将文件保存为cp936,正确的方法是重新以cp936的编码方式加载文件为:edit
++enc=cp936,可以简写为:e ++enc=cp936。
解决方案2:临时改变vim运行的locale环境,方法是以LANG=zh_CN vim
abc.txt的方式来启动vim,则此时encoding=euc-cn(locale决定的),fileencoding=空(此locale下文件
编码自动判别功能不启用,所以fileencoding为文件本身编码方式不变,也就是euc-cn),termencoding=空(默认值,为空则等
于encoding)此时还是乱码的,因为我们的ssh终端认为接受的数据为utf-8,但vim发送数据为euc-cn,所以还是不对。此时再用命令:
set termencoding=utf-8将终端数据输出为utf-8,则显示正常。
2,情况与1基本相同,只是使用的ssh软件为secure CRT类ansi类软件。
vim打开文档后,encoding=utf-8(locale决定的),fileencoding=latin1(自动编码判断机制不准导致的),termencoding=空(默认无需转换term编码),显示文件为乱码。
解决方案1:首先要保证运行secure CRT的windows机器的默认代码页为CP936,这一点中文windows已经是默认设置了。其他的与上面方案1相同,只是要增加一步,:set termencoding=cp936
解决方案2:与上面方案2类似,不过最后一步修改termencoding省略即可,在此情况下需要的修改最少,只要以locale为zh_CN
开启
vim,则encoding=euc-cn,fileencoding和termencoding都为空即为encoding的值,是最理想的一种情况。
可见理解这3个关键点和3个参数的意义,对于编码问题有很大助力,以后就可以随心所欲的处理文档了,同时不仅仅是应用于vim,在其他需要编码转换的环境里,都可以应用类似的思路来处理问题解决问题。
posted @ 2009-07-28 10:12 小马歌 阅读(179) | 评论 (0)编辑 收藏
 

好兄弟友情支持的虚拟主机最近老出问题,仔细询问了缘由,看来还是技术维护人员不到位造成,且服务器是Win2003+IIS,不稳定之余对PHP的支持也存在些微的问题. 不想去埋怨什么,期待早点完成维护即可.

  今天上午挺意外的发现服务器恢复,但我的Movie Castle页面显示却很奇怪...全屏,且上方多了一行小空行,测试浏览器为IE7.然后去Firefox下查看,发现页面的Width正常,但上方的小空行依然存在-.-

  我是善于Google的人,于是遇到不明白的先询问这本百科全书. 得到的答案是主题PHP文件编码是UTF-8 with bom造成的,至于这个bom是什么,看下这个中文解释吧.

  在UCS 编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输 字符"ZERO WIDTH NO-BREAK SPACE"。这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little- Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被称作BOM。

  UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8编码是EF BB BF。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。

  Windows就是使用BOM来标记文本文件的编码方式的。

 

  很显然...我的小空行是因为这个bom而产生的.

  找到问题后的就是解决问题.去WP群里问了声,得到了一些建议,但个人觉得CSS样式之前在相同的环境下没有一点问题,没理由现在突然显示不了! 还是先解决已知问题吧...Google告诉我了很多去除bom的方法,但操作上来讲都有点烦,最后终于找到了个称心如意滴~muhahaha 一个自动移除bom的小程序...备份后大胆的试用,果然问题立刻解决.

 

<?php
//remove the utf-8 boms
//by magicbug at gmail dot com

if (isset($_GET['dir'])){ //config the basedir
$basedir=$_GET['dir'];
}else{
$basedir = '.';
}

$auto = 1;

checkdir($basedir);

function checkdir($basedir){
if ($dh = opendir($basedir)) {
   while (($file = readdir($dh)) !== false) {
    if ($file != '.' && $file != '..'){
     if (!is_dir($basedir."/".$file)) {
      echo "filename: $basedir/
$file ".checkBOM("$basedir/$file")." <br>";
     }else{
      $dirname = $basedir."/".
$file;
      checkdir($dirname);
     }
    }
   }
closedir($dh);
}
}

function checkBOM ($filename) {
global $auto;
$contents = file_get_contents($filename);
$charset[1] = substr($contents, 0, 1);
$charset[2] = substr($contents, 1, 1);
$charset[3] = substr($contents, 2, 1);
if (ord($charset[1]) == 239 && ord($charset[2]) == 187 &&
ord($charset[3]) == 191) {
   if ($auto == 1) {
    $rest = substr($contents, 3);
    rewrite ($filename, $rest);
    return ("<font color=red>BOM found,
automatically removed.</font>");
   } else {
    return ("<font color=red>BOM found.
</font>");
   }
}
else return ("BOM Not Found.");
}

function rewrite ($filename, $data) {
$filenum = fopen($filename, "w");
flock($filenum, LOCK_EX);
fwrite($filenum, $data);
fclose($filenum);
}
?>

posted @ 2009-07-11 14:51 小马歌 阅读(518) | 评论 (0)编辑 收藏
 
tcpdump采用命令行方式,它的命令格式为:
  tcpdump [ -adeflnNOpqStvx ] [ -c 数量 ] [ -F 文件名 ]
          [ -i 网络接口 ] [ -r 文件名] [ -s snaplen ]
          [ -T 类型 ] [ -w 文件名 ] [表达式 ]

  1. tcpdump的选项介绍
   -a    将网络地址和广播地址转变成名字;
   -d    将匹配信息包的代码以人们能够理解的汇编格式给出;
   -dd    将匹配信息包的代码以c语言程序段的格式给出;
   -ddd    将匹配信息包的代码以十进制的形式给出;
   -e    在输出行打印出数据链路层的头部信息;
   -f    将外部的Internet地址以数字的形式打印出来;
   -l    使标准输出变为缓冲行形式;
   -n    不把网络地址转换成名字;
   -t    在输出的每一行不打印时间戳;
   -v    输出一个稍微详细的信息,例如在ip包中可以包括ttl和服务类型的信息;
   -vv    输出详细的报文信息;
   -c    在收到指定的包的数目后,tcpdump就会停止;
   -F    从指定的文件中读取表达式,忽略其它的表达式;
   -i    指定监听的网络接口;
   -r    从指定的文件中读取包(这些包一般通过-w选项产生);
   -w    直接将包写入文件中,并不分析和打印出来;
   -T    将监听到的包直接解释为指定的类型的报文,常见的类型有rpc (远程过程
调用)和snmp(简单       网络管理协议;)

  2. tcpdump的表达式介绍
   表达式是一个正则表达式,tcpdump利用它作为过滤报文的条件,如果一个报文满足表
达式的条件,则这个报文将会被捕获。如果没有给出任何条件,则网络上所有的信息包将会
被截获。
   在表达式中一般如下几种类型的关键字,一种是关于类型的关键字,主要包括host,
net,port, 例如 host 210.27.48.2,指明 210.27.48.2是一台主机,net 202.0.0.0 指明
202.0.0.0是一个网络地址,port 23 指明端口号是23。如果没有指定类型,缺省的类型是
host.
   第二种是确定传输方向的关键字,主要包括src , dst ,dst or src, dst and src ,
这些关键字指明了传输的方向。举例说明,src 210.27.48.2 ,指明ip包中源地址是210.27.
48.2 , dst net 202.0.0.0 指明目的网络地址是202.0.0.0 。如果没有指明方向关键字,则
缺省是src or dst关键字。
   第三种是协议的关键字,主要包括fddi,ip ,arp,rarp,tcp,udp等类型。Fddi指明是在
FDDI(分布式光纤数据接口网络)上的特定的网络协议,实际上它是"ether"的别名,fddi和e
ther具有类似的源地址和目的地址,所以可以将fddi协议包当作ether的包进行处理和分析。
其他的几个关键字就是指明了监听的包的协议内容。如果没有指定任何协议,则tcpdump将会
监听所有协议的信息包。
   除了这三种类型的关键字之外,其他重要的关键字如下:gateway, broadcast,less,
greater,还有三种逻辑运算,取非运算是 'not ' '! ', 与运算是'and','&&';或运算 是'o
r' ,'||';
   这些关键字可以组合起来构成强大的组合条件来满足人们的需要,下面举几个例子来
说明。
   (1)想要截获所有210.27.48.1 的主机收到的和发出的所有的数据包:
    #tcpdump host 210.27.48.1
   (2) 想要截获主机210.27.48.1 和主机210.27.48.2 或210.27.48.3的通信,使用命令
:(在命令行中适用   括号时,一定要
    #tcpdump host 210.27.48.1 and \ (210.27.48.2 or 210.27.48.3 \)
   (3) 如果想要获取主机210.27.48.1除了和主机210.27.48.2之外所有主机通信的ip包
,使用命令:
    #tcpdump ip host 210.27.48.1 and ! 210.27.48.2
   (4)如果想要获取主机210.27.48.1接收或发出的telnet包,使用如下命令:
    #tcpdump tcp port 23 host 210.27.48.1

  3. tcpdump 的输出结果介绍
   下面我们介绍几种典型的tcpdump命令的输出信息
   (1) 数据链路层头信息
   使用命令#tcpdump --e host ice
   ice 是一台装有linux的主机,她的MAC地址是0:90:27:58:AF:1A
   H219是一台装有SOLARIC的SUN工作站,它的MAC地址是8:0:20:79:5B:46;上一条
命令的输出结果如下所示:
21:50:12.847509 eth0 < 8:0:20:79:5b:46 0:90:27:58:af:1a ip 60: h219.33357 > ice.
telne
t 0:0(0) ack 22535 win 8760 (DF)
  分析:21:50:12是显示的时间, 847509是ID号,eth0 <表示从网络接口eth0 接受该
数据包,eth0 >表示从网络接口设备发送数据包, 8:0:20:79:5b:46是主机H219的MAC地址,它
表明是从源地址H219发来的数据包. 0:90:27:58:af:1a是主机ICE的MAC地址,表示该数据包的
目的地址是ICE . ip 是表明该数据包是IP数据包,60 是数据包的长度, h219.33357 > ice.
telnet 表明该数据包是从主机H219的33357端口发往主机ICE的TELNET(23)端口. ack 22535
表明对序列号是222535的包进行响应. win 8760表明发送窗口的大小是8760.

  (2) ARP包的TCPDUMP输出信息
   使用命令#tcpdump arp
   得到的输出结果是:
  22:32:42.802509 eth0 > arp who-has route tell ice (0:90:27:58:af:1a)
  22:32:42.802902 eth0 < arp reply route is-at 0:90:27:12:10:66 (0:90:27:58:af
:1a)
  分析: 22:32:42是时间戳, 802509是ID号, eth0 >表明从主机发出该数据包, arp表明是
ARP请求包, who-has route tell ice表明是主机ICE请求主机ROUTE的MAC地址。 0:90:27:5
8:af:1a是主机ICE的MAC地址。

  (3) TCP包的输出信息
   用TCPDUMP捕获的TCP包的一般输出信息是:
  src > dst: flags data-seqno ack window urgent options
  src > dst:表明从源地址到目的地址, flags是TCP包中的标志信息,S 是SYN标志, F (F
IN), P (PUSH) , R (RST) "." (没有标记); data-seqno是数据包中的数据的顺序号, ack是
下次期望的顺序号, window是接收缓存的窗口大小, urgent表明数据包中是否有紧急指针.
Options是选项.

  (4) UDP包的输出信息
   用TCPDUMP捕获的UDP包的一般输出信息是:
  route.port1 > ice.port2: udp lenth
  UDP十分简单,上面的输出行表明从主机ROUTE的port1端口发出的一个UDP数据包到主机
ICE的port2端口,类型是UDP, 包的长度是lenth


应用:
TCPDUMP简介

在传统的网络分析和测试技术中,嗅探器(sniffer)是最常见,也是最重要的技术之一。sniffer工具首先是为网络管理员和网络程序员进行网络分析而设计的。对于网络管理人员来说,使用嗅探器可以随时掌握网络的实际情况,在网络性能急剧下降的时候,可以通过sniffer工具来分析原因,找出造成网络阻塞的来源。对于网络程序员来说,通过sniffer工具来调试程序。

用过windows平台上的sniffer工具(例如,netxray和sniffer pro软件)的朋友可能都知道,在共享式的局域网中,采用sniffer工具简直可以对网络中的所有流量一览无余!Sniffer工具实际上就是一个网络上的抓包工具,同时还可以对抓到的包进行分析。由于在共享式的网络中,信息包是会广播到网络中所有主机的网络接口,只不过在没有使用sniffer工具之前,主机的网络设备会判断该信息包是否应该接收,这样它就会抛弃不应该接收的信息包,sniffer工具却使主机的网络设备接收所有到达的信息包,这样就达到了网络监听的效果。

Linux作为网络服务器,特别是作为路由器和网关时,数据的采集和分析是必不可少的。所以,今天我们就来看看Linux中强大的网络数据采集分析工具——TcpDump。

用简单的话来定义tcpdump,就是:dump the traffice on a network,根据使用者的定义对网络上的数据包进行截获的包分析工具。

作为互联网上经典的的系统管理员必备工具,tcpdump以其强大的功能,灵活的截取策略,成为每个高级的系统管理员分析网络,排查问题等所必备的东东之一。

顾名思义,TcpDump可以将网络中传送的数据包的“头”完全截获下来提供分析。它支持针对网络层、协议、主机、网络或端口的过滤,并提供and、or、not等逻辑语句来帮助你去掉无用的信息。

tcpdump提供了源代码,公开了接口,因此具备很强的可扩展性,对于网络维护和入侵者都是非常有用的工具。tcpdump存在于基本的FreeBSD系统中,由于它需要将网络界面设置为混杂模式,普通用户不能正常执行,但具备root权限的用户可以直接执行它来获取网络上的信息。因此系统中存在网络分析工具主要不是对本机安全的威胁,而是对网络上的其他计算机的安全存在威胁。

普通情况下,直接启动tcpdump将监视第一个网络界面上所有流过的数据包。
-----------------------
bash-2.02# tcpdump
tcpdump: listening on eth0
11:58:47.873028 202.102.245.40.netbios-ns > 202.102.245.127.netbios-ns: udp 50
11:58:47.974331 0:10:7b:8:3a:56 > 1:80:c2:0:0:0 802.1d ui/C len=43
0000 0000 0080 0000 1007 cf08 0900 0000
0e80 0000 902b 4695 0980 8701 0014 0002
000f 0000 902b 4695 0008 00
11:58:48.373134 0:0:e8:5b:6d:85 > Broadcast sap e0 ui/C len=97
ffff 0060 0004 ffff ffff ffff ffff ffff
0452 ffff ffff 0000 e85b 6d85 4008 0002
0640 4d41 5354 4552 5f57 4542 0000 0000
0000 00
^C
------------------------

首先我们注意一下,从上面的输出结果上可以看出来,基本上tcpdump总的的输出格式为:系统时间 来源主机.端口 > 目标主机.端口 数据包参数

TcpDump的参数化支持

  tcpdump支持相当多的不同参数,如使用-i参数指定tcpdump监听的网络界面,这在计算机具有多个网络界面时非常有用,使用-c参数指定要监听的数据包数量,使用-w参数指定将监听到的数据包写入文件中保存,等等。

  然而更复杂的tcpdump参数是用于过滤目的,这是因为网络中流量很大,如果不加分辨将所有的数据包都截留下来,数据量太大,反而不容易发现需要的数据包。使用这些参数定义的过滤规则可以截留特定的数据包,以缩小目标,才能更好的分析网络中存在的问题。tcpdump使用参数指定要监视数据包的类型、地址、端口等,根据具体的网络问题,充分利用这些过滤规则就能达到迅速定位故障的目的。请使用man tcpdump查看这些过滤规则的具体用法。

  显然为了安全起见,不用作网络管理用途的计算机上不应该运行这一类的网络分析软件,为了屏蔽它们,可以屏蔽内核中的bpfilter伪设备。一般情况下网络硬件和TCP/IP堆栈不支持接收或发送与本计算机无关的数据包,为了接收这些数据包,就必须使用网卡的混杂模式,并绕过标准的TCP/IP堆栈才行。在FreeBSD下,这就需要内核支持伪设备bpfilter。因此,在内核中取消bpfilter支持,就能屏蔽tcpdump之类的网络分析工具。

  并且当网卡被设置为混杂模式时,系统会在控制台和日志文件中留下记录,提醒管理员留意这台系统是否被用作攻击同网络的其他计算机的跳板。

  May 15 16:27:20 host1 /kernel: fxp0: promiscuous mode enabled

  虽然网络分析工具能将网络中传送的数据记录下来,但是网络中的数据流量相当大,如何对这些数据进行分析、分类统计、发现并报告错误却是更关键的问题。网络中的数据包属于不同的协议,而不同协议数据包的格式也不同。因此对捕获的数据进行解码,将包中的信息尽可能的展示出来,对于协议分析工具来讲更为重要。昂贵的商业分析工具的优势就在于它们能支持很多种类的应用层协议,而不仅仅只支持tcp、udp等低层协议。

  从上面tcpdump的输出可以看出,tcpdump对截获的数据并没有进行彻底解码,数据包内的大部分内容是使用十六进制的形式直接打印输出的。显然这不利于分析网络故障,通常的解决办法是先使用带-w参数的tcpdump 截获数据并保存到文件中,然后再使用其他程序进行解码分析。当然也应该定义过滤规则,以避免捕获的数据包填满整个硬盘。

TCP功能

数据过滤

不带任何参数的TcpDump将搜索系统中所有的网络接口,并显示它截获的所有数据,这些数据对我们不一定全都需要,而且数据太多不利于分析。所以,我们应当先想好需要哪些数据,TcpDump提供以下参数供我们选择数据:

-b 在数据-链路层上选择协议,包括ip、arp、rarp、ipx都是这一层的。

例如:tcpdump -b arp 将只显示网络中的arp即地址转换协议信息。

-i 选择过滤的网络接口,如果是作为路由器至少有两个网络接口,通过这个选项,就可以只过滤指定的接口上通过的数据。例如:

tcpdump -i eth0 只显示通过eth0接口上的所有报头。

src、dst、port、host、net、ether、gateway这几个选项又分别包含src、dst 、port、host、net、ehost等附加选项。他们用来分辨数据包的来源和去向,src host 192.168.0.1指定源主机IP地址是192.168.0.1,dst net 192.168.0.0/24指定目标是网络192.168.0.0。以此类推,host是与其指定主机相关无论它是源还是目的,net是与其指定网络相关的,ether后面跟的不是IP地址而是物理地址,而gateway则用于网关主机。可能有点复杂,看下面例子就知道了:

tcpdump src host 192.168.0.1 and dst net 192.168.0.0/24

过滤的是源主机为192.168.0.1与目的网络为192.168.0.0的报头。

tcpdump ether src 00:50:04:BA:9B and dst……

过滤源主机物理地址为XXX的报头(为什么ether src后面没有host或者net?物理地址当然不可能有网络喽)。

Tcpdump src host 192.168.0.1 and dst port not telnet

过滤源主机192.168.0.1和目的端口不是telnet的报头。

ip icmp arp rarp 和 tcp、udp、icmp这些选项等都要放到第一个参数的位置,用来过滤数据报的类型。
例如:

tcpdump ip src……

只过滤数据-链路层上的IP报头。

tcpdump udp and src host 192.168.0.1

只过滤源主机192.168.0.1的所有udp报头。

数据显示/输入输出

TcpDump提供了足够的参数来让我们选择如何处理得到的数据,如下所示:

-l 可以将数据重定向。

如tcpdump -l >tcpcap.txt将得到的数据存入tcpcap.txt文件中。

-n 不进行IP地址到主机名的转换。

如果不使用这一项,当系统中存在某一主机的主机名时,TcpDump会把IP地址转换为主机名显示,就像这样:eth0 < ntc9.1165> router.domain.net.telnet,使用-n后变成了:eth0 < 192.168.0.9.1165 > 192.168.0.1.telnet。

-nn 不进行端口名称的转换。

上面这条信息使用-nn后就变成了:eth0 < ntc9.1165 > router.domain.net.23。

-N 不打印出默认的域名。

还是这条信息-N 后就是:eth0 < ntc9.1165 > router.telnet。

-O 不进行匹配代码的优化。
-t 不打印UNIX时间戳,也就是不显示时间。
-tt 打印原始的、未格式化过的时间。
-v 详细的输出,也就比普通的多了个TTL和服务类型。

 
TCPDUMP的安装

 在linux下tcpdump的安装十分简单,一般由两种安装方式。一种是以rpm包的形式来进行安装。另外一种是以源程序的形式安装。
  1. rpm包的形式安装
    #rpm -ivh tcpdump-3_4a5.rpm
  这样tcpdump就顺利地安装到你的linux系统中。怎么样,很简单吧。
  2. 源程序的安装
     #tar xvfz tcpdump-3_4a5.tar.Z
    rpm的包可以使用如下命令安装:
     #rpm -ivh tcpdump-3_4a5.src.rpm
    这样就把tcpdump的源代码解压到/usr/src/redhat/SOURCES目录下.

第二步 做好编译源程序前的准备活动

在编译源程序之前,最好已经确定库文件libpcap已经安装完毕,这个库文件是tcpdump软件所需的库文件 。同样,你同时还要有一个标准的c语言编译器。在linux下标准的c 语言编译器一般是gcc。 在tcpdump的源程序目录中。有一个文件是Makefile.in,configure命令就是从Makefile.in文件中自动产生Makefile文件。在Makefile.in文件中,可以根据系统的配置来修改BINDEST 和 MANDEST 这两个宏定义,缺省值是
      BINDEST = @sbindir@
      MANDEST = @mandir@
 
第一个宏值表明安装tcpdump的二进制文件的路径名,第二个表明tcpdump的man 帮助页的路径名,你可以修改它们来满足系统的需求。

  第三步 编译源程序
 
使用源程序目录中的configure脚本,它从系统中读出各种所需的属性。并且根据Makefile.in文件自动生成Makefile文件,以便编译使用.make 命令则根据Makefile文件中的规则编译tcpdump的源程序。使用make install命令安装编译好的tcpdump的二进制文件。
 
总结一下就是:
 
      # tar xvfz tcpdump-3_4a5.tar.Z
      # vi Makefile.in
      # . /configure
      # make
      # make install
posted @ 2009-07-10 12:44 小马歌 阅读(137) | 评论 (0)编辑 收藏
 
调用:
strace [ -dffhiqrtttTvxx ] [ -acolumn ] [ -eexpr ] ...
[ -ofile ] [ -ppid ] ... [ -sstrsize ] [ -uusername ] [ command [ arg ... ] ]

strace -c [ -eexpr ] ... [ -Ooverhead ] [ -Ssortby ] [ command [ arg ... ] ]
功能:
跟踪程式执行时的系统调用和所接收的信号.通常的用法是strace执行一直到commande结束.
并且将所调用的系统调用的名称、参数和返回值输出到标准输出或者输出到-o指定的文件.
strace是一个功能强大的调试,分析诊断工具.你将发现他是一个极好的帮手在你要调试一个无法看到源码或者源码无法在编译的程序.
你将轻松的学习到一个软件是如何通过系统调用来实现他的功能的.而且作为一个程序设计师,你可以了解到在用户态和内核态是如何通过系统调用和信号来实现程序的功能的.
strace的每一行输出包括系统调用名称,然后是参数和返回值.这个例子:
strace cat /dev/null
他的输出会有:
open(\\"/dev/null\\",O_RDONLY) = 3
有错误产生时,一般会返回-1.所以会有错误标志和描述:
open(\\"/foor/bar\\",)_RDONLY) = -1 ENOENT (no such file or directory)
信号将输出喂信号标志和信号的描述.跟踪并中断这个命令\\"sleep 600\\":
sigsuspend({}
--- SIGINT (Interrupt) ---
+++ killed by SIGINT +++
参数的输出有些不一致.如shell命令中的 \\">>tmp\\",将输出:
open(\\"tmp\\",O_WRONLY|O_APPEND|A_CREAT,0666) = 3
对于结构指针,将进行适当的显示.如:\\"ls -l /dev/null\\":
lstat(\\"/dev/null\\",{st_mode=S_IFCHR|0666},st_rdev=makdev[1,3],...}) = 0
请注意\\"struct stat\\" 的声明和这里的输出.lstat的第一个参数是输入参数,而第二个参数是向外传值.
当你尝试\\"ls -l\\" 一个不存在的文件时,会有:
lstat(/foot/ball\\",0xb004) = -1 ENOENT (no such file or directory)
char*将作为C的字符串类型输出.没有字符串输出时一般是char* 是一个转义字符,只输出字符串的长度.
当字符串过长是会使用\\"...\\"省略.如在\\"ls -l\\"会有一个gepwuid调用读取password文件:
read(3,\\"root::0:0:System Administrator:/\\"...,1024) = 422
当参数是结构数组时,将按照简单的指针和数组输出如:
getgroups(4,[0,2,4,5]) = 4
关于bit作为参数的情形,也是使用方括号,并且用空格将每一项参数隔开.如:
sigprocmask(SIG_BLOCK,[CHLD TTOU],[]) = 0
这里第二个参数代表两个信号SIGCHLD 和 SIGTTOU.如果bit型参数全部置位,则有如下的输出:
sigprocmask(SIG_UNBLOCK,~[],NULL) = 0
这里第二个参数全部置位.

参数说明:
-c 统计每一系统调用的所执行的时间,次数和出错的次数等.
-d 输出strace关于标准错误的调试信息.
-f 跟踪由fork调用所产生的子进程.
-ff 如果提供-o filename,则所有进程的跟踪结果输出到相应的filename.pid中,pid是各进程的进程号.
-F 尝试跟踪vfork调用.在-f时,vfork不被跟踪.
-h 输出简要的帮助信息.
-i 输出系统调用的入口指针.
-q 禁止输出关于脱离的消息.
-r 打印出相对时间关于,,每一个系统调用.
-t 在输出中的每一行前加上时间信息.
-tt 在输出中的每一行前加上时间信息,微秒级.
-ttt 微秒级输出,以秒了表示时间.
-T 显示每一调用所耗的时间.
-v 输出所有的系统调用.一些调用关于环境变量,状态,输入输出等调用由于使用频繁,默认不输出.
-V 输出strace的版本信息.
-x 以十六进制形式输出非标准字符串
-xx 所有字符串以十六进制形式输出.
-a column
设置返回值的输出位置.默认为40.
-e expr
指定一个表达式,用来控制如何跟踪.格式如下:
[qualifier=][!]value1[,value2]...
qualifier只能是 trace,abbrev,verbose,raw,signal,read,write其中之一.value是用来限定的符号或数字.默认的qualifier是 trace.感叹号是否定符号.例如:
-eopen等价于 -e trace=open,表示只跟踪open调用.而-etrace!=open表示跟踪除了open以外的其他调用.有两个特殊的符号 all 和 none.
注意有些shell使用!来执行历史记录里的命令,所以要使用\\\\.
-e trace=set
只跟踪指定的系统调用.例如:-e trace=open,close,rean,write表示只跟踪这四个系统调用.默认的为set=all.
-e trace=file
只跟踪有关文件操作的系统调用.
-e trace=process
只跟踪有关进程控制的系统调用.
-e trace=network
跟踪与网络有关的所有系统调用.
-e strace=signal
跟踪所有与系统信号有关的系统调用
-e trace=ipc
跟踪所有与进程通讯有关的系统调用
-e abbrev=set
设定strace输出的系统调用的结果集.-v 等与 abbrev=none.默认为abbrev=all.
-e raw=set
将指定的系统调用的参数以十六进制显示.
-e signal=set
指定跟踪的系统信号.默认为all.如signal=!SIGIO(或者signal=!io),表示不跟踪SIGIO信号.
-e read=set
输出从指定文件中读出的数据.例如:
-e read=3,5
-e write=set
输出写入到指定文件中的数据.
-o filename
strace的输出写入文件filename
-p pid
跟踪指定的进程pid.
-s strsize
指定输出的字符串的最大长度.默认为32.文件名一直全部输出.
-u username
以username的UID和GID执行被跟踪的命令.

strace调试程序

     在理想世界里,每当一个程序不能正常执行一个功能时,它就会给出一个有用的错误提示,告诉你在足够的改正错误的线索。但遗憾的是,我们不是生活在理想世界里,起码不总是生活在理想世界里。有时候一个程序出现了问题,你无法找到原因。

这就是调试程序出现的原因。strace是一个必不可少的调试工具,strace用来监视系统调用。你不仅可以调试一个新开始的程序,也可以调试一个已经在运行的程序(把strace绑定到一个已有的PID上面)。

首先让我们看一个真实的例子:

[BOLD]启动KDE时出现问题[/BOLD]

前一段时间,我在启动KDE的时候出了问题,KDE的错误信息无法给我任何有帮助的线索。

代码:

_KDE_IceTransSocketCreateListener: failed to bind listener
_KDE_IceTransSocketUNIXCreateListener: ...SocketCreateListener() failed
_KDE_IceTransMakeAllCOTSServerListeners: failed to create listener for local

Cannot establish any listening sockets DCOPServer self-test failed.

对我来说这个错误信息没有太多意义,只是一个对KDE来说至关重要的负责进程间通信的程序无法启动。我还可以知道这个错误和ICE协议(Inter Client Exchange)有关,除此之外,我不知道什么是KDE启动出错的原因。

我决定采用strace看一下在启动dcopserver时到底程序做了什么:

代码:

strace -f -F -o ~/dcop-strace.txt dcopserver

这里 -f -F选项告诉strace同时跟踪fork和vfork出来的进程,-o选项把所有strace输出写到~/dcop-strace.txt里面,dcopserver是要启动和调试的程序。

再次出现错误之后,我检查了错误输出文件dcop-strace.txt,文件里有很多系统调用的记录。在程序运行出错前的有关记录如下:

代码:

27207 mkdir("/tmp/.ICE-unix", 0777) = -1 EEXIST (File exists)
27207 lstat64("/tmp/.ICE-unix", {st_mode=S_IFDIR|S_ISVTX|0755, st_size=4096, ...}) = 0
27207 unlink("/tmp/.ICE-unix/dcop27207-1066844596") = -1 ENOENT (No such file or directory)
27207 bind(3, {sin_family=AF_UNIX, path="/tmp/.ICE-unix/dcop27207-1066844596"}, 3 = -1 EACCES (Permission denied)
27207 write(2, "_KDE_IceTrans", 13) = 13
27207 write(2, "SocketCreateListener: failed to "..., 46) = 46
27207 close(3) = 0 27207 write(2, "_KDE_IceTrans", 13) = 13
27207 write(2, "SocketUNIXCreateListener: ...Soc"..., 59) = 59
27207 umask(0) = 0 27207 write(2, "_KDE_IceTrans", 13) = 13
27207 write(2, "MakeAllCOTSServerListeners: fail"..., 64) = 64
27207 write(2, "Cannot establish any listening s"..., 39) = 39

其中第一行显示程序试图创建/tmp/.ICE-unix目录,权限为0777,这个操作因为目录已经存在而失败了。第二个系统调用(lstat64)检查 了目录状态,并显示这个目录的权限是0755,这里出现了第一个程序运行错误的线索:程序试图创建属性为0777的目录,但是已经存在了一个属性为 0755的目录。第三个系统调用(unlink)试图删除一个文件,但是这个文件并不存在。这并不奇怪,因为这个操作只是试图删掉可能存在的老文件。

但是,第四行确认了错误所在。他试图绑定到/tmp/.ICE-unix/dcop27207-1066844596,但是出现了拒绝访问错误。. ICE_unix目录的用户和组都是root,并且只有所有者具有写权限。一个非root用户无法在这个目录下面建立文件,如果把目录属性改成0777, 则前面的操作有可能可以执行,而这正是第一步错误出现时进行过的操作。

所以我运行了chmod 0777 /tmp/.ICE-unix之后KDE就可以正常启动了,问题解决了,用strace进行跟踪调试只需要花很短的几分钟时间跟踪程序运行,然后检查并分析输出文件。

说明:运行chmod 0777只是一个测试,一般不要把一个目录设置成所有用户可读写,同时不设置粘滞位(sticky bit)。给目录设置粘滞位可以阻止一个用户随意删除可写目录下面其他人的文件。一般你会发现/tmp目录因为这个原因设置了粘滞位。KDE可以正常启动 之后,运行chmod +t /tmp/.ICE-unix给.ICE_unix设置粘滞位。

解决库依赖问题

starce 的另一个用处是解决和动态库相关的问题。当对一个可执行文件运行ldd时,它会告诉你程序使用的动态库和找到动态库的位置。但是如果你正在使用一个比较老 的glibc版本(2.2或更早),你可能会有一个有bug的ldd程序,它可能会报告在一个目录下发现一个动态库,但是真正运行程序时动态连接程序 (/lib/ld-linux.so.2)却可能到另外一个目录去找动态连接库。这通常因为/etc/ld.so.conf和 /etc/ld.so.cache文件不一致,或者/etc/ld.so.cache被破坏。在glibc 2.3.2版本上这个错误不会出现,可能ld-linux的这个bug已经被解决了。

尽管这样,ldd并不能把所有程序依赖的动态库列出 来,系统调用dlopen可以在需要的时候自动调入需要的动态库,而这些库可能不会被ldd列出来。作为glibc的一部分的NSS (Name Server Switch)库就是一个典型的例子,NSS的一个作用就是告诉应用程序到哪里去寻找系统帐号数据库。应用程序不会直接连接到NSS库,glibc则会通 过dlopen自动调入NSS库。如果这样的库偶然丢失,你不会被告知存在库依赖问题,但这样的程序就无法通过用户名解析得到用户ID了。让我们看一个例 子:

whoami程序会给出你自己的用户名,这个程序在一些需要知道运行程序的真正用户的脚本程序里面非常有用,whoami的一个示例输出如下:
代码:

# whoami
root

假设因为某种原因在升级glibc的过程中负责用户名和用户ID转换的库NSS丢失,我们可以通过把nss库改名来模拟这个环境:
代码:

# mv /lib/libnss_files.so.2 /lib/libnss_files.so.2.backup
# whoami
whoami: cannot find username for UID 0

这里你可以看到,运行whoami时出现了错误,ldd程序的输出不会提供有用的帮助:
代码:

# ldd /usr/bin/whoami
libc.so.6 => /lib/libc.so.6 (0x4001f000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

你只会看到whoami依赖Libc.so.6和ld-linux.so.2,它没有给出运行whoami所必须的其他库。这里时用strace跟踪whoami时的输出:
代码:

strace -o whoami-strace.txt whoami

open("/lib/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/lib/i686/mmx/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/lib/i686/mmx", 0xbffff190) = -1 ENOENT (No such file or directory)
open("/lib/i686/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/lib/i686", 0xbffff190) = -1 ENOENT (No such file or directory)
open("/lib/mmx/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/lib/mmx", 0xbffff190) = -1 ENOENT (No such file or directory)
open("/lib/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/lib", {st_mode=S_IFDIR|0755, st_size=2352, ...}) = 0
open("/usr/lib/i686/mmx/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/usr/lib/i686/mmx", 0xbffff190) = -1 ENOENT (No such file or directory)
open("/usr/lib/i686/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)

你可以发现在不同目录下面查找libnss.so.2的尝试,但是都失败了。如果没有strace这样的工具,很难发现这个错误是由于缺少动态库造成的。现在只需要找到libnss.so.2并把它放回到正确的位置就可以了。

限制strace只跟踪特定的系统调用

如果你已经知道你要找什么,你可以让strace只跟踪一些类型的系统调用。例如,你需要看看在configure脚本里面执行的程序,你需要监视的系统调用就是execve。让strace只记录execve的调用用这个命令:

代码:

strace -f -o configure-strace.txt -e execve ./configure

部分输出结果为:
代码:

2720 execve("/usr/bin/expr", ["expr", "a", ":", "(a)"], [/* 31 vars */]) = 0
2725 execve("/bin/basename", ["basename", "./configure"], [/* 31 vars */]) = 0
2726 execve("/bin/chmod", ["chmod", "+x", "conftest.sh"], [/* 31 vars */]) = 0
2729 execve("/bin/rm", ["rm", "-f", "conftest.sh"], [/* 31 vars */]) = 0
2731 execve("/usr/bin/expr", ["expr", "99", "+", "1"], [/* 31 vars */]) = 0
2736 execve("/bin/ln", ["ln", "-s", "conf2693.file", "conf2693"], [/* 31 vars */]) = 0

你 已经看到了,strace不仅可以被程序员使用,普通系统管理员和用户也可以使用strace来调试系统错误。必须承认,strace的输出不总是容易理 解,但是很多输出对大多数人来说是不重要的。你会慢慢学会从大量输出中找到你可能需要的信息,像权限错误,文件未找到之类的,那时strace就会成为一 个有力的工具了。
posted @ 2009-07-10 12:27 小马歌 阅读(573) | 评论 (0)编辑 收藏
 

from : http://hi.baidu.com/xiaochongs/blog/item/23a70b5592e662c4b645aef2.html

Windows系统一样Linux也有静态/动态链接库,下面介绍创建和使用方法: 
   

假设有下面几个文件: 
头文件String.h,声明相关函数原形,内容如下: 
Strlen.c
:函数Strlen的实现,获取给定字符串的长度,内容如下: 
Strlnen.c
:函数StrNlen的实现,获取给定字符串的长度,如果输入字符串的长度大于指定的最大长度,则返回最大长度,否者返回字符串的实际长度,内容如下: 
生成静态库: 
 
利用GCC生成对应目标文件: 
gcc –c Strlen.c Strnlen.c 
如果对应的文件没有错误,gcc会对文件进行编译生成Strlen.oStrnlen.o两个目标文件(相当于windows下的obj文件)。然后用ar创建一个名字为libstr.a的库文件,并把Strlen.o Strnlen.o的内容插入到对应的库文件中。,相关命令如下: 
ar –rc libstr.a Strlen.o Strnlen.o 
命令执行成功以后,对应的静态库libstr.a已经成功生成。 

/*********************************** 
Filename : String.h 
Description : 
Author   : HCJ 
Date     : 2006-5-7 
************************************/ 

int Strlen(char *pStr); 
int StrNlen(char *pStr, unsigned long ulMaxLen); 



/************************************** 
Filename    : get string length 
Description  :  
Author      : HCJ 
Date        : 2006/5/7 
**************************************/ 
#include<stdio.h> 
#include<assert.h> 
int Strlen(char *pStr) 

    unsigned long ulLength; 
    assert(NULL != pStr); 
    ulLength = 0; 
    while(*pStr++) 
    { 
        ulLength++; 
    } 
    return ulLength; 




********************************************** 
Fileneme: mystrnlen.c 
Description: get input string length,if string large 
             max length input return max length, 
             else real length 
Author: HCJ 
Date  : 2006-5-7 
**********************************************/ 
#include<stdio.h> 
#include<assert.h> 
int StrNlen(char *pStr, unsigned long ulMaxLen) 

    unsigned long ulLength; 
    assert(NULL != pStr); 
    if(ulMaxLen <= 0) 
    { 
        printf("Wrong Max Length!\n"); 
        return -1; 
    } 
    ulLength = 0; 
    while(*pStr++ &&  ulLength < ulMaxLen) 
    { 
        ulLength++; 
    } 
    return ulLength; 
}




生成动态链接库: 
 gcc  -fpic -shared -o libstr.so  Strlen.c Strnlen.c 
-fpic 
使输出的对象模块是按照可重定位地址方式生成的。 
-shared
指定把对应的源文件生成对应的动态链接库文件libstr.so文件。 
对应的链接库已经生成,下面看一下如何使用对应的链接库。 
静态库的使用: 
假设有下面的文件要使用对应的的静态库
编译生成对应的目标文件: 
gcc -c -I/home/hcj/xxxxxxxx main.c  
生成可执行文件: 
gcc -o main1 -L/home/hcj/xxxxxxxx main.o libstr.a  
其中-I/home/hcj/xxxxxxxx-L/home/hcj/xxxxxxxx是通过-I-L指定对应的头文件和库文件的路径。libstr.a是对应的静态库的名称。这样对应的静态库已经编译到对应的可执行程序中。执行对应的可执行文件便可以对应得函数调用的结果。 

/***************************************** 
FileName: main.c 
Description: test static/dynamic library 
Author: HCJ 
Date  : 2005-5-7 
******************************************/ 
#include<stdio.h> 
#include <String.h>   //
静态库对应函数的头文件 
int main(int argc, char* argv[]) 

    char str[] = {"hello world"}; 
    unsigned long ulLength = 0; 
    printf("The string is : %s\n", str); 
    ulLength = Strlen(str); 
    printf("The string length is : %d(use Strlen)\n", ulLength); 
    ulLength = StrNlen(str, 10); 
    printf("The string length is : %d(use StrNlen)\n", ulLength); 
    return 0; 




动态库的分为隐式调用和显式调用两种调用方法: 
隐式调用的使用使用方法和静态库的调用差不多,具体方法如下: 
gcc -c -I/home/hcj/xxxxxxxx main.c  
gcc -o main1 -L/home/hcj/xxxxxxxx main.o libstr.so  //
这里是*.so 
在这种调用方式中,需要维护动态链接库的配置文件/etc/ld.so.conf来让动态链接库为系统所使用,通常将动态链接库所在目录名追加到动态链接库配置文件中。否则在执行相关的可执行文件的时候就会出现载入动态链接库失败的现象。在编译所引用的动态库时,可以在gcc采用 –l-L选项或直接引用所需的动态链接库方式进行编译。在Linux里面,可以采用ldd命令来检查程序依赖共享库。 
显式调用: 

/***************************************** 
FileName: main2.c 
Description: test static/dynamic library 
Author: HCJ 
Date  : 2005-5-7 
******************************************/ 
#include<stdio.h> 
#include<dlfcn.h> 
int main(int argc, char* argv[]) 

    //define function pointor 
    int (*pStrlenFun)(char* pStr);     //
声明对应的函数的函数指针 
    int (*pStrnlenFun)(char* pStr, int ulMaxLen); 
    char str[] = {"hello world"}; 
    unsigned long ulLength = 0; 
    void *pdlHandle; 
    char *pszErr; 
    pdlHandle = dlopen("./libstr.so", RTLD_LAZY);  //
加载链接库/libstr.so 
    if(!pdlHandle) 
    { 
        printf("Failed load library\n"); 
    } 
    pszErr = dlerror(); 
    if(pszErr != NULL) 
    { 
        printf("%s\n", pszErr); 
        return 0; 
    } 
    //get function from lib 
    pStrlenFun = dlsym(pdlHandle, "Strlen"); //
获取函数的地址 
    pszErr = dlerror(); 
    if(pszErr != NULL) 
    { 
        printf("%s\n", pszErr); 
        return 0; 
    } 
    pStrnlenFun = dlsym(pdlHandle, "StrNlen"); 
    pszErr = dlerror(); 
    if(pszErr != NULL) 
    { 
        printf("%s\n", pszErr); 
        return 0; 
    } 
    printf("The string is : %s\n", str); 
    ulLength = pStrlenFun(str);   //
调用相关的函数 
    printf("The string length is : %d(use Strlen)\n", ulLength); 
    ulLength = pStrnlenFun(str, 10); 
    printf("The string length is : %d(use StrNlen)\n", ulLength); 
 dlclose(pdlHandle); 
    return 0; 





gcc -o mian2 -ldl main2.c 

gcc编译对应的源文件生成可执行文件,-ldl选项,表示生成的对象模块需要使用共享库。执行对应得文件同样可以得到正确的结果。 
相关函数的说明如下: 
(1)dlopen() 
第一个参数:指定共享库的名称,将会在下面位置查找指定的共享库。 
-环境变量LD_LIBRARY_PATH列出的用分号间隔的所有目录。 
-文件/etc/ld.so.cache中找到的库的列表,用ldconfig维护。 
-目录usr/lib 
-目录/lib 
-当前目录。 
第二个参数:指定如何打开共享库。 
RTLD_NOW:将共享库中的所有函数加载到内存 
RTLD_LAZY:会推后共享库中的函数的加载操作,直到调用dlsym()时方加载某函数 
(2)dlsym() 
调用dlsym时,利用dlopen()返回的共享库的phandle以及函数名称作为参数,返回要加载函数的入口地址。 
(3)dlerror() 
该函数用于检查调用共享库的相关函数出现的错误。 
 
这样我们就用简单的例子说明了在Linux下静态/动态库的创建和使用。                                                                                                                                                                                                                                                      

posted @ 2009-07-10 11:54 小马歌 阅读(273) | 评论 (0)编辑 收藏
 
from :http://blog.163.com/qj_l12@126/blog/static/35930826200852724816969/

本文将讨论在PHP4环境下如何使用进程间通讯机制——IPC(Inter-Process-Communication)。本文讨论的软件环境是linux+php4.0.4或更高版本。首先,我们假设你已经装好了PHP4和UNIX, 为了使得php4可以使用共享内存和信号量,必须在编译php4程序时激活shmop和sysvsem这两个扩展模块。

  实现方法:在PHP设定(configure)时加入如下选项。

--enable-shmop --enable-sysvsem 

  这样就使得你的PHP系统可以处理相关的IPC函数了。

  IPC是什么?

  IPC (Inter-process communication) 是一个Unix标准通讯机制,它提供了使得在同一台主机不同进程之间可以互相通讯的方法。基本的IPC处理机制有3种:它们分别是共享内存、信号量和消息队列。本文中我们主要讨论共享内存和信号量的使用。关于消息队列,笔者在不久的将来还会专门介绍。

  在PHP中使用共享内存段

  在不同的处理进程之间使用共享内存是一个实现不同进程之间相互通讯的好方法。如果你在一个进程中向所共享的内存写入一段信息,那么所有其他的进程也可以看到这段被写入的数据。非常方便。在PHP中有了共享内存的帮助,你可以实现不同进程在运行同一段PHP脚本时返回不同的结果。或实现对PHP同时运行数量的实时查询等等。

  共享内存允许两个或者多个进程共享一给定的存储区。因为数据不需要在客户机和服务器之间复制,所以这是最快的一种IPC。使用共享内存的唯一窍门是多个进程对一给定存储区的同步存取。

  如何建立一个共享内存段呢?下面的代码可以帮你建立共享内存。

$shm_id = shmop_open($key, $mode, $perm, $size);

  注意,每个共享内存段都有一个唯一的ID, 在PHP中,shmop_open会把建立好的共享内存段的ID返回,这里我们用$shm_id记录它。而$key是一个我们逻辑上表示共享内存段的 Key值。不同进程只要选择同一个Key id就可以共享同一段存储段。习惯上我们用一个串(类似文件名一样的东西)的散列值作为key id. $mode指明了共享内存段的使用方式。这里由于是新建,因此值为’c’ –取create之意。如果你是访问已经建立过的共享内存那么请用’a’,-- 取access之意。$perm参数定义了访问的权限,8进制,关于权限定义请看UNIX文件系统帮助。$size定义了共享内存的大小。尽管有点象 fopen(文件处理)你可不要当它同文件处理一样。后面的描述你将看到着一点。

  例如:

$shm_id = shmop_open(0xff3, "c", 0644, 100);

  这里我们打开了一个共享内存段 键值0xff3 –rw-r—r—格式,大小为100字节。

  如果需要访问已有的共享内存段,你必须在调用shmop_open中设第3、4个参数为0。

  IPC工作状态的查询

  在Unix下,你可以用一个命令行程序ipcs查询系统所有的IPC资源状态。不过有些系统要求需要超级用户方能执行。下图是一段ipcs的运行结果。

  上图中系统显示了4个共享内存段,注意其中第4个键值为0x00000ff3的就是我们刚刚运行过的PHP程序所创建的。关于ipcs的用法请参考UNIX用户手册。

  如何释放共享内存呢

  释放共享内存的办法是调用PHP指令:shmop_delete($id)

shmop_delete($id);

  $id 就是你调用shmop_open所存的shmop_op的返回值。还有一个办法就是用UNIX的管理指令:

  ipcrm id, id就是你用ipcs看到的ID.和你程序中的$id不一样。不过要小心,如果你用ipcrm直接删除共享内存段那么有可能导致其他不知道这一情况的进程在引用这个已经不复存在的共享内存器时出现一些不可预测的错误(往往结果不妙)。

  如何使用(读写)共享内存呢

  使用如下所示函数向共享内存写入数据

int shmop_write (int shmid, string data, int offset)

  其中shmid是用shmop_open返回的句柄。$Data变量存放了要存放的数据。$offset描述了写入从共享内存的开始第一个字节的位置(以0开始)。

  读取操作是:

string shmop_read (int shmid, int start, int count)

  同样,指明$shmid,开始偏移量(以0开始)、总读取数量。返回结果串。这样,你就可以把共享内存段当作是一个字节数组。读几个再写几个,想干嘛就干嘛,十分方便。

  多进程问题的考虑

  现在,在单独的一个PHP进程中读写、创建、删除共享内存方面上你应该没有问题了。但是,显然实际运行中不可能只是一个PHP进程在运行中。如果在多个进程的情况下你还是沿用单个进程的处理方法,你一定会碰到问题 ---- 著名的并行和互斥问题。比如说有2个进程同时需要对同一段内存进行读写。当两个进程同时执行写入操作时,你将得到一个错误的数据,因为该段内存将之可能是最后执行的进程的内容,甚至是由2个进程写入的数据轮流随机出现的一段混合的四不象。这显然是不能接受的。为了解决这个问题,我们必须引入互斥机制。互斥机制在很多操作系统的教材上都有专门讲述,这里不多重复。实现互斥机制的最简单办法就是使用信号灯。信号量是另外一种进程间通讯(IPC)的方式,它同其他IPC机构(管道、FIFO、消息队列)不同。它是一个记数器,用于控制多进程对共享数据的存储。同样的是你可以用ipcs和ipcrm实现对信号灯使用状态的查询和对其实现删除操作。在PHP中你可以用下列函数创建一个新的信号量并返回操作该信号量的句柄。如果该key指向的信号量已经存在, sem_get直接返回操作该信号量的句柄。

int sem_get (int key [, int max_acquire [, int perm]])

  $max_acquire 指明同时最多可以用几个进程进入该信号而不必等待该信号被释放(也就是最大同时处理某一资源的进程数目,一般该值均为一)。$perm指明了访问权限。

  一旦你成功的拥有了一个信号量,你对它所能做的只有2种:请求、释放。当你执行释放操作时, 系统将把该信号值减一。如果小于0那就还设为0。而当你执行请求操作时,系统将把该信号值加一,如果该值大于设定的最大值那么系统将挂起你的处理进程直到其他进程释放到小于最大值为止。一般情况下最大值设为1,这样一来当一个进程获得请求时其他后面的进程只能等待它退出互斥区后释放信号量才能进入该互斥区并同时设为独占方式。这样的信号量常称为双态信号量。当然,如果初值是任意一个正数就表明有多少个共享资源单位可供共享应用。

  申请、释放操作的PHP格式如下:

int sem_acquire (int sem_identifier) 申请
int sem_release (int sem_identifier) 释放
其中sem_identifier是调用sem_get的返回值(句柄)。 
一个简单的互斥协议例子
下面是一段很简单的互斥操作规程。
$semid=sem_get(0xee3,1,0666);
$shm_id = shmop_open(0xff3, "c", 0644, 100);
sem_acquire($semid);      //申请
/* 进入临界区*/
  这里,对共享内存进行处理
sem_release($semid);      //释放

  正如你所看到的,互斥的实现很简单:申请进入临界区,对临界区资源进行操作(比如修改共享内存)退出临界区并释放信号。这样一来就可以保证在同一个时间片中不可能有同时2个进程对同一段共享内存进行操作。因为信号量机制保证一个时间片只能由一个进程进入,其他进程必须等待当前处理的进程完成后方能进入。

  临界区一般是指那些不允许同时有多个进程并发处理的代码段。

  要注意的是:在PHP中必须由同一个进程释放它所占用的信号量。在一般系统中允许进程释放别的进程占用的信号。在编写临界区代码一定要小心设计资源的分配,避免A等B,B等A的死锁情况发生。 

  运 用

  IPC的运用是十分广泛的。比如,在不同进程间保存一个解释过的复杂的配置文件、或具体设置的用户等,以避免重复处理。我也曾经用共享内存的技术把一大批PHP脚本必须引用的一个很大的文件放入共享内存,并由此显著提升了Web服务的速度、消除了部分瓶颈。关于它的使用还有聊天室,多路广播等等。IPC的威力取决于你的想象力的大小。如果本文对你有一点点启发,那我不胜荣幸。愿意很你讨论这令人入迷的电脑技术。Email: qwyaxm@163.net

posted @ 2009-07-10 11:50 小马歌 阅读(137) | 评论 (0)编辑 收藏
 
from : http://hi.baidu.com/yancncen/blog/item/b6e0ad38031b06cbd4622547.html

联系作者,请加qq:1-1-3-8-5-7-1-5-4

thrift里的c++ lib支持很多种协议,不过鉴于有些协议在别的语言的thrift lib并没有得到支持,如php只支持binaryprotocol协议。所以,建议交互都走binaryprotocol协议,在此也只分析binaryprotocol的协议。

废话不说了,直入正题

binaryprotocol协议分析:

使用工具:
strace、tcpdump、vi、thrift及其源码

(1)0-4个字节:
协议版本|消息类型 (对于TBinaryProtocol.cpp而言协议版本为0x80010000和消息类型进行或运算)
其中消息类型包括:call == 1, reply == 2, excetpion == 3

(2)4-8字节:
请求的函数名称的长度,这里假设为functionNameLen


(3)8-functionNameLen字节{functionNameLen为请求函数名的长度}:
请求的函数名称名称

(4)functionNameLen-functionNameLen+4个字节:(4个字节)
请求的序列号
(貌似生成的代码里面,不管是哪个请求序列号都为0)


如果function没有参数:
最后一个字节为0

参数具有以下形式:{类型}{序号}{值}, 详细请看下面的解释

如果function有参数:
(5)functionNameLen+4-functionNameLen+5个字节:(1个字节)
参数1的类型, 包括以下类型:

参数类型表:
T_STOP       = 0,
T_VOID       = 1,
T_BOOL       = 2,
T_BYTE       = 3,
T_I08        = 3,
T_I16        = 6,
T_I32        = 8,
T_U64        = 9,
T_I64        = 10,
T_DOUBLE     = 4,
T_STRING     = 11,
T_UTF7       = 11,
T_STRUCT     = 12,
T_MAP        = 13,
T_SET        = 14,
T_LIST       = 15,
T_UTF8       = 16,
T_UTF16      = 17

(6)functionNameLen+5-functionNameLen+7个字节:(2个字节)
参数序号,取决于你定义的idl文件中参数所定义的序号


(7)接下来的n个字节,取决于参数的类型:

a)对于以下具有固定长度的简单数据类型的参数:
T_STOP       = 0, n==1
T_VOID       = 1,   n==1
T_BOOL       = 2, n==1
T_BYTE       = 3, n==1
T_I08        = 3, n==1
T_I16        = 6, n==2
T_I32        = 8, n==4
T_U64        = 9, n==8 ? (虽然给出了定义,但是TBinaryProtocol.cpp并没有实现,
     所以,如果要使用该数据类型的必须注意, 应该使用string类型来代替它
     unsigned long long 类型就需要特别注意了)
T_I64        = 10, n==8
T_DOUBLE     = 4, n==8   (double在目标机器上必须是8个字节的,符合IEC-559标准的浮点数,貌似对我们没有影响)
这n个字节就是参数的值。


以下的数据类型被我归为复合数据类型:

b)对于String,这n个字节包含以下内容:
前面4个字节:字符串的长度stringLen
接下来的stringLen个字节:字符串的内容

c)对于struct,这n个字节包含以下内容:
   假设这个结构体包含m个字段:(为了便于说明问题,下面所说的字节偏移是相对于struct内部结构而言的)
   0-1字节:字段的数据类型
   1-3字节:字段序号,取决于你定义的idl文件中参数所定义的序号

   接下来的k个字节:goto (7)
   以此类推,直至m个字段
   其实,struct的字段和函数参数具有一样的编码方式

d)对于set,这n个字节包含以下内容:(为了便于说明问题,下面所说的字节偏移是相对于set内部结构而言的)
   0-1字节:set里面的元素的数据类型
   1-5字节:元素个数
   假设元素的数据类型的长度为k个字节,那么接下来每k个字节作为一个元素值,至于元素值的分析,请goto(7)
   注意,这里和函数参数/struct的区别在于,这里不存在元素的序号值

e)对于list,这n个字节包含以下内容:
和set类似,这里就不重复累赘了。
值得注意的一点是,thrift白皮书提到了“list<type> An ordered list of elements.”,实际上,list在映射到stl的list时并不是经过排序的list。

f)对于map,这n个字节包含以下内容:(为了便于说明问题,下面所说的字节偏移是相对于map内部结构而言的)
0-1字节:key的数据类型。注意,可能是复合数据类型
1-2字节:value的数据类型。
假设key的数据类型的长度为k个字节,value的数据类型的长度为v个字节
那么接下来每k+v个字节作为一个key-value值,
至于key的值的分析和value的值的分析,请goto(7)

总结:
(1)关于定义idl的一些总结,尽量避免定义过于复杂的数据结构。

从上面的协议分析来看,复合数据类型的存在着一个递归包含的关系。
不过thrift在生成封/解包的代码里,并没有出现递归调用来封/解包,而是采用了循环嵌套循环的方式来生成代码,
这种做法避免了频繁递归调用封/解包函数,可提高封/解包的效率。同时带来的问题就是生成的代码量的急剧膨胀。

虽然没有递归调用来封/解包, 如果定义太过于复杂的数据结构也会随之产生多重循环,看下面的例子
假设定义以下一个数据结构:
map< string, list< set<string> > >,thrift将会产生类似于以下的循环来进行封/解包:
foreach (key in map)
{
foreach ( set in map[key] )
{
    foreach (string in set )
      encode()/decode();  
}
}

假设map,list,set的元素各有100个,这将是一个严重影响性能的地方,应该避免。

(2)建议使用了unsigned long long的字段使用string类型,而不是u64类型,因为目前的thrift不支持。

(3)在网络IO层一个潜在的瓶颈
由于thrift的binaryprotocol协议的包头没有任何的字节描述了整个网络包的长度的信息。
所以thrift的binaryprotocol协议在解包的时候是每次都只能采用从socket读取一个变量的类型接着读取变量的值出来这样的解释方式。
这种解包的方式可能引起的潜在问题:
当请求的client数量非常多,交互的数据量也非常多(这里可能是交互了很多字段,或者使用了太多复合数据类型)时,tcp/ip协议栈的缓冲区可能会被塞满了
还没有被处理的数据,就会严重影响服务质量。

至于为何不提供某些字节来标识整个数据包的长度,是因为thrift的binaryprotocol协议需要支持复杂数据类型,像set,list,map,而这些复合数据类型的大小是难以确定的。
为了支持标识整个数据包长度,封包前需要知道set,list,map的总体大小,那么就需要遍历set,list,map的大小,这是相当不划算,会增加运算逻辑,而且还会导致协议变得很复杂。


(4)如何做到兼容旧接口
当我们的server更新接口的同时,还需要保证旧client能够和新server交互,那么在定义IDL时就需要特别注意。
假设,我们定义以下一个这个一个结构体来交互用户信息。
struct user
{
1:username string,
2:password string,
3:sex i16,
}

当我们需求变更时,假设以下两种情况:
a)需要新增字段, age来表示年龄
struct user
{
1:username string,
2:password string,
3:sex i16,
4:age i32,
}

注意,原来字段的序号标识一定不能被改变,1:username string, 不能改成 5:username string。
此时,如果server是新的,client是旧的,并不影响client的工作,client从server那边收到的包里包含了age的信息,只是没有decode出来而已。

b)删除字段sex,新增字段age
struct user
{
1:username string,
2:password string,
//3:sex i16,
4:age i32, (注意,为了保证a)所定义的client能够和b)的server交互,这里的字段序号必须定义为4)
}

此时,如果server是新的,client是a)所生成的也并不影响和b)的server交互,因为client从server那边收到的包虽然没有包含sex的信息,但是client并不会崩溃,只是缺少了sex的信息。
因此,我们需求变更时,尽量保存旧的字段不要删除,做到只增不减的方式来兼容旧接口。

这里字段序号是唯一标识字段的关键。

posted @ 2009-07-10 11:48 小马歌 阅读(8969) | 评论 (0)编辑 收藏
 

find / -amin -10 # 查找在系统中最后10分钟访问的文件
find / -atime -2 # 查找在系统中最后48小时访问的文件
find / -empty # 查找在系统中为空的文件或者文件夹
find / -group cat # 查找在系统中属于 groupcat的文件
find / -mmin -5 # 查找在系统中最后5分钟里修改过的文件
find / -mtime -1 #查找在系统中最后24小时里修改过的文件
find / -nouser #查找在系统中属于作废用户的文件
find / -user fred #查找在系统中属于FRED这个用户的文件
find / -mtime +2 两天之前
find / -mtime -2 两天以内

/sbin/iptables -A INPUT-i lo -j ACCEPT
# Accept EstablishedConnections
/sbin/iptables -A INPUT-m state --state ESTABLISHED,RELATED -j ACCEPT

# ICMP Control
/sbin/iptables -A INPUT-p icmp -m limit --limit 1/s --limit-burst 10 -j ACCEPT

watch -n 1 "ifconfig eth0|grep bytes" 查看网卡速率
rpm -i --test *.rpm 查询 rpm 包是否可以被安装
tar 小结
1.#查看tar包中的内容
tar -tf XXX.tar来查看tar包中的内容
2.#删除tar包中的目录
tar --delete (tar包中目录) -vf XXX.tar
3.#打包时排除个别目录
tar -zcvf XXX.tar.gz --exclude=test/XXX1 --exclude=test/XXX2 test
要注意的有3点
1. "-f"参数后要紧跟文件名
2."tar.gz" 包不能用tar --delete删除其中目录(先用gzip -d解开.gz)
3.配合是用file命令查看文件类型,到底是tar包,还是tar.gz

1.如果主机的 tar 是 GNU 的版本,exclude 参数就要放在前面了:
2.注意--exclude后面的排除目录后不能带/ ,否则不起作用。

# export PATH=$PATH:/usr/local/mysql/bin
检查下 PATH 中是否写入了 /usr/local/mysql/bin 路径:
# echo $PATH
/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/usr/local/mysql/bin

小注意点:在进行./configure安装配置软件的时候,此时会用/tmp目录,如果此时/tmp被挂载别的设备,此时./configure就无法进行,会出错.我发生过/tmp挂载光盘, 在./configure安装别的软件是发生错误.[root@localhost ~]# ifconfig eth0 |awk '/HWaddr/{print $5}'
00:0C:29:0F:C7:D8

[root@localhost ~]# ifconfig eth0 |awk '/inet addr/{print $2}'|awk -F: '{print $2}'
192.168.187.129
查看是否中了arp欺骗方法:发现网关的mac在变化
arping -I eth0 网关地址
如sh# arping 192.168.0.125
ARPING 192.168.0.125 from 192.168.0.1 eth0
Unicast reply from 192.168.0.125 [00:E0:4D:06:5C:C4] 0.700ms
Unicast reply from 192.168.0.125 [00:E0:4D:06:5C:C4] 0.677ms
Unicast reply from 192.168.0.125 [00:E0:4C:00:32:F9] 837.700ms

查看是否中的洪水syn flood:查看是否有大量请求来自同一个主机
netstat -ant | wc -l
netstat -ant | grep -c SYN_RECV

查看节点号inode
stat filename
ls -i filename
df -i

给CentOS YUM加速
CentOS 5.x下 安装 yum-fastestmirror (yum install yum-fastestmirror)
CentOS 4.x下 安装 yum-plugin-fastestmirror (yum install yum-plugin-fastestmirror)
确保/etc/yum.conf里有 plugins=1 一行

curl -I www.badiu.com
curl --head www.baidu.com
host/nslookup/dig
www.baidu.com
netstat -an |awk '/^tcp/{++a[$NF]}END{for(i in a)print i, a[i]}'

# netstat -lntp # 查看所有监听端口
# netstat -antp # 查看所有已经建立的连接
# netstat -s # 查看网络统计信息

rpm -qpl 包名,查看包中内容

rpm -qf /bin/ping 可以查看命令属于那个包
redhat/solaris下允许root通过telnet登录
在redhat中对于远程login的限制,体现在/etc/pam.d/login文件中,缺省有一行:
 auth required /lib/security/pam_security.so注释该行,任何限制都没有,root当然可以直接telnet登陆echo 1 > /proc/sys/net/ipv4/ip_forward
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all
vi /etc/sysctl.conf

file /sbin/init   或 file /bin/ls查看系统是32位还是64位的(os) ,i386,i686都是32位的, x86_64 x86_64 x86_64 是64位的
dd if=/etc/passwd of=/tmp/passwd.bak    备份
gcc -v    查看GCC版本
chattr +i filename 禁止删除   chattr -i filename 取消禁止
lsattr    显示隐藏档属性
ifdown eth0 关闭网卡
ifup eth0    开启网卡
clear    清屏
history    历史记录       !55 执行第55个指令
stty   设置终端    stty -a
fdisk /mbr   删除GRUB
at     僅進行一次的工作排程
jobs    观看后台暂停的程序   jobs -l
kill    结束进程 kill -9 PID [9]强制结束,[15]正常结束,[l]列出可用的kill信号
top     查看后台程序   top -d 2    每两秒更新一次        top -d 2 -p10604   观看某个PID
         top -b -n 2 > /tmp/top.txt ----->將 top 的資訊進行 2 次,然後將結果輸出到 /tmp/top.txt   
pstree   以树状图显示程序    [A]以 ASCII 來連接, [u]列出PID, [p]列出帐号
killall   要刪除某個服務    killall -9 httpd
free      显示内存状态     free -m -------->以M为单位显示
uptime    显示目前系统开机时间
netstat   显示网络状态    netstat -tulnp------>找出目前系統上已在監聽的網路連線及其 PID
nice      设置优先权      nice -n -5 vi & ----->用 root 給一個 nice 植為 -5 ,用於執行 vi
runlevel 显示目前的runlevel
depmod    分析可载入模块的相依性
lsmod     显示已载入系统的模块
modinfo   显示kernel模块的信息
insmod    载入模块
modprobe   自动处理可载入模块 modprobe -l
rmmod     删除模块
chkconfig   检查,设置系统的各种服务     chkconfig --list ----->列出各项服务状态
ntsysv     设置系统的各种服务
cpio      备份文件
vi一般用法
一般模式              编辑模式                  指令模式
h 左               a,i,r,o,A,I,R,O             :w 保存
j 下                进入编辑模式                :w! 强制保存
k 上                dd 删除光标当前行           :q! 不保存离开
l 右                ndd 删除n行                 :wq! 保存后离开
0 移动到行首        yy 复制当前行                :e! 还原原始档
$ 移动到行尾        nyy 复制n行                  :w filename 另存为
H 屏幕最上          p,P 粘贴                     :set nu 设置行号
M 屏幕中央          u 撤消                      :set nonu 取消行号
L 屏幕最下          [Ctrl]+r 重做上一个动作       ZZ 保存离开
G 档案最后一行      [ctrl]+z 暂停退出            :set nohlsearch   永久地关闭高亮显示
/work 向下搜索                                   :sp 同时打开两个文档
?work 向上搜索                                   [Ctrl]+w 两个文档设换
gg 移动到档案第一行                              :nohlsearch    暂时关闭高亮显示
有用:
G 档案最后一行
gg 移动到档案第一行
H 屏幕最上
M 屏幕中央
L 屏幕最下

4yl是向后复制4个字符,l是用来指明方向的吧? 4yh用向前复制四个字符。

通过vim 编辑文件,用V   进行块选

alias 显示当前所有的命令别名  
alias lm="ls -al"   命令别名 unalias lm 取消命令别
type      类似which
exprot    设置或显示环境变量
exprot PATH="$PATH":/sbin 添加/sbin入PATH路径
echo $PATH    显示PATH路径
bash      进入子程序
name=yang     设定变量
unset name    取消变量
echo $name    显示变量的内容
myname="$name its me"   &   myname='$name its me'     单引号时$name失去变量内容
ciw=/etc/sysconfig/network-scripts/     设置路径
env      列出所有环境变量
echo $RANDOM    显示随意产生的数
set      设置SHELL
PS1='[\u@\h \w \A #\#]\$ '     提示字元的設定
[root@linux ~]# read [-pt] variable     -----------读取键盘输入的变量
   參數:
    -p :後面可以接提示字元!
    -t :後面可以接等待的『秒數!』
declare    声明 shell 变量
ulimit -a   显示所有限制资料
ls /tmp/yang && echo "exist" || echo "not exist"
意思是說,當 ls /tmp/yang 執行後,若正確,就執行echo "exist" ,若有問題,就執行echo "not exist"
echo $PATH | cut -d ':' -f 5       以:为分隔符,读取第5段内容
export | cut -c 10-20      读取第10到20个字节的内容
last | grep 'root'    搜索有root的一行,加[-v]反向搜索
cat /etc/passwd | sort    排序显示
cat /etc/passwd | wc      显示『行、字数、字节数』
正规表示法
[root@test root]# grep [-acinv] '搜尋字串' filename
    參數說明:
        -a :將 binary 檔案以 text 檔案的方式搜尋資料
        -c :計算找到 '搜尋字串' 的次數
        -i :忽略大小寫的不同,所以大小寫視為相同
        -n :順便輸出行號
        -v :反向選擇,亦即顯示出沒有 '搜尋字串' 內容的那一行!
grep -n 'the' 123.txt     搜索the字符 -----------搜尋特定字串      
grep -n 't[ea]st' 123.txt    搜索test或taste两个字符---------利用 [] 來搜尋集合字元
grep -n '[^g]oo' 123.txt     搜索前面不为g的oo-----------向選擇 [^]
grep -n '[0-9]' 123.txt 搜索有0-9的数字
grep -n '^the' 123.txt 搜索以the为行首-----------行首搜索^
grep -n '^[^a-zA-Z]' 123.txt 搜索不以英文字母开头
grep -n '[a-z]$' 123.txt    搜索以a-z结尾的行---------- 行尾搜索$
grep -n 'g..d' 123.txt     搜索开头g结尾d字符----------任意一個字元 .
grep -n 'ooo*' 123.txt     搜索至少有两个oo的字符---------重複字元 *
sed    文本流编辑器    利用脚本命令来处理文本文件
awk    模式扫描和处理语言
nl 123.txt | sed '2,5d'   删除第二到第五行的内容
nl 123.txt | sed -n '2,5p'显示2-5行内容
diff     比较文件的差异
cmp      比较两个文件是否有差异
patch    修补文件
pr       要打印的文件格式化
sudo       以其他身份来执行指令
visudo     编辑/etc/sudoers      加入一行『 test ALL=(ALL) ALL 』
            %wheel ALL = (ALL) ALL               系统里所有wheel群组的用户都可用sudo
            %wheel ALL = (ALL) NOPASSWD: ALL     wheel群组所有用户都不用密码NOPASSWD
        User_Alias ADMPW = vbird, dmtsai, vbird1, vbird3         加入ADMPW组
        ADMPW ALL = NOPASSWD: !/usr/bin/passwd, /usr/bin/passwd [A-Za-z]*, \
        !/usr/bin/passwd root      可以更改使用者密码,但不能更改root密码 (在指令前面加入 ! 代表不可)
PAM (Pluggable Authentication Modules, 嵌入式模組)
who & w     看谁在线                    
last        最近登陆主机的信息
lastlog     最近登入的時間    读取 /var/log/lastlog    这点重要
talk        与其他用户交谈
write       发送信息    write test   [ctrl]+d 发送
mesg        设置终端机的写入权限    mesg n 禁止接收     mesg y
wall        向所有用户发送信息    wall this is q test
mail        写mail  
/etc/default/useradd    家目录默认设置
quota      显示磁盘已使用的空间与限制     quota -guvs ----->秀出目前 root 自己的 quota 限制值
            quota -vu   查询
quotacheck   检查磁盘的使用空间与限制     quotacheck -avug ----->將所有的在 /etc/mtab 內,含有 quota

支援的 partition 進行掃瞄
              [-m] 强制扫描
      quota一定要是独立的分区,要有quota.user和quota.group两件文件,在/etc/fstab添加一句:
      /dev/hda3 /home ext3 defaults,usrquota,grpquota 1 2
      chmod 600 quota*         设置完成,重启生效
edquota    编辑用户或群组的quota [u]用户,[g]群组,[p]复制,[t]设置宽限期限
            edquota -a yang       edquota -p yang -u young ----->复制   
quotaon    开启磁盘空间限制     quotaon -auvg -------->啟動所有的具有 quota 的 filesystem
quotaoff   关闭磁盘空间限制     quotaoff -a -------->關閉了 quota 的限制
repquota -av     查閱系統內所有的具有 quota 的 filesystem 的限值狀態
Quota 從開始準備 filesystem 的支援到整個設定結束的主要的步驟大概是:
1、設定 partition 的 filesystem 支援 quota 參數:
由於 quota 必須要讓 partition 上面的 filesystem 支援才行,一般來說, 支援度最好的是 ext2/ext3 ,
其他的 filesystem 類型鳥哥我是沒有試過啦! 啟動 filesystem 支援 quota 最簡單就是編輯 /etc/fstab ,
使得準備要開放的 quota 磁碟可以支援 quota 囉;
2、建立 quota 記錄檔:
剛剛前面講過,整個 quota 進行磁碟限制值記錄的檔案是 aquota.user/aquota.group,
要建立這兩個檔案就必須要先利用 quotacheck 掃瞄才行喔!
3、編輯 quota 限制值資料:
再來就是使用 edquota 來編輯每個使用者或群組的可使用空間囉;
4、重新掃瞄與啟動 quota :
設定好 quota 之後,建議可以再進行一次 quotacheck ,然後再以 quotaon 來啟動吧!

开机流程简介
1、載入 BIOS 的硬體資訊,並取得第一個開機裝置的代號;
2、讀取第一個開機裝置的 MBR 的 boot Loader (亦即是 lilo, grub, spfdisk 等等) 的開機資訊;
3、載入 Kernel 作業系統核心資訊, Kernel 開始解壓縮,並且嘗試驅動所有硬體裝置;
4、Kernel 執行 init 程式並取得 run-level 資訊;
5、init 執行 /etc/rc.d/rc.sysinit 檔案;
6、啟動核心的外掛模組 (/etc/modprobe.conf);
7、init 執行 run-level 的各個批次檔( Scripts );
8、init 執行 /etc/rc.d/rc.local 檔案;
9、執行 /bin/login 程式,並等待使用者登入;
10、登入之後開始以 Shell 控管主機。
在/etc/rc.d/rc3.d內,以S开头的为开机启动,以K开头的为关闭,接着的数字代表执行顺序
GRUB vga设定
彩度\解析度 640x480 800x600 1024x768 1280x1024   bit
     256        769      771      773       775      8 bit
    32768       784      787      790       793     15 bit
    65536       785      788      791       794     16 bit
    16.8M       786      789      792       795     32 bit

./configure    检查系统信息       ./configure --help | more 帮助信息
make clean     清除之前留下的文件
make           编译
make install   安装
rpm -q ----->查询是否安装             rpm -ql ------>查询该套件所有的目录
rpm -qi ----->查询套件的说明资料       rpm -qc[d] ----->设定档与说明档
rpm -ivh ---->安装                    rpm -V -------->查看套件有否更动过
rpm -e ------>删除                    rpm -Uvh ------->升级安装
--nodeps ----->强行安装                --test ----->测试安装
-pql   查看包中内容    -qf    command 查命令属于那个包

posted @ 2009-07-10 11:47 小马歌 阅读(360) | 评论 (0)编辑 收藏
 
修改注册表键值:

[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main]

RunOnceComplete=dword:00000001

RunOnceHasShown=dword:00000001
以上查找没有这个注册表信息,你新建就可以了,添加上面这两个就可以修复了
posted @ 2009-07-07 12:13 小马歌 阅读(3312) | 评论 (3)编辑 收藏
 

需求:
一个千万级数据量的服务,不停的插入和删除记录,每条记录需要知道自己的排名,比如SNS中的抢车位,如何让每个uid能够知道自己在所有人中的车总价排名?

致命伤(cache无用论)
有1000万个用户,试想排名第500万的用户突然发飙了,把他的车全卖了,那么他之后的500万个用户的排名都提高了,也就是cache全部瞬间失效了。。。pity,此时加再多的cache只能是浮云

解决方法:
1,划分子空间,比如k心网,不提供全部用户的排名,只提供用户在其好友中的车总价的排名(其实这样更有意义,不过这是产品层面),这样即时一个用户车价变化,影响的也只是其好友的cache,别人不做影响
2,牺牲实时性,算不过来就离线算呗,这个太容易想到了,比如k心网车总价的排名是每12个小时更新一次的

BT的需求:
假如,只是假如,我们就需要uid在所有用户中的实时准确排名怎么办??(产品不想牺牲实时性的UE),这时解决问题只能靠更好的算法模型

扩展的红黑树:
这个结构在一般数据结构书不提,在CLRS是以扩展话题为讨论的,在TAOCP中是以课后题出现,但在CLRS的视频中可是重点介绍,讲了一节课呢,所以推荐看这个视频11.Dynamic.Statistics。拷贝书上的介绍nonsense,所以只是简单的介绍一下:扩展红黑树ERBT中,每个节点不仅有color,link,key信息,还包括了一个很重要的信息=>该节点所有子节点的数目(包括其自身在内),这样每个节点的排名可以在找到它的那一霎那得到,因为(初始rank(root)=0):
rank(lnode)=rank(pnode)
rank(rnode)=children_count(lnode)+1
而作为补偿,同样需要在更改操作时,维护子节点的数目
查找和维护的时间复杂度都是log(n)

解决方案:
还是车总价的排名显示问题,我们在内存中维护这样一颗ERBT,key就是车的总价位,当有用户的车总价发生变化时,我们就删除这个节点并插入一个新节点。当需要显示用户的车总价排名时,先从uid得到车总价的数值(比如从mysql中),然后拿这个数值到ERBT中做查找,当找到这个值的时候,排名自然得到。

对于千万级数据,log(n)基本在20-30,而使mc的话,每秒请求可以到2万这个级别,我们假设hash的拉链平均长度为3,也就是使用ERBT的速度理论上是直接hash的1/10,也就是能够支撑2000r/s的请求,这样的能力对于一般的SNS应用也是够了。当然如果要求更高性能还需要做更多的优化。

故障恢复:
首先这个服务就支持分布式,因为每台机器可以独立的跑ERBT,另外即时down机了,恢复也很容易,只要从mysql中导入数据一遍则自动生成,我们也可以把ERBT定时按照hash的形式dump出一份,以备意外时访问

posted @ 2009-07-03 22:23 小马歌 阅读(194) | 评论 (0)编辑 收藏
仅列出标题
共95页: First 上一页 65 66 67 68 69 70 71 72 73 下一页 Last