2008年12月30日星期二

听人大教授周孝正讲以色列的故事

http://club.cat898.com/newbbs/dispbbs.asp?boardid=1&id=2618863

讲述:周孝正 整理:一点五

同学们,今天我准备调整一下原有的课程,就当前以色列和巴勒斯坦冲突谈谈个人看法,我的第一个观点是,在信息不对称的情况下,不要轻易下自己的结论;第二,我个人的知识和经历告诉我,以色列是个好国家,这也是我今天讲课的主要内容。

有一次我在校内网看同学们发的图片,有一张图片引起了我的深思。这张图片的标题叫“英雄”,图片上是一个赤手空拳的巴勒斯坦青年,站在长长一列以色列坦克面前,硬是把这列坦克给拦停了。

同 学们,这个巴勒斯坦青年确实是“英雄”,敢以血肉这躯和全幅武装的坦克抗衡,但是同学们想过没有,在处于“敌对”的情况下,有几个国家的坦克会停下来?当 年日本侵略中国的坦克不会停,侵入格鲁吉亚的俄罗斯坦克不会停,但以色列的坦克停下来了,这样的士兵、这样的国度,我个人认为,才是真正的英雄,当之无愧 的英雄。

有一年我到福建做个调查,福建省政府的高官,给我讲了这么一个故事:

几年前,耶路撒路发生了一起公交车爆炸的恐怖袭击,炸死了十来个人,其中包括两名中国人,这两名中国人都是福建人,是去打工的。以色列政府立刻与中国方面联系协商赔偿事宜,但经过中国领事馆的核实,此两人系偷渡客,属于非法入境,于是使馆方面不再配合。

后来,以色列政府专门开了一个会,会议认为,在以色列国土上无辜死亡的人,政府都有责任对其负责,至于这个人偷渡与否,那是另外一回事。会议最后决定,对两名死难的中国人一视同仁地按照国民待遇善后。

  会后,以色列政府派专人到福建找到两位农民工的家人,抚恤金标准如下:

死 者健在的父母按照每月1100美金的标准发放直到老人去世;未成年子女按每月1100美金的标准发放直到成年;有妻子的按照每月1700元美金发放直到去 世。死者家属要求一次性支付,以色列政府也同意了,最后支付的金额是每位死者赔偿70万美金。所有相关的调查费用全部由以色列政府负担。

消息传开,在福建掀起了去以色列打工的狂潮。福建省政府的官员说,怎么挡也挡不住。以色列政府就是这样对待偷渡打工者的:没发现,你就在那儿打工;发现了,政府出钱购买机票送你回国;死了,按照以色列国民标准抚恤。

2001年,云南丽江发生了以色列游客不慎在虎跳峡落水的事故,经中国方面寻找无果,为此,以色列政府派专机来丽江,带着专业的搜救设备和一个专业搜救队,并高薪雇佣中国人沿江几百里进行拉网似的搜索,活要见人,死要见尸,时间持续一个多月。

同学们,一个这样对待它国和自己死去国民的国家,不管你怎么说,我都坚信,这是个好国家。

任何一个稍微了解以色列的人,至少不会对以色列产生恶感。中国人喜欢把自己的近代史说成是“多灾多难”,那其中有很多是我们自己的原因,犹太人却几乎完全因为外因,几千年来一直灾难深重,这一切,仅仅因为信仰。

这个苦难的民族,在多年的战乱动荡中,在长期的漂泊迁徙中,在饥饿和苦难、杀戮和欺侮的磨难中,他们始终坚持自己的信仰,在逆境中砥砺发奋,顽强发展,不仅没有倒下,竟奇迹般地在科技、军事、教育、现代农业等领域获得举世瞩目的巨大成就。

这个仅有1000多万人口的民族,涌现出了一大批伟大人物:爱因斯坦、弗洛伊德、海涅、拉斐尔、季诺维耶夫、卓别林、洛克菲勒、索罗斯……,这个民族和这些伟人为世界文明做出了杰出贡献。

