Archives

《读者》

已经很久没买《读者》了,这两天又想起来开始买着看了。

记得上大一大二的时候经常去食堂旁边的那个杂志摊去买,有一段时间甚至是每一期都买。上了大三大四就很少买了,主要是没闲功夫看这些“课外”的文章了。每天看的几乎都是英文的计算机技术文章。哎,其实就是好久没有给自己的心灵放个假了。

自打上高中起,就一直很喜欢《读者》这个杂志,里面的有很多好文章,甚至现在也偶尔会被里面的一两篇文章所感动,也还会感叹:“这个世界上还是好人多啊!”里面歌颂的真善美谁不向往呢。可以这么说,《读者》对我来说是心灵的旅行,精神的放松。

闲来无事时,沏上一杯清茶,手捧《读者》翻阅,真是一种享受!

一个shell技巧

有时可能要碰到分解$PATH,那就得想法处理它的“:”分隔符。

首先想到的应该是用gawk,如下:

$ echo $PATH | gawk -F: -v OFS=”n” -v num=0 ‘{NF-=num; $1=$1; print}’

恩,这样其实挺麻烦的。有没有更好的技巧呢?当然有,看下面这个:

$ OLDIFS=$IFS; IFS=: ; printf “%sn” $PATH; IFS=$OLDIFS;

这个技巧在ksh下还可以这样用:

$ IFS=”:”; set -A array $PATH; for eachone in ${array[*]}; do echo $eachone; done

《新上海滩》

回家两天除了串串门就是憋在家里看电视了。

发现N个台都在放《新上海滩》,也就随着看看。一看发现还不错,结果一天看了8集,一共42集看到了第21集,上瘾呐~~说实话,很喜欢这个国语版的新主题曲。

浪奔浪流
万里江海点点星光耀
人间事多纷扰
化作滚滚东逝波涛

有泪有笑
浪里浮沉着悲喜煎熬
鸿飞泥沼
转眼间谁人能记牢

爱你恨你
有谁知晓
情似水无处可逃

走千山绕千道
直到天上万里云霄

人生路路迢迢
谁道自古英雄多寂寥
若一朝看透了
一生清风争多少

这首歌的MTV在这里:http://www.tudou.com/programs/view/pdNFaDeRZk8/

新版的许文强和冯程程是黄晓明和孙俪演的:

再对比一下老版的《上海滩》,发哥和赵雅芝~下面还有搜集的老上海滩中许文强和冯程程在一起的片段,还配着老版主题曲~~伤感哪~~

http://www.tudou.com/programs/view/zWGTjqPFq9Y/

回家几天

恩,现在工作的事也不用愁了,期末还没到,学习也不是很紧张,再加上暑假没有回家,于是决定这个周末回家一趟,待两三天再回来。

下午5:30的火车,明天一早就能到了!就能见到爸妈了,也能住进刚搬的新楼了。;-)

这三天的邮件肯定就不能回复了,不管您有什么事情,等下周二我回来了再说吧!

八皇后问题的非递归解法

用C++实现了八皇后问题的非递归算法。原理很简单,看代码就是了,无须多说。

BTW: C++的algorithm就是好用啊!

include

include

include

include

using namespace std;
const int MAX = 8;

vector board(MAX);

void show_result()
{
for(size_t i = 0; i < board.size(); i++)
cout<<"("<<i<<","<<board[i]<<")";
cout<<endl;
}

int check_cross()
{
for(size_t i = 0; i < board.size()-1; i++)
{
for(size_t j = i+1; j < board.size(); j++)
{
if((j-i) == (size_t)abs(board[i]-board[j]))
return 1;
}
}
return 0;
}

void put_chess()
{
while(next_permutation(board.begin(), board.end()))
{
if(!check_cross())
{
show_result();
}
}
}

int main()
{
for(size_t i =0; i < board.size(); i++)
board[i] = i;
put_chess();
return 0;
}

谈谈版权

虽然我是一个自由软件的支持者,但说来惭愧,一直以来我对版权这问题关注比较少。因为我更关心的是自由软件可以自由获取/修改源代码这一面。

但最近听说的一些事情,使我不能不再关注这个问题了。一件事就是美国的“P2P的圣女贞德”事件,另一件是我们老师上课提到的,说学校曾因使用盗版VB而接到警方的“通知”。

这两件事使我对这个问题有了更深刻的认识,版权问题就实实在在地在我们身边,如果我们再不关心这个问题,下一个被起诉的,或者接到警方“通知”的可能就是我们自己!

