PHP 代码美化工具

phpCodeBeautifier is a tool which avoid you of spending hours on reformating code to suit your own way of presenting it.

The tool has been declined into 3 versions:

        

  • A GUI version which allow to process file visually.
  •     

  • A command line version which allow to be batched or integrated with other tools (CVS, SubVersion, IDE …).
  •     

  • As an integrated tool of PHPEdit.

 

官方地址:http://www.waterproof.fr/products/phpCodeBeautifier/

官方下载:
http://www.waterproof.fr/products/phpCodeBeautifier/download.php

本地下载:
windows版:http://phpor.net/download/phpCB-1.0.1-windows.zip
linux版:http://phpor.net/download/phpCB-1.0.1-linux.tgz

 

手册地址:http://www.waterproof.fr/products/phpCodeBeautifier/manual.php

apache 模块编写 之 helloworld篇

关于apache模块的资料比较少,这里给出两个比较简单的例子,来揭开apache模块神秘的面纱,当然例子很初级,不过只有初级才容易入门,写一个helloworld吧:

/**
 * filename:    helloworld.c
 * author:      lijunjie <lijunjie1982@yahoo.com.cn>
 * version:     1.0
 */
#include <httpd.h>
#include <http_protocol.h>
#include <http_config.h>

static int helloworld_handler(request_rec *r) {
        if (!
r->handler || strcmp(r->handler"helloworld"
)) {
                return 
DECLINED
;
        }
        if (
r->method_number != M_GET
){
                return 
HTTP_METHOD_NOT_ALLOWED
;
        }
        
ap_set_content_type(r,"text/html;charset=asscii"
);
        
ap_rputs("hello world"r
);
        return 
OK
;
}

static void helloworld_hooks(apr_pool_t *pool) {
        
ap_hook_handler(helloworld_handlerNULLNULLAPR_HOOK_MIDDLE
);
}

module AP_MODULE_DECLARE_DATA helloworld_module = {
        
STANDARD20_MODULE_STUFF
,
        
NULL
,
        
NULL
,
        
NULL
,
        
NULL
,
        
NULL
,
        
helloworld_hooks
};

/****** install ***********
compile: apxs -i -c mod_helloworld.c

modify httpd.conf, add

LoadModule helloworld_module modules/mod_helloworld.so

<Location /helloworld>
    SetHandler helloworld
</Location>

********************************/

 

下面给出一个稍微复杂一点的,对我们进一步的了解有很大帮助的,它可以输出一些比较有意义的东西了

/**
 * filename:    helloworld.c
 * author:      lijunjie <lijunjie1982@yahoo.com.cn>
 * version:     1.1
 */
#include <httpd.h>
#include <http_protocol.h>
#include <http_config.h>

static int printitem(void *rec, const char *key, const char *value){
        
// recive rec pointer , we will send  some request use it
        
request_rec *rec;
        
ap_rprintf(r"<tr><th scope=’row’>%s</th><td>%s</td></tr>\n"
                                        
ap_escape_html(r->poolkey), 
                                        
ap_escape_html(r->poolvalue));
        return 
1;
}

static void printtable(request_rec *rapr_table_t *t
                                const 
char *caption, const char *keyhead,
                                const 
char *valhead) {
                
ap_rprintf(r,"<table border=’1′ width=’100%’><caption>%s</caption><thead>"
                                                "<tr><th scope=’col’>%s</th><th scope=’col’>%s"
                                                "</th></tr></thead><tbody>"
,
                                                 
captionkeyheadvalhead);
                
apr_table_do(printitemrtNULL);

                ap_rputs("</tbody></table>\n",r);

}
static int helloworld_handler(request_rec *r) {
        if (!
r->handler || strcmp(r->handler"helloworld")) {
                return 
DECLINED;
        }
        if (
r->method_number != M_GET){
                return 
HTTP_METHOD_NOT_ALLOWED;
        }
        
ap_set_content_type(r,"text/html;charset=asscii");
        
ap_rputs("This is the Apache hello world module<br>"r);
        
printtable(rr->headers_in"Request Headers""Header""Value");
        
printtable(rr->headers_out"Response Headers""Header""Value");
        
printtable(rr->headers_in"Environment""Variable""Value");

        return OK;
}

static void helloworld_hooks(apr_pool_t *pool) {
        
ap_hook_handler(helloworld_handlerNULLNULLAPR_HOOK_MIDDLE);
}

module AP_MODULE_DECLARE_DATA helloworld_module = {
        
STANDARD20_MODULE_STUFF,
        
NULL,
        
NULL,
        
NULL,
        
NULL,
        
NULL,
        
helloworld_hooks
};
/****** install ***********
compile: apxs -i -c mod_helloworld.c

modify httpd.conf, add

LoadModule helloworld_module modules/mod_helloworld.so

<Location /helloworld>
    SetHandler helloworld
</Location>

********************************/

关于浏览器缓存的问题

1. 浏览器缓存问题一般通过在http头里添加cache-control 可以控制

对于一般的浏览器,只要cache-control: no-cache ,这样浏览器的后退也不会走cache了,但是firfox就不行,需要 cache-control: no-cache, no-store

后来由遇到了safari,对于后退按钮,no-store 也不要使了,官方的解释是在页面里添加一个iframe,只要有iframe,后退就不会走cache了

 

相关文章:

————–如何禁止页面在safari中缓存—————————————————

基本上safari会缓存所有页面以便加速访问。如果要禁止页面在safari中缓存,常用的header肯定要加上的

<?php

header(”Expires: Mon, 26 Jul 1997 05:00:00 GMT”); // Date in the past