一 般人只知道犹太民族善于经商,殊不知犹太民族特别重视教育,他们把学习作为终生的使命,重智慧胜于重金钱。有一项调查显示,全世界人均读书最多的藏书最多 的都是以色列人。犹太民族还特别重视儿童教育,他们在儿童教育方面研发的教具、教材、课程模式等被许多国家所采用。一个国家越相信自己的未来,越会重视自 己的儿童教育。一个建国以来一直战火不断、四面楚歌的国家,如此重视教育,如此重视儿童教育,这样的国度值得我们每一个人景仰。

2008年12月24日星期三

JMS CreateSession参数

createSession(paramA,paramB);
paramA是设置事务的,paramB设置acknowledgment mode
paramA设置为false时:paramB的值可为Session.AUTO_ACKNOWLEDGE,Session.CLIENT_ACKNOWLEDGE,DUPS_OK_ACKNOWLEDGE其中一个。
paramA设置为true时:paramB的值忽略, acknowledgment mode被jms服务器设置为SESSION_TRANSACTED 。
Session.AUTO_ACKNOWLEDGE为自动确认,客户端发送和接收消息不需要做额外的工作。
Session.CLIENT_ACKNOWLEDGE为客户端确认。客户端接收到消息后,必须调用javax.jms.Message的acknowledge方法。jms服务器才会删除消息。
DUPS_OK_ACKNOWLEDGE允许副本的确认模式。一旦接收方应用程序的方法调用从处理消息处返回,会话对象就会确认消息的接收;而且允许重复确认。在需要考虑资源使用时,这种模式非常有效。

2008年12月15日星期一

APR server侦听

static apr_status_t do_listen(apr_socket_t **sock, apr_pool_t *mp)
{
apr_status_t rv;
apr_socket_t *s;
apr_sockaddr_t *sa;

rv = apr_sockaddr_info_get(&sa, NULL, APR_INET6, DEF_LISTEN_PORT, 0, mp);
//取得Socket地址
if (rv != APR_SUCCESS) {
return rv;
}

rv = apr_socket_create(&s, sa->family, SOCK_STREAM, APR_PROTO_TCP, mp);
//建立Socket对象
if (rv != APR_SUCCESS) {
return rv;
}

/* it is a good idea to specify socket options explicitly.
* in this case, we make a blocking socket as the listening socket */
//设置属性
apr_socket_opt_set(s, APR_SO_NONBLOCK, 0);
apr_socket_timeout_set(s, -1);
apr_socket_opt_set(s, APR_SO_REUSEADDR, 1);/* this is useful for a server(socket listening) process */
//将Socekt地址绑定到Socket对象
rv = apr_socket_bind(s, sa);
if (rv != APR_SUCCESS) {
return rv;
}
//建立侦听
rv = apr_socket_listen(s, DEF_SOCKET_BACKLOG);
if (rv != APR_SUCCESS) {
return rv;
}

*sock = s;
return rv;
}

中国最坏的六种人

1,民主的敌人,比如形形色色的专权者。因为,专制或者说缺少民主,是中国一切政治经济社会弊端的总根源。

2,愚昧的国民,比如形形色色的左粪(或者说得直接一点,范围小一点,就是文革余孽。)因为,愚昧的左粪是滋生中国专制政治的一大温床和思想文化基础。

3,贪污腐败的官员,包括企事业单位各类干部和专业技术人员(他们手中握有的也是一种权力资源)。因为,贪污腐败是是中国一切政治经济社会弊端及其他一切不公平现象的集中体现和直接原因,也是中国专制政治的必然结果。

4,猖狂致富的不法奸商。但是他们总体上还得仰仗贪官污吏。

5,学术虚伪、学术愚民、没有良知、为虎作伥的知识分子。他们在思想本质上或经济政治利益上与贪官、奸商沆瀣一气,分一杯羹。

6,黑社会、偷扒抢骗等刑事犯罪分子。但是他们中相当一部分只是社会腐败和社会不公的派生物。

