2009年6月28日星期日

办公族五个坏习惯让身体长石头

肾结石一跃成为全民最为关注的疾病之一。但是要预防结石病,仅仅关注奶粉或者牛奶的食用安全远远不够,而需要被关怀的也绝不仅止于婴幼儿群体。相关资料显示,近年来结石的发病率逐年升高,发病群体涵盖所有年龄层,并有年轻化的趋势,其中办公室白领占据相当大的比例。
  结石为何盯上办公族?有关专家指出,这与办公族工作繁忙、工作节奏紧张等客观因素有关,更与其不良的生活习惯紧密相连,其中五个坏习惯,是致病的罪魁祸首。
  不吃早餐
  不吃早餐的办公族不在少数,有的是因为早上赶着上班,来不及吃,有的是为了减肥,不愿意吃。这一看似寻常的生活习惯却是导致结石病的重要原因。据健康863网的保健专家介绍,不吃早餐诱发结石病的几率相当大。这是因为人体在经过夜晚的长时间睡眠后,需要在早晨摄入食物来补充能量,胆作为消化系统的一部分,会在早上分泌胆汁,做好消化食物的准备。人如果不吃早餐,胆就没有食物可消化,胆汁就会长时间停留在胆囊,长此以往,胆汁会淤积在胆囊或肠道,胆固醇自胆汁中析出就易形成结石。
  防石计:不要给自己任何借口不吃早餐。吃早餐耽搁不了太多时间,也不会让你长胖。即使是简单的喝点牛奶、吃片面包,也能起到预防作用。
  不爱喝水
  不少办公族因为工作节奏快,喝水的时间相应较少,还有为数不少的人即使有时间喝水,量也不够大,而这正是诱发结石病的另一重要原因。专家表示,喝水少会减少人体尿液,并会使尿液过度浓缩,尿中盐类的浓度增高,沉淀增多,就容易形成肾结石或尿路结石。
  防石计:多喝水可以增加排尿量,稀释尿液,降低尿内晶体浓度,冲洗尿路,有利于预防结石形成及促使结石排出,所以即便不口渴,个人每天也应喝水2000毫升以上,并最好选择清水。
  不喜欢运动
  运动量少也会导致结石的产生。而办公族的工作性质注定了坐的时间非常长,运动的机会少,下班后很多人也不爱运动。专家指出,人如果很少运动,一方面不利于钙质吸收,会增加尿液中的钙盐成分,产生肾结石或尿路结石;另一方面人体腹壁会松弛,引致内脏下垂,压迫胆管,使胆汁排泄不畅而淤积,从而形成胆结石。

  防石计:加强运动,不要"坐等"结石的形成。在办公室工作两个小时左右,就应站起来做些简单的放松运动,业余也应保证一定的运动量,每天的运动时间应在30分钟以上。
  吃得太油
  办公族因为工作繁忙,应酬较多等原因,在外就餐的机会较多,吃大鱼大肉的频率较高,并容易暴饮暴食,尤其是男性,往往吃得过于油腻,而这正是结石病的重要诱因。因为高脂肪、高蛋白食物会增高胆汁中的胆固醇含量,形成结石;动物内脏、肉类代谢也会产生尿酸,导致结石。
  防石计:管住嘴,限制食物中胆固醇的含量,少吃或忌吃富含胆固醇的食物,如肥肉、动物内脏、鱼籽、蟹黄、蛋黄等。多吃新鲜瓜果和蔬菜以及大蒜、洋葱、香菇、黑木耳等具有降低胆固醇作用的保护性食物。
  吃得太素
  吃得太油腻容易得结石,吃得太素同样容易长石头。办公室MM大多热衷减肥,不少人信奉素食主义,以蔬菜为主食。专家提醒,虽然蔬菜富含维生素、矿物质和膳食纤维,但是,菠菜、芹菜、番茄、竹笋等蔬菜中同时还富含草酸,过量食用可能从尿中析出而形成结石,其与豆制品或者钙片中的钙结合后,也容易形成结石。
  防石计:含草酸盐较多的蔬菜在吃之前应先焯一下,然后再过一遍水,以减少草酸摄入量;可多吃碱性蔬菜和苹果,综合酸碱度;宜适量摄入高脂肪、高蛋白食物,均衡饮食结构,减小结石风险。

2009年6月27日星期六

sh一在建楼盘轰然倒塌

事情发生在早上5:40分左右。

行人车辆请注意,飞机就要开过来了!

请在拦木外等候,不要抢行,不要翻栏杆!

Linux代码淬火工具