header(”Last-Modified: ” . gmdate(”D, d M Y H:i:s”) . ” GMT”); // always modified

header(”Cache-Control: no-store, no-cache, must-revalidate, max-age=0″); // HTTP/1.1

header(”Cache-Control: post-check=0, pre-check=0″, false);

header(”Pragma: no-cache”); // HTTP/1.0

?>

加上上面这些header,可以让页面在大多数浏览器中都不缓存。但还是有个问题,上面的代码对safari的前进和后退不起作用,safari还是会在缓存里面读取数据。要做到完全禁止,根据官方的Safari Developer FAQ,还需要在页面中加上一个iframe。加上iframe后的页面,safari永远不缓存。

<iframe style=”height:0px;width:0px;visibility:hidden” src=”about:blank”>

this frame prevents back forward cache

</iframe>

——————————————————————————————-

 

相关文章2:

http://www.apple.com.cn/developer/internet/webcontent/safari_faq.html

 

非对称加密算法 之 PHP版

这里演示了公钥加密、私钥解密 和私钥加密、公钥解密的实例

<?php
$publickey 
file_get_contents("/etc/ssl/crt/public.der"
);
$privatekeyfile_get_contents("/etc/ssl/crt/private.key"
);
$plaintext "String to encrypt"
;
echo 
"test : encrypt 10000 times\n"
;
$st time
();
for(
$i 0$i 10000$i
++){
        
openssl_public_encrypt($plaintext$encrypted$publickey
);
}
$et time
();
echo 
"use time:".($et$st)."\n"
;
echo 
"public encrypt and private decrypt:\n"
;
echo 
$encrypted;  
//encrypted string
openssl_private_decrypt($encrypted$plain$privatekey
);
echo 
"\n\n"
;
echo 
$plain."\n"
;
echo 
"private encrypt and public decrypt:\n"
;
openssl_private_encrypt($plaintext$encrypted$privatekey
);

echo $encrypted;  //encrypted string
echo "\n"
;
openssl_public_decrypt($encrypted$plain$publickey
);
echo 
$plain
;
echo 
"\n"
;
?>

什么是KPI

什么是KPI?2006-11-14 14:42KPI(Key Performance Indication)即关键业绩指标,是通过对组织内部某一流程的输入端、输出端的关键参数进行设置、取样、计算、分析,衡量流程绩效的一种目标式量化管理指标,是把企业的战略目标分解为可运作的远景目标的工具,是企业绩效管理系统的基础。KPI是现代企业中受到普遍重视的业绩考评方法。KPI可以使部门主管明确部门的主要责任,并以此为基础,明确部门人员的业绩衡量指标,使业绩考评建立在量化的基础之上。建立明确的切实可行的KPI指标体系是做好绩效管理的关键。

KPI法符合一个重要的管理原理——“二八原则”在一个企业的价值创造过程中,在在着"20/80"的规律,即20%的骨干人员创造企业80%的价值;而且在每一位员工身上"二八原理"同样适用,即80%的工作任务是由20%的关键行为完成的。因此,必须抓住20%的关键行为,对之进行分析和衡量,这样就能抓住业绩评价的重心。

一、 建立关键业绩指标体系遵循的原则

1、 目标导向。即KPI必须依据企业目标、部门目标、职务目标等来进行确定。

2、 注重工作质量。因工作质量是企业竞争力的核心,但又难以衡量,因此,对工作质量建立指标进行控制特别重要。

3、 可操作性。关键业绩指标必须从技术上保证指标的可操作性,对每一指标都必须给予明确的定义,建立完善的信息收集渠道。

4、 强调输入和输出过程的控制。设立KPI指标,要优先考虑流程的输入和输出状况,将两者之间的过程视为一个整体,进行端点控制。

二、确立KPI指标应把握的要点

1、 把个人和部门的目标与公司的整体战略目标联系起来。以全局的观念来思考问题。

2、 指标一般应当比较稳定,即如果业务流程基本未变,则关键指标的项目也不应有较大的变动。

3、 指标应该可控制,可以达到。

4、 关键指标应当简单明了,容易被执行这所接受和理解。

5、 对关键业绩指标要进行规范定义,可以对每一KPI指标建立"KPI定义指标表"。

三、运用KPI进行绩效考核的难点

绩效管理最重要的是让员工明白企业对他的要求是什么,以及他将如何开展工作和改进工作,他的工作的报酬会是什么样的。主管回答这些问题的前提是他清楚地了解企业对他的要求是什么,对所在部门的要求是什么,说到底,也就是了解部门的KPI是什么。同时,主管也要了解员工的素质,以便有针对性的分配工作与制定目标。

绩效考核是绩效管理循环中的一个环节,绩效考核主要实现两个目的:一是绩效改进,二是价值评价。面向绩效改进的考核是遵循PDCA循环模式的,它的重点是问题的解决及方法的改进,从而实现绩效的改进。它往往不和薪酬直接挂钩,但可以为价值评价提供依据。这种考核中主管对员工的评价不仅反馈员工的工作表现,而且可以充分体现主管的管理艺术。因为主管的目标和员工的目标是一致的,且员工的成绩也是主管的成绩,这样,主管和员工的关系就比较融洽。主管在工作过程中与下属不断沟通,不断辅导与帮助下属,不断记录员工的工作数据或事实依据,这比考核本身更重要。

我们从KPI中如果能分析出每个职位的正确定位,那么这些职位上员工的待遇跟他所在的职位是没有关系的。面向价值评价的绩效考核,强调的重点是公正与公平,因为它和员工的利益直接挂钩。这种考核要求主管的评价要比较准确,而且对同类人员的考核要严格把握同一尺度,这对于行政服务人员、一线生产人员比较好操作。因为这种职位的价值创造周期比较短,很快就可以体现出他们的行动结果,而且,标准也比较明确,工作的重复性也较强。但对于职位内容变动较大,或价值创造周期较长的职位来说,这种评价就比较难操作。