最后,要说一句的是,中国的老百姓,我们的父老乡亲,还是好人多,尽管他们也是凡夫俗子,在这个世俗的社会,免不了有这样或那样的缺点。总之,世上好人多,中国也不例外,这是我,作为一个中国人的起码的信念。

有点韩非--《五蠹》的意思

2008年12月4日星期四

13.1 server side programming(急用,先写)

A typical server process opens a listen port, and listen to the port for any client process to connect. Then, it accepts the client's connection, and communicate with the client using their network protocol. Although the network protocol depends on your application, the basic structure of server code is almost same.
典型的服务器进程是打开一个端口,然后为客户端连接侦听它。这样我们就可以接受客户端连接,和客户端进行各种网络协议的通信。尽管客户端应用各种网络协议,但最基本的服务器代码还是差不多的。

At first, we have to create a socket address object, apr_sockaddr_t. In traditional socket programming, socket address structure would cause confusion. In contrast, libapr's socket address structure is simple. It can hide chaos among various platforms and IPv4/IPv6 stacks. We can create the object by apr_sockaddr_info_get(). The prototype declaration is as follows:
首先,我们必须要创建一个socket地址对象,apr_sockaddr_t。socekt地址结构常常导致传统项目混乱,相比之下libapr的socket地址显得简单多了。它能隐藏不同平台,IPv4/IPv6之间细节的处理。我们能用 apr_sockaddr_info_get()创建一个对象,典型的用法如下:

/* excerpted from apr_network_io.h */

APR_DECLARE(apr_status_t) apr_sockaddr_info_get(apr_sockaddr_t **sa,
const char *hostname,
apr_int32_t family,
apr_port_t port,
apr_int32_t flags,
apr_pool_t *p);
The first argument is result argument. The second argument is a hostname, or an IP address. I'll describe it later. The third argument is address family. It is usually APR_INET. If you intend to use IPv6, please specify APR_INET6. The fourth argument is a port number. Server side program should specify the port number to listen. For example, if you're creating a Web server, you might have to specify number 80. As you will see, client side program specifies the port number of the remote server. So, if you're creating a Web browser, you might have to specify number 80, too. Note that you can set the port number to zero. If so, the system selects a port number, which is available. The fifth argument is flags. In most cases, it is 0. The final argument is memory pool to use.

第一个参数是返回结果;第二个参数是主机地址,或者是IP地址,在后面将详细说明。第三个参数是个地址家族,它常常是APR_INET。如果你使用IPv6,请使用APR_INET6;第四个参数是端口号码,服务器端是侦听端口号。例如,你创建一个Web服务器,应该使用端口80,因为Web浏览器默认使用端口80。注意你也可以使用端口0,这样的话,系统将自动分配一个可用的端口号;第五个参数是个标记,在大多数情况写0;最后一个参数是正在使用的内存池。

We are back to the second argument. As you will see in client side programming below, client program generally specifies the server(remote) hostname or IP address. In contrast, server program should specifies its local address, and it binds the socket address object to a socket by apr_socket_bind().

我们再回到第二个参数。在后面你将看到客户端程序怎么使用远程服务器主机名或者IP地址。这里,服务器端应该通过 apr_socket_bind()去指定socket地址对象。

What value is allowed as a local address? One choice is a solid address or hostname. Namely, if you are creating a yahoo server, you can specify "www.yahoo.com" or "66.94.230.38". In general, such values are supplied by configuration files. Second choice is loopback address, i.e. "127.0.0.1" or "localhost". It works and it's valid. However, in such a case, only a client process running on the same host can connect to the server. If your purpose is to allow only local processes to connect to your server, specifying loopback address is a right choice.
局部地址应该选取个什么样的值呢?第一个办法是固定IP地址,或者服务器名,例如创建一个yahoo服务器,可以选择“www.yahoo.com”或者"66.94.230.38"。在一般情况下,这样的值需要通过配置文件完成。第二个办法是使用有效的Loopback地址"127.0.0.1" or "localhost"(回环地址,这个名词特别扭),这样的话,只有运行在服务器上的程序才能连接到服务器。如果服务器程序的想法就是只让本机访问的话,这样做无可厚非。