介绍用来提高Linux应用程序安全性和可靠性的开源工具和代码追踪技术。
一、源代码检查工具
在软件开发过程中,我们可以利用源码检查工具来找出常见的编程错误以及安全漏洞。这些工具用起来并不复杂,下面介绍splint和flawfinder这两款源码检查工具的使用方法。
splint是一款静态源代码检查工具,能对源代码进行全面的分析。对于没有注释的源代码,可以使用-weak选项:
splint -weak *.c -I./inc
其中,./inc是头文件所在的子目录。此外,Splint还支持标准检查模式(选项-standard),若要进行中等强度检查则使用选项-checks,若使用选项-strict则进行最严格的检查。
flawfinder也是一款用来寻找源代码错误的静态分析工具。通过该工具提供错误消息,开发人员可以更快的找到错误所在。请看下面的例子:
$ flawfinder test.c
test.c:11: [2] (buffer) char:
Statically-sized arrays can be overflowed. Perform bounds
checking, use functions that limit length, or ensure that
the size is larger than the maximum possible length.
$
本例中,flawfinder给出了一个提示,指出静态尺寸的数组可能被恶意利用的潜在危险。
除了上面介绍的splint和flawfinder这两款工具外,还有RATS(一款安全审计工具)以及ITS4(静态漏洞扫描工具)等工具可用。但需要
注意的是,虽然这些工具能够分担一部分工作,但却无法完全替代人类。因为工具在发现漏洞的同时,也可能遗漏安全漏洞。

二、代码跟踪技术
我们知道,strace工具通常是用来追踪系统调用的,实际上,它还可以作为间接的源代码审计工具。从系统调用的角度来跟踪应用程序的执行,可以让我们了解到Linux应用程序的底层操作,借助这些低层操作我们可以更好的理解我们的源代码。
在下面的例子中,有多处违反了我们前面讨论的代码淬火原则,现在我们展示如何利用strace来进行调试。
#include <unistd.h>
#include <fcntl.h>
#define MAX_BUF 128
int main()
{
int fd;
char buf[MAX_BUF+1];
fd = open( "myfile.txt", O_RDONLY );
read( fd, buf, MAX_BUF );
printf( "read %s\n", buf );
close( fd );
}
我们注意到,上面的代码的第11行,即:fd = open( "myfile.txt", O_RDONLY
);
试图打开一个称为myfile.txt的文件,但事前并没有检查该文件是否业已存在。在这种情况下执行该程序的话,会导致无法预测的结果:
$ gcc -o bad bad.c
$ ./bad
read @?8Z@
$
看看,这样的结果是你没料到的吧。所以,先让我们利用strace来看看到底发生了什么。注意,下面的输出已经作了删减,但重要的信息都保留下来了:
$ strace ./bad
execve("./bad", ["./bad"], [/* 20 vars */]) = 0
uname({sys="Linux", node="camus", ...}) = 0
...
open("myfile.txt", O_RDONLY) = -1 ENOENT ( No such file or
directory)
read(-1, 0xbfffef20, 128) = -1 EBADF (Bad file descriptor)
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS,
-1, 0) = 0x40017000
write(1, "read \300\357\377\2778Z\1@\n", 14read /à???8z@
) = 14
close(-1) = -1 EBADF (Bad file descriptor)
munmap(0x40017000, 4096) = 0
exit_group(-1) = ?
$
执行程序后,我们看到用来启动该程序的系统调用是execve();不久又调用了open(),该系统调用对应于代码中的第11行。并且我们看到系统调用
open()的右边的返回值是-1,并指出错误"ENOENT ( No such file or
directory)",即不存在这个文件或目录。换句话说,这是在告诉我们需要先建立文件。此外,系统调用read()也以失败而告终,它的错误是非法
的文件描述符,因为open调用失败了。
strace工具不仅用来帮助理解有源代码的程序的行为,而且也对于没有源代码的程序也同样有效。因为,透过对系统调用的观察,我们能够在二进制级别来理解程序的行为。

三、小结
古人云,工欲善其事,必先利其器。借助于上文介绍的代码淬火方面的编码知识,用来提高Linux应用程序安全性和可靠性的调试工具,相信读者能够更快更好开发出安全可靠的高品质软件来。

编程利器——splint工具

