??xml version="1.0" encoding="utf-8" standalone="yes"?> q些最基本的职业技能通常军_了一个程序员的别,能否用好q些技能,直接关系CE序员的职业生(dng)。很多程序新手也是因为缺、达不到或是不熟(zhn)在q些基本技能,所以,他们需要有老手带,需要努力补齐这些技能。而高U程序员应该非常熟?zhn)q些基本技能,而且有能力胜dƈ带领其他l验不的程序员?/p> 下面q些基本职业技术可以用来做为对一个程序员的评伎ͼ很明显,下面的这些技能都可以用来做面试。虽?dng)q有很多非技术的因素Q但对于评估一个程序员的技术能力来_(d)其应该是_的了?/p> 下面是程序员所应该具备的基本职业技能:(x) 当然Q还有很多的基本技术也是非帔R要的Q比如,与h的沟通能力,语言的表达能力,写作能力Q团队协作能力,适应变化的能力,旉理能力Q多d处理能力Q自我学?fn)能力,故障处理能力Q等{,{等Q这里只是列举了和技术相关的能力Q这些是E序最最最基本的能力,只要是程序员必需要有的能力?br />基本技?/th> 技能描q?/th> 阅读代码 q个技能需要程序员能够具备L已经存在的代码的能力Q这L(fng)能力可以让程序员分析E序的行为,了解E序Q这h能和开发团队一起工作,l承l护或是改进现有的程序?/td> ~写E序 ~写E序q不包括E序设计。不要以为编E是一件很单的事情Q很多程序员都认为编E只需要懂得程序语a的语法,q把设计实现可以了。但是这ȝ写程序还q远不够Q用什么样的编码风格成为编写程序员最需要具备的基本技能。能否用非常良好的~程风格直接军_了程序员的别?/td> 软g设计 q一能力直接军_了需要吏用什么样的代码技术达到怎么L(fng)功能Q而系l架构设计直接决定了软g的质量、性能和可l护性。ƈ不是所有的E序在这一斚w都非怼UQ但每个E序员都需要或多或的明白和掌握这一基本技能?/td> 熟?zhn)软g工程 每个E序员都应该明白软g工程是什么东西,都应该知道,需求分析,设计Q编码,试QRelease和维护这几个阶段。当?dng)几乎所有的人都知道q些东西Q但q不是每个h都很清楚q些东西。现在很多高U程序员都会(x)h“需求规D明书FS”?#8220;概要设计HLD”。另外,E序员还需要知道一些Y件开发的Ҏ(gu)论,比如Q敏捷开发或瀑布模型?/td> 使用E序库或框架 一个程序员需要学?x)用已有的代码Q无论是标论的程序库Q或是第三方的,q是自己公司内部的,都需要学?x)做。比如:(x)C++中,需要学?x)用STLQMFCQATLQBOOSTQACEQCPPUNIT{等。用这些东西,可以让你的工作事半功倍?/td> E序调试 E序调试是分析BUG和解决问题最直接的能力。没有h能够保证E序写出来不用调试就可以q行正常Q也没有人可以保证程序永q不?x)出BUG。所以,熟练使用调试器是一个程序员需要具备的基本技能?/td> 使用IDE 学会(x)使用IDE工具也会(x)让你的工作事半功倍。比如,VC++QEmacsQEclipse{等Qƈ要知道这些IDE的长处和短处?/td> 使用版本控制 一定要学会(x)使用版本控制工具Q什么叫mainline/trunkQ什么叫tagQ什么叫branchQ怎么做patchQ怎么merge代码Q怎么reverseQ怎么利用版本控制工具l护不同版本的Y件。这是程序员需要明的的软g配置理中最重要的一块?/td> 单元试 单元试是每个程序都需要做的。很多单元测试也是需要编码的。一定要学会(x)在xUnit框架下进行单元测试。比如JUnit, NUnit, CppUnit{等?/td> 重构代码 每个E序员都需要有最基本的能力去重构目前已有的代码,使代码达到最优但却不能媄(jing)响Q何的已有的功能。有一本书叫《Y件的重构》,每个E序员都应该M下?/td> 自动化编?/td> E序员需要用一个脚本,其能自动化编E所有的工程和代码,q样Q整个开发团队可以不停地集成代码Q自动化试Q自动化部vQ以?qing)用一些工兯行静态代码分析或是自动化试?/td>
本文转自Q?a style="font-family: verdana, 'courier new'; line-height: 21px;">http://coolshell.cn/articles/428.html
]]>
可以修改下面属性:(x)
2?/span>VS2010~译错误Q?/span>
fatal error C1189: #error : This file requires _WIN32_WINNT to be #defined at least to 0x
在工E的stdafx.h中添加(如有cM语句Q需注释掉)
#define WINVER 0x0501 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
#endif
#ifndef _WIN32_WINNT // Allow use of features specific to Windows NT 4 or later.
#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
#endif
#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later.
#define _WIN32_WINDOWS 0x0501 // Change this to the appropriate value to target Windows Me or later.
#endif
#ifndef _WIN32_IE // Allow use of features specific to IE 4.0 or later.
#define _WIN32_IE 0x0601 // Change this to the appropriate value to target IE 5.0 or later.
#endif
]]>
1?/span>new A;
2?/span>new A();
也许很多人包括我自己Q都可以马上l出W一U情늚{案Q在堆上?/span>Acd配内存,然后调用A的构造函数。这U说法被大家所熟知Q因为包括?/span>STL源码剖析》等大作在内也都是这么写的(但是你认U说法完全正吗Q?/span>其实不尽?dng){案后面揭晓)
W二U情况,对象构造的时候初始化列表为空?x)和W一U有什么不同呢Q对于这U在实际工程中很用的情况Q我一时还真给不出切的答案?/span>
|上搜了一下,看到CSDN里面q有专门针对q个问题的一个帖子(原帖链接 http://bbs.csdn.net/topics/320161716Q?/span>
好像最l也没有可以信服的答案,认同度比较高的是q样的说法:(x)“加括可用没有参数的构造函敎ͼ不加括号调用默认构造函数或唯一的构造函敎ͼ看需?/span>” Q?/span>peakflys注:(x)q种说法是错误的Q答案后面揭晓)
既然没有特别靠谱的答案,不如自己动手扑և{案?/span>
构造以下示例:(x)
查看main函数的汇~代?/span>(~译器:(x)gcc (GCC) 4.4.6 20120305 (Red Hat 4.4.6-4) )
q种情况是类昄提供含默认值的构造函数?/span>
查看汇编实现如下Q?/span>
上面的汇~代码就不在d注释了,因ؓ(f)两种操作产生的汇~代码是一L(fng)Q都是先调用operator new分配内存Q然后调用构造函数?/span>
上面的情况在VS2010下验证是一L(fng)情况Q有兴趣的朋友可以自己去看,q里׃再脓(chung)?/span>VS2010下的汇编代码了?/span>
通过上面的分析,对于new A?/span> new A() 的区?/span>Q我们可以得Z面的l论Q?/span>
1、类体含有显C适合地默认构造函数时Q?/span>new A?/span>new A()的作用一_(d)都是首先调用operator new分配内存Q然后调用默认构造函数初始化对象?/span>
2、类体无昄构造函数时Q?/span>new A()首先调用operator new来ؓ(f)对象分配内存Q然后用空值初始化对象成员变量Q?/span>new A仅仅是调?/span>operator new分配内存Q对象的成员变量是无意义的随机| Q?/span>peakflys注:(x)对于基本数据cdQ如int{?/span> 适用此条Q?/span>
注意刎ͼ现在很多书籍?/span>new操作W的说明都存在纰漏,例如?/span>STL源码剖析》中2.2.2节中有以下的描述Q?/span>
事实证明Q?/span>new Foo的操作是否有构造函数的调用是不定的,具体要看FoocM里是否有昄构造函数的出现?/span>
/*****************************************华丽分割U?/span>**************************************
补充Q刚才发玎ͼ?/span>C++PrimerW四?/span>5.11节中Q已l有了对?/span>new A()的说明:(x)
We indicate that we want to value-initialize the newly allocated object by following the type nameby a pair of empty parentheses. The empty parentheses signal that we want initialization but arenot supplying a specific initial value. In the case of class types (such as string) that define their own constructors, requesting value-initialization is of no consequence: The object is initialized by running the default constructor whether we leave it apparently uninitialized orask for value-initialization. In the case of built-in types or types that do not define any constructors, the difference is significantQ?/span>
int *pi = new int; // pi points to an uninitialized int
int *pi = new int(); // pi points to an int value-initialized to 0
In the first case, the int is uninitialized; in the second case, the int is initialized to zero.
q里l出的解释和上面自己分析?/span>new A()的行为是一致的?br />
/***************************************再次华丽分割U?/span>************************************
鉴于上面的结论是通过GCC?/span>VS2010得出的,而且有朋友也提出同样的质疑,Z定q种l果是否是编译器相关的,刚才Ҏ(gu)查看了一?/span>C++的标准化文档?/span>
摘自Q?/span>ISO/IEC 14882:2003(E) 5.3.4 - 15
— If the new-initializer is omitted:
— If T is a (possibly cv-qualified) non-POD class type (or array thereof), the object is default-initialized(8.5). If T is a const-qualified type, the underlying class type shall have a user-declared default constructor.
— Otherwise, the object created has indeterminate value. If T is a const-qualified type, or a (possibly cv-qualified) POD class type (or array thereof) containing (directly or indirectly) a member of const-qualified type, the program is ill-formed;
— If the new-initializer is of the form (), the item is value-initialized (8.5);
所以可以确定,q种情况完全是编译器无关?/span>(当然那些不完全按照标准实现的~译器除?/span>)?/span>
但是通过上面标准化文档的描述Q我们可以看出文中对new A在无昄构造函数时的ȝq不是特别准,鉴于很多公司都有q道面试?/span>(撇去q些题目的实际考察意义不说)Q我们有必要再补充一下:(x) 对于new A: q样的语句,再调用完operator new分配内存之后Q如?/span>AcM内含?/span>PODcdQ则PODcd的成员变量处于未定义状态,如果含有?/span>PODcd则调用该cd的默认构造函数。?/span> new A()在这些情况下都会(x)初始化?/span>
PSQ估计很多公司的“正确{案“ 也不一定正吧?/span>
本文转自Q?/span>http://www.shnenglu.com/peakflys/archive/2013/04/08/199208.html
l 僵化性(RigidityQ:(x)很难对系l进行改动,因ؓ(f)每个改动都会(x)q许多对系l其他部分的其他改动?/span>
l 脆弱性(FragilityQ:(x)对系l的改动?x)导致系l中和改动的地方在概念上无关的许多地方出现问题?/span>
l 牢固性(ImmobilityQ:(x)很难解开pȝ的纠l,使之成ؓ(f)一些可在其他系l中重用的组件?/span>
l _滞性(ViscosityQ:(x)做正的事情比做错误的事情要困难?/span>
l 不必要的复杂性(Needless ComplexityQ:(x)设计中包含有不具M直接好处的基l构?/span>
l 不必要的重复Q?/span>Needless RepetitionQ:(x)设计中包含有重复的结构,而该重复的结构本可以使用单一的抽象进行统一?/span>
l 晦ӆ性(OpacityQ:(x)很难阅读、理解。没有很好的表现出意图?br />
敏捷设计是一个过E,不是一个事件。它是一个持l的应用原则、模式以?qing)实跉|改进软g的结构和可读性的q程。它致力于保持系l设计在M旉都尽可能得简单、干净以及(qing)富有表现?/span>?/span>
1。我们最优先要做的是通过早的、持l的交付有h(hun)值的软g来客户满意?/strong>
规划q代故事时必L照优先安排Qؓ(f)客户先提供最有h(hun)值的功能。通过频繁q代能与客户形成早期的良好合作,?qing)时反馈提高产品质量。敏捷小l关注完成和?付具有用户h(hun)值的功能Q而不是孤立的d。以前我们都用需求规D明书或者用例来~写详细的需求,敏捷使用用户故事来罗列需求。用h事是一U表C需求的 轻量U技术,它没?/span>
固定的Ş式和强制性的语法。但是有一些固定的形式可以用来参考还是比较有益的。敏捷估中使用了这个模板:(x)“作ؓ(f)【用L(fng)cd】,我希 望可以【能力】以ѝ业务h(hun)倹{?#8220;。用基于用h事的需求分析方法时Q仍可能需要原型和~写文档Q只是工作重Ҏ(gu)多的转移C口头交流?/span>
2。即使到了开发的后期Q也Ƣ迎改变需求。敏捯E利用变化来为客户创造竞争优ѝ?/strong>
敏捷q程参与者不怕变化,他们认ؓ(f)改变需求是好事情,因ؓ(f)q些改变意味着我们更了解市场需求?/span>
3。经常性的交付可以工作的YӞ交付的间隔可以从几周到几个月Q交付的旉间隔短好?/strong>
q代是受实践框限制的Q意味着即攑ּ一些功能也必须按时l束q代。只要我们可以保证交付的软g可以很好的工作,那么交付旉短Q我们和客户协作p 紧密Q对产品质量更有益。虽然我们多ơP代,但ƈ不是每次q代的结果都需要交付给用户Q敏捷开发的目标是让他们可以交付。这意味着开发小l在每次q代?都会(x)增加一些功能,增加的每个功能都是经q编码、测试,辑ֈ了可发布的质量标准的?/span>
另外敏捷开发项目中对开发阶D|有什么重要的分割Q没有先期的需求阶D,然后是分析阶D,架构设计阶段Q编码测试阶D늭Q在目真正开始后Q每ơP代中都会(x)同时q?/span>
行所有的上述阶段工作?/span>
4。在整个目开发期_(d)业务人员和开发h员必d天都在一起工作?/strong>
软g目不会(x)依照之前讑֮的计划原路执行,中间对业务的理解、Y件的解决Ҏ(gu)肯定?x)存在偏差,所以客戗需求h员、开发h员以?qing)涉众之间必进行有意义的、频J?nbsp;
的交互,q样可以在早期?qing)时的发现ƈ解决问题?/span>
5。围l被Ȁpv来的Z来构建项目。给他们提供所需要的环境和支持,q且信Q他们能够完成工作?/strong>
业务和技术是引v不确定的二个主要斚wQh是第三个斚w。而业务和技术又必须׃h来执行,所以能够激׃h来解册些问题是解决不确定性的关键。只要个人的目标和团
队的目标一_(d)我们需要鼓舞v每个人的U极性,以个Zؓ(f)中心构徏目Q提供所需的环境、支持与信Q?/span>
6。在团队内部Q最h效果q且富有效率的传递信息的Ҏ(gu)Q就是面寚w的交谈?/strong>
在十几或者二十几个hl成的大团队中,文档是一U比较合适的传递知识和交流的途径。而敏捷团队一般不?x)很多hQ大团队实施敏捷时也?x)分成多个小的敏捷团队)Q所?/span>
大量的文档交其实ƈ不是很经的做法。此旉寚w的交谈反而更快速有效?/span>
7、可工作的Y件是首要q度度量标准?/strong>
一般的工作都比较容易衡量Q务进展,比如让你Lq?吨的矛_Q我只要ȝ一下你已经搬运的石头重量就知道你完成多了。而对于Y件来_(d)在Y件没有编 码、测试完
成之前,我们都不能因Z码编写了多少行,试用例跑了多少个就d量这个功能是否完成了。衡量这个功能是否完成的首要标准是q个功能可以?作了Q对用户来说已经?/span>
以应用了?/span>
8。敏捯E提可持l的开发速度。责Mh、开发者和用户应该能够保持一个长期的、恒定的开发速度?/strong>
很多人都认ؓ(f)软g开发中加班是很正常的,不加班反而不正常Q我Ҏ(gu)有点不理解,q个可能是国情所致吧。敏捯E希望能够可持箋的进行开发,开发速度不会(x) 随着q代的Q务不同而不同,不欣赏所谓的gg能完成的态度Q开发工作不应该是突击行为。我们不能指望说H击q个目后就可以L了,因ؓ(f)完成一个项?后会(x)接踵而来下一个项目,而只要还是拼拼的态度Q下一个项目依旧会(x)让你的组员再ơ突凅R这时不知道有h?x)不会(x)说Q那我们׃直加班,也是“持箋的开发??#8221;啊,q时可要注意了,持箋加班?/span>
慧导致h疲劳、厌倦,保持长期恒定的速度也只是一U理惌已?/span>
9。不断地x优秀的技能和好的设计?x)增强敏捯力?/strong>
敏捷q程有很多好的技术实践可以加Z品敏捯力,很多原则、模式和实践也可以增强敏捷开发能力?《敏捯Y件开发-原则、模式与实践》一书中介绍了很多设计,感兴的可以Ml看看?/span>
10。简?---使未完成的工作最大化的艺?---是根本的?/strong>
我们不可能预期后面需求会(x)如何变化Q所以不可能一开始就构徏一个完的架构来适应以后的所有变化。敏捷团队不?x)去构徏明天的YӞ而把注意力放在如何?q最单的Ҏ(gu)完成现在需要解决的问题。这时有Z(x)_(d)我已l预计到了肯定存在哪些需求扩展点Q我们在一开始是否需要考虑呢?q时团队需要根据自q理解 d定是否考虑Q如果深信在明天发生了这个问题也可以L处理的话Q那么就最好先不考虑?/span>
11。最好的构架、需求和设计与自l织的团队?/strong>
敏捷中有很多U实践,大家都知道,q代式开发是主要的实跉|法,而自l织团队也是主要的实践之一。在自组l团队中Q管理者不再发h令,而是让团队自w寻找最佳的工作方式来完成工作。要形成一个自l织团队其实比较难。CSDN采访Mishkin Berteig中说?自组l团队的W一个要素就是必L一个团队,而不仅仅是一h。一h是一帮在一起工作的人,他们彼此之间q没有太多的沟通,他们也ƈ不视彼此Z体。项目一开始,我们׃(x)l徏“团队”Q但很多时候由构架师、需求h员、开发h员和试人员l成的是一h而已。他q认为,团队的Ş成必ȝ历几个时期。在 l历了初期的合后,成员才会(x)开始对团队共同的工作理念与文化形成一个基本的认识和理解。团队内?x)逐渐形成规矩Q而且q些规矩是不a而喻的。比如,每个?都知道上午九(ji)Ҏ(gu)上班Q都?x)主动询问别人是否需要帮助,也都?x)去d和别人探讨问题。如果团队成员之间能够达成这L(fng)默契Q那么这个团队将成ؓ(f)一个真正高 效的工作团队。在q样团队中,成员之间怺理解Q工作效率非帔R。在自组l团队中Q团队成员不需要遵从别人的详细指o(h)。他们需要更高层ơ的指导Q这U指 导更像是一个目标,一个致力于开发出更好的Y件的目标。MQ自l织团队是一个自动自发、有着共同目标和工作文化的团队Q这L(fng)团队L在向它的l织做出 承诺。但是,实现q些承诺对于自组l团队来说非帔R要。否则,一旦出现问题,团队成员之间׃(x)出现信Q危机?/span>
虽然敏捷开发小l是以小lؓ(f)整体 来工作的Q但是还是有必要指明一些承担一定Q务的角色。第一个角色是产品所有者(Product OwnerQ。品所有者的主要职责包括Q确认小l所有成员都在追求一个共同的目前景Q确定功能的优先U以便L在处理最h价值的功能Q以?qing)作出决?使得寚w目的投入可以产生良好的回报。可以对应ؓ(f)以前开发中?#8220;产品l理”。另一角色是开发团队(developerQ,q里的开发h员包括了架构师、设计师、程序员、需求h员、测试h员、文档编写者等Q有时品所有者也可以被看作是
开发h员。还有一个重要角色就是项目经理(project managerQ。敏捷开发的目l理?x)更多的x领导而不是管理。在某些目中,目l理可能同时也是开发h员,数时候也?x)担M品所有者?/span>
12。每隔一定时_(d)团队?x)在如何才能更有效地工作斚wq行反省Q然后相应地对自q行ؓ(f)q行调整?/strong>
׃很多不确定性因素会(x)D计划失效Q比如项目成员增减、技术应用效果、用户需求的改变、竞争者对我们的媄(jing)响等都会(x)让我们作Z同的反应。 敏捷不是Z预定义的工作方式Q而是Zl验性的方式Q对以上q些变化Q小l通过不断的反省调整来保持团队的敏h?/span>
l 单一职责原则Q?/span>The Single Responsibility PrincipleQ简U?/span>SRPQ:(x)׃个类而言Q应该仅有一个引起它变化的原?/span>。在SRP中,我们把职责定义ؓ(f)“变化的原因(Q?#8221;。如果你能够惛_多于一个的动机L变一个类Q那么这个类具有多于一个的职责。Y件设计真正要做的许多内容Q就是发现职责ƈ把那些职责相互分R?/span>事实上,我们要的其余原则都?x)以q样或那L(fng)方式回到q个问题上?/span>
l 开攑ְ闭原?/span>Q?/span>The Open-Close PrincipleQ简U?/span>OCPQ:(x)软g实体Q类、模块、函数等{)应该是可以扩展的Q但是不可以修改?/span>。遵循开攑ְ闭原则设计出的模块具有两个主要的特征。它们是Q(1Q、对于扩展是开攄。这意味着模块的行为是可以扩展的。当应用的需求改变时Q我们可以对模块q行扩展Q其具有满那些改变的新行为。换句话_(d)我们可以改变模块的功能。(2Q、对模块行ؓ(f)q行扩展Ӟ不必改动模块的源代码或者二q制代码。模块的二进制可执行版本Q无论是可链接的库?/span>DLL或?/span>Java?/span>.jar文gQ都无需改动?/span>
l Liskov替换原则Q?/span>The Liskov Substitution PrincipleQ简U?/span>LSPQ:(x)子类型必能够替换掉它们的基cd?/span>OCP原则?/span>OOD中很多说法的核心?/span>LSP是OCP成ؓ(f)可能的主要原则之一。正式子cd的可替换性才使得使用基类cd的模块在无需修改的情况下可以扩展。这U可替换性必L开发h员可以隐式依赖的东西?/span>
l 依赖倒置原则Q?/span>The Dependency Inversion PrincipleQ简U?/span>DIPQ:(x)Q?/span>1Q、高层模块不应该依赖于底层模块。二者都应该依赖于抽?/span>。(2Q、抽象不应该依赖于细节。细节应该依赖于抽象。用传l的q程化设计所创徏出来的依赖关pȝ构,{略是依赖于l节的。面向对象的E序设计倒置了依赖关pȝ构,使得l节和策略都依赖于抽象,q且常常是客h有服务接口。事实上Q这U依赖关pL式好的面向对象设计的标志所在?/span>
l 接口隔离原则Q?/span>The Interface Segregation InterfaceQ简U?/span>ISPQ:(x)不应该强q客户依赖它们不用的Ҏ(gu)。如果强q客L(fng)序依赖于那些它们不适用的方法,那么q些客户E序面临着׃q些未用方法的改变所带来的变更。这无意中D了所有客L(fng)序之间的耦合。我们希望尽可能地避免这U耦合Q因此我们希望分L口?/span>
极限~程Q?/span>eXtreme ProgrammingQ简U?/span>XPQ是敏捷Ҏ(gu)中最著名的一个。它׃pd单却怺依赖的时间组成。这些实늻合在一起Ş成了一个胜于部分结合的整体。其中一个非帔R要的Q当前也受到格外重视的实践就?/span>TDDQ测试驱动的开发方法)?/span>
在测试驱动的开发方法中Q编写所有的代码的目的都是ؓ(f)了p|的单元测试能够通过。首先编写一个单元测试,׃它要试的功能还不在Q所以它?x)运行失败。然后编写代码ɋ试通过?/span>
~写试用例和代码之间的更P速度是很快的Q基本上几分钟左叟뀂测试用例和代码共同演化Q其中测试用例@序渐q地对代码的~写q行指导。作为结果,一个非常完整的试用例集和代码一起发展v来?/span>
试_略的可以分为单元测试和验收试。单元测试是用来验证pȝ中个别机制的白盒试?/span>
单元试用来验证pȝ的小的组成单元应该按照所期望的方式工作,但是它们没有验证pȝ作ؓ(f)一个整体时工作的正性。所以,单元试是必要的Q但是不够充分?/span>
验收试是用来验证系l满_户需求的黑盒试。验收测试由不了解系l内部机制的人编写。验收测试是E序Q因此是可运行的。通常通过使用专门为应用程序的客户创徏的脚本语a来编写验收测试。正如单元测试作为可~译、运行的有关pȝ内部l构的文档那P验收试是有关系l特性的可编译、执行的文档?/span>
~写代码前就~写单元试?x)带来四个很明显的好处?x)
1、首先编写测试得程序中的每一功能都有测试来验证它的操作的正性。这可以给以后的开发提供支_(d)使我们可以更自由地对E序q行更改Q因为测试可以告诉我们程序仍然具有正的行ؓ(f)?/span>
2、首先编写测试迫使我们必ME序调用者的有利视角去观察我们将要编写的E序。这P我们׃(x)在关注程序的功能的同Ӟ直接x它的接口Q我们也可以设计出便于调用的Y件?/span>
3、首先编写测试迫使我们把E序设计为可试的。ؓ(f)了把E序设计为易于调用和可测试的Q程序必d它周边环境解耦。这样首先编写测试迫使我们解除Y件中的耦合。面向对象设计的原则在进行这U解除耦合斚wh巨大的帮助作用?/span>
4、首先编写测试的另一个重要效果是Q测试可以作ZU无L(fng)文档形式。测试就像一套范例,它帮助其他程序员了解如何使用代码。这份文档是可编译、可q行的。它保持最新。它不会(x)撒谎?/span>
首先~写验收试的行为对于系l的架构斚whp的媄(jing)响。ؓ(f)了ɾpȝh可测试性,必要在很高的pȝ架构层面对系l进行解耦合。正如单元测试可以促使你在小的方面可以做Z良的设计决策一P验收试可以促你在大的斚w做出优良的系l架构决{?br />
软g大师?/span>C++之父Bjarne Stroustrup曄说过Q设计和~程都是人的zd。忘Cq一点,会(x)失去一?/span>。敏捯Y件开发方法正是认识到软g开发的q一本质特征而提出的革新性开发方法。用敏捷开发方法会(x)l我们带来巨大的好处。当然要完全做到也是很困隄。这不仅需要对敏捷的深ȝ解,更需要敏捷团队成员的共同努力?/span>
我们常常?x)通过观摩C体会(x)q学?fn)艺术的_NQ而可扩展性也应该遵@同样的\U!
在这文章中Q我列出数ƾؓ(f)大家所耳熟能详的可扩展性架构。通常情况下,架构师们完全可以借鉴已知的可扩展架构模式Q进而创造出新的可扩展架构?/p>
lg所qͼ可扩展性的实现只有三种方式Q即Q分布、缓存及(qing)异步处理。前文所提到的各U架构事实上都是把这三种方式q行不同l合q加以实施。而另一?面,不利于可扩展性的因素Q除了糟p的~码本nQ全局性协调也起到了重要的影响。简单来_(d)M一U全局性协调都?x)限制系l的可扩展性。本文中所提到的各 U架构也只是在做好了本地性协调,而非全局性协调?/p>
然而,它们有机地l合h以创Z套极具可扩展性的架构可不像说h那么Ҏ(gu)Q除非我们能扑ֈ一U全新的扩展模式。不q经验告诉我们,比v搞一套全新的架构Q采用ؓ(f)我们所熟知且更易驾驭的可扩展性解x案永q是更好的选择?/p>
搜烦(ch)质量评估是搜索技术研I的基础性工作,也是核心工作之一。评PMetricsQ在搜烦(ch)技术研发中扮演着重要角色Q以至于M一U新Ҏ(gu)与他们的评h(hun)方式是融Z体的?/p>
A Cranfield-like approachq个名称来源于英国Cranfield UniversityQ因为在二十世纪五十q代该大学首先提Zq样一套评L(fng)l:(x)由查询样例集、正答案集、评指标构成的完整评测Ҏ(gu)Qƈ从此立?#8220;评h(hun)”在信息检索研I中的核心地位?/p>
Cranfield评h(hun)体系׃个环节组成:(x)
Cranfield评h(hun)pȝ在各大搜索引擎公司内有广泛的应用。具体应用时Q首先需要解决的问题是构造一个测试用查询词集合?/p>
按照Andrei BroderQ曾在AltaVista/IBM/Yahoo任职Q的研究Q查询词可分?c:(x)dcL询(NavigationalQ、信息类查询(Informational)、事务类查询(Transactional)。对应的比例分别?/p>
Navigational Q?12.3% Informational Q?62.0% Transactional Q?25.7%
Z使得评估W合U上实际情况Q通常查询词集合也?x)按比例q行选取。通常从线上用L(fng)Query Log文g中自动抽取?/p>
另外查询集合的构造时Q除了上q查询类型外Q还可以考虑Query的频ơ,对热门queryQ高频查询)、长queryQ中低频Q分别占特定的比例?/p>
另外Q在抽取QueryӞ往往Query的长短也是一个待考虑的因素。因为短queryQ单term的查询)和长QueryQ多Term的查询)排序法往往?x)有一些不同?/p>
构成查询集合后,使用q些查询词,在不同系l(例如Ҏ(gu)癑ֺ和GoogleQ或不同技术间Q新旧两套Ranking法的环境)q行搜烦(ch)Qƈ对结果进行评分,以决定优劣?/p>
附图Q对同一QueryQ?#8220;C会(x)保险?#8221;Q各大搜索引擎的l果C意图。下面具体谈谈评分的Ҏ(gu)?/p>
信息(g)索领域最qؓ(f)人知的评h标ؓ(f)Precision-RecallQ准率-召回率)Ҏ(gu)。该Ҏ(gu)从提今已l历半个世纪Q至今在很多搜烦(ch)引擎公司的效果评C使用?/p>
思义Q这个方法由准确率和召回率这两个怺兌的统计量构成Q召回率QRecallQ衡量一个查询搜索到所有相x档的能力Q而准率QPrecisionQ衡量搜索系l排除不相关文档的能力。(通俗的解释一下:(x)准确率就是算一你查询得到的结果中有多是靠谱的;而召回率表示所有靠ql果中,有多被你给扑֛来了Q。这两项是评h索效果的最基础指标Q其具体的计方法如下?/p>
Precision-recallҎ(gu)假定对一个给定的查询Q对应一个被(g)索的文档集合和一个不相关的文档集合。这里相x被假设Z元的Q用数学形式化方法来描述Q则是:(x)
A表示相关文档集合
A表示不相关集?/p>
B表示被检索到的文档集?/p>
B表示未被(g)索到的文档集?/p>
则单ơ查询的准确率和召回率可以用下述公式来表达:(x)
Q运符∩ 表示两个集合的交集。|x|W号表示集合x中的元素数量Q?/p>
从上面的定义不难看出Q召回率和准率的取D围均在[0,1]之间。那么不难想象,如果q个pȝ扑֛的相兌多,那么召回率越高,如果相关l果全部都给召回了,那么recall此时q?.0?/p>
相关?/p> | 不相?/p> | |
被检索到 | A∩ B | A∩ B |
未被(g)索到 | A∩B | A∩B |
召回率和准确率分别反映了(g)索系l的两个最重要的侧面,而这两个侧面又相互制U。因为大规模数据集合中,如果期望(g)索到更多相关的文档,必然需?#8220;攑֮”(g)索标准,因此?x)导致一些不相关l果淯来,从而准确率受到媄(jing)响。类似的Q期望提高准率Q将不相x档尽量去除时Q务必要执行?#8220;严格”的检索策略,q样也会(x)使一些相关的文档被排除在外,使召回率下降?/p>
所以ؓ(f)了更清晰的描qC者间的关p,通常我们Precison-Recall用曲U的方式l制出来Q可以简UCؓ(f)P-R diagram。常见的形式如下图所C。(通常曲线是一个逐步向下的走势,即随着Recall的提高,Precision逐步降低Q?/p>
一些特定搜索应用,?x)更x搜烦(ch)l果中错误的l果。例如,搜烦(ch)引擎的反作弊pȝQAnti-Spam SystemQ会(x)更关注检索结果中混入了多条作弊l果。学术界把这些错误结果称作假x(F(tun)alse PositiveQ结果,对这些应用,通常选择用虚报率QF(tun)alloutQ来l计Q?/p>
Fallout和Presion本质是完全相同的。只是分别从正反两方面来计算。实际上是P-R的一个变U?/p>
再回C图,Presion-Recall是一个曲U,用来比较两个Ҏ(gu)的效果往往不够直观Q能不能对两者进行综合,直接反映C个数g呢?为此IR学术界提ZF值度量(F(tun) -MeasureQ的Ҏ(gu)。F-Measure通过Presion和Recall的调和^均数来计,公式为:(x)
其中参数λε(0,1)调节pȝ对Precision和Recall的^衡程度。(通常?#955;=0.5Q此?nbsp;Q?/p>
q里使用调和q_数而不是通常的几何^均或术q_Q原因是调和q_数强调较?yu)数值的重要性,能敏感的反映数字的变化Q因此更适合用来反映(g)索效果?/p>
使用F Measure的好处是只需要一个单一的数字就可以ȝpȝ的检索效果,便于比较不同搜烦(ch)pȝ的整体效果?/p>
传统的Precision-Recallq不完全适用Ҏ(gu)索引擎的评估Q原因是搜烦(ch)引擎用户的点?yn)L式有其特D性,包括Q?/p>
A 60-65%的查询点M名列搜烦(ch)l果?0条的|页Q? B 20-25%的h?x)考虑点击名列11?0的网; C 仅有3-4%的会(x)点击名列搜烦(ch)l果中列W?1到第30名的|页
也就是说Q绝大部分用h不愿意翻去看搜索引擎给出的后面的结果?/p>
而即使在搜烦(ch)l果的首(通常列出的是?0条结果)Q用L(fng)点击行ؓ(f)也很有意思,我们通过下面的Google点击热图QHeat MapQ来观察Q这个热囑֜二维搜烦(ch)l果上通过光谱来Ş象的表达不同位置用户的点ȝ度。颜色约靠近U色表示点击强度高Q:(x)
从图中可以看出,搜烦(ch)l果的前3条吸引了大量的点击,属于热度最高的部分。也是_(d)Ҏ(gu)苏引擎来_(d)最前的几条l果是最关键的,军_了用L(fng)满意E度?/p>
康乃?yu)(dng)大学的研究人员通过eye tracking实验获得了更为精的Google搜烦(ch)l果的用戯为分析图。从q张图中可以看出Q第一条结果获得了56.38%的搜索流量,W二条和W三条结果的排名依次降低Q但q低于排名第一的结果。前三条l果的点?yn)L例大Uؓ(f)11:3:2 。而前三条l果的ȝd乎分了搜烦(ch)量?0%?/p>
另外的一些有的l论是,点击量ƈ不是按照序依次递减的。排名第七位获得的点?yn)L最的Q原因可能在于用户在览q程中下拉页面到底部Q这时候就只显C最后三位排名网站,W七名便Ҏ(gu)被忽略。而首屏最后一个结果获得的注意力(2.55Q是大于倒数W二位的(1.45)Q原因是用户在翻前Q对最后一条结果印象相对较深。搜索结果页面第二页排名W一的网(xL?1位的l果Q所获得的点d有首|名第十网站的40%Q与首页的第一条结果相比,更是只有?/60?/100的点击量?/p>
因此在量化评估搜索引擎的效果Ӟ往往需要根据以上搜索用L(fng)行ؓ(f)特点Q进行针Ҏ(gu)的设计?/p>
P@N本n是Precision@N的简Uͼ指的是对特定的查询,考虑位置因素Q检前N条结果的准确率。例如对单次搜烦(ch)的结果中?,如果?ؓ(f)相关文档Q则P@5 = 4/5 = 0.8 ?/p>
试通常?x)用一个查询集合(按照前文所q方法构造)Q包含若q条不同的查询词Q在实际使用P@Nq行评估Ӟ通常使用所有查询的P@N数据Q计算术^均|用来评判该系l的整体搜烦(ch)l果质量?/p>
对用h_(d)通常只关注搜索结果最前若q条l果Q因此通常搜烦(ch)引擎的效果评估只x?、或者前3l果Q所以我们常用的N取gؓ(f)P@3或P@5{?/p>
对一些特定类型的查询应用Q如dcȝ查询QNavigational SearchQ,׃目标l果极ؓ(f)明确Q因此在评估Ӟ?x)选择N=1Q即使用P@1Q。D个例子来_(d)搜烦(ch)“新浪|?#8221;、或“新浪首页”Q如果首条结果不?新浪|(urlQ?a style="box-sizing: border-box; color: #0b59b2;">www.sina.com.cnQ,则直接判该次查询_ֺ不满需求,即P@1=0
上述的P@NҎ(gu)Q易于计和理解。但l心的读者一定会(x)发现问题Q就是在前Nl果中,排序W?位和WN位的l果Q对准确率的影响是一L(fng)。但实际情况是,搜烦(ch)引擎的评h和排序位|极为相关的。即排第一的结果错误,和第10位的l果错误Q其严重E度有天壤之别。因此在评h(hun)pȝ中,需要引入位|这个因素?/p>
MRR是^均排序倒数QMean Reciprocal RankQ的UͼMRRҎ(gu)主要用于dcL索(Navigational SearchQ或问答cL索(Question AnsweringQ,q些(g)索方法只需要一个相x档,对召回率不敏感,而是更关注搜索引擎检索到的相x档是否排在结果列表的前面。MRRҎ(gu)首先计算每一个查询的W一个相x档位|的倒数Q然后将所有倒数值求q_。例如一个包含三个查询词的测试集Q前5l果分别为:(x)
查询一l果Q?.AN 2.AR 3.AN 4.AN 5.AR 查询二结果:(x)1.AN 2.AR 3.AR 4.AR 5.AN 查询三结果:(x)1.AR 2.AN 3.AN 4.AN 5.AR
其中AN表示不相关结果,AR表示相关l果。那么第一个查询的排序倒数QReciprocal RankQRR1 = 1/2=0.5 Q第二个l果RR2 = 1/2 = 0.5 Q?注意倒数的g变,即查询二获得的相关l果更多。同理,RR3= 1/1 = 1?对于q个试集合Q最lMRR=QRR1+RR2+RR3Q? 3 = 0.67
然而对大部分检索应用来_(d)只有一条结果无法满需求,对这U情况,需要更合适的Ҏ(gu)来计效果,其中最常用的是下述MAPҎ(gu)?/p>
MAPҎ(gu)是Mean Average PrecisonQ即q_准确率法的简U。其定义是求每个相关文档(g)索出后的准确率的q_|即Average PrecisionQ的术q_|MeanQ。这里对准确率求了两ơ^均,因此UCؓ(f)Mean Average Precision。(注:(x)没叫Average Average Precision一是因为难听,二是因ؓ(f)无法区分两次q_的意义)
MAP 是反映系l在全部相关文档上性能的单值指标。系l检索出来的相关文档靠?rank 高)QMAP应该越高。如果系l没有返回相x档,则准率默认??/p>
例如Q假设有两个主题Q?/p>
主题1?个相关网,主题2?个相关网c(din)?/p>
某系l对于主?(g)索出4个相关网,其rank分别?, 2, 4, 7Q?/p>
对于主题2(g)索出3个相关网,其rank分别?,3,5?/p>
对于主题1Q^均准率MAP计算公式为:(x)
(1/1+2/2+3/4+4/7)/4=0.83?
对于主题2Q^均准率MAP计算公式为:(x)
(1/1+2/3+3/5+0+0)/5=0.45?
则MAP= (0.83+0.45)/2=0.64?#8221;
DCG是英文Discounted cumulative gain的简Uͼ中文可翻译ؓ(f)“折扣增益?#8221;。DCGҎ(gu)的基本思想是:(x)
我们首先来看W一条:(x)相关性分U。这里比计算Precision时简单统?#8220;准确”?#8220;不准?#8221;要更为精l。我们可以将l果l分为多个等U。比如常用的3U:(x)GoodQ好Q、FairQ一般)、BadQ差Q。对应的分值rel为:(x)Good:3 / Fair:2 / Bad:1 。一些更为细致的评估使用5U分cLQVery GoodQ明昑֥Q、GoodQ好Q、FairQ一般)、BadQ差Q、Very BadQ明昑ַQ,可以对应分值rel讄为:(x)Very Good:2 / Good:1 / Fair:0 / Bad:-1 / Very Bad: -2
评判l果的标准可以根据具体的应用来确定,Very Good通常是指l果的主题完全相养Iq且|页内容丰富、质量很高。而具体到每条
DCG的计公式ƈ不唯一Q理Z只要求对数折扣因子的qx性。我个h认ؓ(f)下面的DCG公式更合理,了相x,W??条结果的折扣pL也更合理Q?/p>
此时DCG?个位|上l果的折扣因子(Discount factorQ数gؓ(f)Q?/p>
i | log2 (i+1) | 1/log2 (i+1) |
1 | 1 | 1 |
2 | 1.59 | 0.63 |
3 | 2 | 0.5 |
4 | 2.32 | 0.43 |
取以2为底的logg来自于经验公式,q不存在理论上的依据。实际上QLog的基数可以根据^滑的需求进行修改,当加大数值时Q例如用log5 代替log2Q,折扣因子降低更ؓ(f)q速,此时了前面结果的权重?/p>
Z便于不同cd的queryl果之间横向比较Q以DCG为基Q一些评L(fng)l还对DCGq行了归一Q这些方法统UCؓ(f)nDCGQ即 normalize DCGQ。最常用的计方法是通过除以每一个查询的理想值iDCGQideal DCGQ来q行归一Q公式ؓ(f)Q?/p>
求nDCG需要标定出理想情况的iDCGQ实际操作的时候是异常困难的,因ؓ(f)每个人对“最好的l果”理解往往各不相同Q从量数据里选出最优结果是很困隄dQ但是比较两l结果哪个更好通常更容易,所以实践应用中Q通常选择l果Ҏ(gu)的方法进行评估?/p>
以上所介绍的搜索引擎量化评估指标,在Cranfield评估框架QCranfield Evaluation FrameworkQ中被广泛用。业界知名的TRECQ文本信息检索会(x)议)׃直基于此cL法组l信息检索评和技术交。除了TREC外,一些针对不同应用设计的Cranfield评测论坛也在q行q行Q如 NTCIR、IREX{)?/p>
但Cranfield评估框架存在的问题是查询样例集合的标注上。利用手工标注答案的方式q行|络信息(g)索的评h(hun)是一个既耗费人力、又耗费旉的过E,只有数大公司能够用。ƈ且由于搜索引擎算法改q、运营维护的需要,(g)索效果评价反馈的旉需要尽量羃短,因此自动化的评测Ҏ(gu)Ҏ(gu)高评估效率十分重要。最常用的自动评估方法是A/B testingpȝ?/p>
A/B Testingpȝ
A/B testingpȝ在用h索时Q由pȝ来自动决定用L(fng)分组PBucket idQ,通过自动抽取量导入不同分支Q得相应分l的用户看到的是不同产品版本Q或不同搜烦(ch)引擎Q提供的l果。用户在不同版本产品下的行ؓ(f)被记录下来Q这些行为数据通过数据分析形成一pd指标Q而通过q些指标的比较,最后就形成了各版本之间C孰劣的结论?/p>
在指标计时Q又可细分ؓ(f)两种Ҏ(gu)Q一U是Z专家评分的方法;一U是Z点击l计的方法?/p>
专家评分的方法通常由搜索核心技术研发和产品人员来进行,Ҏ(gu)预先讑֮的标准对A、B两套环境的结果给予评分,获取每个Query的结果对比,q根据nDCG{方法计整体质量?/p>
点击评分有更高的自动化程度,q里使用了一个假设:(x)同样的排序位|,点击数量多的l果质量优于点击数量的l果。(即A2表示A试环境W?条结果,如果A2 > B2Q则表示A2质量更好Q。通俗的说Q相信群众(因ؓ(f)众的眼睛是雪亮的)。在q个假设前提下,我们可以A/B环境前N条结果的点击率自动映ؓ(f)评分Q通过l计大量的Query点击l果Q可以获得可靠的评分Ҏ(gu)?/p>
另外2003q由Thorsten Joachims {h提出的Interleaving testingҎ(gu)也被q泛使用。该Ҏ(gu)设计了一个元搜烦(ch)引擎Q用戯入查询词后,查询词在几个著名搜索引擎中的查询结果随机合反馈给用户Qƈ攉随后用户的结果点击行Z息.Ҏ(gu)用户不同的点d性,可以判断搜索引擎返回结果的优劣Q?/p>
如下图所C,算法A和B的结果交叉放|,q分量q行试Q记录用L(fng)M息。根据点d布来判断A和B环境的优劣?/p>
Interleaving Testing评估Ҏ(gu)
Joachims同时证明了Interleaving Testing评h(hun)Ҏ(gu)与传lCranfield评h(hun)Ҏ(gu)的结果具有较高的相关性。由于记录用户选择(g)索结果的行ؓ(f)是一个不耗费人力的过E,因此可以便捷的实现自动化的搜索效果评估?/p>
没有评估没有进?#8212;—Ҏ(gu)索效果的量化评测Q目的是准确的找出现有搜索系l的不Q没有哪个搜索系l是完美的)Q进而一步一个脚印对法、系l进行改q。本文ؓ(f)大家ȝ了常用的评h(hun)框架和评h标。这些技术像一把把子Q度量着搜烦(ch)技术每一ơ前q的距离?/p>
感谢张凯?/a>?本文的审校?/p> lInfoQ中文站投E或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也Ƣ迎大家加入?a target="_blank" style="box-sizing: border-box; color: #0b59b2;">InfoQ中文站用戯论组
我们截获函数执行最直接的目的就是ؓ(f)函数增添功能Q修改返回|或者ؓ(f)调试以及(qing)性能试加入附加的代码,或者截获函数的输入输出作研IӞ破解使用。通过?问源代码Q我们可以轻而易丄使用重徏QRebuildingQ操作系l或者应用程序的Ҏ(gu)在它们中间插入新的功能或者做功能扩展。然而,在今天这个商?化的开发世界里Q以?qing)在只有二进制代码发布的pȝ中,研究人员几乎没有Z(x)可以得到源代码。本文主要讨论Detour在Windows二进制PE文g基础 上的API截获技术。对于Linuxq_Q作qg事情会(x)非常的简单,׃最初的操作pȝ设计者引入了LD_PRELOAD。如果你讄 LD_PRELOAD=mylib.so Q那么应用程序在载入 dllӞ?x)先查看mylib.so的符可Q在relocation 的时候会(x)优先 使用mylib.so 里的 symbol 。假如你在mylib.so里有个printf() Q那么这个printf׃(x)替代libc?printf?而在mylib.so里的q个printf可以直接讉K libc.so里的printf函数指针来获得真正的 printf的入口地 址?q样Q所有的dll的API HOOK在loader加蝲dll的时候就已经完成Q非常自?dng)和^台相关的部分全部交给loaderd理?/span>
一?nbsp; Detour开发库Q?/span>
?nbsp; ?/span>
Detours是一个在x86q_上截获Q意Win32函数调用的工具库。中断代码可以在q行时动态加载。Detours使用一个无条g转移指o(h)来替换目 标函数的最初几条指令,控制流转移C个用h供的截获函数。而目标函C的一些指令被保存在一个被UCؓ(f)“trampoline” Q译注:(x)英文意ؓ(f)y?床,杂技Q的函数中,在这里我觉得译成目标函数的部分克隆/拯比较贴切。这些指令包括目标函C被替换的代码以及(qing)一个重新蟩转到目标函数的无条g?支。而截获函数可以替换目标函敎ͼ或者通过执行“trampoline”函数的时候将目标函数作ؓ(f)子程序来调用的办法来扩展功能?/span>
Detours是执行时被插入的。内存中的目标函数的代码不是在硬盘上被修改的Q因而可以在一个很好的_度上得截获二q制函数的执行变得更Ҏ(gu)。例如, 一个应用程序执行时加蝲的DLL中的函数q程可以被插入一D|获代码(detouredQ,与此同时Q这个DLLq可以被其他应用E序按正常情冉|行(?注:(x)也就是按照不被截L(fng)方式执行Q因为DLL二进制文件没有被修改Q所以发生截h不会(x)影响其他q程I间加蝲q个DLLQ。不同于DLL的重新链接或?静态重定向QDetours库中使用的这U中断技术确保不?x)?jing)响到应用E序中的Ҏ(gu)或者系l代码对目标函数的定位?/span>
如果其他Zؓ(f)了调试或者在内部使用其他pȝ(g)手D而试图修改二q制代码QDetours是一个可以普遍用的开发包。据我所知,Detours是第一 个可以在Lq_上将未修改的目标代码作ؓ(f)一个可以通过“trampoline”调用的子E序来保留的开发包。而以前的pȝ在逻辑上预先将截获代码攑ֈ?标代码中Q而不是将原始的目标代码做Z个普通的子程序来调用。我们独特的“trampoline”设计对于扩展现有的Y件的二进制代码是臛_重要的?/span>
Z使用基本的函数截获功能的目的QDetours同样提供了编辑Q何DLL导入表的功能Q达到向存在的二q制代码中添加Q意数据节表的目的Q向一个新q?E或者一个已l运行着的进E中注入一个DLL。一旦向一个进E注入了DLLQ这个动态库可以截获Q何Win32函数Q不论它是在应用E序中或者在pȝ?中?/span>
?nbsp; 基本原理
1Q?nbsp; WIN32q程的内存管?
众所周知QW(xu)INDOWS NT实现了虚拟存储器Q每一WIN32q程拥有4GB的虚存空_(d) 关于WIN32q程的虚存结构及(qing)其操作的具体l节请参阅WIN32 API手册Q?以下仅指ZDetours相关的几点:(x)
(1) q程要执行的指o(h)也放在虚存空间中
(2) 可以使用QueryProtectEx函数把存放指令的面的权限更改ؓ(f)可读可写可执行,再改写其内容Q从而修Ҏ(gu)在运行的E序
(3) 可以使用VirtualAllocEx从一个进Eؓ(f)另一正运行的q程分配虚存Q再使用 QueryProtectEx函数把页面的权限更改为可d写可执行Qƈ把要执行的指令以二进制机器码的Ş式写入,从而ؓ(f)一个正在运行的q程注入L的代??/span>
2Q?拦截WIN32 API的原?
Detours定义了三个概念:(x)
(1) Target函数Q要拦截的函敎ͼ通常为Windows的API?/span>
(2) Trampoline函数QTarget函数的部分复制品。因为Detours会(x)改写Target函数Q所以先把Target函数的前5个字节复制保存好Q一斚w仍然保存Target函数的过E调用语义,另一斚w便于以后的恢复?/span>
(3) Detour 函数Q用来替代Target函数的函数?
Detours在Target函数的开头加入JMP Address_of_ Detour_ Function指o(h)Q共5个字节)把对Target函数 的调用引导到自己的Detour函数Q?把Target函数的开头的5个字节加上JMP Address_of_ Target _ Function+ 5?0个字节作为Trampoline函数。请参考下面的?和图2?/span>
(?QDetour函数的过E?
Q图2Q?Detour函数的调用过E)
说明Q?/span>
?nbsp; 目标函数Q?/span>
目标函数的函CQ二q制Q至有5个字节以上。按照微软的说明文档Trampoline函数的函C是拷贝前5个字节加一个无条g跌{指o(h)的话Q如果没 有特D处理不可分割指令的话)Q那么前5个字节必L完整指o(h)Q也是不能W?个字节和W?个字节是一条不可分割的指o(h)Q否则会(x)造成Trampoline 函数执行错误Q一条完整的指o(h)被硬性分割开来,造成E序崩溃。对于第5字节和第6个字节是不可分割指o(h)需要调整拷贝到杂技函数(Trampoline)?字节个数Q这个值可以查看目标函数的汇编代码得到。此函数是目标函数的修改版本Q不能在Detour函数中直接调用,需要通过对Trampoline函数 的调用来辑ֈ间接调用?/span>
?nbsp; Trampoline函数Q?/span>
此函数默认分配了32个字节,函数的内容就是拷贝的目标函数的前5个字节,加上一个JMP Address_of_ Target _ Function+5指o(h),?0个字节?/span>
此函C供?zhn)的Detour函数调用Q执行完?个字节的指o(h)后再l对跌{到目标函数的W?个字节l执行原功能函数?/span>
?nbsp; Detour函数Q?/span>
此函数是用户需要的截获API的一个模拟版本,调用方式Q参C数必d目标函数怸致。如目标函数是__stdcallQ则Detour函数声明也必?是__stdcall,参数个数和类型也必须相同Q否则会(x)造成E序崩溃。此函数在程序调用目标函数的W一条指令的时候就?x)被调用Q无条g跌{q来的)Q如 果在此函C想l调用目标函敎ͼ必须调用Trampoline函数QTrampoline函数在执行完目标函数的前5个字节的指o(h)后会(x)无条件蟩转到目标 函数?个字节后l箋执行Q,不能再直接调用目标函敎ͼ否则进入无I递归Q目标函数蟩转到Detour函数QDetour函数又蟩转到目标函数的递归Q?因ؓ(f)目标函数在内存中的前5个字节已l被修改成绝对蟩转)。通过对Trampoline函数的调用后可以获取目标函数的执行结果,此特性对分析目标函数?常有用,而且可以目标函数的输出l果q行修改后再传回l应用程序?/span>
Detour提供了向q行中的应用E序注入Detour函数和在二进制文件基上注入Detour函数两种方式。本章主要讨论第二种工作方式。通过 Detours提供的开发包可以在二q制EXE文g中添加一个名UCؓ(f)Detour的节表,如下?所C,主要目的是实现PE加蝲器加载应用程序的时候会(x)?动加载?zhn)~写的Detours DLLQ在Detours Dll中的DLLMain中完成对目标函数的Detour?/span>
Q图3Q?/span>
二?nbsp; Detours提供的截获API的相x?/span>
Detours的提供的API 接口可以作ؓ(f)一个共享DLLl外部程序调用,也可以作Z个静态Lib链接到?zhn)的程序内部?/span>
Trampoline函数可以动态或者静态的创徏Q如果目标函数本w是一个链接符P使用静态的trampoline函数非常简单。如果目标函C能在链接时可见,那么可以使用动态trampoline函数?/span>
?nbsp; 要用静态的trampoline函数来截L(fng)标函敎ͼ应用E序生成trampoline的时候必M?/span>
DETOUR_TRAMPOLINE宏。DETOUR_TRAMPOLINE有两个输入参敎ͼ(x)trampoline的原型和目标函数的名字?/span>
注意Q对于正的截获模型Q包括目标函敎ͼtrampoline函数Q以?qing)截获函数都必须是完全一致的调用形式Q包括参数格式和调用U定。当通过 trampoline函数调用目标函数的时候拷贝正参数是截获函数的责仅R由于目标函C仅是截获函数的一个可调用分支Q截获函数可以调?trampoline函数也可以不调用Q,q种责Q几乎是一U下意识的行为?/span>
使用相同的调用约定可以确保寄存器中的D正确的保存,q且保证调用堆栈在截获函数调用目标函数的时候能正确的徏立和销毁?/span>
可以使用DetourFunctionWithTrampoline函数来截L(fng)标函数。这个函数有两个参数Qtrampoline函数以及(qing)截获函数的指针。因为目标函数已l被加到trampoline函数中,所有不需要在参数中特别指定?/span>
?nbsp; 我们可以使用DetourFunction函数来创Z个动态的trampoline函数Q它包括两个参数Q一个指向目标函数的指针和一个截获函数的指针。DetourFunction分配一个新的trampoline函数q将适当的截获代码插入到目标函数中去?/span>
当目标函C是很Ҏ(gu)使用的时候,DetourFindFunction函数可以扑ֈ那个函数Q不它是DLL中导出的函数Q或者是可以通过二进制目标函数的调试W号扑ֈ?/span>
DetourFindFunction接受两个参数Q库的名字和函数的名字。如果DetourFindFunction函数扑ֈ了指定的函数Q返回该函数 的指针,否则返回一个NULL指针。DetourFindFunction?x)首先用Win32函数LoadLibrary ?GetProcAddress来定位函敎ͼ如果函数没有在DLL的导中找刎ͼDetourFindFunction用ImageHlp库来搜烦(ch)?效的调试W号Q译注:(x)q里的调试符h指Windows本n提供的调试符P需要单独安装,具体信息请参考Windows的用戯断支持信息)?DetourFindFunctionq回的函数指针可以用来传递给DetourFunction以生成一个动态的trampoline函数?/span>
我们可以调用DetourRemoveTrampoline来去掉对一个目标函数的截获?/span>
注意Q因为Detours中的函数?x)修改应用程序的地址I间Q请保当加入截获函数或者去掉截获函数的时候没有其他线E在q程I间中执行,q是E序员的责Q。一个简单的Ҏ(gu)保证q个时候是单线E执行就是在加蝲Detours库的时候在DllMain中呼叫函数?/span>
三?nbsp; 使用Detours实现对API的截L(fng)两种Ҏ(gu)
建立一个MFC对话框工E,在对话框的OK按钮的单M件中加入对MessageBoxA函数的调用,~译后的E序名称MessageBoxApp,效果如图?/span>
(?)
?nbsp; 静态方?/span>
建立一个Dll工程Q名UCؓ(f)ApiHookQ这里以Visual C++6.0开发环境,以截获ASCII版本的MessageBoxA函数来说明。在Dll的工E加入:(x)
DETOUR_TRAMPOLINE(int WINAPI Real_Messagebox(HWND hWnd ,
LPCSTR lpText,
LPCSTR lpCaption,
UINT uType), ::MessageBoxA);
生成一个静态的MessageBoxA的Trampoline函数Q在Dll工程中加入目标函数的Detour函数Q?/span>
int WINAPI MessageBox_Mine( HWND hWnd ,
LPCSTR lpText,
LPCSTR lpCaption,
UINT uType)
{
CString tmp= lpText;
tmp+=” 被Detour截获”;
return Real_Messagebox(hWnd,tmp,lpCaption,uType);
// return ::MessageBoxA(hWnd,tmp,lpCaption,uType); //Error
}
在Dll入口函数中的加蝲Dll事g中加入:(x)
DetourFunctionWithTrampoline((PBYTE)Real_Messagebox, (PBYTE)MessageBox_Mine);
在Dll入口函数中的卸蝲Dll事g中加入:(x)
DetourRemove((PBYTE)Real_Messagebox, (PBYTE)MessageBox_Mine);
?nbsp; 动态方?/span>
建立一个Dll工程Q名UCؓ(f)ApiHookQ这里以Visual C++6.0开发环境,以截获ASCII版本的MessageBoxA函数来说明。在Dll的工E加入:(x)
//声明MessageBoxA一L(fng)函数原型
typedef int (WINAPI * MessageBoxSys)( HWND hWnd ,
LPCSTR lpText,
LPCSTR lpCaption,
UINT uType);
//目标函数指针
MessageBoxSys SystemMessageBox=NULL;
//Trampoline函数指针
MessageBoxSys Real_MessageBox=NULL;
在Dll工程中加入目标函数的Detour函数Q?/span>
int WINAPI MessageBox_Mine( HWND hWnd ,
LPCSTR lpText,
LPCSTR lpCaption,
UINT uType)
{
CString tmp= lpText;
tmp+=” 被Detour截获”;
return Real_Messagebox(hWnd,tmp,lpCaption,uType);
// return ::MessageBoxA(hWnd,tmp,lpCaption,uType); //Error
}
在Dll入口函数中的加蝲Dll事g中加入:(x)
SystemMessageBox=(MessageBoxSys)DetourFindFunction("user32.dll","MessageBoxA");
if(SystemMessageBox==NULL)
{
return FASLE;
}
Real_MessageBox=(MessageBoxSys)DetourFunction((PBYTE)SystemMessageBox, (PBYTE)MessageBox_Mine);
在Dll入口函数中的卸蝲Dll事g中加入:(x)
DetourRemove((PBYTE)Real_Messagebox, (PBYTE)MessageBox_Mine);
?nbsp; 重写二进制可执行文g
使用Detours自带的SetDll.exe重写二进制可执行文gQ可以在需要截L(fng)E序中加入一个新的Detours的PE节表。对于本文就是新Z个批处理文g调用SetDll.exe?/span>
@echo off
if not exist MessageBoxApp.exe (
echo 请将文g解压到MessageBoxApp.exe的安装目? 然后执行补丁E序
) else (
setdll /d:ApiHook.dll MessageBoxApp.exe
)
Pause
调用后用depends.exeQ微软VC6.0开发包的工具之一Q观察MessageBoxApp.exe前后变化Q?可以看到Setdll已经重写MessageBoxApp.exe
成功Q加入了对ApiHook.dll的依赖关pR?/span>
Q执行SetDll.exe前) (执行SetDll.exe?
执行SetDll.exe重写后的MessageBoxApp.exeQ点ȝ定后可以看到l果如下Q?/span>
xQMessageBoxApp.exe对MessageBoxA函数的调用已l被截获Q弹出的对话框内容已l明显说明这一炏V?/span>
本文转自Q?/span>http://www.cnblogs.com/flying_bat/archive/2008/04/18/1159996.html
1、围l数据编E与不是围绕UI~程
当我们拿到需求最先接触到的就是UI的设计,也许是美工画的,也许是设计草图。工E师在具体设计的时候容易受UI的媄(jing)响,或者干脆从UI开始编E?/span>
q是一个错误的~程?fn)惯Q无论UI如何展现与交互,最l都应该围绕数据~程。拿到需求后Q应该先思考和推敲数据的设计与{QUI不过是数据的一U展现Ş式而已?/span>
2、做好UI与逻辑的解?/span>
UI的编E会(x)涉及(qing)到许多控件的操作Q消息的处理Q不知不觉,一个UIcȝ代码?x)越写越大,以至于一D|间以后,览和梳理都?x)变得不太方ѝ?/span>
在UIc里Q除了与UI本n的操作有关的代码以外QQ何逻辑代码都应该与此解耦,q根据具体情况进行封装调用。如果一个控件关联了太多数据操作Q应该把q些操作装到控件的l承cMQ把一cM码进行集中管理和l护?/span>
上述问题Q在E序写作的初期还不太明显Q随着代码逐渐膨胀Q会(x)会(x)让人难以忍受?/span>
3、数据单向依赖,单向更新
UI围绕的数据进行展C更新Q在q个q程中,所以对数据的操作应该进行封装,而不是散落在UIE序在各个角落,数据的更新、获取和UI传递消息时Q应该单向操作,如果出现循环处理的情况,在以后维护调试的BUG的过E中?x)变得比较困难,Dl护效率下降?/span>
本文来自CSDN博客Q{载请标明出处Q?/span>http://www.shnenglu.com/humanchao
1、不愿意就的h
E序设计工作是一地地道道的脑力力_Q把工作做得很好和做的很差往往只在工作中的一个小的l节Q我发现我n边优U的程序员都不太喜Ƣ将,始终把自q计算机和自己的开发环境调整到最佳状态,原来带我的老员工甚至会(x)自己写一些小工具Q来提高工作效率?/span>
2、不喜欢蛮干
脑力力_与体力劳动不同,很多时候很N过单的量的U篏辑ֈ目的Q尤其是处理一些难题的时候。一味的蛮干Q加班几乎天生与高手无缘。没有思\的时候,换个环境Q也许答案就在明天上班的路上惌v?/span>
3、愿意思考、专注改q?/strong>
E序员与其他力_者相|熟练了以后都?x)Ş成惯性思维Q会(x)不自觉的用自׃(fn)惯的方式解决问题Q但问题的Ş式与本质M(x)变化Q只有不断的改进才能使工作效率不断提高。而把脑力力_变成体力力_的现象在实际工作中比比皆是?/span>
4、良好的基础和不断的学习(fn)
良好的基与不断的学习(fn)是天生的一对孪生兄弟,因ؓ(f)基础好所以学的快Q因为学得快Q所以基本功好。良好学?fn)?fn)惯不是不停的单追t新技术,一斚w是了解新技术,另一斚w需要不断的弥补思维盲区Q学?fn)可以有很多U状态,有一U是M而知一Q技也,有一U是M而知三,术也Q有一U是M而知十,道也?/span>
5、直接切入问题的能力
在解决一个问题的时候,有些人L能够直接切入问题核心Q而有些hL喜欢x边缘问题。直入主题是一U核心能力,需要思考,实践Q改q,U篏Q提高,周而复使,螺旋上升。另外我觉得q与思维方式与知识面关系很大Q多涉猎一些领域没有坏处?/span>
***p***Q呵呵,对,q是pQ流利的听说d?/span>
本文来自CSDN博客Q{载请标明出处Q?/span>http://www.shnenglu.com/humanchao
先给大家看一D|说是史上最强的E序Q?br />e100 33 f6 bf 0 20 b5 10 f3 a5 8c c8 5 0 2 50 68 13 1 cb e 1f be a1 1 bf 0 1
e11b 6 57 b8 11 1 bb 21 13 89 7 4b 4b 48 79 f9 ad 86 e0 8b c8 bd ff ff e8 20
e134 0 3d 0 1 74 1a 7f 3 aa eb f3 2d ff 0 50 e8 f 0 5a f7 d8 8b d8 26 8a 1 aa
e14f 4a 75 f9 eb de cb 57 bb 21 13 8b c1 40 f7 27 f7 f5 8b fb ba 11 1 4f 4f 4a
e168 39 5 7f f9 52 8b c5 f7 25 f7 37 2b c8 95 f7 65 2 f7 37 95 2b e8 fe e fe
e181 10 79 6 c6 6 fe 10 7 46 d0 14 d1 d1 d1 e5 79 ec 5a b8 11 1 ff 7 4b 4b 48
e19b 3b d0 75 f7 5f c3 83 f7 83 a6 5d 59 82 cd b2 8 42 46 9 57 a9 c5 ca aa 1b
.............................................................................
q段E序?997q世界程序设计大赛的一{奖作品的部分代码(完整的代码下载,把代码复制粘贴到cmd的debug命o(h)中,回R看到效果Q。这个程序运行后是一?D的且伴随着音乐的动甅R震撼吧Q?br />是不是从事Y件开发的人员都希望成L(fng)武林高手呢?然而真要是用这L(fng)高手来设计、编写我们的产品代码Q恐怕某一天,我们什么都不用q了Q只能h手一本机器代码,一句一句进行翻译了Q那么对于Y件品开发而言Q如何写好代码呢Q一的软g产品的代码具备哪些特征呢Q?/p>
一代码的特征
1、稳定可靠(RobustnessQ?
代码写出来以后,一定要能够q行得非常好Q非常稳定可靠。在C的IT行业QY件品都是是24*7Q即要保证系l一?4时Q一星期7天中都可以无间断的正常运行。比如我们百度的搜烦(ch)引擎pȝQ比如我们的通信pȝQ等{。到了品开发后期,大部分的成本都将投入C品稳定性的提高?
2、可l护且简z(Maintainable and Simple CodeQ?br />在写代码Ӟ首先要考虑的是Q写出来的代码不但要自己可以LQ而且我们的同事、测试工E师都可能要修改q些代码Q对其进行增减。如果代码很复杂Q不Ҏ(gu)LQ如E序中的递归一大堆、程序不知何时或从何地蟩出,则会(x)使程序的可维护性和z性降低。所以必要的注释、统一的编E规范等都是非常重要的?
3、高效(F(tun)astQ?br />在Y件行业中效率是非帔R要的Q比如搜索引擎。有些Y件的搜烦(ch)效率׃高,搜烦(ch)q程特别~慢Q让人难以接受。当然这里面有一个带宽的问题Q但是程序效率不高也是一个重要的原因。而实际上E序的效率提高,有时候很单,q没有什么神U之处,如用数l烦(ch)引时候,可以用指针方式而不使用数组下标Q数l的I间定义应该定义?的Nơ幂{等?
4、简短(SmallQ?br />q方面大家的感受可能不是很深Q但是我的感受是很深的。配|过PSTNE控交换机、\由器、VoIP|关讑֤的h都知道,q些讑֤的Y仉是从PC机通过|口或串口下载到q些讑֤的Flash上(cMPC机的BIOSQ再通过讑֤上的CPU启动。如果程序写的很|嗦Q随着Ҏ(gu)不断增加,E序规模变大的巨大QFlashI间告急、内存告急、下载升U变的不可忍受,{等Q带来的是成本不断增加Q利润不断下降?
5、共享性(ReusableQ?br />如果做大型品开发,E序的共享性也是非帔R要的。我们品有那么多开发h员,如果每一个h都自己定义字W串、链表等数据l构Q那么开发效率就?x)降低,我们的品恐怕到今天也不能出台。我所说的“׃n”不是指将别h的代码复制到自己的代码中Q而是指直接调用别人的代码Q拿来即可用。这一斚w可以减少代码的冗余性,另一斚w可以增强代码的可l护性。如果别人的代码里有BugQ只需修改他的代码Q而调用此代码的程序不用进行Q何修改就可以辑ֈ同步。这同时要求我们在设计的时候,如何考虑pȝ的内聚和耦合的问题?
6、可试性(TestableQ?br />我们的品开发里Q除了Y件开发h员,q有一部分工程师负责Y件测试。Y件测试h员会(x)开发代码拿来,一行一行地q行Q看E序q行是否有错。如果Y件开发h员的代码不可试Q那试工程师就没有办法q行工作。因此可试性在大型软g开发里是很重要的一炏V可试性有时候与可维护性是遥相呼应的,一个具有好的可试性和可维护性的代码Q测试h员可以根据开发提供的l护手册、debug信息手册{就可以判断出程序出错在哪个模块?
7、可UL性(PortableQ?br />可移植性是指程序写出来以后Q不仅在windows 2000里可以运行,在NT/9X下可以运行,而且在Linux甚至Macintosh{系l下都可以运行。所有这些特性都是一代码所具备的特性。但是其中有些特性是?x)有冲突的。比如高效性,E序写的效率很高Q就可能变得很复杂,牺牲的就是简z。好的代码要在这些特性中取得q?
写好代码?0个秘?br />
1、百家之长归我所有(F(tun)ollow Basic Coding StyleQ?br />其实写代码的方式有很多,每个人都有自q风格Q但是众多的风格中L一些共性的、基本的写代码的风格Q如为程序写注释、代码对齐,{等。是不是~程规范Q对是~程规范?
2、取个好名字QUse Naming ConventionsQ?br />取个好的函数名、变量名Q最好按照一定的规则起名。还是编E规范?
3、凌波微步,未必摔跤QEvil goto's?Maybe Not...Q?br />q里我用“凌L微步”来Ş容goto语句。通常Qgoto语句使程序蟩来蟩去,不容易读Q而且不能优化Q但是在某种情况下,goto语句反而可以增强程序的可读性。Just go aheadQnot go back?
4、先发制人,后发制于人(Practic Defensive CodingQ?br />Defensive Coding指一些可能会(x)出错的情况,如变量的初始化等Q要考虑到出现错误情况下的处理策略。测试时要多q行几个U程。有些程序在一个线城下q行是正常的Q但是在多个U程q行q行时就?x)出现问题;而有些程序在一个CPU下运行几个线E是正常的,但是在多个CPU下运行时׃(x)出现问题Q因为单CPUq行U程只是狭义的ƈ行,多CPU一赯行程序,才是真正的ƈ行运?
5、见招拆招,滴水不漏QHandle The Error CasesQThey Will OccurQ)
q里的Error CaseQ错误情况)Q是指那些不易重视的错误。如果不对Error Caseq行处理Q程序在多数情况下不?x)出错,但是一旦出现异常,E序׃(x)崩溃?6、熟?fn)剑法刀术,所向无敌(Learn Win32 API SeriouslyQ?br />?#8220;剑法刀?#8221;来Ş容一些API是因为它们都是经q了很多优秀开发h员的不断开发、测试,其效率很高,而且z易懂,希望大家能掌握它Q熟(zhn)它Q用它。是不是象我们的ULIB?
7、双手互搏,无坚不摧QTest,but don't stop thereQ?br />q里的测试不是指别h来测试你的代码,而是指自己去试。因Z是写代码的原作者,对代码的了解最深,别h不可能比你更了解Q所以你自己在测试时Q可以很好地L试哪些边界条Ӟ以及(qing)一些意向不到的情况?
8、活用断aQUse,don't abuse,assertionsQ?br />断言QassertionQ是个很好的调试工具和方法,希望大家能多用断aQ但是ƈ不是所有的情况下都可以用到断言。有些情况用断a反而不合适?
9、草木皆兵,不可大意QAvoid AssumptionsQ?br />是指在写代码Ӟ要小心一些输入的情况Q比如输入文件、TCP的sockets、函数的参数{等Q不要认Z用我们的API的用户都知道什么是正确的、什么是错的Q也是说一定要考虑到对外接口的出错处理问题?
10、最高境界、无招胜有招QStop writing so much codeQ?br />意思就是说量避免写太多的代码Q写的越多,出错的机?x)也多。最好能重用别h开攄接口函数或直接调用别人的api?
本文来自CSDN博客Q{载请标明出处Q?a href="http://www.shnenglu.com/humanchao/archive/2010/08/05/122334.html">http://www.shnenglu.com/humanchao/archive/2010/08/05/122334.html
转自Q?a >http://yinkai210.blog.163.com/blog/static/287483452009050256466/
q些端口如果被其他程序占用就不能正常启动Q比如有时启动时?x)提CWEB启动p|Q其实就?0端口被占用了Q而迅L(fng)下蝲软g恰恰是占用?0端口Q关掉就行了。但有时q雷{都没有开也启动不了,那就是别的东西占用了Q那怎么办呢Q我来叫你查看端口ƈx的方法?br />1.在开?-q行 里面输入cmd点回车,?x)出现运行窗口?br />2.在提C符后输入netstat -ano回RQ找到tcp 80端口对应的pidQ比?484.
3.ctrl+alt+del打开d理器,选进E,q里有很多正在运行的E序怎么找?别急点上面?nbsp; 查看--选择?-在PIDQ进E标C符Q前面打钩。好了,下面的进E前面都有了PIDL(fng)。这时上一步找到的PID有用了Q找?484Q比如PEER.EXE什么的Q结束进E吧。这时再开服务器,看WEB可以启动了!
如上面的不清楚还有简明的Q?/strong>
假如我们需要确定谁占用了我们的80端口
1、Windowsq_
在windows命o(h)行窗口下执行Q?br />C:\>netstat -aon|findstr "80"
TCP 127.0.0.1:80 0.0.0.0:0 LISTENING 2448
看到了吗Q端口被q程号ؓ(f)2448的进E占用,l箋执行下面命o(h)Q?br />C:\>tasklist|findstr "2448"
thread.exe 2016 Console 0 16,064 K
很清楚吧Qthread占用了你的端?Kill it
如果W二步查不到Q那开d理器,看哪个进E是2448Q然后杀之即可?/strong>
如果需要查看其他端口。把 80 Ҏ(gu)卛_
Linux查看端口使用状态、关闭端口方?br />转自Q?a >http://blog.csdn.net/wudiyi815/article/details/7473097
前提Q首先你必须知道Q端口不是独立存在的Q它是依附于q程的。某个进E开启,那么它对应的端口开启了Q进E关闭,则该端口也就关闭了。下ơ若某个q程再次开启,则相应的端口也再ơ开启。而不要纯_的理解为关闭掉某个端口Q不q可以禁用某个端口?/span>
1. 可以通过"netstat -anp" 来查看哪些端口被打开?/span>
Q注Q加参数'-n'?x)将应用E序转ؓ(f)端口昄Q即数字格式的地址Q如Qnfs->2049, ftp->21Q因此可以开启两个终端,一一对应一下程序所对应的端口号Q?/span>
2. 然后可以通过"lsof -i:$PORT"查看应用该端口的E序Q?PORT指对应的端口P。或者你也可以查看文?etc/servicesQ从里面可以扑և端口所对应的服务?/span>
Q注Q有些端口通过netstat查不出来Q更可靠的方法是"sudo nmap -sT -O localhost"Q?/span>
3. 若要关闭某个端口Q则可以Q?/span>
1)通过iptables工具该端口掉Q如Q?/span>
"sudo iptables -A INPUT -p tcp --dport $PORT -j DROP"
"sudo iptables -A OUTPUT -p tcp --dport $PORT -j DROP"
2)或者关掉对应的应用E序Q则端口p然关闭了Q如Q?/span>
"kill -9 PID" (PIDQ进E号)
如:(x) 通过"netstat -anp | grep ssh"
有显C:(x) tcp 0 127.0.0.1:2121 0.0.0.0:* LISTEN 7546/ssh
则:(x) "kill -9 7546"
Q可通过"chkconfig"查看pȝ服务的开启状态)