The other choice is to specify NULL or APR_ANYADDR(="0.0.0.0"). They imply that the server will bind all network interfaces to a socket. Accordingly, in such a case, any client process can connect to the server via a solid address or loopback address. Internally, NULL is better than APR_ANYADDR. As a result, it's usually good to specify NULL as the second argument of apr_sockaddr_info_get(). There is one exception. When the server host is multihome host, i.e. it has multiple solid IP addresses, and you don't want some IP addresses available from remote hosts, you shouldn't specify NULL. You must bind solid IP addresses to the listening socket.

另外一个办法就是使用NULL或者APR_ANYADDR(="0.0.0.0")。它能让服务器绑定网络接口到socket。相应的,这种情况下,任何客户端都能访问服务器物理地址或者Loopback 地址。通常NULL比APR_ANYADDR要方便。我们常常使用NULL作为apr_sockaddr_info_get()的第二个参数。但是这里有个例外,当服务器是多IP的机器,我们又需要屏蔽其中一些IP段地址,我们只能绑定侦听的绑定的物理地址。

Next, we create a socket object, apr_socket_t. In traditional socket progamming, socket type is just integer, and it acts as a file descriptor. apr_socket_t is opaque type and it hides such the OS dependencies. We can create socket object by apr_socket_create(). The prototype declaration is as follows:

下面,创建一个socket对象,apr_socket_t。在传统项目中,socket类型是一个整形,或者像一个文件描述符。这里apr_socket_t是一个不透明的类型,并且隐藏了操作系统的属性。我们可以通过apr_socket_create()创建Socket对象,属性定义如下:
/* excerpted from apr_network_io.h */

APR_DECLARE(apr_status_t) apr_socket_create(apr_socket_t **new_sock,
int family, int type,
int protocol,
apr_pool_t *cont);


The first argument is result argument. The second argument is address family. It is same as one of apr_sockaddr_info_get()'s third argument. Later, we make a relation between socket address object and socket object. In which, if they have different address family, it fails. The third and fourth arguments are socket type and protocol type. In general, all you have to know is two combinations. One is SOCK_STREAM as type and APR_PROTO_TCP as protocol. The other is SOCK_DGRAM as type and APR_PROTO_UDP as protocol. The final argument is memory pool to use.
第一个参数是结果返回参数;第二个参数是地址家族,它和 apr_sockaddr_info_get()第三个参数作用相同,之后我们将建立Socket地址对象和Socket对象之间的关系。他们必须有相同的地址家族。第三个和第四个参数是Socket类型和通信协议类型。总之,开发者必须知道这两个类型。一通常,一个是SOCK_STREAM,另外一个是APR_PROTO_UDP。最后个参数是使用的内存池。

Now, let's take a look at server-sample.c. The following is a typical code of server side to create a TCP listening socket.
让我们看看 server-sample.c 。下面是服务器端建立TCP侦听的典型代码:
/* excerpted from server-sample.c, but I omitted error checks */

apr_sockaddr_t *sa;
apr_socket_t *s;

apr_sockaddr_info_get(&sa, NULL, APR_INET, DEF_LISTEN_PORT, 0, mp);
apr_socket_create(&s, sa->family, SOCK_STREAM, mp);
apr_socket_bind(s, sa);
apr_socket_listen(s, DEF_SOCKET_BACKLOG);

There are two application dependent constant numbers, DEF_LISTEN_PORT and DEF_SOCKET_BACKLOG. Don't care about them.
两个常量DEF_LISTEN_PORT 和DEF_SOCKET_BACKLOG,不用管他们。

