1.js编译器与引擎(js编译器有哪些)
2.c++ 中__declspec 的关键用法
3.C++ 中的Item是什么关键字?可以定义什么型的变量?
4.redis 有一个端口占用cpu特别高
js编译器与引擎(js编译器有哪些)
javascript中的this到底指什么?
javascript中的this到底指什么?
this是一个语言中的关键字,它就是字驱一个对象。
thispage的动源意思是这个页旁并败面。
JavaScript一种直译式脚本语言,码关是键字一种动态类型、弱类型、驱动orb slam 源码基于原型的源码用语言,内置支持类型。关键它的字驱解释器被称为JavaScript引擎,为浏览器的动源一部分,广泛用于客户端的码关脚本语言运颤,最早是键字在HTML(标准通用标记语言下的一个应用)网页上使用,用来给HTML网页增加动态功能。驱动
JAVASCRIPT中的源码用this到底是谁
全局对象
在全局执行上下文(函数之外),this引用的是全局对象.
函数
在函数里面,this这个值,得看怎么来调用这个函数
.没有申明为严格模式下,this必须要有一个值去赋予.默认情况下就是指向的是全局对象
严格模式下,this没有被申明,则为undefined.他也可以是任何值,比如null或者或者其他.
当一个函数作为一个对象的方法去调用,this指向的是对象本身.
对象原型链中的this是继承的原型类对象
JavaScript中的Object到底是什么呢?
Object是一种引用类型,是关键一种数据结构,具有属性和方法。JavaScript中,除了数字、字符串、布尔值、null和undefined外,其他的所有值都是对象。数组、函数等都是一个对象。
手机中的JAVA到底指什么?
就是手机上装有java虚拟机,可以运行java编写的手机软件,一般的国产机都支持这个
佛教中的“上人”到底指什么?
指持戒严格并精于佛学的僧侣。《释氏要览》称:「智德,外有德行,在人之上、名上人。」
防晒霜中的UV到底指什么?
UV=ultravioletradiation,在化妆品行业里,以UV来表示紫外线,像防晒霜等夏日化妆品上有很多UV的标志,是表示防紫外线。
ACG中的G到底指什么?Game还是Gal
ACG是Animation、Comic、Game的缩写,是动画、漫画、游戏(通常指电玩游戏或GalGame)的总称。GAL就是Galgame了,是一种可以与美丽动人的动画少女进行互动的电子游戏,特属于日本的文化现象。所以ACG是包含着GAL的~
java中的语法到底指的什么?
java中的语法是指java中的规则,即java的命名规则:
包的命名(全部小写,由域名定义)
Java包的名字都是由小写单词组成。但是由于Java面向对象编程的特性,每一名Java程序员都可以编写属于自己的Java包,为了保障每个Java包命名的唯一性,在最新的Java编程规范中,要求程序员在自己定义的包的名称之前加上唯一的前缀。由于互联网上的域名称是不会重复的,所以程序员一般采用自己在互联网上的域名称作为自己程序包的唯一前缀。例如:.frontfree.javagroup
类的命名(单词首字母大写)
根据约定,Java类名通常以大写字母开头,如果类名称由多个单词组成,则每个单词的首字母均应为大写例如TestPage;如果类名称中包含单词缩写,则这个所写词的每个字母均应大写,如:XMLExample,还有一点命名技巧就是由于类是设计用来代表对象的,所以在命名类时应尽量选择名词。
例如:Graphics
方法的命名(首字母小写,字母开头大写)
方法的名字的第一个单词应以小写字母作为开头,后面的单词则用大写字母开头。
例如:drawImage
常量的命名(全部大写,常加下划线)
常量的名字应该都使用大写字母,并且指出该常量完整含义。如果一个常量名称由多个单词组成,则应该用下划线来分割这些单词。
例如:MAX_VALUE
参数的命名
参数的命名规范和方法的命名规范相同,而且为了避免阅读程序时造成迷惑,请在尽量保证参数名称为一个单词的情况下使参数的命名尽可能明确。
知识扩展:
在变量命名时要注意以下几点:
1.选择有意义的名字,注意每个单词首字母要大写。
2.在一段函数中不使用同一个变量表示前后意义不同的两个蔽粗数值。
3.i、j、k等只作为小型循环的循环索引变量。
4.避免用Flag来命名状态变量。
5.用Is来命名逻辑变量,如:blnFileIsFound。通过这种给布尔变量肯定形式的命名方式,使得其它开发人员能够更为清楚的理解布尔变量所代表的意义。
6.如果需要的话,在变量最后附加计算限定词,如:curSalesSum。
7.命名不相包含,curSales和curSalesSum。
8.staticfinal变量(常量)的名字应该都大写,并且指出完整含义。
9.如果需要对变量名进行缩写时,一定要注意整个代码中缩写规则的一致性。例如,如果在代码的某些区域中使用intCnt,而在另一些区域中又使用intCount,kmp源码输出设置就会给代码增加不必要的复杂性。建议变量名中尽量不要出现缩写。
.通过在结尾处放置一个量词,就可创建更加统一的变量,它们更容易理解,也更容易搜索。例如,请使用strCustomerFirst和strCustomerLast,而不要使用strFirstCustomer和strLastCustomer。常用的量词后缀有:First(一组变量中的第一个)、Last(一组变量中的最后一个)、Next(一组变量中的下一个变量)、Prev(一组变量中的上一个)、Cur(一组变量中的当前变量)。
.每个变量选择最佳的数据类型,这样即能减少对内存的需求量,加快代码的执行速度,又会降低出错的可能性。用于变量的数据类型可能会影响该变量进行计算所产生的结果。在这种情况下,编译器不会产生运行期错误,它只是迫使该值符合数据类型的要求。这类问题极难查找。
.尽量缩小变量的作用域。如果变量的作用域大于它应有的范围,变量可继续存在,并且在不再需要该变量后的很长时间内仍然占用资源。它们的主要问题是,任何类中的任何方法都能对它们进行修改,并且很难跟踪究竟是何处进行修改的。占用资源是作用域涉及的一个重要问题。对变量来说,尽量缩小作用域将会对应用程序的可靠性产生巨大的影响。
关于常量的命名方法,在JAVA代码中,无论什么时候,均提倡应用常量取代数字、固定字符串。也就是说,程序中除0,1以外,尽量不应该出现其他数字。常量可以集中在程序开始部分定义或者更宽的作用域内,名字应该都使用大写字母,并且指出该常量完整含义。如果一个常量名称由多个单词组成,则应该用下划线“_”来分割这些单词如:NUM_DAYS_IN_WEEK、MAX_VALUE。
wifi中的fingerprint到底指的什么意思
fingerprint
英[?fg?pr?nt]美[?fg?rpr?nt]
n.指纹,指印
vt.采指纹
装个腾讯WIFI管家就好了嘛
它可以自动发现附近可直接连接的WIFI进行连接
而且在地铁都可以用,现在也就它支持了,其他软件都还不行呢
JavaScript用什么编译器?
WebStorm.3.Learnmore.onJetBrains.
Komodo?IDE?.1.1.Learnmore.onActiveState.
NetBeans.0.Learnmore.onApacheFoundation.
VisualStudio.Learnmore.onMicrosoft.
VisualStudioCode1..Learnmore.onMicrosoft.
Eclipsewith?JavaScript?DevelopmentTools.Learnmore.
跨平台常用visualstudiocode,免费。型御团
好卜橘用的话,应该webstorm最好。拆稿
请高手解释下为什么Javascript是一种解释性语言,不需要进行编译和构建.在看Jquery的书,有句话是这样说的解释执行主要是针对编译执行编译执行来说的,C语言,java等静态语颤渗言,写好代码后需要经过编译器编译,将源代码编译成别的代码,比如机器码,汇编等,解释执行则不需要编译过程,直接由解释器解析并执行代码。
javascript就属于解释执行,所以说他是一种解释性语言。
但是,随着技术的发展,越来越多的javascript引擎拦昌为了提高性能,也会对javascript进行一些编译,所以也很难清楚的界定javascript到底是解释执行还是编译简洞扒执行。所以也没必要去深究,知道就行。
jsp和js的区别。JSP与JavaScript(JavaScript的缩写就是js)之间的一些主要区别:
1、JavaServerPages是一种动态网页技术,而JavaScript是一种脚本语言,可以使静态HTML内容
成为动态。
2、JavaServerPages具有在HTML之间添加Java代码的scriptlet,而JavaScript具有许多内置
函数,可以使用基于面向对象编程模型中基于原型模式的继承的JavaScript对象来修改数据。
3、JavaServerPages具有JSTL支持以处理一些复杂的功能,而JavaScript具有不同的数据类
型,如Boolean,Number,String,Date,Math,HTMLDOM和RegExp等,
4、JavaServerPages几乎支持所有Web浏览器,而JavaScript不支持跨浏览器功能,宝来棋牌源码导致在
浏览器更改期间执行少量功能的失败导致不利。
5、JavaServerPages将通过Web服务器从后端呈现和提供,而JavaScript是一种脚本语言,
可以在客户端和服务器端使用,或者在浏览器端或客户端使用,其中代码将由内部编译。
JavaScript内置编译器称为JIT编译器,然后它将在浏览器中解释,模块的执行稍后在客户端环
境(即浏览器)上发生。
6、JavaServerPages具有JSR规范,这是Oracle的标准,而JavaScript具有最新标准,称为
ES9(ECMAScript标准),支持其编程模型中的高级功能方面和几个高阶函数。
7、JavaServerPages在开发复杂功能方面存在局限性,而JavaScript有一个标准规范,可以
使用JS强大的函数编程方面来操作复杂模块。
8、JavaServerPages在Web容器中具有JSP隐式对象功能,而JavaScript具有可通过使用let
关键字在ES6标准中使用的提升功能。
9、JavaServerPages支持表达式语言(EL),它提供对Java对象中的函数和数据的访问,而
JavaScript具有隐式原型引用,用于引用JS对象中的数据。
、JavaServerPages有JSP编译器,它将JSP转换为Servlet来解释网页内容和显示,而
JavaScript有Javascript解释器来解析称为Javascript引擎的代码。
扩展资料:
JavaScript的优点
1、速度。客户端JavaScript非常快,因为它可李简以在客户端浏览器中立即运行。除非需要外部资
源,否则JavaScript不会受到后端服务器的网络调用的阻碍。它也没有必要在客户哪液裤端编译,这
给了它一定的速度优势(授予,增加一些风险取决于所开发代码的质量)。
2、简单。JavaScript的学习和实现相对简单。
3、人气。JavaScript在Web中随处可用。学习JavaScript的资源很多。StackOverflow和
GitHub有许多使用Javascript的项目,并且语言作为一个整体近年来在业界获得了很大的关
注,尤其是。
4、互操作性。JavaScript可以很好地与其他语言一起使用,并且可以在各种各样的应用程序中
使用。与PHP或SSI脚本不同,JavaScript可以插入任何网页,无论文件扩展名如何。
JavaScript也可以在用其他语言编写的脚本中使用,例如Perl和PHP。
5、服务器负载。客户端减少了对网站服务器的需求。
6、丰富的接口。拖放组件或滑块可为您的网站提供丰富的界面。
7、扩展功能。像Greasemonkey这样的第三方附加组件使JavaScript开发人员能够编写可以在
所需网页上执行以扩展其功能的JavaScript代码片段。
8、多功埋昌能性。如今,有许多方法可以通过Node.js服务器使用JavaScript。如果您使用
Express引导node.js,使用像mongodb这样的文档数据库,并在前端为客户端使用
JavaScript,则可以仅使用JavaScript从前到后开发整个JavaScript应用程序。
试述JavaScript和Java的区别?程序员和用户经常在Java和JavaScript之间感到困惑。认为Java和JavaScript相同。如果从表面看,它们可能看起来一样。由于Java和JavaScript均指相同的OOP语言,并且共享相同的控制结构和运算符。但是,当您单独学习它们时,您将了解它们彼此完全不同。尽管有这些相似之处,但它们在各个方面都有所不同。
Java
Java是JamesGosling发明并由SunMicrosystems开发的一种流行的计算机软件编程语言。它是年创建的通用高级编程语言。Java是一种面向对象的语言,旨在为您提供C++的感觉。但是,它比C++更简单易用。Java最初被命名为OAK,钓鱼源码错误14但后来又更改为Java。借助其虚拟机平台,它允许您创建可在几乎所有平台上运行的编译程序。
JavaScript
JavaScript是HTML和Web的轻量级编程语言,用于使网页具有交互性。作为一种多范式语言,它支持事件驱动,功能,命令和编程样式。JavaScript网页实现允许客户端脚本与用户交互并创建动态页面。它最初被称为LiveScript,但后来Netscape将其名称更改为JavaScript。
Java和JavaScript之间的差异
认为Java和JavaScript相同是一种非常普遍的看法。但事实是,除了Java之外,它们之间没有其他共同之处。两者是完全不同的,彼此无关。它们的工作,功能和功能都非常不同。
这是Java和JavaScript作为编程语言之间的主要区别的列表。由于Java具有许多重要功能,因此它是最常用的编程语言。另一方面,JavaScript具有Java缺少的某些功能。JavaScript不需要任何编译器或编辑器,它被认为是最容易学习的语言。
JavaScript的基本语法和对象体系,是模仿Java而设计的。但是,JavaScript没有采用Java的静态类型。正是因为JavaScript与Java有很大的相似念烂性,所以这门语言才从一开始的LiveScript改名为JavaScript。基本上,JavaScript这个名字的原意是“很像Java的脚本语言”。
JavaScript语言的函数是一种独立的数据类型,以及采用基于原型对象(prototype)的继承链。这是它与Java语法最大的两点区别。JavaScript语法要比Java自由得多。
另外,Java语言需野孝要编译,而JavaScript语言则是运行时由解释器直接执行。
总之,JavaScript的原始设计目标是一种小型的、简单的动态语言,与Java有足够的相似性,仔脊漏使得使用者(尤其是Java程序员)可以快速上手。
这就是这两者的区别与联系,希望回答对你有多帮助
c++ 中__declspec 的用法
语法说明:__declspec ( extended-decl-modifier-seq )
extended-decl-modifier-seq 为扩展修饰符
align(#) 用__declspec(align(#))精确控制用户自定数据的对齐方式 ,#是对齐值。 e.g__declspec(align())struct Str1{ int a, b, c, d, e;};转它与#pragma pack()是一对兄弟,前者规定了对齐的最小值,后者规定了对齐的最大值。同时出现时,前者优先级高。 __declspec(align())的一个特点是,它仅仅规定了数据对齐的位置,而没有规定数据实际占用的内存长度,当指定的数据被放置在确定的位置之后,其后的数据填充仍然是按照#pragma pack规定的方式填充的,这时候类/结构的实际大小和内存格局的规则是这样的:在__declspec(align())之前,数据按照#pragma pack规定的方式填充,如前所述。当遇到__declspec(align())的时候,首先寻找距离当前偏移向后最近的对齐点(满足对齐长度为max(数据自身长度,指定值)),然后把被指定的数据类型从这个点开始填充,其后的数据类型从它的后面开始,仍然按照#pragma pack填充,直到遇到下一个__declspec(align())。当所有数据填充完毕,把结构的整体对齐数值和__declspec(align())规定的值做比较,取其中较大的作为整个结构的对齐长度。 特别的,当__declspec(align())指定的数值比对应类型长度小的时候,这个指定不起作用。
allocate("segname")用__declspec(allocate("segname")) 声明一个已经分配了数据段的一个数据项。它和#pragma 的code_seg, const_seg, data_seg,section,init_seg配合使用,segname必须有这些东东声明。e.g#pragma data_seg("share_data")int a = 0;int b;#pragma data_seg() __declspec(allocate("share_data")) int c = 1;__declspec(allocate("share_data")) int d;
deprecated用__declspec(deprecated ) 说明一个函数,类型,或别的标识符在新的版本或未来版本中不再支持,你不应该用这个函数或类型。它和#pragma deprecated作用一样。e.g#define MY_TEXT "function is deprecated"void func1(void) { }__declspec(deprecated) void func1(int) { printf("func1n");}__declspec(deprecated("** this is a deprecated function **")) void func2(int) { printf("func2n");}__declspec(deprecated(MY_TEXT)) void func3(int) { printf("func3");}int main(){ fun1();fun2();fun3();}
dllimport 和dllexport用__declspec(dllexport),__declspec(dllimport)显式的定义dll接口给调用它的exe或dll文件,用 dllexport定义的函数不再需要(.def)文件声明这些函数接口了。注意:若在dll中定义了模板类那它已经隐式的进行了这两种声明,我们只需在 调用的时候实例化即可,呵呵。e.g 常规方式dll中class ___declspec(dllexport)testdll{ testdll(){ };~testdll(){ };};调用客户端中声明#import comment(lib, "**.lib)class ___declspec(dllimportt)testdll{ testdll(){ };~testdll(){ };};e.g 模板类:dll中templateclass tclass test{ test(){ };~test(){ };}调用客户端中声明int main(){ test int b;return 0;}
jitintrinsic用__declspec(jitintrinsic)标记一个函数或元素为位公共语言运行时。具体用法未见到。
__declspec( naked )对于没有用naked声明的函数一般编译器都会产生保存现场(进入函数时编译器会产生代码来保存ESI,EDI,EBX,拾柴网源码EBP寄存器 ——prolog)和清除现场(退出函数时则产生代码恢复这些寄存器的内容——epilog) 代码,而对于用naked声明的函数一般不会产生这些代码,这个属性对于写设备驱动程序非常有用,我们自己可以写这样一个过程,它仅支持x 。naked只对函数有效,而对类型定义无效。对于一个标志了naked的函数不能产生一个内联函数即时使用了__forceinline 关键字。 e.g__declspec ( naked ) func(){ int i;int j;__asm /* prolog */{ push ebpmov ebp, espsub esp, __LOCAL_SIZE}/* Function body */__asm /* epilog */{ mov esp, ebppop ebpret}}
restrict 和 noalias__declspec(restrict) 和 __declspec(noalias)用于提高程序性能,优化程序。这两个关键字都仅用于函数,restrict针对于函数返回指针,restrict 说明函数返回值没有被别名化,返回的指针是唯一的,没有被别的函数指针别名花,也就是说返回指针还没有被用过是唯一的。编译器一般会去检查指针是否可用和 是否被别名化,是否已经在使用,使用了这个关键字,编译器就不在去检查这些信息了。noalias 意味着函数调用不能修改或引用可见的全局状态并且仅仅修改指针参数直接指向的内存。如果一个函数指定了noalias关键字,优化器认为除参数自生之外, 仅仅参数指针第一级间接是被引用或修改在函数内部。可见全局状态是指没有定义或引用在编码范围外的全部数据集,它们的直至不可以取得。编码范围是指所有源 文件或单个源文件。其实这两个关键字就是给编译器了一种保证,编译器信任他就不在进行一些检查操作了。 e.g#include stdio.h#include stdlib.h#define M #define N #define P float * mempool, * memptr;__declspec(restrict) float * ma(int size){ float * retval; retval = memptr; memptr += size;return retval;}__declspec(restrict) float * init(int m, int n){ float * a; int i, j;int k=1;a = ma(m * n); if (!a) exit(1);for (i=0; im; i++) for (j=0; jn; j++) a[i*n+j] = 0.1/k++;return a;}__declspec(noalias) void multiply(float * a, float * b, float * c){ int i, j, k;for (j=0; jP; j++) for (i=0; iM; i++) for (k=0; kN; k++) c[i * P + j] = a[i * N + k] * b[k * P + j];}int main(){ float * a, * b, * c;mempool = (float *) malloc(sizeof(float) * (M*N + N*P + M*P));if (!mempool) puts("ERROR: Malloc returned null"); exit(1);memptr = mempool; a = init(M, N);b = init(N, P);c = init(M, P); multiply(a, b, c);}
noinline__declspec(noinline)告诉编译器不去内联一个具体函数。
noreturn__declspec(noreturn)告诉编译器没有返回值.注意添加__declspec(noreturn)到一个不希望返回的函数会导致已没有定义错误.
nothrow__declspec(nothrow)用于函数声明,它告诉编译器函数不会抛出异常。e.g#define WINAPI __declspec(nothrow) __stdcallvoid WINAPI f1();void __declspec(nothrow) __stdcall f2();void __stdcall f3() throw();
novtable __declspec(novtable)用在任意类的声明,但是只用在纯虚接口类,因此这样的不能够被自己实例话.它阻止编译器初始化虚表指针在构造和析构类的时候,这将移除对关联到类的虚表的 引用.如果你尝试这实例化一个有novtable关键字的类,它将发生AV(access violation)错误.C++里virtual的缺陷就是vtable会增大代码的尺寸,在不需要实例化的类或者纯虚接口的时候,用这个关键字可以减 小代码的大小. e.g#if _MSC_VER = !defined(_DEBUG)#define AFX_NOVTABLE __declspec(novtable)#else#define AFX_NOVTABLE#endif....class AFX_NOVTABLE CObject{ ...};这是vc里面的一段代码,我们可以看出编译Release版本时,在CObject前是__declspec(novtable),在debug版本没有这个限制。e.g#include stdio.hstruct __declspec(novtable) X{ virtual void mf();};struct Y : public X{ void mf(){ printf_s("In Yn");}};
selectany的作用 (转)__declspec(selectany)可以让我们在.h文件中初始化一个全局变量而不是只能放在.cpp中。比如有一个类,其中有一个静态变量,那 么我们可以在.h中通过类似" __declspec(selectany) type class::variable = value; "这样的代码来初始化这个全局变量。既是该.h被多次include,链接器也会为我们剔除多重定义的错误。这个有什么好处呢,我觉得对于 teamplate的编程会有很多便利。e.gclass test{ public:static int t;};__declspec(selectany) int test::t = 0;
threadthread 用于声明一个线程本地变量. __declspec(thread)的前缀是Microsoft添加给Visual C++编译器的一个修改符。它告诉编译器,对应的变量应该放入可执行文件或DLL文件中它的自己的节中。__declspec(thread)后面的变量 必须声明为函数中(或函数外)的一个全局变量或静态变量。不能声明一个类型为__declspec(thread)的局部变量。e.g__declspec(thread)class X{ public:int I;} x; // x is a thread objectX y; // y is not a thread object
uuid__declspec(uuid)用于编译器关联一个GUID到一个有uuid属性的类或结构的声明或者定义.e.gstruct __declspec(uuid("---c-")) IUnknown;struct __declspec(uuid("{ ---c-}")) IDispatch;我们可以在MFC中查看源码.:)
C++ 中的Item是什么关键字?可以定义什么型的变量?
NEW是C 的关键字,能进行类型的检查之类的
malloc是C跟C 都可以用的
不能进行类型检查之类
如果是在C 中,推荐使用new
inline函数区别与普通函数在于调用普通函数时程序有压栈和出栈操作,而inline(内联)函数编译器在预处理的时候会把它的代码加到调用它的函数中,而不用额外的跳转操作,从而提高了程序的效率。
但是inline不允许有switch, 循环等复杂语句。
堆,可用NEW对它分配内存,DELETE销毁内存空间。
栈,是由程序本身建立,分配,消除的内存空间!他服从先进后出(FILO)的原则,从而可以把各个变量按生存期分开!
static 声明的变量在C语言中有两方面的特征:
1)、变量会被放在程序的全局存储区中,这样可以在下一次调用的时候还可以保持原来的赋值。这一点是它与堆栈变量和堆变量的区别。
2)、变量用static告知编译器,自己仅仅在变量的作用范围内可见。这一点是它与全局变量的区别。
Tips:
A.若全局变量仅在单个C文件中访问,则可以将这个变量修改为静态全局变量,以降低模块间的耦合度;
B.若全局变量仅由单个函数访问,则可以将这个变量改为该函数的静态局部变量,以降低模块间的耦合度;
C.设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题;
D.如果我们需要一个可重入的函数,那么,我们一定要避免函数中使用static变量(这样的函数被称为:带“内部存储器”功能的的函数)
E.函数中必须要使用static变量情况:比如当某函数的返回值为指针类型时,则必须是static的局部变量的地址作为返回值,若为auto类型,则返回为错指针。
函数前加static使得函数成为静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件(所以又称内部函数)。使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名。
扩展分析:术语static有着不寻常的历史.起初,在C中引入关键字static是为了表示退出一个块后仍然存在的局部变量。随后,static在C中有了第二种含义:用来表示不能被其它文件访问的全局变量和函数。为了避免引入新的关键字,所以仍使用static关键字来表示这第二种含义。最后,C 重用了这个关键字,并赋予它与前面不同的第三种含义:表示属于一个类而不是属于此类的任何特定对象的变量和函数(与Java中此关键字的含义相同)。
全局变量、静态全局变量、静态局部变量和局部变量的区别变量可以分为:全局变量、静态全局变量、静态局部变量和局部变量。
按存储区域分,全局变量、静态全局变量和静态局部变量都存放在内存的静态存储区域,局部变量存放在内存的栈区。
按作用域分,全局变量在整个工程文件内都有效;静态全局变量只在定义它的文件内有效;静态局部变量只在定义它的函数内有效,只是程序仅分配一次内存,函数返回后,该变量不会消失;局部变量在定义它的函数内有效,但是函数返回后失效。全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。 这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序, 当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用, 因此可以避免在其它源文件中引起错误。
从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用范围。
static函数与普通函数作用域不同。仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件
static全局变量与普通的全局变量有什么区别:static全局变量只初使化一次,防止在其他文件单元中被引用;
static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,下一次依据上一次结果值;
static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝
全局变量和静态变量如果没有手工初始化,则由编译器初始化为0。局部变量的值不可知。
C 中extern “C”含义深层探索
1.引言
C 语言的创建初衷是“a better C”,但是这并不意味着C 中类似C 语言的全局变量
和函数所采用的编译和链接方式与C 语言完全相同。作为一种欲与C 兼容的语言,C 保留了
一部分过程式语言的特点,因而它可以定义不属于任何类的全局变量和函数。但是,C 毕竟
是一种面向对象的程序设计语言,为了支持函数的重载,C 对全局函数的处理方式与C 有明
显的不同。
2.从标准头文件说起
某企业曾经给出如下的一道面试题:
面试题
为什么标准头文件都有类似以下的结构?
#ifndef _TEST_H
#define _TEST_H
#ifdef __cplusplus
extern "C" {
#endif
/*...*/
#ifdef __cplusplus
}
#endif
#endif /* _TEST_H */
分析
显然,头文件中的编译宏“#ifndef _TEST_H、#define _TEST_H、#endif” 的作用是防止
该头文件被重复引用。
那么
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
的作用又是什么呢?
3.深层揭密extern "C"
extern "C" 包含双重含义,从字面上即可得到:首先,被它修饰的目标是“extern”的;
其次,被它修饰的目标是“C”的。让我们来详细解读这两重含义。
被extern "C"限定的函数或变量是extern 类型的;
extern 是C/C 语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告
诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。记住,下列语句:
extern int a;
仅仅是一个变量的声明,其并不是在定义变量a,并未为a 分配内存空间(特别注意:实
际上现在一般的编译器都会对上述语句作声明处理,但链接器在链接过程中如果没有发现该
变量的定义,一般会在第一次遇到该变量声明的地方,自动定义)。变量a 在所有模块中作为
一种全局变量只能被定义一次,否则会出现连接错误。
通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字
extern 声明。例如,如果模块B 欲引用该模块A 中定义的全局变量和函数时只需包含模块A
的头文件即可。这样,模块B 中调用模块A 中的函数时,在编译阶段,模块B 虽然找不到该
函数,但是并不会报错;它会在连接阶段中从模块A 编译生成的目标代码中找到此函数。
与extern 对应的关键字是static,被它修饰的全局变量和函数只能在本模块中使用。因
此,一个函数或变量只可能被本模块使用时,其不可能被extern “C”修饰。
被extern "C"修饰的变量和函数是按照C 语言方式编译和连接的;
未加extern “C”声明时的编译方式
首先看看C 中对类似C 的函数是怎样编译的。
作为一种面向对象的语言,C 支持函数重载,而过程式语言C 则不支持。函数被C 编
译后在符号库中的名字与C 语言的不同。例如,假设某个函数的原型为:
void foo( int x, int y );
该函数被C 编译器编译后在符号库中的名字为_foo,而C 编译器则会产生像
_foo_int_int 之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,
生成的新名字称为“mangled name”)。
_foo_int_int 这样的名字包含了函数名、函数参数数量及类型信息,C 就是靠这种机制
来实现函数重载的。例如,在C 中,函数void foo( int x, int y )与void foo( int x, float
y )编译生成的符号是不相同的,后者为_foo_int_float。
同样地,C 中的变量除支持局部变量外,还支持类成员变量和全局变量。用户所编写程序的
类成员变量可能与全局变量同名,我们以"."来区分。而本质上,编译器在进行编译时,与函
数的处理相似,也为类中的变量取了一个独一无二的名字,这个名字与用户程序中同名的全
局变量名字不同。
未加extern "C"声明时的连接方式
假设在C 中,模块A 的头文件如下:
// 模块A 头文件 moduleA.h
#ifndef MODULE_A_H
#define MODULE_A_H
int foo( int x, int y );
#endif
在模块B 中引用该函数:
// 模块B 实现文件 moduleB.cpp
#i nclude "moduleA.h"
foo(2,3);
实际上,在连接阶段,连接器会从模块A 生成的目标文件moduleA.obj 中寻找
_foo_int_int 这样的符号!
加extern "C"声明后的编译和连接方式
加extern "C"声明后,模块A 的头文件变为:
// 模块A 头文件 moduleA.h
#ifndef MODULE_A_H
#define MODULE_A_H
extern "C" int foo( int x, int y );
#endif
在模块B 的实现文件中仍然调用foo( 2,3 ),其结果是:
(1)模块A 编译生成foo 的目标代码时,没有对其名字进行特殊处理,采用了C 语言的
方式;
(2)连接器在为模块B 的目标代码寻找foo(2,3)调用时,寻找的是未经修改的符号名_foo。
如果在模块A 中函数声明了foo 为extern "C"类型,而模块B 中包含的是extern int
foo( int x, int y ) ,则模块B 找不到模块A 中的函数;反之亦然。
所以,可以用一句话概括extern “C”这个声明的真实目的(任何语言中的任何语法特
性的诞生都不是随意而为的,来源于真实世界的需求驱动。我们在思考问题时,不能只停留
在这个语言是怎么做的,还要问一问它为什么要这么做,动机是什么,这样我们可以更深入
地理解许多问题):
实现C 与C 及其它语言的混合编程。
明白了C 中extern "C"的设立动机,我们下面来具体分析extern "C"通常的使用技巧。
4.extern "C"的惯用法
(1)在C 中引用C 语言中的函数和变量,在包含C 语言头文件(假设为cExample.h)
时,需进行下列处理:
extern "C"
{
#i nclude "cExample.h"
}
而在C 语言的头文件中,对其外部函数只能指定为extern 类型,C 语言中不支持extern
"C"声明,在.c 文件中包含了extern "C"时会出现编译语法错误。
笔者编写的C 引用C 函数例子工程中包含的三个文件的源代码如下:
/* c 语言头文件:cExample.h */
#ifndef C_EXAMPLE_H
#define C_EXAMPLE_H
extern int add(int x,int y);
#endif
/* c 语言实现文件:cExample.c */
#i nclude "cExample.h"
int add( int x, int y )
{
return x y;
}
// c 实现文件,调用add:cppFile.cpp
extern "C"
{
#i nclude "cExample.h"
}
int main(int argc, char* argv[])
{
add(2,3);
return 0;
}
如果C 调用一个C 语言编写的.DLL 时,当包括.DLL 的头文件或声明接口函数时,应加
extern "C" 。
(2)在C 中引用C 语言中的函数和变量时,C 的头文件需添加extern "C",但是在C
语言中不能直接引用声明了extern "C"的该头文件,应该仅将C 文件中将C 中定义的extern
"C"函数声明为extern 类型。
笔者编写的C 引用C 函数例子工程中包含的三个文件的源代码如下:
//C 头文件 cppExample.h
#ifndef CPP_EXAMPLE_H
#define CPP_EXAMPLE_H
extern "C" int add( int x, int y );
#endif
//C 实现文件 cppExample.cpp
#i nclude "cppExample.h"
int add( int x, int y )
{
return x y;
}
/* C 实现文件 cFile.c
/* 这样会编译出错:#i nclude "cExample.h" */
extern int add( int x, int y );
int main( int argc, char* argv[] )
{
add( 2, 3 );
return 0;
}
如果深入理解了第3 节中所阐述的extern "C"在编译和连接阶段发挥的作用,就能真正
理解本节所阐述的从C 引用C 函数和C 引用C 函数的惯用法。对第4 节给出的示例代码,
需要特别留意各个细节。
volatile 影响编译器编译的结果,指出,volatile 变量是随时可能发生变化的,与volatile变量有关的运算,不要进行编译优化,以免出错,(VC 在产生release版可执行码时会进行编译优化,加volatile关键字的变量有关的运算,将不进行编译优化。)。
例如:
volatile int i=;
int j = i;
...
int k = i;
volatile 告诉编译器i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的可执行码会重新从i的地址读取数据放在k中。
而优化做法是,由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在k中。而不是重新从i里面读。这样以来,如果i是一个寄存器变量或者表示一个端口数据就容易出错,所以说volatile可以保证对特殊地址的稳定访问,不会出错。
断言(assert)是一个包含布尔表达式的语句,在执行这个语句时假定该表达式为 true。如果表达式计算为 false,那么系统会报告一个 Assertionerror。它用于调试目的:
assert(a
redis 有一个端口占用cpu特别高
我来回答通常sniffer所要关心的内容可以分成这样几类:1、口令我想这是绝大多数非法使用sniffer的理由,sniffer可以记录到明文传送的userid和passwd.就算你在网络传送过程中使用了加密的数据,sniffer记录的数据一样有可能使入侵者在家里边吃肉串边想法算出你的算法。2、金融帐号许多用户很放心在网上使用自己的信用卡或现金帐号,然而sniffer可以很轻松截获在网上传送的用户姓名、口令、信用卡号码、截止日期、帐号和pin.3、偷窥机密或敏感的信息数据通过拦截数据包,入侵者可以很方便记录别人之间敏感的信息传送,或者干脆拦截整个的email会话过程。4、窥探低级的协议信息。这是很可怕的事,我认为,通过对底层的信息协议记录,比如记录两台主机之间的网络接口地址、远程网络接口ip地址、ip路由信息和tcp连接的字节顺序号码等。这些信息由非法入侵的人掌握后将对网络安全构成极大的危害,通常有人用sniffer收集这些信息只有一个原因:他正在进行一次欺诈,(通常的ip地址欺诈就要求你准确插入tcp连接的字节顺序号,这将在以后整理的文章中指出)如果某人很关心这个问题,那么sniffer对他来说只是前奏,今后的问题要大得多。(对于高级的hacker而言,我想这是使用sniffer的唯一理由吧)二.sniffer的工作环境snifffer就是能够捕获网络报文的设备。嗅探器的正当用处在于分析网络的流量,以便找出所关心的网络中潜在的问题。例如,假设网络的某一段运行得不是很好,报文的发送比较慢,而我们又不知道问题出在什么地方,此时就可以用嗅探器来作出精确的问题判断。嗅探器在功能和设计方面有很多不同。有些只能分析一种协议,而另一些可能能够分析几百种协议。一般情况下,大多数的嗅探器至少能够分析下面的协议:1.标准以太网2.TCP/IP3.IPX4.DECNet嗅探器通常是软硬件的结合。专用的嗅探器价格非常昂贵。另一方面,免费的嗅探器虽然不需要花什么钱,但得不到什么支持。嗅探器与一般的键盘捕获程序不同。键盘捕获程序捕获在终端上输入的键值,而嗅探器则捕获真实的网络报文。嗅探器通过将其置身于网络接口来达到这个目的——例如将以太网卡设置成杂收模式。(为了理解杂收模式是怎么回事,先解释局域网是怎么工作的)。数据在网络上是以很小的称为帧(Ftame)的单位传输的帧由好几部分组成,不同的部分执行不同的功能。(例如,以太网的前个字节存放的是源和目的的地址,这些位告诉网络:数据的来源和去处。以太网帧的其他部分存放实际的用户数据、TCP/IP的报文头或IPX报文头等等)。帧通过特定的称为网络驱动程序的软件进行成型,然后通过网卡发送到网线上。通过网线到达它们的目的机器,在目的机器的一端执行相反的过程。接收端机器的以太网卡捕获到这些帧,并告诉操作系统帧的到达,然后对其进行存储。就是在这个传输和接收的过程中,嗅探器会造成安全方面的问题。每一个在LAN上的工作站都有其硬件地址。这些地址唯一地表示着网络上的机器(这一点于Internet地址系统比较相似)。当用户发送一个报文时,这些报文就会发送到LAN上所有可用的机器。在一般情况下,网络上所有的机器都可以“听”到通过的流量,但对不属于自己的报文则不予响应(换句话说,工作站A不会捕获属于工作站B的数据,而是简单的忽略这些数据)。如果某在工作站的网络接口处于杂收模式,那么它就可以捕获网络上所有的报文和帧,如果一个工作站被配置成这样的方式,它(包括其软件)就是一个嗅探器。嗅探器可能造成的危害:1.嗅探器能够捕获口令2.能够捕获专用的或者机密的信息3.可以用来危害网络邻居的安全,或者用来获取更高级别的访问权限事实上,如果你在网络上存在非授权的嗅探器就以为着你的系统已经暴露在别人面前了。(大家可以试试天行2的嗅探功能)一般我们只嗅探每个报文的前到个字节。用户名和口令都包含在这一部分中,这是我们关心的真正部分。工人,也可以嗅探给定接口上的所有报文,如果有足够的空间进行存储,有足够的那里进行处理的话,将会发现另一些非常有趣的东西……简单的放置一个嗅探器宾将其放到随便什么地方将不会起到什么作用。将嗅探器放置于被攻击机器或网络附近,这样将捕获到很多口令,还有一个比较好的方法就是放在网关上。如果这样的话就能捕获网络和其他网络进行身份鉴别的过程。这样的方式将成倍地增加我们能够攻击的范围。三.谁会使用sniffers可能谁都回知道谁会使用sniffer,但是并不是每个使用它的人都是网络高手,因为现在有很多的sniffer都成了傻瓜似的了,前段时间用的最多的不外乎oicqsniffer。我想那些喜欢查好友ip的朋友都应该记得它吧。呵呵,我都使用过它,现在当然不用了啊!当然系统管理员使用sniffer来分析网络信息交通并且找出网络上何处发生问题。一个安全管理员可以同时用多种sniffer,将它们放置在网络的各处,形成一个入侵警报系统。对于系统管理员来说sniffer是一个非常好的工具,但是它同样是一个经常被黑客使用的工具.骇客安装sniffer以获得用户名和账号,信用卡号码,个人信息,和其他的信息可以导致对你或是你的公司的极大危害如果向坏的方面发展。当它们得到这些信息后,骇客将使用密码来进攻其他的internet站点甚至倒卖信用卡号码。三.sniffer是如何在网络上实施的谈这个问题之前还应该先说一下Ethernet的通讯。通常在同一个网段的所有网络接口都有访问在媒体上传输的所有数据的能力,而每个网络接口都还应该有一个硬件地址,该硬件地址不同于网络中存在的其它网络接口的硬件地址,同时,每个网络至少还要一个广播地址。在正常情况下,一个合法的网络接口应该只响应这样的两种数据帧:1帧的目标区域具有和本地网络接口相匹配的硬件地址。2帧的目标区域具有“广播地址”。在接受到上面两种情况的数据包时,网卡通过cpu产生一个硬件中断。该中断能引起操作系统注意,然后将帧中所包含的数据传送给系统进一步处理。而sniffer就是一种能将本地网卡状态设成杂乱模式(promiscuousMode)的软件。当网卡处于杂乱模式时,该网卡具备“广播地址”,它对所有遇到的每一个帧都产生一个硬件中断以提醒操作系统处理每一个报文包。(绝大多数的网卡具备设置成杂乱模式的能力。可见,sniffer工作在网络环境中的底层,它会拦截所有的正在网络上传送的数据。通过相应的软件处理,可以实时分析这些数据的内容,进而分析所处的网络状态和整体布局。值得注意的是:sniffer是极其安静的,它是一种消极的安全攻击。四.哪里可以得到sniffer我们讲的sniffer,主要是在unix系统下运用的,至于那些oicqsniffer就不在我们讨论的范围。Sniffer是黑客们最常用的入侵手段之一。你可以在经过允许的网络中运行sniffer,了解它是如何有效地危及本地机器安全。Sniffer可以是硬件,也可以是软件。现在品种最多,应用最广的是软件Sniffer,绝大多数黑客们用的也是软件Sniffer。以下是一些也被广泛用于调试网络故障的sniffer工具:(一).商用sniffer:1.NetworkGeneral.NetworkGeneral开发了多种产品。最重要的是ExpertSniffer,它不仅仅可以sniff,还能够通过高性能的专门系统发送/接收数据包,帮助诊断故障。还有一个增强产品"DistrbutedSnifferSystem"可以将UNIX工作站作为sniffer控制台,而将snifferagents(代理)分布到远程主机上。2.Microsoft'sNetMonitor对于某些商业站点,可能同时需要运行多种协议--NetBEUI、IPX/SPX、TCP/IP、.3和SNA等。这时很难找到一种sniffer帮助解决网络问题,因为许多sniffer往往将某些正确的协议数据包当成了错误数据包。Microsoft的NetMonitor(以前叫Bloodhound)可以解决这个难题。它能够正确区分诸如Netware控制数据包、NTNetBios名字服务广播等独特的数据包。(etherfind只会将这些数据包标识为类型的广播数据包。)这个工具运行在MSWindows平台上。它甚至能够按MAC地址(或主机名)进行网络统计和会话信息监视。只需简单地单击某个会话即可获得tcpdump标准的输出。过滤器设置也是最为简单的,只要在一个对话框中单击需要监视的主机即可。(二).免费软件sniffer1.Sniffit由LawrenceBerkeley实验室开发,运行于Solaris、SGI和Linux等平台。可以选择源、目标地址或地址集合,还可以选择监听的端口、协议和网络接口等。这个SNIFFER默认状态下只接受最先的个字节的信息包,这对于一次登陆会话进程刚刚好。2.SNORT:这个SNIFFER有很多选项供你使用并可移植性强,可以记录一些连接信息,用来跟踪一些网络活动。3.TCPDUMP:这个SNIFFER很有名,linux,FREEBSD还搭带在系统上,是一个被很多UNIX高手认为是一个专业的网络管理工具,记得以前TsutomuShimomura(应该叫下村侵吧)就是使用他自己修改过的TCPDUMP版本来记录了KEVINMITNICK攻击他系统的记录,后来就配合FBI抓住了KEVINMITNICK,后来他写了一文:使用这些LOG记录描述了那次的攻击,HowMitnickhackedTsutomuShimomurawithanIPsequenceattack((四).Linux下的sniffer工具Linux下的sniffer工具,我推荐Tcpdump。[1].tcpdump的安装在linux下tcpdump的安装十分简单,一般由两种安装方式。一种是以rpm包的形式来进行安装。另外一种是以源程序的形式安装。1.rpm包的形式安装这种形式的安装是最简单的安装方法,rpm包是将软件编译后打包成二进制的格式,通过rpm命令可以直接安装,不需要修改任何东西。以超级用户登录,使用命令如下:#rpm-ivhtcpdump-3_4a5.rpm这样tcpdump就顺利地安装到你的linux系统中。怎么样,很简单吧。2.源程序的安装既然rpm包的安装很简单,为什么还要采用比较复杂的源程序安装呢其实,linux一个最大的诱人之处就是在她上面有很多软件是提供源程序的,人们可以修改源程序来满足自己的特殊的需要。所以我特别建议朋友们都采取这种源程序的安装方法。·第一步取得源程序在源程序的安装方式中,我们首先要取得tcpdump的源程序分发包,这种分发包有两种形式,一种是tar压缩包(tcpdump-3_4a5.tar.Z),另一种是rpm的分发包(tcpdump-3_4a5.src.rpm)。这两种形式的内容都是一样的,不同的仅仅是压缩的方式.tar的压缩包可以使用如下命令解开:#tarxvfztcpdump-3_4a5.tar.Zrpm的包可以使用如下命令安装:#rpm-ivhtcpdump-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的源程序。使用makeinstall命令安装编译好的tcpdump的二进制文件。总结一下就是:#tarxvfztcpdump-3_4a5.tar.Z#viMakefile.in#./configure#make#makeinstall[2].Tcpdump的使用tcpdump采用命令行方式,它的命令格式为:tcpdump[-adeflnNOpqStvx][-c数量][-F文件名][-i网络接口][-r文件名][-ssnaplen][-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...2,指明...2是一台主机,net.0.0.0指明.0.0.0是一个网络地址,port指明端口号是。如果没有指定类型,缺省的类型是host.第二种是确定传输方向的关键字,主要包括src,dst,dstorsrc,dstandsrc,这些关键字指明了传输的方向。举例说明,src...2,指明ip包中源地址是...2,dstnet.0.0.0指明目的网络地址是.0.0.0。如果没有指明方向关键字,则缺省是srcordst关键字。第三种是协议的关键字,主要包括fddi,ip,arp,rarp,tcp,udp等类型。Fddi指明是在FDDI(分布式光纤数据接口网络)上的特定的网络协议,实际上它是"ether"的别名,fddi和ether具有类似的源地址和目的地址,所以可以将fddi协议包当作ether的包进行处理和分析。其他的几个关键字就是指明了监听的包的协议内容。如果没有指定任何协议,则tcpdump将会监听所有协议的信息包。除了这三种类型的关键字之外,其他重要的关键字如下:gateway,broadcast,less,greater,还有三种逻辑运算,取非运算是'not''!',与运算是'and','&&';或运算是'or','';这些关键字可以组合起来构成强大的组合条件来满足人们的需要,下面举几个例子来说明。(1)想要截获所有...1的主机收到的和发出的所有的数据包:#tcpdumphost...1(2)想要截获主机...1和主机...2或...3的通信,使用命令:(在命令行中适用括号时,一定要#tcpdumphost...1and\(...2or...3\)(3)如果想要获取主机...1除了和主机...2之外所有主机通信的ip包,使用命令:#tcpdumpiphost...1and!...2(4)如果想要获取主机...1接收或发出的telnet包,使用如下命令:#tcpdumptcpporthost....tcpdump的输出结果介绍下面我们介绍几种典型的tcpdump命令的输出信息(1)数据链路层头信息使用命令#tcpdump--ehosticeice是一台装有linux的主机,她的MAC地址是0::::AF:1AH是一台装有SOLARIC的SUN工作站,它的MAC地址是8:0:::5B:;上一条命令的输出结果如下所示:::.eth:0:::5b:::::af:1aip:h.>ice.telnet0:0(0)ackwin(DF)分析:::是显示的时间,是ID号,eth0表示从网络接口设备发送数据包,8:0:::5b:是主机H的MAC地址,它表明是从源地址H发来的数据包.0::::af:1a是主机ICE的MAC地址,表示该数据包的目的地址是ICE.ip是表明该数据包是IP数据包,是数据包的长度,h.>ice.telnet表明该数据包是从主机H的端口发往主机ICE的TELNET()端口.ack表明对序列号是的包进行响应.win表明发送窗口的大小是.(2)ARP包的TCPDUMP输出信息使用命令#tcpdumparp得到的输出结果是:::.eth0>arpwho-hasroutetellice(0::::af:1a)::.eth0表明从主机发出该数据包,arp表明是ARP请求包,who-hasroutetellice表明是主机ICE请求主机ROUTE的MAC地址。0::::af:1a是主机ICE的MAC地址。(3)TCP包的输出信息用TCPDUMP捕获的TCP包的一般输出信息是:src>dst:flagsdata-seqnoackwindowurgentoptionssrc>dst:表明从源地址到目的地址,flags是TCP包中的标志信息,S是SYN标志,F(FIN),P(PUSH),R(RST)"."(没有标记);data-seqno是数据包中的数据的顺序号,ack是下次期望的顺序号,window是接收缓存的窗口大小,urgent表明数据包中是否有紧急指针.Options是选项.(4)UDP包的输出信息用TCPDUMP捕获的UDP包的一般输出信息是:route.port1>ice.port2:udplenthUDP十分简单,上面的输出行表明从主机ROUTE的port1端口发出的一个UDP数据包到主机ICE的port2端口,类型是UDP,包的长度是lenth上面,我就详细介绍了TCPDUMP的安装和使用,希望会对大家有所帮助。如果想要熟练运用TCPDUMP这个LINUX环境下的SNIFFER利器,还需要大家在实践中总结经验,充分发挥它的威力。(五).windows平台上的sniffer我推荐netxray和snifferpro软件,想必大家都用过他们,不过我在这儿还要再简单介绍一下他们。