到底需不需要编译器之外的独立的静态代码检查工具呢?这个问题'仁者见仁,智者见智'。但是有一个结论我想大家都会认可,那就是越是在开发周期早期发现的
Bug,修复它所付出的代价就越小。而像lint这样的静态代码检查程序恰恰是让Bug在早期阶段'显露原型'的绝佳工具,而追求'lint-
clean'[注1]境界的代码也向来是专家级程序员的嗜好。别忘了在'C专家编程'一书中曾经提到Sun
OS的内核一直是保持'lint-clean'状态的,这就是榜样!还等什么?赶快学呀!^_^

有人抱怨'不敢用lint工具,
太多的Warnings把快屏幕都淹没了!',不过高手一般不这么想,他会细心琢磨这些Warnings背后的'暗示',并和lint工具沟通,利用
lint工具提供的交互方法屏蔽掉一些经过分析认为不能成为错误的Warnings。久而久之,高手本身就成了一个lint程序,就能够很快的用肉眼发现
代码中的问题,并指出问题所在,如何解决!他还能告知如何嵌入一些Annotations从而避免让lint程序产生不必要的Warnings,这时这位
高手对语言和程序的理解就又提高了一个档次了。其实使用ling工具不仅仅是为了提早发现程序中的Bug,其使用过程有助于你加深对程序的认识和理解。的
确事实就是这样。

Splint就是一款强大而且应用广泛的开源lint工具。它的强大的代码检查能力固
然让人称道,但是让我更欣赏的却是它提供的'Annotations'机制。
Splint可以让程序员在自己的代码中嵌入相应的Anotations,这些Anotations作为Splint分析代码时的输入以帮助Splint
产生对程序员更有用的信息。下面是一些Splint的使用入门,更多详细信息请查看'Splint
manual'。

1、最简单的Splint使用方法
>> splint *.c

2、Splint输出Warnings的基本格式
<file>:<line>[,<column>]: message
[hint]
<file>:<line>,<column>: extra location information, if appropriate
我们可以使用'+/-<flags>'来自定义其输出格式,如'splint -showcol
*c',则Splint不会在输出信息中显示'列'信息。

3、使用flags控制splint的检查范围和输出格式
'+<flag>' -- 表明某个flag处于打开状态,如'+unixlib';
'-<flag>' -- 表明某个flag处于关闭状态,如'-weak';

4、使用.splintrc环境文件
如果不想每次使用splint的时候都手工输入一堆'+/-<flags>',那么你可以把这些'+/-<flags>'预先写
到.splintrc文件中,当splint执行的时候它会自动加上这些flags的。默认的flags设置在'~/splintrc'文件中,但是如果
一旦splint的当前工作路径下也有.splintrc文件,那么这个.splintrc文件中的flag设置会覆盖'~/splintrc'中的
flags设置,但是命令行中的flags设置是具备最高优先级的,它会覆盖前面提到的任何一个文件中的flags设置。

5、使用Annotations
对于'Annotations'的作用,Java程序员并不陌生,但是C程序员则对这个不是那么了解。C代码中的Annotations用来指导Splint生成恰当的代码检查报告。下面这个例子对比使用和不使用Annotations,Splint的输出的差别:
/* testlint.c */
void foo1() {
/*@unused@*/int *p = NULL;
}

void foo2() {
int *p = NULL;
}

splint testlint.c
Splint 3.1.1 --- 28 Apr 2003

testlint.c: (in function foo2)
testlint.c:6:7: Variable p declared but not used
A variable is declared but never used. Use /*@unused@*/ in front of
declaration to suppress message. (Use -varuse to inhibit warning)

Finished checking --- 1 code warning

可以看出没使用Annotation的函数foo2被给出Warning了。Splint的Annotations繁多,我们在平时做lint时可以多多接触。

'早用lint,勤用lint',这是C专家给我们的建议。'lint-clean'也许离你并不遥远。

[注1]
'lint-clean' -- 程序能够顺利通过lint程序的检查。

2009年6月25日星期四

Socket send函数和recv函数详解