You can find two new APIs, apr_socket_bind() and apr_socket_listen(). By calling apr_socket_bind(), we can make a relation between socket address object(apr_sockaddr_t) and socket object(apr_socket_t). We call it binding the address to the socket. Then, by calling apr_socket_listen(), we change the socket's status to listening. It means we allow the socket to accept connections from remote clients. The second argument of apr_socket_listen() is length of the internal queue. The queue is a waiting queue of remote clients. They wait in the queue in (OS)kernel until the application accepts them. The length is historically called backlog. If you are not sure about proper value, I suggest you to use 'SOMAXCONN', which is a system default max value.
介绍apr_socket_bind() 和 apr_socket_listen()这两个函数,apr_socket_bind() 这个函数负责建立Socket地址对象和Socket对象之间的关系。apr_socket_listen()改变Socket的状态,使得Socket可以处理远程客户端连接请求。apr_socket_listen()的第二个参数是远程客户端请求的队列长度,这个队列由操作系统维护,直到应用程序处理他们。这个长度代表了能够积压的最大限度。如果程序没有特别要求,建议使用SOMAXCONN,它表示才做系统默认的最大值。

Next, we have to handle new connections from remote clients. At first, we have to call apr_socket_accept().
接着我们将处理远程客户端的请求。首先,使用apr_socket_accept()这个函数。

/* excerpted from server-sample.c, but I omit error checks */

apr_socket_t *ns;/* accepted socket */
apr_socket_accept(&ns, s, mp);

The second argument of apr_socket_accept() is the listening socket that we create above. Here, we get another socket object, named 'ns', accepted socket. From socket object creation's perspective, apr_socket_accept() is similar to apr_socket_create(). Namely, apr_socket_accept() also creates a new socket object. The first argument is result argument. Note that the newly created socket object is completely different from the listening socket object, which is passed as second argument to apr_socket_accept(). After returing from apr_socket_accept(), the listening socket is still just listening socket. It means we can continue to call apr_socket_accept(), and when the other remote client connects to the server, we're going to have a yet another socket object from apr_socket_accept(). After apr_socket_accept(), we have to handle two sockets independently. In general, we have the listening socket keep listening, and we have the accepted socket talk network protocol with the remote client. In server-sample.c, we send a simple HTTP request and receive the response.

apr_socket_accept() 第二个参数是我们之前创建的侦听Socket。apr_socket_accept()和 apr_socket_create()相似,第一个参数也是返回结果,创建了新的Socket对象。值得注意的是这个新的Socket和apr_socket_accept() 第二个参数是两个完全不同的Socket对象。apr_socket_accept() 第二个参数仅仅是个侦听Socket,需要继续去侦听新的客户端请求。而新的Socket对象将和已经相应的请求进行通话,他处理请求和发回响应。

To send and receive using socket, we call apr_socket_send() and apr_socket_recv(). Their prototype declarations are as follows:
接受请求和发回响应,需要apr_socket_send() and apr_socket_recv()这两个函数,他们的声明如下:
/* excerpted from apr_network_io.h */

APR_DECLARE(apr_status_t) apr_socket_send(apr_socket_t *sock, const char *buf,
apr_size_t *len);
APR_DECLARE(apr_status_t) apr_socket_recv(apr_socket_t *sock,
char *buf, apr_size_t *len);


They are similar to apr_file_read() and apr_file_write() described above. The first and second argumnts are needless to explain. The third argument of both is value-result argument. By which, we specify the input buffer's length on entry and get the output result's length on exit. apr_socket_send() returns the length of sent bytes. apr_socket_recv() returns the length of received bytes.
这两个函数和之前的 apr_file_read(), apr_file_write() 两个函数相似,第一和第二个参数不需要解释了,第三个参数同时是输入和返回结果。 先指定Socket对象,缓冲,缓冲长度,然后得到结果长度。apr_socket_send()返回的是发送字节数。apr_socket_recv()得到的是接受字节数。

2. libapr skeleton code

I believe it is a good idea to write 'skeleton code' at first, when you start to learn a new library or a new framework programming. 'skeleton code' is the smallest source code, but you can compile and execute it (although it usually do nothing useful).

当我们学新的LIB或者框架时,龙骨代码是个不错的点子,这玩意包含了代码的最小单元,但是却不做任何事情。