企业绩效评估经常遇到的一个很实际的问题就是,很难确定客观、量化的绩效指标。其实,对所有的绩效指标进行量化并不现实,也没有必要这么做。通过行为性的指标体系,也同样可以衡量企业绩效。
—企业关键业绩指标(KPI:Key Process Indication)是通过对组织内部流程的输入端、输出端的关键参数进行设置、取样、计算、分析,衡量流程绩效的一种目标式量化管理指标,是把企业的战略目标分解为可操作的工作目标的工具,是企业绩效管理的基础。KPI可以使部门主管明确部门的主要责任,并以此为基础,明确部门人员的业绩衡量指标。建立明确的切实可行的KPI体系,是做好绩效管理的关键。

—确定关键绩效指标有一个重要的SMART原则。SMART是5个英文单词首字母的缩写:S代表具体(Specific),指绩效考核要切中特定的工作指标,不能笼统;M代表可度量(Measurable),指绩效指标是数量化或者行为化的,验证这些绩效指标的数据或者信息是可以获得的;A代表可实现(Attainable),指绩效指标在付出努力的情况下可以实现,避免设立过高或过低的目标;R代表现实性(Realistic),指绩效指标是实实在在的,可以证明和观察;T代表有时限(Time bound),注重完成绩效指标的特定期限。

—建立KPI指标的要点在于流程性、计划性和系统性。首先明确企业的战略目标,并在企业会议上利用头脑风暴法和鱼骨分析法找出企业的业务重点,也就是企业价值评估的重点。然后,再用头脑风暴法找出这些关键业务领域的关键业绩指标(KPI),即企业级KPI。

—接下来,各部门的主管需要依据企业级KPI建立部门级KPI,并对相应部门的KPI进行分解,确定相关的要素目标,分析绩效驱动因数(技术、组织、人),确定实现目标的工作流程,分解出各部门级的KPI,以便确定评价指标体系。

—然后,各部门的主管和部门的KPI人员一起再将KPI进一步细分,分解为更细的KPI及各职位的业绩衡量指标。这些业绩衡量指标就是员工考核的要素和依据。这种对KPI体系的建立和测评过程本身,就是统一全体员工朝着企业战略目标努力的过程,也必将对各部门管理者的绩效管理工作起到很大的促进作用。

—指标体系确立之后,还需要设定评价标准。一般来说,指标指的是从哪些方面衡量或评价工作,解决“评价什么”的问题;而标准指的是在各个指标上分别应该达到什么样的水平,解决“被评价者怎样做,做多少”的问题。

—最后,必须对关键绩效指标进行审核。比如,审核这样的一些问题:多个评价者对同一个绩效指标进行评价,结果是否能取得一致?这些指标的总和是否可以解释被评估者80%以上的工作目标?跟踪和监控这些关键绩效指标是否可以操作?等等。审核主要是为了确保这些关键绩效指标能够全面、客观地反映被评价对象的绩效,而且易于操作。

—每一个职位都影响某项业务流程的一个过程,或影响过程中的某个点。在订立目标及进行绩效考核时,应考虑职位的任职者是否能控制该指标的结果,如果任职者不能控制,则该项指标就不能作为任职者的业绩衡量指标。比如,跨部门的指标就不能作为基层员工的考核指标,而应作为部门主管或更高层主管的考核指标。

—绩效管理是管理双方就目标及如何实现目标达成共识的过程,以及增强员工成功地达到目标的管理方法。管理者给下属订立工作目标的依据来自部门的KPI,部门的KPI来自上级部门的KPI,上级部门的KPI来自企业级KPI。只有这样,才能保证每个职位都是按照企业要求的方向去努力。

—善用KPI考评企业,将有助于企业组织结构集成化,提高企业的效率,精简不必要的机构、不必要的流程和不必要的系统。

做事方法 之 抓住主要矛盾

  前出塞(其六)

  杜甫

  挽弓当挽强,用箭当用长。

  射人先射马,擒贼先擒王。

  杀人亦有限,列国自有疆。
  
苟能制侵陵,岂在多杀伤。


  注释:

  1.挽弓:拉弓。

  2.强:指坚硬的弓。拉这种弓要用很大力气,但射的远。

  3.亦有限:也应该有个限度。

  4.自有疆:本来应该有个疆界。

  5.苟:如果。

  6.制侵陵:制止侵犯,侵略。

  7.岂:难道。

   译文:
   用弓就要用强弓,用箭就要用长箭,要射敌人,先要射敌人的马,要抓敌人,先得抓敌人的头。杀人也应该有个限度,各国都有自己的边界。只要能够制止敌人的侵犯就成了,难道打仗就是为了多杀人吗?

       题解:
       射人先射马,擒贼先擒王。  说的就是要在解决事情上抓住关键,解决主要矛盾。

用人之道

  古文:用人之道

  太宗令封德彝举贤,久无所举。上诘之,对曰:“非不尽心,但于今未有奇才耳!”上曰:“君子用人如器,各取所长。古之致治者,岂借才于异代乎?正患己不能知,安可诬一世之人!”
  注释:
  ⑴上:即唐太宗李世民 ⑵诘:责备 ⑶器:器皿,器具。 ⑷致治:治理好国家(5)代:朝代. (6)封德彝:名伦,太宗手下的官员
  译:
  唐太宗让封德彝举荐有才能的人,他过了好久也没有推荐一个人。太宗责问他,他回答说:“不是我不尽心去做,只是当今没有杰出的人才啊!”太宗说:“用人跟用器物一样,每一种东西都要选用它的长处。古来能使国家达到大治的帝王,难道是向别的朝代去借人才来用的吗?我们只是担心自己不能识人,怎么可以冤枉当今一世的人呢?”
  道理:要知人善用。