1.send 函数
int send( SOCKET s, const char FAR *buf, int len, int flags );
不论是客户还是服务器应用程序都用send函数来向TCP连接的另一端发送数据。客户程序一般用send函数向服务器发送请求,而服务器则通常用send函数来向客户程序发送应答。
该函数的第一个参数指定发送端套接字描述符;
第二个参数指明一个存放应用程序要发送数据的缓冲区;
第三个参数指明实际要发送的数据的字节数;
第四个参数一般置0。
这里只描述同步Socket的send函数的执行流程。当调用该函数时,
(1)send先比较待发送数据的长度len和套接字s的发送缓冲的长度,
如果len大于s的发送缓冲区的长度,该函数返回SOCKET_ERROR;
(2)如果len小于或者等于s的发送缓冲区的长度,那么send先检查协议是否正在发送s的发送缓冲中的数据,如果是就等待协议把数据发送完,如果协议还没有开始发送s的发送缓冲中的数据或者s的发送缓冲中没有数据,那么send就比较s的发送缓冲区的剩余空间和len
(3)如果len大于剩余空间大小,send就一直等待协议把s的发送缓冲中的数据发送完
(4)如果len小于剩余
空间大小,send就仅仅把buf中的数据copy到剩余空间里(注意并不是send把s的发送缓冲中的数据传到连接的另一端的,而是协议传的,send仅仅是把buf中的数据copy到s的发送缓冲区的剩余空间里)。
如果send函数copy数据成功,就返回实际copy的字节数,如果send在copy数据时出现错误,那么send就返回SOCKET_ERROR;如果send在等待协议传送数据时网络断开的话,那么send函数也返回SOCKET_ERROR。
要注意send函数把buf中的数据成功copy到s的发送缓冲的剩余空间里后它就返回了,但是此时这些数据并不一定马上被传到连接的另一端。如果协议在后续的传送过程中出现网络错误的话,那么下一个Socket函数就会返回SOCKET_ERROR。(每一个除send外的Socket函数在执
行的最开始总要先等待套接字的发送缓冲中的数据被协议传送完毕才能继续,如果在等待时出现网络错误,那么该Socket函数就返回
SOCKET_ERROR)
注意:在Unix系统下,如果send在等待协议传送数据时网络断开的话,调用send的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。
通过测试发现,异步socket的send函数在网络刚刚断开时还能发送返回相应的字节数,同时使用select检测也是可写的,但是过几秒钟之后,再send就会出错了,返回-1。select也不能检测出可写了。
2. recv函数
int recv( SOCKET s, char FAR *buf, int len, int flags);
不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据。该函数的第一个参数指定接收端套接字描述符;
第二个参数指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;
第三个参数指明buf的长度;
第四个参数一般置0。
这里只描述同步Socket的recv函数的执行流程。当应用程序调用recv函数时,
(1)recv先等待s的发送缓冲中的数据被协议传送完毕,如果协议在传送s的发送缓冲中的数据时出现网络错误,那么recv函数返回SOCKET_ERROR,
(2)如果s的发送缓冲中没有数据或者数据被协议成功发送完毕后,recv先检查套接字s的接收缓冲区,如果s接收缓冲区中没有数据或者协议正在接收数据,那么recv就一直等待,直到协议把数据接收完毕。当协议把数据接收完毕,recv函数就把s的接收缓冲中的数据copy到buf中(注意协议接收到的数据可能大于buf的长度,所以
在这种情况下要调用几次recv函数才能把s的接收缓冲中的数据copy完。recv函数仅仅是copy数据,真正的接收数据是协议来完成的),
recv函数返回其实际copy的字节数。如果recv在copy时出错,那么它返回SOCKET_ERROR;如果recv函数在等待协议接收数据时网络中断了,那么它返回0。
注意:在Unix系统下,如果recv函数在等待协议接收数据时网络断开了,那么调用recv的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。

VIM显示十六进制出错

在linux下用vim打开jpg文件,使用%!xxd进行16进制显示时,文件头显示为"3f3f
3f3f 0011 0804"文件尾端显示为 "3f3f
0a";而同样的操作在windows下,就显示为"ffd8 ffc0 0011 0804"和 "ffd9
0a",这才是正确的jpeg文件头和文件尾标志。
很蹊跷 !
初时,我以为是jpeg在windows和linux下是不同的文件头,后来把jpg后缀去掉,就一个纯文件,现象依旧。考虑可能不是操作系统的差异了。
重新使用ghex打开jpeg数据查看,发现显示正常,为"ffd8 ffc0 0011
0804"和 "ffd9 0a",正确。
估计应该是vim的问题了。
3f的ascii码是?,那表示vim对文件头、尾没有正常解析,是不是和vim解析文件时用的编码格式有关系呢?
打开.vimrc配置项,屏蔽掉下面这句话:
set fileencodings=utf-8,gb2312,gbk,gb18030,ucs-bom
再用vim打开jpeg文件,显示"ffd8 ffc0 0011 0804"和 "ffd9 0a",
显示正确。
原来,为了支持识别和显示中文,我规定了vim的fileencodings,
当vim打开文件时,会使用规定的编码格式对数据进行解析,可惜jpeg的文件头FFD8、尾FFD9
不是任何一个中文的编码,vim找不到对应的中文字,就显示为??,即:3f3f。
至此,困惑全部打开。