Fortunately, libapr's skeleton code is much simpler than other modern frameworks. Let's take a look at apr-skeleton.c. We call apr_initialize() at the initialization, and call apr_terminate() at the finalization. That's all. As you can imagine, the code does nothing.

运气不错,APR的龙骨代码比起其他框架非常精炼,打开apr-skeleton.c,

int main(int argc, const char *argv[])
{
apr_status_t rv;

/* per-process initialization */
rv = apr_initialize();
if (rv != APR_SUCCESS) {
assert(0);
return -1;
}

/* application impl. */

apr_terminate();
return 0;
}


调用apr_initialize()进行初始化,调用apr_terminate()完成,就这些,也正如你所想,这段代码什么也没做。

Here, we have some libapr programming styles and rules:

* naming rule is very simple and clear.
* opaque data types are commonly used (a.k.a. incomplete types)
* most of return types are apr_status_t. As a result, result-arguments are commonly used.
* memory pool rules

我们给出一些libapr编程的风格和规则:
* 命名规则非常简单和清楚。
* 不透明类型被广泛地使用。(又名不完整类型)
* 返回结果或是结果输出参数大多数返回类型为apr_status_t。
* 内存池规则。

We are able to see these styles in the following code.

/* excerpted from mp-sample.c */

apr_status_t rv;
apr_pool_t *mp;
rv = apr_pool_create(&mp, NULL);

I will describe the meaning of the code. Here, please take a look at only style. You can see apr_ prefix. The apr_ prefix indicates that the symbol is in libapr naming scope. You can see _t suffix. It indicates that the symbol is a type name.

我们经常能看见以下这种代码:
/* excerpted from mp-sample.c */

apr_status_t rv;
apr_pool_t *mp;
rv = apr_pool_create(&mp, NULL);
apr_为前缀表示是LIBAPR的代码,_t表示是一种抽象类型,多数都是结构体。

apr_pool_t is opaque type. It means the type's structure is not public. By OO(Object Oriented) terminology, all member variables are private. You can't touch them directly. Furthermore, you can't see them in public header files. All you can do for the type is to call APIs such as apr_foo_bar() functions. Most importantly, you can't allocate their instance memories directly. All you can do is to call construct APIs. Only libapr knows how to construct and destruct the objects.
apr_pool_t是一个分装的类,这意味着类型的结构体不是公开的,根据OO(面向对象)的思维,所有成员变量都是私有的。我们不能直接操作他们,此外,我们也没必要去关心公共头文件。例如我们会用到名字像apr_foo_bar()这样的函数,要注意的是,我们并不需要关心怎么去给他们分配内存,当我们需要调用这些API的时候,libapr知道怎么去构造和销毁他们。

As you see, apr_pool_create()'s return type is apr_status_t. apr_status_t is either status code or error code. apr_status_t is a commonly used as return types of most APIs. Accordingly, we can get results from functions by arguments. Such arguments are called result-argument. There are many result-arguments in the libapr world.
正如你所见,apr_pool_create()返回类型是 apr_status_t, apr_status_t是一种状态码和错误码。 apr_status_t是最常用的返回类型。相应的,我们能通过各种参数调用函数来得到各种类型的结果。当然,libapr也使用了相当多的返回参数。

In general, if you see apr_foo_t type, you will see apr_foo_bar() functions, which are related to apr_foo_t type. The following code is a typical pseudo code.

/* pseudo code of libapr. error checks omitted */
apr_status_t rv;
apr_foo_t *foo;
rv = apr_foo_create(&foo, args...);/* create a @foo object by @args */
rv = apr_foo_do_something(foo, args...); /* do something with @foo */
apr_foo_destroy(foo);

一般情况下,如果看见apr_foo_t类型,一般会有apr_foo_bar()方法,他使用到apr_foo_t类型,如这种很典型的代码。

1. Tutorial Availability

Please look for updates on http://dev.ariel-networks.com/apr/.

转载出自

http://dev.ariel-networks.com/apr/


该系列均是出自这里,后面的内容不再特殊说明