曹操的五个用人之道

  曹操的五个用人之道:
  曹操的用人政策一: 名至实归 更重实际;
  曹操的用人政策二: 德才兼备 唯才是举;
  曹操的用人政策三: 重用清官 不避小贪;
  曹操的用人政策四: 招降纳叛 尽释前嫌;
  曹操的用人政策五: 抓大放小 不拘小节

诸葛亮的用人之道

  诸葛亮当权期间,反刘备依靠大族的政策,开始实行法治,大力打击益洲派的豪强;由于川中战乱没中原那严重,加上刘焉父子纵容大族,所以豪强势力还是十分强大,收益不错但是为后来的李严不供粮草埋下伏笔。诸葛亮很善于发现、培养、利用人才,如蒋琬、费文伟、董允等,诸葛亮的识人方面,杨洪、何诋的例子一直为后人所乐道;诸葛亮也注意提拔敌方投降过来的人才,如姜维、王平。诸葛亮大力起用荆洲派人才,在选拔人才和使用人才方面过分强调以“奉职循理”作为衡量优劣、取舍的标准,因而忽略了人才的多样性,尤其是开拓型人才的培养和造就。如街亭用的马谡、四相中的蒋琬、费文伟、董允都是荆洲派。
  由于诸葛亮的人才政策局限,加上刘蜀中生代人才大部分在夷陵之战中消亡,无奈后来只好“蜀中无大将,廖化当先锋”的悲惨局面。

刘邦的用人之道

  《史记高祖本纪》载, 上(刘邦)问曰:“如我能将几何?”信(韩信)曰:“陛下不过能将十万。”上曰:“于君如何?”信曰:“臣多多而益善耳。”上笑曰:“多多益善,何为我禽?”信曰:“陛下不能将兵,而善将将,此乃信之所以为陛下禽也。”
  刘邦在用人方面确实有他独到的地方,在谋略方面,他比不上张良、陈平;在打仗方面,他比不上韩信、彭越;在治理国家上,他不及萧何。然而,刘邦能够最大限度地使用人才,知道把手下的人才放在最合适的位置,这就是刘邦的用人之道,其精妙之处,究竟在什么地方呢?
  刘邦的用人之道
  一:知人善任
  二:不拘一格
  三:不计前嫌
  四:坦诚相待
  五:用人不疑
  六:论功行赏

唐太宗的用人之道

  唐太宗李世民是中国古代历史上最为贤明的皇帝之一,他的很多治国之道久为后世所推崇,即便放在今天仍值得我们认真借鉴学习。而在他的所有治国方略中,用人之道又更为重要。
  唐太宗喜欢人才,也擅长用人,在他理政的23年时间里,所用的文臣武将不胜枚举,著名点的有魏征、尉迟敬德、房玄龄、杜如晦等。纵观太宗用人之道,可以归纳为以下几点:
  首先,重视人才,太宗认为“能安天下者,惟在用得人才”。当年太宗平定刘周武,刘下属部将虽然投降,但随后又纷纷叛逃而去,只剩尉迟敬德还留在营中。太宗手下诸将劝他杀了敬得,免生后患,但太宗却认为敬德是个人才,不仅不杀反而重用之。后来敬德果然屡立战功,甚至还救了太宗一命;
  其次,知人善用。太宗命封德彝举荐人才,封领命很久都没有举荐一个。太宗问他为何,他说:“不是我不尽心,而是现在没有旷世奇才。”太宗责备他说:“人的才能,各有所长,君子用人,就如同用器皿一样,大才大用,小才小用,各取所长。”
  第三,对人推心置腹,以诚相待。有人给太宗出主意,要太宗采用些计谋或权术来试探朝中大臣的忠奸。太宗回答说:“如果用这些权术去试探部下,自身就不够光明磊落,如何要求他们正直呢?”张居正对此的评论也非常深刻:“君德贵明不贵察,明生于诚,其效至于不忍欺,察生于疑,其弊至于无所容,盖其相去远矣。”
  最后,有容人之量。太宗在位,时常有大臣秉理直谏,而太宗却常能接受各种不同意见,从不固执己见,也不偏听偏信。张居正更是认为太宗能够兼听为明主要是他虚心求教的结果,这也正是孔夫子“敏而好学,不耻下问”所要达到的境界。

摘自: http://baike.baidu.com/view/1384826.htm

linux kernel 2.4.5 ipv4 socket层的一点解释

1.新建socket
函数原形:
static int inet_create(struct socket *sock, int protocol)
在net/ipv4/af_inet.c中
详细解释