在版权方面,我绝对站在Richard Stallman这边。他写的两篇文章对我触动很大,一是《为什么软件不应该有所有者?》,里面讨论了专有软件版权的不合理性,限制软件自由的危害——不利于良好的社会风气,不利于社会的自由。这也是为什么他一贯主张“自由的软件,自由的社会”。另一篇是《科学必须摒弃版权》,里面的最后一句话至今记忆犹新:

“版权的存在是‘为了推动科学的进步’。当版权阻碍科学进步时,科学必须摒弃版权。”
这句话再正确不过了。任何阻碍科学发展的东西我们都应该摒弃它。Richard Stallman发起浩浩荡荡的自由软件运动的本意也正在于此!(所以我更愿意把Richard Stallman看作是一个哲学家,一个圣人。;-)

记得美国的一个博客作家曾说过这么一句话:

“比特天生就是用来拷贝的,它们永远不会变得难以复制。”
我非常欣赏。把上面的话换一句说就是,错误不在那些拷贝比特的人,而在那些想方设法阻止你拷贝的人!现存的版权制度有很多不合理的地方,它已经远离了最初作为“保护作者权益”的目的,沦落成了某些组织借此打压弱者的工具!我从来不反对保护软件作者的权力,但是,一个显而易见的事实是,没有了版权的约束作者利益并不会受到侵犯,反而倒有可能对作者更有利。软件方面最好的例子莫过于Linus,假设当年他并没有公开Linux源代码,他还会像今天这么有名吗?显然不能!也就是说,Linus放弃了用版权法限制他的作品反而倒让他获得更大的成功。其它方面,Magnatune就是一个很好的例子,把自己的作品“开源”并没有让这些艺术家吃不上饭,反而找到了更多的知音。

技术,能够给我们提供自由,也能剥夺我们的自由。关键在于你是怎么选择。我所能做的,就是用自己的技术来为更多人提供自由,自由的软件,自由的社会。

引用Zoom Quiet模仿马丁·尼莫拉名言的话作为结束:

在中国,起初他们忽视Unix用户,我没有说话——因为我不是Unix用户;
接着他们忽略GNU/Linux用户,我没有说话——因为我不是GNU/Linux用户;
后来他们封杀Mac用户,我没有说话——因为我不是Mac用户;
此后他们追杀D版XP用户,我没有说话,因为我不是D版XP用户;
最后他们奔我而来,不交钱,不使用捆绑广告的专用软件就不准开户使用任何在线银行业务,却再也没有人站出来为我说话了!

TCP Closure

今天在看TCP的释放时遇到几个问题,查了一下《TCP/IP详解 卷一》和RFC793,也请教了一下Herbert Xu,基本上都解决了。在这里总结一下。

TCP的释放过程如下图所示(取自《TCP/IP详解 卷一》):

问题1:既然TCP的CLOSE是单工的,那么,一方在收到FIN的ACK之后可能会过很长一段时间才收到对方的FIN。那么如果这个时间里这方已经关闭该进程,谁又来ACK对方的FIN呢?

Herbert解释到:

For you particular scenario, the key is that the TCP socket is
maintained by the OS, not the process.

So even after your process has called close(2) and exited, the
OS will continue to respond in ways required by RFC793 until
such a time when the socket has been CLOSEed in the sense of the
protocol.
问题2:两方同时发送FIN又如何呢?

没想到这个问题连RFC里都有,里面这样解释:

A simultaneous CLOSE by users at both ends of a connection causes
FIN segments to be exchanged. When all segments preceding the FINs
have been processed and acknowledged, each TCP can ACK the FIN it
has received. Both will, upon receiving these ACKs, delete the
connection.
也就是像下图所示(也是取自TCP/IP详解):

问题3:关于MSL。

MSL是maximum segment lifetime的缩写。TCP状态机里有个TIME_WAIT状态,设置它是为了防止最后一个ACK丢失,这个时间一般就是2MSL。而且,在这个2MSL的时间中,这个socket是不能被重用的,除非我们setsockopt(…,SO_REUSEADDR,…)。

shebang

在Unix中,shebang其实就是指“#!”,它取自#(SHArp)和!(bang)。

它是很多脚本文件中第一行的前两个字符,用来告诉Unix系统要用shebang后面指定的解释器
来解释该脚本。所以,在很多脚本中,第一行往往都是这么写的:

! /abs/path/to/interpreter

根据wikipedia上的解释),shebang最初由
Dennis Ritchie引入的,时间大概是在Version 7和Version 8之间。也正是因为shebang是以#
开头,所以很多Unix上的脚本都是用#作为注释的开始。常见的有:

!/bin/sh

!/usr/bin/perl -w

!/bin/awk -f

!/usr/bin/env python

!/usr/bin/ruby

shebang没有你想象得这么简单。首先,它后面的解释器路径一般来说必须是绝对路径。(当然了,
有人也说像#!python这样的也能执行。)如果不是,可能就会出现类似的错误:


bash: ./foo.py: python: bad interpreter: No such file or directory

因为shell会直接用execve去执行这个文件,出错马上就退出。而execve会通过shebang辨认出这个一
个脚本文件,然后尝试用后面的解释器去执行,但它并没有在PATH中寻找解释器,而是完全依靠
你给出的路径。如果你不想指定绝对路径或者出于可移植的原因不好指定,那么你应该试试用env(1)
,就上面的python的shebang一样,它会帮你在PATH中搜索。python之所以更倾向于这个还有个原因,
就是env一般固定在/usr/bin目录下,而python的安装位置就相对不那么固定。

用env时你应该注意这么一个事实:传递给解释器的argv和你想象得并不一样。下面这个就是不对的:

!/usr/bin/env perl -w

shell会提示:/usr/bin/env: perl -w: No such file or directory
错误的根源就是perl -w被当成了整体传递给env。

用下面的程序来看一下参数传递过程:


/test.c/

include <stdio.h>

int main(int argc, char** argv) {
int i;
for (i=0; i<argc; i++)
fprintf(stdout, “argv[%d]: “%s”n”, i, argv[i]);
return 0;
}
然后把编译出的test当作解释器:


$ cat invoker.sh

!/home/wangcong/test -1 -2 -3

结果如下:


$ ./invoker.sh a b c
argv[0]: “/home/wangcong/test”
argv[1]: “-1 -2 -3”
argv[2]: “./invoker.sh”
argv[3]: “a”
argv[4]: “b”
argv[5]: “c”

当然了,并不是所有的Unix都是这样,但最起码Linux上的bash和zsh上就是如此。所以,要编写可移植
的脚本,你应该当心这一点!

RSS的问题

因为这个博客自带的rss出了点问题,使用这个网址订阅的看客会收不到更新。原因我不清楚,毕竟我对php一窍不通。;(

鉴于此,我在feedsky上注册了一个。使用rss订阅本博客的可以换用下面这个地址来更新。

http://feed.feedsky.com/wangcong

Sigh, feedburner is blocked by something…

强符号,弱符号

对于链接器来说,所有的全局符号可分为两种:强符号(Strong symbols),弱符号(Weak symbols)。gcc的attribute中有个attribute((weak)),就是用来声明这个符号是弱符号的。gcc手册中这样写道:

The weak attribute causes the declaration to be emitted as a weak symbol rather than a global. This is primarily useful in defining library functions which can be overridden in user code, though it can also be used with non-function declarations. Weak symbols are supported for ELF targets, and also for a.out targets when using the GNU assembler and linker.
对于这个gcc扩展,这里作了一个简洁的介绍。我们来看更通用的情况。;)

一般来说,函数和已初始化的变量是强符号,而未初始化的变量是弱符号。对于它们,下列三条规则适用:

1. 同名的强符号只能有一个。
2. 有一个强符号和多个同名的弱符号是可以的,但定义会选择强符号的。
3. 有多个弱符号时,链接器可以选择其中任意一个。

这三条规则看起来很好理解,其实不然,尤其是当这些弱符号类型和强符号不同时!表面上看起来正确的程序会导致严重的错误!考虑下面这个csapp中的例子:

===a.c===
int x=7;
int y=5;
p1() {}

===b.c===
double x;
p2() {}

我们把它们一起编译,并且在p2()函数中给x赋值,你会发现,y也改变了! 虽然x被看作是double,但其定义会取a.c中的int x,也就是说,在b.c中会把a.c中的int x当double来用!这当然是错误!之所以会这样,就是因为上面的规则2。避免这种错误的一个方法是,给gcc加上-fno-common选项。

关于弱符号,man手册中这样解释到:

When a weak defined symbol is linked with a normal defined symbol, the normal defined symbol is used with no error. When a weak undefined symbol is linked and the symbol is not defined, the value of the weak symbol becomes zero with no error.
因此,我们也可以看出:强弱符号和声明没任何关系。弱符号不会有static的storage duration。同名的多个弱符号的定义不应该出现在同一个翻译单元中,如果出现,链接器会选择第一个。