static int inet_create(struct socket *sockint protocol

struct sock *sk

struct proto *prot

sock->state SS_UNCONNECTED; 
/* 设置状态为未连接 */ 
sk sk_alloc(PF_INETGFP_KERNEL1); 
/* 申请sock所需的内存 */ 
   
/* net/core/sock.c */ 
if (sk == NULL

 goto do_oom

switch (
sock->type
) { 
case 
SOCK_STREAM:  
/* TCP协议 */ 
 if (protocol && protocol != IPPROTO_TCP

  goto free_and_noproto

 protocol IPPROTO_TCP

 prot = &tcp_prot; 
/* tcp_prot定义在net/ipv4/tcp_ipv4.c */ 
 sock->ops = &inet_stream_ops
/* 针对STREAM的socket操作 */ 
 break

case 
SOCK_SEQPACKET:  
/* 不支持 */ 
 goto free_and_badtype

case 
SOCK_DGRAM:  
/* UDP协议 */ 
 if (protocol && protocol != IPPROTO_UDP

  goto free_and_noproto

 protocol IPPROTO_UDP

 sk->no_check UDP_CSUM_DEFAULT

 prot=&udp_prot;  
/* udp_prot定义在net/ipv4/udp.c */ 
 sock->ops = &inet_dgram_ops
/* 针对DGRAM的socket操作 */ 
 break

case 
SOCK_RAW:  
/* RAW */ 
 if (!capable(CAP_NET_RAW)) 
/* 判断是否有权利建立SOCK_RAW */ 
  goto free_and_badperm

 if (!protocol)  
/* protocol不能为0 */ 
  goto free_and_noproto

 prot = &raw_prot; 
/* raw_prot定义在net/ipv4/raw.c */ 
 sk->reuse 1;  
/* 允许地址重用 */ 
 sk->num protocol

 sock->ops = &inet_dgram_ops
/* RAW的一些特性和DGRAM相同 */ 
 if (protocol == IPPROTO_RAW

  sk->protinfo.af_inet.hdrincl 1

   
/* 允许自己定制ip头 */ 
 break

default: 
 goto free_and_badtype


if (
ipv4_config.no_pmtu_disc

 sk->protinfo.af_inet.pmtudisc IP_PMTUDISC_DONT

else 
 sk->protinfo.af_inet.pmtudisc IP_PMTUDISC_WANT

sk->protinfo.af_inet.id 0

sock_init_data(sock,sk); 
/* 初始化一些数据 */ 
   
/* net/core/sock.c */ 
sk->destruct inet_sock_destruct
/* 当销毁socket时调用inet_sock_destruct */ 
sk->zapped 0

sk->family PF_INET

sk->protocol protocol

sk->prot prot

sk->backlog_rcv prot->backlog_rcv
/* prot->backlog_rcv()见各个类型的定义 */ 
sk->protinfo.af_inet.ttl sysctl_ip_default_ttl
/* 设置默认ttl */ 
   
/* 修改/proc/sys/net/ipv4/ip_default_ttl */ 
sk->protinfo.af_inet.mc_loop 1

sk->protinfo.af_inet.mc_ttl 1

sk->protinfo.af_inet.mc_index 0

sk->protinfo.af_inet.mc_list NULL

#ifdef INET_REFCNT_DEBUG 
atomic_inc(&inet_sock_nr
); 
#endif 
if (sk->num
) { 
 
/* It assumes that any protocol which allows 
  * the user to assign a number at socket 
  * creation time automatically 
  * shares. 
  */ 
 sk->sport htons(sk->num); 
/* 设置本地端口 */ 
 
/* Add to protocol hash chains. */ 
 sk->prot->hash(sk
); 

if (
sk->prot->init
) { 
 int err sk->prot->init(sk); 
/* 协议对socket的初始化 */ 
 if (err != 0
) { 
  inet_sock_release(sk
); 
  return(err
); 
 


return(
0
); 
free_and_badtype

sk_free(sk);  
/* 释放内存 */ 
return –ESOCKTNOSUPPORT

free_and_badperm

sk_free(sk
); 
return –
EPERM

free_and_noproto

sk_free(sk
); 
return –
EPROTONOSUPPORT

do_oom

return –
ENOBUFS


在net/core/sock.

void sock_init_data
(struct socket *sockstruct sock *sk


skb_queue_head_init(&sk->receive_queue); 
/* 初始化3条队列 接受,发送,错误*/ 
skb_queue_head_init(&sk->write_queue
); 
skb_queue_head_init(&sk->error_queue
); 
init_timer(&sk->timer);  
/* 初始化timer */ 

sk->allocation GFP_KERNEL
sk->rcvbuf sysctl_rmem_default

sk->sndbuf sysctl_wmem_default

sk->state = TCP_CLOSE

sk->zapped 1

sk->socket sock

if(
sock


 sk->type sock->type

 sk->sleep = &sock->wait

 sock->sk sk

} else 
 sk->sleep NULL

sk->dst_lock RW_LOCK_UNLOCKED

sk->callback_lock RW_LOCK_UNLOCKED

   
/* sock_def_wakeup(),sock_def_readable(), 
    sock_def_write_space(),sock_def_error_report(), 
    sock_def_destruct() 在net/core/sock.c */ 
sk->state_change sock_def_wakeup

sk->data_ready sock_def_readable

sk->write_space sock_def_write_space

sk->error_report sock_def_error_report

sk->destruct      =    sock_def_destruct

sk->peercred.pid 0

sk->peercred.uid = –1

sk->peercred.gid = –1

sk->rcvlowat 1

sk->rcvtimeo MAX_SCHEDULE_TIMEOUT
/* 设置接受,发送超时 */ 
sk->sndtimeo MAX_SCHEDULE_TIMEOUT

atomic_set(&sk->refcnt1
); 

1.1 SOCK_STREAM的初始化 
在net
/ipv4/tcp_ipv4.

static int tcp_v4_init_sock(struct sock *sk


struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp
); 
skb_queue_head_init(&tp->out_of_order_queue
); 
tcp_init_xmit_timers(sk
); 
tcp_prequeue_init(tp
); 
tp->rto TCP_TIMEOUT_INIT

tp->mdev TCP_TIMEOUT_INIT

    
/* So many TCP implementations out there (incorrectly) count the 
 * initial SYN frame in their delayed-ACK and congestion control 
 * algorithms that we must have the following bandaid to talk 
 * efficiently to them. -DaveM 
 */ 
tp->snd_cwnd 2

/* See draft-stevens-tcpca-spec-01 for discussion of the 
 * initialization of these values. 
 */ 
tp->snd_ssthresh 0x7fffffff
/* Infinity */ 
tp->snd_cwnd_clamp = ~0

tp->mss_cache 536

tp->reordering sysctl_tcp_reordering

sk->state TCP_CLOSE

sk->write_space tcp_write_space
/* tcp_write_space() 在net/ipv4/tcp.c */ 
sk->use_write_queue 1

sk->tp_pinfo.af_tcp.af_specific = &ipv4_specific

   
/* ipv4_specific 在net/ipv4/tcp_ipv4.c */ 
sk->sndbuf sysctl_tcp_wmem[1]; 
/* 设置发送和接收缓冲区大小 */ 
sk->rcvbuf sysctl_tcp_rmem[1]; 
/* sysctl_tcp_* 在net/ipv4/tcp.c */ 
atomic_inc(&tcp_sockets_allocated); 
/* tcp_sockets_allocated是当前TCP socket的数量 */ 
return 0

}

SOCK_DGRAM无初始化
1.2 SOCK_RAW初始化
在net/ipv4/raw.c

static int raw_init(struct sock *sk

struct raw_opt *tp = &(sk->tp_pinfo.tp_raw4
); 
if (
sk->num == IPPROTO_ICMP

 memset(&tp->filter0sizeof(tp->filter
)); 
return 
0

}

2.Server
2.1 bind

static int inet_bind(struct socket *sockstruct sockaddr *uaddrint addr_len

struct sockaddr_in *addr=(struct sockaddr_in *)uaddr

struct sock *sk=sock->sk

unsigned short snum

int chk_addr_ret

int err

/* If the socket has its own bind function then use it. (RAW) */ 
if(sk->prot->bind

 return sk->prot->bind(skuaddraddr_len
); 
    
/* 只有SOCK_RAW定义了自己的bind函数 */ 
if (addr_len sizeof(struct sockaddr_in
)) 
 return EINVAL

chk_addr_ret inet_addr_type(addr->sin_addr.s_addr
); 
    
/* inet_addr_type返回地址的类型 */ 
    
/* 在net/ipv4/fib_frontend.c */ 
/* Not specified by any standard per-se, however it breaks too 
 * many applications when removed. It is unfortunate since 
 * allowing applications to make a non-local bind solves 
 * several problems with systems using dynamic addressing. 
 * (ie. your servers still start up even if your ISDN link 
 * is temporarily down) 
 */ 
if (sysctl_ip_nonlocal_bind == 
&& 
   sk->protinfo.af_inet.freebind == 
&& 
   addr->sin_addr.s_addr != INADDR_ANY 
&& 
   chk_addr_ret != RTN_LOCAL 
&& 
   chk_addr_ret != RTN_MULTICAST 
&& 
   chk_addr_ret != RTN_BROADCAST

 return EADDRNOTAVAIL

snum ntohs(addr->sin_port
); 
if (
snum && snum PROT_SOCK && !capable(CAP_NET_BIND_SERVICE
)) 
   
/* 检查是否有权利bind端口到1-1024 */ 
 return EACCES

/*   We keep a pair of addresses. rcv_saddr is the one 
 *   used by hash lookups, and saddr is used for transmit. 
 * 
 *   In the BSD API these are the same except where it 
 *   would be illegal to use them (multicast/broadcast) in 
 *   which case the sending device address is used. 
 */ 
lock_sock(sk
); 
/* Check these errors (active socket, double bind). */ 
err = –EINVAL

if ((
sk->state != TCP_CLOSE)  
|| 
   (sk->num != 0
)) 
 goto out

sk->rcv_saddr sk->saddr addr->sin_addr.s_addr

if (
chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST

 sk->saddr 0; 
/* Use device */ 
/* Make sure we are allowed to bind here. */ 
if (sk->prot->get_port(sksnum) != 0) { 
/* get_port检查是否重用 */ 
 sk->saddr sk->rcv_saddr 0

 err = –EADDRINUSE

 goto out


if (
sk->rcv_saddr

 sk->userlocks |= SOCK_BINDADDR_LOCK

if (
snum

 sk->userlocks |= SOCK_BINDPORT_LOCK

sk->sport htons(sk->num
); 
sk->daddr 0

sk->dport 0

sk_dst_reset(sk
); 
err 0

out

release_sock(sk
); 
return 
err

SOCK_STREAM和SOCK_DGRAM用默认的bind
2.1.1 SOCK_RAW的bind
在net/ipv4/raw.c

static int raw_bind(struct sock *skstruct sockaddr *uaddrint addr_len

struct sockaddr_in *addr = (struct sockaddr_in *) uaddr

int ret = –EINVAL

int chk_addr_ret

if (
sk->state != TCP_CLOSE || addr_len sizeof(struct sockaddr_in
)) 
 goto out

chk_addr_ret inet_addr_type(addr->sin_addr.s_addr
); 
    
/* inet_addr_type返回地址的类型 */ 
    
/* 在net/ipv4/fib_frontend.c */ 
ret = –EADDRNOTAVAIL

if (
addr->sin_addr.s_addr && chk_addr_ret != RTN_LOCAL 
&& 
   chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST

 goto out

sk->rcv_saddr sk->saddr addr->sin_addr.s_addr

    
/* sk->rcv_saddr 捆绑的本地地址 */ 
    
/* sk->saddr 源地址 */ 
if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST

 sk->saddr 0; 
/* Use device */ /* 地址类型如为多播或是广播源地址为0 */ 
sk_dst_reset(sk
); 
ret 0

out: return ret


2.2 listen
2.2.1 SOCK_STREAM的listen
在net/ipv4/af_inet.c

int inet_listen(struct socket *sockint backlog

struct sock *sk sock->sk

unsigned char old_state

int err

lock_sock(sk
); 
err = –EINVAL

if (
sock->state != SS_UNCONNECTED || sock->type != SOCK_STREAM

 goto out

old_state sk->state

if (!((
1<<old_state)&(TCPF_CLOSE|TCPF_LISTEN
))) 
 goto out

/* Really, if the socket is already in listen state 
 * we can only allow the backlog to be adjusted. 
 */ 
if (old_state != TCP_LISTEN
) { 
 err tcp_listen_start(sk); 
/* 真正实现TCP协议listen */ 
 if (err

  goto out


sk->max_ack_backlog backlog

err 0

out

release_sock(sk
); 
return 
err


//tcp_listen_start在net/ipv4/tcp.h 
int tcp_listen_start(struct sock *sk


struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp
); 
struct tcp_listen_opt *lopt

sk->max_ack_backlog 0

sk->ack_backlog 0

tp->accept_queue tp->accept_queue_tail NULL

tp->syn_wait_lock RW_LOCK_UNLOCKED

tcp_delack_init(tp);  
/* tp清0 */ 
   
/* include/net/tcp.h */ 
lopt kmalloc(sizeof(struct tcp_listen_opt), GFP_KERNEL
); 
if (!
lopt

 return ENOMEM

memset(lopt0sizeof(struct tcp_listen_opt
)); 
for (
lopt->max_qlen_log 6; ; lopt->max_qlen_log
++) 
 if ((1<<lopt->max_qlen_log) >= sysctl_max_syn_backlog

  
break; 
write_lock_bh(&tp->syn_wait_lock
); 
tp->listen_opt lopt

write_unlock_bh(&tp->syn_wait_lock
); 
/* There is race window here: we announce ourselves listening, 
 * but this transition is still not validated by get_port(). 
 * It is OK, because this socket enters to hash table only 
 * after validation is complete. 
 */ 
sk->state TCP_LISTEN

if (
sk->prot->get_port(sksk->num) == 0) { 
/* 确认地址没有重用 */ 
 sk->sport htons(sk->num); 
/* 设置源端口 */ 
 sk_dst_reset(sk
); 
 sk->prot->hash(sk);  
/* 将端口加到hash表中 */ 
 return 0


sk->state TCP_CLOSE

write_lock_bh(&tp->syn_wait_lock
); 
tp->listen_opt NULL

write_unlock_bh(&tp->syn_wait_lock
); 
kfree(lopt
); 
return –
EADDRINUSE


SOCK_DGRAM 和 SOCK_RAW 不支持listen
2.3 accept
2.3.1 SOCK_STREAM的accept
在net/ipv4/af_inet.c

int inet_accept(struct socket *sockstruct socket *newsockint flags

struct sock *sk1 sock->sk

struct sock *sk2

int err = –EINVAL

if((
sk2 sk1->prot->accept(sk1,flags,&err)) == NULL

 goto do_err

lock_sock(sk2
); 
BUG_TRAP((1<<sk2->state)&(TCPF_ESTABLISHED|TCPF_CLOSE_WAIT|TCPF_CLOSE
)); 
sock_graft(sk2newsock); 
/* 将sk2转接到newsock */ 
   
/* 在include/net/sock.h */ 
newsock->state SS_CONNECTED

release_sock(sk2
); 
return 
0

do_err

return 
err


SOCK_DGRAM 和 SOCK_RAW 不支持 accept
2.3.1.1 TCP协议的accept
在net/ipv4/tcp.c

struct sock *tcp_accept(struct sock *skint flagsint *err

struct tcp_opt *tp = &sk->tp_pinfo.af_tcp

struct open_request *req

struct sock *newsk

int error

lock_sock(sk
); 
/* We need to make sure that this socket is listening, 
 * and that it has something pending. 
 */ 
error = –EINVAL

if (
sk->state != TCP_LISTEN) 
/* 检查socket是否处于listen状态 */ 
 goto out

/* Find already established connection */ 
if (!tp->accept_queue) { 
/* 判断accept队列是否准备好 */ 
 long timeo sock_rcvtimeo(skflags O_NONBLOCK
); 
   
/* 判断是否为堵塞模式 */ 
   
/* 在include/net/sock.h */ 
 
/* If this is a non blocking socket don’t sleep */ 
 error = –EAGAIN

 if (!timeo)  
/* 不堵塞模式,直接返回 */ 
  goto out

 error wait_for_connect(sktimeo); 
/* 进入空闲等待连接 */ 
 if (error

  goto out


req tp->accept_queue

if ((
tp->accept_queue req->dl_next) == NULL

 tp->accept_queue_tail NULL

 newsk req->sk

tcp_acceptq_removed(sk);  
/* sk当前连接数减1 */ 
    
/*在include/net/tcp.h */ 
tcp_openreq_fastfree(req);  
/* 释放内存 */ 
    
/*在include/net/tcp.h */ 
BUG_TRAP(newsk->state != TCP_SYN_RECV);
  
release_sock
(sk
); 
return 
newsk

out

release_sock(sk
); 
*
err error

return 
NULL


/* 只有当socket为堵塞模式,该函数才会被调用 */ 
/* 在net/ipv4/tcp.c */ 
static int wait_for_connect(struct sock sklong timeo


DECLARE_WAITQUEUE(waitcurrent
); 
int err

/* 
 * True wake-one mechanism for incoming connections: only 
 * one process gets woken up, not the ‘whole herd’. 
 * Since we do not ‘race & poll’ for established sockets 
 * anymore, the common case will execute the loop only once. 
 * 
 * Subtle issue: "add_wait_queue_exclusive()" will be added 
 * after any current non-exclusive waiters, and we know that 
 * it will always _stay_ after any new non-exclusive waiters 
 * because all non-exclusive waiters are added at the 
 * beginning of the wait-queue. As such, it’s ok to "drop" 
 * our exclusiveness temporarily when we get woken up without 
 * having to remove and re-insert us on the wait queue. 
 */ 
add_wait_queue_exclusive(sk->sleep, &wait
); 
for (;;) { 
 current->state TASK_INTERRUPTIBLE

 release_sock(sk
); 
 if (sk->tp_pinfo.af_tcp.accept_queue == NULL

  timeo schedule_timeout(timeo); 
/* 休眠timeo时长 */ 
 lock_sock(sk
); 
 err 0

 if (sk->tp_pinfo.af_tcp.accept_queue) 
/* accept队列可用 */ 
    
/* 也就是有连接进入 */ 
  
break; 
 err = –EINVAL

 if (sk->state != TCP_LISTEN

  
break; 
 err sock_intr_errno(timeo
); 
 if (signal_pending(current
)) 
  
break; 
 err = –EAGAIN

 if (!timeo

  
break; 

current->state TASK_RUNNING

remove_wait_queue(sk->sleep, &wait
); 
return 
err


3.Client
3.1 connect
3.1.1 SOCK_STREAM的connect
在net/ipv4/af_inet.c

int inet_stream_connect(struct socket *sockstruct sockaddr uaddr
  int addr_lenint flags


struct sock *sk=sock->sk

int err

long timeo

lock_sock(sk
); 
if (
uaddr->sa_family == AF_UNSPEC
) { 
 err sk->prot->disconnect(skflags); 
/* 关闭连接 */ 
 sock->state err SS_DISCONNECTING SS_UNCONNECTED

 goto out


switch (
sock->state
) { 
default: 
 err = –EINVAL

 goto out

case 
SS_CONNECTED

 err = –EISCONN

 goto out

case 
SS_CONNECTING

 err = –EALREADY

 
/* Fall out of switch with err, set for this state */ 
 break

case 
SS_UNCONNECTED

 err = –EISCONN

 if (sk->state != TCP_CLOSE

  goto out

 err = –EAGAIN

 if (sk->num == 0
) { 
  if (sk->prot->get_port(sk0) != 0
/* 是否重用 */ 
  goto out

  sk->sport htons(sk->num
); 
 

 err sk->prot->connect(skuaddraddr_len); 
/* 调用协议的connect */ 
 if (err 0

  goto out

  sock->state SS_CONNECTING;  
/* socket状态设置成连接中 */ 
 
/* Just entered SS_CONNECTING state; the only 
  * difference is that return value in non-blocking 
  * case is EINPROGRESS, rather than EALREADY. 
  */ 
 err = –EINPROGRESS

 break


timeo sock_sndtimeo(skflags&O_NONBLOCK); 
/* 是否为堵塞模式 */ 
    
/* 在include/net/sock.h */ 
if ((1<<sk->state)&(TCPF_SYN_SENT|TCPF_SYN_RECV)) { 
/* 连接为完成 */ 
 
/* Error code is set above */ 
 if (!timeo || !inet_wait_for_connect(sktimeo
)) 
    
/* 非堵塞模式立即返回 */ 
    
/* 堵塞模式调用inet_wait_for_connect() */ 
  goto out

 err sock_intr_errno(timeo
); 
 if (signal_pending(current
)) 
  goto out


/* Connection was closed by RST, timeout, ICMP error 
 * or another process disconnected us. 
 */ 
if (sk->state == TCP_CLOSE

 goto sock_error

/* sk->err may be not zero now, if RECVERR was ordered by user 
 * and error was received after socket entered established state. 
 * Hence, it is handled normally after connect() return successfully. 
 */ 
sock->state SS_CONNECTED;  
/* 设置状态为已连接 */ 
err 0

out

release_sock(sk
); 
return 
err

sock_error

err sock_error(sk) ? : –ECONNABORTED

sock->state SS_UNCONNECTED

if (
sk->prot->disconnect(skflags
)) 
 sock->state SS_DISCONNECTING

goto out


/* 只有当socket为堵塞模式,该函数才会被调用 */ 
/* 在/net/ipv4/af_inet.c */ 
static long inet_wait_for_connect(struct sock *sklong timeo


DECLARE_WAITQUEUE(waitcurrent
); 
__set_current_state(TASK_INTERRUPTIBLE
); 
add_wait_queue(sk->sleep, &wait
); 
/* Basic assumption: if someone sets sk->err, he _must_ 
 * change state of the socket from TCP_SYN_*. 
 * Connect() does not allow to get error notifications 
 * without closing the socket. 
 */ 
while ((1<<sk->state)&(TCPF_SYN_SENT|TCPF_SYN_RECV
)) { 
 release_sock(sk
); 
 timeo schedule_timeout(timeo); 
/* 进入休眠 */ 
 lock_sock(sk
); 
 if (signal_pending(current) || !timeo

  
break; 
 set_current_state(TASK_INTERRUPTIBLE
); 

__set_current_state(TASK_RUNNING
); 
remove_wait_queue(sk->sleep, &wait
); 
return 
timeo


摘自: http://www.infosecurity.org.cn/article/hacker/tutor/12424.html