海阔天空

I'm on my way!
随笔 - 17, 文章 - 69, 评论 - 21, 引用 - 0
数据加载中……

2009年7月27日

经典的Linux Socket 编程 示例代码 (下)


摘自:http://fanqiang.chinaunix.net/a4/b7/20010810/1200001101.html


在例程main()函数快要结束时,我们看到,在服务器接受了客户机的连接请求后,将为其创建子进程,并在子进程中执行代理服务程序do_proxy()。
-----------------------------------------------------------------/****************************************************************
function:    do_proxy
description:  does the actual work of virtually connecting a client to the telnet service on the          isolated host.
arguments:   usersockfd socket to which the client is connected. return value: none.
calls:     none.
globals:     reads hostaddr.
****************************************************************/
void do_proxy (usersockfd)
int usersockfd;
{
int isosockfd;
fd_set rdfdset;
int connstat;
int iolen;
char buf[2048];
/* open a socket to connect to the isolated host */
if ((isosockfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
errorout("failed to create socket to host");
/* attempt a connection */
connstat = connect(isosockfd,(struct sockaddr *) &hostaddr, sizeof(hostaddr));
switch (connstat) {
case 0:
break;
case ETIMEDOUT:
case ECONNREFUSED:
case ENETUNREACH:
strcpy(buf,sys_myerrlist[errno]);
strcat(buf,"\r\n");
write(usersockfd,buf,strlen(buf));
close(usersockfd);
exit(1);
/* die peacefully if we can't establish a connection */
break;
default:
errorout("failed to connect to host");
}
/* now we're connected, serve fall into the data echo loop */
while (1) {
/* Select for readability on either of our two sockets */
FD_ZERO(&rdfdset);
FD_SET(usersockfd,&rdfdset);
FD_SET(isosockfd,&rdfdset);
if (select(FD_SETSIZE,&rdfdset,NULL,NULL,NULL) < 0)
errorout("select failed");
/* is the client sending data? */
if (FD_ISSET(usersockfd,&rdfdset)) {
if ((iolen = read(usersockfd,buf,sizeof(buf))) <= 0)
break; /* zero length means the client disconnected */
rite(isosockfd,buf,iolen);
/* copy to host -- blocking semantics */
}
/* is the host sending data? */
if (FD_ISSET(isosockfd,&rdfdset)) {
f ((iolen = read(isosockfd,buf,sizeof(buf))) <= 0)
break; /* zero length means the host disconnected */
rite(usersockfd,buf,iolen);
/* copy to client -- blocking semantics */
}
}
/* we're done with the sockets */
close(isosockfd);
lose(usersockfd);
}
-----------------------------------------------------------------
在 我们这段代理服务器例程中,真正连接用户主机和远端主机的一段操作,就是由这个do_proxy()函数来完成的。回想一下我们一开始对这段 proxy程序用法的介绍。先将我们的proxy与远端主机绑定,然后用户通过proxy的绑定端口与远端主机建立连接。而在main()函数中,我们的 proxy由一段服务器程序与用户主机建立了连接,而在这个do_proxy()函数中,proxy将与远端主机的相应服务端口(由用户在命令行参数中指 定)建立连接,并负责传递用户主机和远端主机之间交换的数据。
由于要和远端主机建立连接,所以我们看到do_proxy()函数的前半部分实际上相当于一段标准的客户机程序。首先创建一个新的套接字描述符 isosockfd,然后调用函数connect()与远端主机之间建立连接。函数connect()的定义为:
-----------------------------------------------------------------
#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, struct sockaddr *servaddr, int addrlen);
-----------------------------------------------------------------
参数sockfd是调用函数socket()返回的套接字描述符,参数servaddr指向远程服务器的套接字地址结构,参数addrlen指定这个 套接字地址结构的长度。函数connect()执行成功时返回"0",如果执行失败则返回"-1",并将全局变量errno设置为相应的错误类型。在例程 中的switch()函数调用中对以下三种出错类型进行了处理: ETIMEDOUT、ECONNREFUSED和ENETUNREACH。这三个出错类型的意思分别为:ETIMEDOUT代表超时,产生这种情况的原因 有很多,最常见的是服务器忙,无法应答客户机的连接请求;ECONNREFUSED代表连接拒绝,即服务器端没有准备好的倾听套接字,或是没有对倾听套接 字的状态进行监听;ENETUNREACH表示网络不可达。
在本例中,connect()函数的第二个参数servaddr是全局变量hostaddr,其中存储着函数parse_args()转换好的命令行 参数。如果连接建立失败,在例程中就调用我们自定义的函数errorout()输出信息"failed to connect to host"。errorout()函数的定义为:
-----------------------------------------------------------------
/****************************************************************
function:  errorout
description: displays an error message on the console and kills the current process.
arguments:  msg -- message to be displayed.
return value: none -- does not return.
calls:    none.
globals:   none.
****************************************************************/
void errorout (msg)
char *msg;
{
FILE *console;
console = fopen("/dev/console","a");
fprintf(console,"proxyd: %s\r\n",msg);
fclose(console);
exit(1);
}
-----------------------------------------------------------------
do_proxy()函数的后半部分是通过proxy建立用户主机与远端主机之间的连接。我们既有proxy与用户主机连接的套接字 (do_proxy()函数的参数usersockfd),又有proxy与远端主机连接的套接字isosockfd,那么最简单直接的通信建立方式就是 从一个套接字读,然后直接写到另一个套接字去。如:
-----------------------------------------------------------------
int n;
char buf[2048];
while((n=read(usersockfd, buf, sizeof(buf))>0)
if(write(isosockfd, buf, n)!=n)
err_sys("write wrror\n");
-----------------------------------------------------------------
这种形式的阻塞I/O在单向数据传递的时候是非常有效的,但是在我们的proxy操作中是要求用户主机和远端主机双向通信的,这样就要求我们对两个套 接字描述符既能够读由能够写。如果还是采用这种方式的阻塞I/O的话,很有可能长时间阻塞在一个描述符上。因此例程在处理这个问题的时候调用了 select()函数,这个函数允许我们执行I/O多路转接。其具体含义就是select()函数可以构造一个表,在这个表中包含了我们所有要用到的文件 描述符。然后我们可以调用一个函数,这个函数可以检测这些文件描述符的状态,当某个(我们指定的)文件描述符准备好进行I/O操作时,此函数就返回,告知 进程哪个文件描述符已经可以执行I/O操作了。这样就避免了长时间的阻塞。
还有一个函数poll()可以实现I/O多路转接,由于在例程中调用的是select(),我们就只对select()进行一下比较详细的介绍。select()系列函数的详细描述为:
-----------------------------------------------------------------
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int n, fd_set *readfds, fd_set *writefds, fd_est *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()函数将创建一个我们所关心的文件描述符表,它的参数将在内核中为这些文件描述符设置我们所关心的条件,例如是否是可读、是否可写以及 是否异常,而且在参数中还可以设置我们希望等待的最大时间。在select()成功执行时,它将返回目前已经准备好的描述符数量,同时内核可以告诉我们各 个描述符的状态信息。如果超时,则返回"0",如果出错,则函数返回"-1",并同时设置errno为相应的值。
select()的最后一个参数timeout将设置等待时间。其中结构timeval是在文件<bits/time.h>中定义的。
-----------------------------------------------------------------
struct timeval
{
__time_t tv_sec; /* Seconds */
__time_t tv_usec; /* Microseconds */
};
-----------------------------------------------------------------
参数timeout的设置有三种情况。象例程中这样timeout==NULL时,这表示用户希望永远等待,直到我们指定的文件描述符中的一个已准备 好,或者是捕捉到一个信号。如果是由于捕捉到信号而中断了这个无限期的等待过程的话,select()将返回"-1",同时设置errno的值为 EINTR。
如果timeout->tv_sec==0&&timeout->tv_usec==0,那么这表示完全不等待。 Select()测试了所有指定文件描述符后立即返回。这是得到多个描述符状态而不阻塞select()函数的轮询方法。
如果timeout->tv_sec!=0||timeout->tv_usec!=0,那么这两个参数的值即为我们希望函数等待的时 间。其中tv_sec设置时间单位为秒,tv_usec设置时间单位为微秒。如果在超时的时候,在我们指定的所有文件描述符里面仍然没有任何一个准备好的 话,则select()将返回"0"。
中间三个参数的数据类型是fd_set,它的意思是文件描述符集,而readfds, writefds和exceptfds则分别是指向文件描述符集的指针,他们分别描述了我们所关心的可读、可写以及状态异常的各个文件描述符。之所以我们 称select()可以创建一个文件描述符"表",那个所谓的表就是由这三个参数指向的数据结构组成的。其具体结构如图1所示。其中在每个set_fd数 据类型中都为我们关心的所有文件描述符保留了一位。所以在监测文件描述符状态的时候,就在这些set_fd数据结构中查询相关的位。
第一个参数n用来说明到底需要遍历多少个描述符位。n的值一般是这样设置的,从我们关心的所有文件描述符中选出最大值再加1。例如我们设置的所有文件 描述符中最大的为6,那么将n设置为7,则系统在检测描述符状态的时候,就只用遍历前7位(fd0~fd6)的状态。不过如果不想这样麻烦的话,我们可以 象例程中那样将n的值直接设置为FD_SETSIZE。这是系统中设定的最大文件描述符个数,不同的系统这个值也不相同,一般是256或是1024。这样 在检测描述符状态的时候,函数将遍历所有的描述符位。
在调用select()函数实现多路I/O转接时,首先我们要声明一个新的文件描述符集,就象例程中这样:
fd_set rdfdset;
然后调用FD_ZERO()清空此文件描述符集的所有位,以免下面检测描述符位的时候返回错误结果:
FD_ZERO(&rdfdset);
然后调用FD_SET()在文件描述符集中设置我们关心的位。在本例中,我们关心的就是分别与用户主机和远端主机连接的两个套接字描述符,所以执行这样的语句:
FD_SET(usersockfd,&rdfdset);
FD_SET(isosockfd,&rdfdset);
然后调用select()返回描述符状态,此时描述符状态被存储进描述符集,也就是set_fd数据结构中。在图1中我们看到所有的描述符位状态都是 "0",在select()返回后,例如fd0可读,则在readfds描述符集中fd0对应的位上将状态标志设置为"1",如果fd1可写,则 writefds描述符集中fd1对应的位上将状态标志设置为"1",状态异常的情况也也与此相同。在本例中,我们只关心两个套接字描述符是否可写,因此 执行这样的select()函数:
select(FD_SETSIZE,&rdfdset,NULL,NULL,NULL)
那么在select()返回后怎样检测set_fd数据结构中描述符位的状态呢?这就要调用函数FD_ISSET(),如果对应文件描述符的状态为"已准备好"(即描述符位为"1"),则FD_ISSET()返回"1",否则返回"0"。
-----------------------------------------------------------------
if (FD_ISSET(usersockfd,&rdfdset)) {
if ((iolen = read(usersockfd,buf,sizeof(buf))) <= 0)
break; /* zero length means the host disconnected */
write(isosockfd,buf,iolen);
-----------------------------------------------------------------
这一段代码就实现从套接字usersockfd(用户主机)到套接字isosockfd(远端主机)的无阻塞传输。而下一段代码实现反方向的无阻塞传输:
-----------------------------------------------------------------
if (FD_ISSET(isosockfd,&rdfdset)) {
if ((iolen = read(isosockfd,buf,sizeof(buf))) <= 0)
break; /* zero length means the host disconnected */
write(usersockfd,buf,iolen);
-----------------------------------------------------------------
这样就通过proxy实现了用户主机与远端主机之间的通信。
对这段proxy代码我只是写了一些自己的理解,大多数是一些函数的用法,这些都是linux网络编程中一些最基础的知识,如果有不对的地方,还请各位大虾批评指正。





posted @ 2009-11-17 21:14 石头@ 阅读(738) | 评论 (0)编辑 收藏

经典的Linux Socket 编程 示例代码 (上)

http://fanqiang.chinaunix.net/a4/b7/20010810/1200001101.html


Linux是一个可靠性非常高的操作系统,但是所有用过Linux的朋友都会感 觉到, Linux和Windows这样的"傻瓜"操作系统(这里丝毫没有贬低Windows的意思,相反这应该是Windows的优点)相比,后者无疑在易操作 性上更胜一筹。但是为什么又有那么多的爱好者钟情于Linux呢,当然自由是最吸引人的一点,另外Linux强大的功能也是一个非常重要的原因,尤其是 Linux强大的网络功能更是引人注目。放眼今天的WAP业务、银行网络业务和曾经红透半边天的电子商务,都越来越倚重基于Linux的解决方案。因此 Linux网络编程是非常重要的,而且当我们一接触到Linux网络编程,我们就会发现这是一件非常有意思的事情,因为以前一些关于网络通信概念似是而非 的地方,在这一段段代码面前马上就豁然开朗了。在刚开始学习编程的时候总是让人感觉有点理不清头绪,不过只要多读几段代码,很快我们就能体会到其中的乐趣 了。下面我就从一段Proxy源代码开始,谈谈如何进行Linux网络编程。

   首先声明,这段源代码不是我编写的,让我们感谢这位名叫Carl Harris的大虾,是他编写了这段代码并将其散播到网上供大家学习讨论。这段代码虽然只是描述了最简单的proxy操作,但它的确是经典,它不仅清晰地 描述了客户机/服务器系统的概念,而且几乎包括了Linux网络编程的方方面面,非常适合Linux网络编程的初学者学习。
这段Proxy程序的用法是这样的,我们可以使用这个proxy登录其它主机的服务端口。假如编译后生成了名为Proxy的可执行文件,那么命令及其参数的描述为:
./Proxy <proxy_port> <remote_host> <service_port>
其中参数proxy_port是指由我们指定的代理服务器端口。参数remote_host是指我们希望连接的远程主机的主机名,IP地址也同样有 效。这个主机名在网络上应该是唯一的,如果您不确定的话,可以在远程主机上使用uname -n命令查看一下。参数service_port是远程主机可提供的服务名,也可直接键入服务对应的端口号。这个命令的相应操作是将代理服务器的 proxy_port端口绑定到remote_host的service_port端口。然后我们就可以通过代理服务器的proxy_port端口访问 remote_host了。例如一台计算机,网络主机名是legends,IP地址为10.10.8.221,如果在我的计算机上执行:
[root@lee /root]#./proxy 8000 legends telnet
那么我们就可以通过下面这条命令访问legends的telnet端口。
-----------------------------------------------------------------
[root@lee /root]#telnet legends 8000
Trying 10.10.8.221...
Connected to legends(10.10.8.221).
Escape character is '^]'

Red Hat Linux release 6.2(Zoot)
Kernel 2.2.14-5.0 on an i686
Login:
-----------------------------------------------------------------
上面的绑定操作也可以使用下面的命令:
[root@lee /root]#./proxy 8000 10.10.8.221 23
23是telnet服务的标准端口号,其它服务的对应端口号我们可以在/etc/services中查看。

下面我就从这段代码出发谈谈我对Linux网络编程的一些粗浅的认识,不对的地方还请各位大虾多多批评指正。

◆main()函数
-----------------------------------------------------------------
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <netdb.h>
#define TCP_PROTO   "tcp"
int proxy_port;    /* port to listen for proxy connections on */
struct sockaddr_in hostaddr;   /* host addr assembled from gethostbyname() */
extern int errno;   /* defined by libc.a */
extern char *sys_myerrlist[];
void parse_args (int argc, char **argv);
void daemonize (int servfd);
void do_proxy (int usersockfd);
void reap_status (void);
void errorout (char *msg);
/*This is my modification.
I'll tell you why we must do this later*/
typedef void Signal(int);
/****************************************************************
function:    main
description:   Main level driver. After daemonizing the process, a socket is opened to listen for         connections on the proxy port, connections are accepted and children are spawned to         handle each new connection.
arguments:    argc,argv you know what those are.
return value:  none.
calls:      parse_args, do_proxy.
globals:     reads proxy_port.
****************************************************************/
main (argc,argv)
int argc;
char **argv;
{
int clilen;
int childpid;
int sockfd, newsockfd;
struct sockaddr_in servaddr, cliaddr;
parse_args(argc,argv);
/* prepare an address struct to listen for connections */
bzero((char *) &servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = proxy_port;
/* get a socket... */
if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) {
fputs("failed to create server socket\r\n",stderr);
exit(1);
}
/* ...and bind our address and port to it */
if   (bind(sockfd,(struct sockaddr_in *) &servaddr,sizeof(servaddr)) < 0) {
fputs("faild to bind server socket to specified port\r\n",stderr);
exit(1);
}
/* get ready to accept with at most 5 clients waiting to connect */
listen(sockfd,5);
/* turn ourselves into a daemon */
daemonize(sockfd);
/* fall into a loop to accept new connections and spawn children */
while (1) {
/* accept the next connection */
clilen = sizeof(cliaddr);
newsockfd = accept(sockfd, (struct sockaddr_in *) &cliaddr, &clilen);
if (newsockfd < 0 && errno == EINTR)
continue;
/* a signal might interrupt our accept() call */
else if (newsockfd < 0)
/* something quite amiss -- kill the server */
errorout("failed to accept connection");
/* fork a child to handle this connection */
if ((childpid = fork()) == 0) {
close(sockfd);
do_proxy(newsockfd);
exit(0);
}
/* if fork() failed, the connection is silently dropped -- oops! */
lose(newsockfd);
}
}
-----------------------------------------------------------------
上面就是Proxy源代码的主程序部分,也许您在网上也曾经看到过这段代码,不过细心的您会发现在上面这段代码中我修改了两个地方,都是在预编译部分。一个地方是在定义外部字符型指针数组时,我将原代码中的
extern char *sys_errlist[];
修改为
extern char *sys_myerrlist[];原因是在我的Linux环境下头文件"stdio.h"已经对sys_errlist[]进行了如下定义:
extern __const char *__const sys_errlist[];
也许Carl Harris在94年编写这段代码时系统还没有定义sys_errlist[],不过现在我们不修改一下的话,编译时系统就会告诉我们sys_errlist发生了定义冲突。
另外我添加了一个函数类型定义:
typedef void Sigfunc(int);
具体原因我将在后面向大家解释。

套接字和套接字地址结构定义

这段主程序是一段典型的服务器程序。网络通讯最重要的就是套接字的使用,在程序的一开始就对套接字描述符sockfd和newsockfd进行了定义。 接下来定义客户机/服务器的套接字地址结构cliaddr和servaddr,存储客户机/服务器的有关通信信息。然后调用parse_args (argc,argv)函数处理命令参数。关于这个parse_args()函数我们待会儿再做介绍。

创建通信套接字

  下面就是建立一个服务器的详细过程。服务器程序的第一个操作是创建一个套接字。这是通过调用函数socket()来实现的。socket()函数的具体描述为:
-----------------------------------------------------------------
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
-----------------------------------------------------------------
参数domain指定套接字使用的协议族,AF_INET表示使用TCP/IP协议族,AF_UNIX表示使用Unix协议族,AF_ISO表示套接 字使用ISO协议族。type指定套接字类型,一般的面向连接通信类型(如TCP)设置为SOCK_STREAM,当套接字为数据报类型时,type应设 置为SOCK_DGRAM,如果是可以直接访问IP协议的原始套接字则type应设置为SOCK_RAW。参数protocol一般设置为"0",表示使 用默认协议。当socket()函数成功执行时,返回一个标志这个套接字的描述符,如果出错则返回"-1",并设置errno为相应的错误类型。

设置服务器套接字地址结构

在通常情况下,首先要将描述服务器信息的套接字地址结构清零,然后在地址结构中填入相应的内容,准备接受客户机送来的连接建立请求。这个清零操作可以用 多种字节处理函数来实现,例如bzero()、bcopy()、memset()、memcpy()等,以字母"b"开始的两个函数是和BSD系统兼容 的,而后面两个是ANSI C提供的函数。这段代码中使用的bzero()其描述为:
void bzero(void *s, int n);
函数的具体操作是将参数s指定的内存的前n个字节清零。memset()同样也很常用,其描述为:
void *memset(void *s, int c, size_t n);
具体操作是将参数s指定的内存区域的前n个字节设置为参数c的内容。
下一步就是在已经清零的服务器套接字地址结构中填入相应的内容。Linux系统的套接字是一个通用的网络编程接口,它应该支持多种网络通信协议,每一 种协议都使用专门为自己定义的套接字地址结构(例如TCP/IP网络的套接字地址结构就是struct sockaddr_in)。不过为了保持套接字函数调用参数的一致性,Linux系统还定义了一种通用的套接字地址结构:
-----------------------------------------------------------------
<linux/socket.h>
struct sockaddr
{
unsigned short sa_family; /* address type */
char sa_data[14]; /* protocol address */
}
-----------------------------------------------------------------
其中sa_family意指套接字使用的协议族地址类型,对于我们的TCP/IP网络,其值应该是AF_INET,sa_data中存储具体的协议地 址,不同的协议族有不同的地址格式。这个通用的套接字地址结构一般不用做定义具体的实例,但是常用做套接字地址结构的强制类型转换,如我们经常可以看到这 样的用法:
bind(sockfd,(struct sockaddr *) &servaddr,sizeof(servaddr))
用于TCP/IP协议族的套接字地址结构是sockaddr_in,其定义为:
-----------------------------------------------------------------
<linux/in.h>
struct in_addr
{
__u32 s_addr;
};
struct sochaddr_in
{
short int sin_family;
unsigned short int sin_port;
struct in_addr sin_addr;
/*This part has not been taken into use yet*/
nsigned char_ _ pad[_ _ SOCK_SIZE__- sizeof(short int) -sizeof(unsigned short int) -       sizeof(struct in_addr)];
};
#define sin_zero_ - pad
-----------------------------------------------------------------
其中sin_zero成员并未使用,它是为了和通用套接字地址struct sockaddr兼容而特意引入的。在编程时,一般都通过bzero()或是memset()将其置零。其他成员的设置一般是这样的:
servaddr.sin_family = AF_INET;
表示套接字使用TCP/IP协议族。
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
设置服务器套接字的IP地址为特殊值INADDR_ANY,这表示服务器愿意接收来自任何网络设备接口的客户机连接。htonl()函数的意思是将主机顺序的字节转换成网络顺序的字节。
servaddr.sin_port = htons(PORT);
设置通信端口号,PORT应该是我们已经定义好的。在本例中servaddr.sin_port = proxy_port;这是表示端口号是函数的返回值proxy_port。
另外需要说明的一点是,在本例中,我们并没有看到在预编译部分中包含有<linux/socket.h>和< linux/in.h>这两个头文件,那是因为这两个头文件已经分别被包含在<sys/types.h>和< sys/types.h>中了,而且后面这两个头文件是与平台无关的,所以在网络通信中一般都使用这两个头文件。

服务器公开地址

  如果服务器要接受客户机的连接请求,那么它必须先要在整个网络上公开自己的地址。在设置了服务器的套接字地址结构之后,可以通过调用函数bind()绑定服务器的地址和套接字来完成公开地址的操作。函数bind()的详细描述为:
-----------------------------------------------------------------
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, struct sockaddr *addr, int addrlen);
-----------------------------------------------------------------
参数sockfd是我们通过调用socket()创建的套接字描述符。参数addr是本机地址,参数addrlen是套接字地址结构的长度。函数执行成功时返回"0",否则返回"-1",并设置errno变量为EADDRINUAER。
如果是服务器调用bind()函数,如果设置了套接字的IP地址为某个本地IP地址,那么这表示服务器只接受来自于这个IP地址的特定主机发出的连接 请求。不过一般情况下都是将IP地址设置为INADDR_ANY,以便接受所有网络设备接口送来的连接请求。
客户机一般是不会调用bind()函数的,因为客户机在连接时不用指定自己的套接字地址端口号,系统会自动为客户机选择一个未用端口号,并且用本地 IP地址自动填充客户机套接字地址结构中的相应项。但是在某些特定的情况下客户机需要使用特定的端口号,例如Linux中的rlogin命令就要求使用保 留端口号,而系统是不能为客户机自动分配保留端口号的,这就需要调用bind()来绑定一个保留端口号了。不过在一些特殊的环境下,这样绑定特定端口号也 会带来一些负面影响,如在HTTP服务器进入TIME_WAIT状态后,客户机如果要求再次与服务器建立连接,则服务器会拒绝这一连接请求。如果客户机最 后进入TIME_WAIT状态,则马上再次执行bind()函数时会返回出错信息"-1",原因是系统会认为同时有两次连接绑定同一个端口。

转换Listening套接字

接下来,服务器需要将我们刚才与IP地址和端口号完成绑定的套接字转换成倾听listening套接字。只有服务器程序才需要执行这一步操作。我们通过调用函数listen()实现这一操作。listen()的详细描述为:
-----------------------------------------------------------------
#include <sys/socket.h>
int listen(int sockfd, int backlog);
-----------------------------------------------------------------
参数sockfd指定我们要求转换的套接字描述符,参数backlog设置请求队列的最大长度。函数listen()主要完成以下操作。
首先是将套接字转换成倾听套接字。因为函数socket()创建的套接字都是主动套接字,所以客户机可以通过调用函数connect()来使用这样的 套接字主动和服务器建立连接。而服务器的情况恰恰相反,服务器需要通过套接字接收客户机的连接请求,这就需要一个"被动"套接字。listen()就可将 一个尚未连接的主动套接字转换成为这样的"被动"套接字,也就是倾听套接字。在执行了listen()函数之后,服务器的TCP就由CLOSED变成 LISTEN状态了。
另外listen()可以设置连接请求队列的最大长度。虽然参数backlog的用法非常简单,只是一个简单的整数。但搞清楚请求队列的含义对理解TCP 协议的通信过程建立非常重要。TCP协议为每个倾听套接字实际上维护两个队列,一个是未完成连接队列,这个队列中的成员都是未完成3次握手的连接;另一个 是完成连接队列,这个队列中的成员都是虽然已经完成了3次握手,但是还未被服务器调用accept()接收的连接。参数backlog实际上指定的是这个 倾听套接字完成连接队列的最大长度。在本例中我们是这样用的:listen(sockfd,5);表示完成连接队列的最大长度为5。

接收连接

接下来我们在主程序中看到通过名为daemonize()的自定义函数创建一个守护进程,关于这个daemonize()以及守护进程的相关概念,我 们等一会儿再做详细介绍。然后服务器程序进入一个无条件循环,用于监听接收客户机的连接请求。在此过程中如果有客户机调用connect()请求连接,那 么函数accept()可以从倾听套接字的完成连接队列中接受一个连接请求。如果完成连接队列为空,这个进程就睡眠。accept()的详细描述为:
-----------------------------------------------------------------
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, int *addrlen);
-----------------------------------------------------------------
参数sockfd是我们转换成功的倾听套接字描述符;参数addr是一个指向套接字地址结构的指针,参数addrlen为一个整型指针。当函数成功执 行时,返回3个结果,函数返回一个新的套接字描述符,服务器可以通过这个新的套接字描述符和客户机进行通信。参数addr所指向的套接字地址结构中将存放 客户机的相关信息,addrlen指针将描述前述套接字地址结构的长度。在通常情况下服务器对这些信息不是很感兴趣,因此我们经常可以看到一些源代码中将 accept()函数的后两个参数都设置为NULL。不过在这段proxy源代码中需要用到有关的客户机信息,因此我们看到通过执行
newsockfd = accept(sockfd, (struct sockaddr_in *) &cliaddr, &clilen);
将客户机的详细信息存放在地址结构cliaddr中。而proxy就通过套接字newsockfd与客户机进行通信。值得注意的是这个返回的套接字描 述符与我们转换的倾听套接字是不同的。在一段服务器程序中,可以始终只用一个倾听套接字来接收多个客户机的连接请求;而如果我们要和客户机建立一个实际的 连接的话,对每一个请求我们都需要调用accept()返回一个新的套接字。当服务器处理完毕客户机的请求后,一定要将相应的套接字关闭;如果整个服务器 程序将要结束,那么一定要将倾听套接字关闭。
如果accept()函数执行失败,则返回"-1",如果accept()函数阻塞等待客户机调用connect()建立连接,进程在此时恰好捕捉到 信号,那么函数在返回"-1"的同时将变量errno的值设置为EINTR。这和accept()函数执行失败是有区别的。因此我们在代码中可以看到这样 的语句:
-----------------------------------------------------------------
if (newsockfd < 0 && errno == EINTR)
continue;
/* a signal might interrupt our accept() call */
else if (newsockfd < 0)
/* something quite amiss -- kill the server */
errorout("failed to accept connection");
-----------------------------------------------------------------
可以看出程序在处理这两种情况时操作是完全不同的,同样是accept()返回"-1",如果有errno == EINTR,那么系统将再次调用accept()接受连接请求,否则服务器进程将直接结束。

posted @ 2009-11-17 21:13 石头@ 阅读(2365) | 评论 (0)编辑 收藏

Unix发展史

先前的一个理想
UNIX系统自 1969 年 Ken ThompsonKen Thompson 与 Dennis RitchieDennis Ritchie 在美国贝尔电话实验室(Bell Telephone Laboratories )发展出雏形至今,已历经近 30 来年。而 "UNIX" 这个字典上查不到其原意的怪字,其实是戏谑 MULTICS(MULTiplexed Information and Computing System)操作系统的大而无当所产生的谐音字。
在 1957 年 10 月,前苏联发射了第一枚人造卫星,此举让当时的美国总统艾森豪威尔决定投下巨额的经费用以支持及发展科学,美国高等研究计划署 (ARPA,Advanced Research Projects Agency )便是在这个时空下设立了,该单位负责推动系统发展等相关计划,成为当时美国电子计算器发展的重要推手。
1960年代是大型计算机的发展年代,当时的麻省理工学院因最先实现了兼容分时系统(CTSS, Compatible Time-Sharing System),在电子计算器领域享有相当崇高的地位。
1963年,麻省理工的里克莱德(J. C. R. Licklider,1915~1990 )
推动了 MAC计划,MAC 以 IBM的大型计算机做为主体,连接了将近 160台终端机,这些终端机就四散在学区以及教职员的家中,可以让 30 位使用者同时共享计算机资源。这项计划到了 1965 年便不堪负荷,于是麻省理工便决定开发更大型的分时计算机系统。新的计划便是—— MULTICS. 一个计算机
史上最为庞大的分时计算机系统,企图连接 1000 部终端机,支持 300位使用者同时上线的分时计算机系统。她面临的是,操作系统的分时观念还在各学术与研究机构探索成形中,计算机硬件亦需重新设计的双重挑战。
当时,麻省理工原本找 IBM来配合这项计划,但 IBM正忙着应付自己的问题而无意配合MULTICS 计划。此时,通用电子公司(General Electric Company)
也就是奇异公司正好在发展自己的大型主机,见机不可失,便极力邀请麻省理工参予她们的 GE 645 大型主机的规格制定。有了奇异热心主动的计算机硬件配合,麻省理工找上的不能贩售计算机却人才济济的贝尔电话实验室来负责承包软件工程。于是 乎,MULTICS 的计划便在 1965 年由麻省理工学院、奇异公司及贝尔电话实验室这三个成员开始共同发展。
1969年,MULTICS 计划在历经四年的奋战后,仍旧未达到原先规划设计的理想,贝尔电话实验室决定退出计划。功能未达原始设计理想的 MULTICS还是安装在奇异公司的 GE 645 大型计算机上供麻省理工使用。奇异公司在该计划草草结束后不到一年便完全淡出大型计算机市场。日后,MULTICS 计划被嘲解为Many Unnecessarily Large Table In Core Simultaneously.
农夫我个人认为, MULTICS计划诞生在大型计算机将开始鼎沸的 1965 年,夭折于大型计算机最为辉煌的 1969 年。她如果适时在 1960 年代末期成功的话,绝对可以助长当时已经普遍被计算机权威人士视为理想的「计算机公用事业」,至少可以让大型计算机的发展与资源集中的应用模式就不至于会 在 1970 年代初期就迅速萎缩。因为 MULTICS计划如果成功,至少能让当时的大型计算机的应用规模大上 10 倍左右。然而,MULTICS 计划失败了。她严重地打击了当时依赖大型计算机主机的计算机公用事业业者在发展上的信心。更由于没有相似的计划后继进行,使得集中式的大型计算机主机没有 明显的使用效能提升,而加速催化计算器工业的转变,以寻找新的道路。另一方面,MULTICS 计划失败的经验亦让当时参与该计划的软件工程师们得到相当宝贵的经验与正面的影响。
几年后,就在 AT&T ,MULTICS 计划这个不同凡响的失败换来的一个不同凡响的成功。
一个戏谑她的名字诞生了…… UNIX.
Ken_Thompso


400) {this.resized=true; this.width=400; this.alt='Click here to open new window';}" onmouseover="if(this.resized) this.style.cursor='hand';" onclick="window.open('/upimg/20070420/11M10351425013001.jpg');" border="0">
Dennis_Ritchie


400) {this.resized=true; this.width=400; this.alt='Click here to open new window';}" onmouseover="if(this.resized) this.style.cursor='hand';" onclick="window.open('/upimg/20070420/11M103514N021A4.jpg');" border="0">

一个游戏的开始
1969年贝尔实验室的计算器科学研究中心(Computing Science Research Center )
成员退出 MULTICS计划的同时,贝尔实验室本身其实也没有一套完善便利的交谈式计算器服务环境。在其中不少工程师们也正为了改善程序设计环境努力着, Ken Thompson 、Dennis Ritchie和其同事们在当时草拟一个新的档案系统架构,这个档案系统也就是早期的 UNIX 操作系统的档案系统的前身。当时的 Ken Thompson 忙着使用 Fortran语言将原本在 Multics系统中开发的game叫 "Space Travel" (太空旅游)转移到 GECOS System 上开发。 当时 GECOS System大型计算机的CPU Time相当昂贵(一秒要 75 块美金),同时控制 "spaceship"(宇宙飞船) 的效果不甚理想,于是 Ken Thompson 不得不寻找替代的开发环境。Thompson看上了一台很少被人使用的 Digital Equipment Corporation PDP-7 迷你计算机,当时 PDP-7使用的是 Graphic-II 显示器,具有不错的图形处理能力。 Brian kernighan 于是 Ken Thompson 便与 Dennis Ritchie 连手将程序设计转移到 PDP-7型计算机上。
Ken Thompson在移转工作环境的同时为了得到较好的发展环境,便与Dennis Ritchie共同动手设计一套包含 File System、Process Subsystem 及一小组 Utility的操作系统,当时这套系统仅能支持 2个使用者使用。由于贝尔实验室对于 MULTICS计划失败的阴霾还未消散, Brian Kernighan这位仁兄开玩笑地戏称这套新的操作系统为 UNiplexed Information and Computing System,缩写为 UNICS,之后大家取谐音便叫她为 "UNIX" ,没想到这个开玩笑的名字会被人叫到今天。
初期的自由发展
事实上该套 "UNIX" 系统在当时仅是私下的被使用,也并没有得到多大的重视,一直到1971年的一个正式的计划,UNIX才正式被搬上台面。
PDP-11/201970 年,当时贝尔实验室的专利部门(Patent department )缺乏一套文书处理系统,为了设计开发的需要,于是买了一台 PDP-11 计算机。当时 PDP-11 计算机的交机过程并不顺利,处理器先到,硬盘则多等了好几个月。
当 PDP-11 一切准备妥当后,他们便将 UNIX 移植到拥有 512K bytes 硬盘的PDP-11/20 型计算机上,并在此系统之下开发了一套文书处理工具。而这套工具便是后来 nroff / troff的前身。那时的 UNIX 提供 16K bytes给系统、8K bytes给使用程序,档案最大的极限是 64K bytes. 而此套含有文书处理工具的系统,也正式获得贝尔实验室的专利部门采用,系统名称并被编为 "First Edition". 在 UNIX 移植成功后 Thompson 用 B语言为它添加了 Fortran Compiler,但因为 B语言属于一种解译语言(interpretive language ),执行成效并不是很好,于是 Ritchie又将它—— Compiler 发展成可产生机器码、允许定义数据形态及结构,Ritchie 称它为 C语言。1973年并以 C语言改写全部UNIX原始程序,UNIX于是首度出现正式版本——V5(第五版)。
此时的 UNIX 慢慢地在贝尔实验室内部蔓延开来,装机数也变成了 25 部之多。
由于当时的贝尔实验室实际上是掌控在美国电信电话公司(AT&T)及其子公司西方电器公司的手上,实验室主要是负责研究改进西方电器公司制造的和 美国电信电话公司在贝尔系统中使用的电信设备。同时根据军方合同,从事与国防有关的研究与改进的工作。而 AT&T 本身由于有反托拉斯法的限制并不能从事于任何有关计算机方面的销售,所以 AT&T 的主管阶层们对于当时 UNIX 的发展并没有太多的支持,因而当时贝尔实验室内部对于 UNIX 的发展并不是相当在意也无意于将之推广。不过为了应付实验室内各部门日益增加的 UNIX 使用者与相关技术支持需求,还是成立了 UNIX ystem Group (简称 USG)。但该组织也仅只是提供技术上的支持,并未赋予继续发展的任务。所以当时的 UNIX 发展,全靠AT&T的工程师们的努力。这段期间 UNIX 的发展完全没有组织及系统性可言,而玩家尽是一些工程师们,于是乎种下了 UNIX 日后较难以被一般人所接受的命运。


400) {this.resized=true; this.width=400; this.alt='Click here to open new window';}" onmouseover="if(this.resized) this.style.cursor='hand';" onclick="window.open('/upimg/20070420/11M10351522035M3.jpg');" border="0">



400) {this.resized=true; this.width=400; this.alt='Click here to open new window';}" onmouseover="if(this.resized) this.style.cursor='hand';" onclick="window.open('/upimg/20070420/11M10351522035M3.jpg');" border="0">

走出贝尔实验室
1974年 Thompson 与 Ritchie共同在 Communications of the ACM发表了一篇 UNIX 论文 "UNIX Time-Sharing System" 得到相当大的回响。 1975 年 UNIX 发表第六版(V6)﹐其提供的强大功能更胜过当时昂贵大计算机的操作系统,其最大特点是以高级语言写成,仅需要做少部份程序的修改便可移植到不同的计算机 平台上。 UNIX V6版本并附有完整的程序原始码在 1976 年正式从贝尔实验室内部传播到各大学及研究机构,UC Berkeley 也就是依据这个版本开始研究并加以发展,并在 1977 年发表 1 BSD(1st Berkeley Software Distribution)版本的 UNIX OS,其后续的发展更为 UNIX OS贡献良多且影响深远,此点稍后再为你说明。
同年 UNIX 因它提供良好程序发展环境、网络传输服务与及时服务(Real-Time Services),而广得各电话公司采用。Interactive System Corporation更因 Value Added Reseller (VAR )运用 UNIX 来强化办公室自动化环境,成为第一家应用UNIX操作系统的公司。此年UNIX亦被修改并第一次装到 Interdata 8/32 型计算机上。这也是 UNIX 操作系统首次安装在非 PDP型的计算机上。自此 UNIX 系统开始被移植改装到各型微处理机及新计算机上
一个稳定的基石
1978年 UNIX 发表对今日影响最重大的 UNIX 第七版(UNIX Time-Sharing System,Seventh Edition )也就是 V7.此版本包含 Fortran 77 compiler、Shell (只有Bourne Shell)、文件处理工具(nroff/troff 、roff、 MS mocro等)、UNIX-to-UNIX-file-Copy(用来支持两台 UNIX 机器间的档案传输)、数据处理工具(AWK 、SED 等强悍的工具)、除错工具(ADB )、程序发展工具(MAKE)、Lexical analyzer generator(LEX 、YACC等)、简单的绘图工具、并支持 C语言及 LINT verifier,主要执行于 PDP-11 及Interdata 8/32型计算机上。在当时那个年代来说其系统的架构与功能已经是相当的完备的了。Bourne Shell的原作者称她为 "improvement over all preceding and following Unices" ,在今日也有人称这个版本是 "last true Unix".由此可见 V7 在 UNIX 发展里程上的扮演了相当重要的盘石角色。
在当时 DEC公司推出了一款 32-bit supermini 主机—— VAX,搭配的 VAX的操作系统叫做 VMS. 这款迷你级计算机的硬件无可挑剔〈直到今日她的稳定度仍是被诸多老一辈的系统管理者所赞许的〉,但 DEC对 VMS操作系统的支持性却让贝尔实验室的工程师们宁愿使用UNIX OS . 而这项工作则是由 John Reiser和Tom London所共同完成。他们以 V7 为基础转移 UNIX OS到 VAX计算机上使用。
这个版本被称为 UNIX V32.同时为了转移的方便性,他们把 32-bit 的 VAX当成是大一点的 PDP-11 (因为 DEC 的 PDF-11 型计算机是 16-bit ),同时为了执行的效率,V32 放弃使用 VAX硬件提供的一项 paging 功能(DEC 的 VMS OS 有支持 paging 功能,也由于 V32舍弃这项功能,所以 V32没有虚拟内存的功能)。
即使是如此,V32 支持的地址已高达 4Gb. 就这样没有支持paging功能的 V32开始被广泛的安装在 VAX的机器上运作。
DEC 则是在 1984 年左右推出来自己的 UNIX OS,叫做 ULTRIX.


400) {this.resized=true; this.width=400; this.alt='Click here to open new window';}" onmouseover="if(this.resized) this.style.cursor='hand';" onclick="window.open('/upimg/20070420/11M1035156104cD.jpg');" border="0">
一个重要的延续及发展—— BSD UNIX
时间回到 1973 年 11 月, Ken Thompson 和 Dennis Ritchie 在印第安纳Purdue大学的一场操作系统原理的座谈会。会场上、坐着一位柏克莱大学(U.C. Berkeley )教授,名字叫 Bob Fabry. 当天的 K&R所发表的 UNIX 立刻引发 Bob Fabry的极度兴趣。当时的柏克莱还是处在使用大型计算机主机、批次执行程序的阶段,并没有像 UNIX 这样的交谈式作业环境。会后,他便决定将UNIX带回柏克莱。
于是柏克莱的计算器科学、数学与统计三个系所合买的一台 PDP-11/45,准备用来迎接UNIX.1974 年 1月,Bell Labs寄来了一卷 V4 的磁带,学生 Keith Standiford 便开始进行安装 V4 的工作。安装时 Standiford 碰到了问题,便转向 Bell Labs求援。人在新泽西州的 Thompson 便透过柏克莱这端速度只有300-baud的调制解调器在在线进行侦错。
在 UNIX 的发展史上,这是 Bell Labs与柏克莱的第一次接触。
完成除错后,V4便顺利地在柏克莱这台新买的 PDP-11/45计算机上工作了。
当时这台是三个系所合买的,计算器科学好不容易装上了 UNIX ,却碰到数学与统计系所要使用 DEC's RSTS system,所以在一阵协调后,UNIX与 DEC's RSTS system以 8:16小时的比例分配,供三个系所轮流使用。一段时日后,具交谈式功能的 UNIX 在效能上的表现得到绝多数学生们喜爱,纷纷将自己的计划转向UNIX的时段。而一天占了 16 个小时的批处理时段却乏人问津。
当时 Eugene Wong与 Michael Stonebraker教授,看上了 UNIX 提供的便利性,便打算将他们的 INGRES 数据库计划重原先批处理的计算机环境转移到UNIX系统上面。在 1974 年,他们为这执行计划添购了一台新的 PDP-11/40 计算机,上面安装了 V5.这个计划也就是柏克莱的第一个将作业环境转移到UNIX的案子。
UNIX作业环境的需求,在柏克莱迅速地成长。为了应付需求,Michael Stonebraker 与Bob Fabry 教授决定再申请购买两台 PDP-11/45. 1975年初,DEC 推出 PDP-11/70,价格差不多等于两台 PDP-11/45,但功能强过 PDP-11/45 所以他们便决定改购买一台 PDP-11/70.
这台机器引来了 Ken Thompson 、碰上 Bill Joy 以及日后产生了 1BSD.她就宛如是一块 UNIX 史上的地标,沿袭自 Bell Labs,竖立在柏克莱,承先启后并开创新局。农夫个人认为,她应该被供在博物馆。
当这台机器在 1975 年终运达柏克莱时;同一时间,Thompson受邀回母校(柏克莱)当客座教授,科目就是 NIX.Thompson 在校期间与 Jeff Schriebman和 Bob Kridle 一起动手将新版的 V6 安装在 PDP-11/70.
Bill Joy1975年,一位密执安州大学的毕业生来到了柏克莱,他的名字就是Bill Joy. 当时 Joy和同学 Chuck Haley (tar 就是他写的)喜欢一起泡在计算机房里面,Thompson也时常插上一脚。他们成功地改善了 Pascal 的解译与侦错的能力,同时还提升了解译与执行的速度。另外换装上 ADM-3的屏幕后,他们觉得ed文字编辑指令并不合用;于是根据另外一个相似的 em 指令,发展了自己的觉得满意的文字编辑工具,也就是指令 ex.
1976年夏天,Thompson结束了他的休假回到 Bell Labs. 此时的 Joy和Haley 已经开始着手探索 UNIX kernal,甚至还做了一些修改。1977年初,Joy 制作了一卷磁带,上头写着"Berkeley Software Distribution." ,这就是 1BSD. 其中包含新的 Pascal compiler与 ex 编辑器。
次年,来了几台新屏幕—— ADM-3a ,这种屏幕支持光标地址显示,Joy 在这种屏幕上完成了有人爱不释手;有人恨之入骨的文字编辑器—— vi.接着不久,Joy 便发现一个问题,老旧的屏幕装备,还是会被用在其它的计算机上。为了支持上的方便,Joy 针对此现象设计了一个接口,用来管理、支持不同的屏幕装备。
这个接口就是现在的 termcap.1978 年中,包含了功能加强的 Pascal 与 vi 及termcap 的 "Second Berkeley Software Distribution ," 也就是 2BSD ,迅速的取代了原先版本。
1979年,至少有 75 部 PDP-11 的机器上安装 2BSD 在运作着。自此在 DEC PDP-11 系列上执行的 BSD版本便一直以 2.xBSD 作为识别。
由于 PDP-11 计算机实在相当长寿,持续到今日农夫我仍然在网络上发现过关于PDP 计算机的网站。似乎到今日它们仍旧在某些地方默默地工作着。
2.xBSD最近的一次改版是在 1987 年,使用 4.3 BSD为主架构改写,版本定为 2.10 BSD.
在 BSD UNIX 中登场的重要功能当中,有一个直到今日仍然叫人又爱又恨的指令– vi.我接触过不少学习 UNIX OS的人,大部分的人对 vi 的使用与掌握都不算顺手,其中恨死这个指令的也大有人在,前些日子农夫我还看到某个网站公开讨论起 vi 是否阻碍了 UNIX 的发展?实在夸张了一点!
Bill Joy多次公开地说,他要是知道 vi 会如此受" 欢迎" 的话,他宁愿当初没有写 vi 这只程序。不过 Bill Joy 也说过,当时他原本还想加入一项 Multiple Windows in vi 的功能,不过当他在写这部分程序的时候,磁带机坏了,所以Bill只好在没有备份的情况下继续工作,想不到" 屋漏偏逢连夜雨" ,程序写到一半,他使用的硬盘也跟着挂了。在无可挽救又没有备份磁带的情况下,Bill宣告放弃为 vi 增加 Multiple Windows 这项功能。事后 Bill 为前一版的 vi 写好使用说明后就继续作其它的事。所以 vi 就长成今天那付德性。农夫我认为这或许是福不是祸!搞不好当初要是连 Multiple Windows 这项功能一起发表的话,上头的图可能就是遗照了。
当时有位 Richard Fateman教授,原先使用一台 PDP-10 上进行着他的Macsyma 研究计划。但他需要更大的内存地址来执行程序,所以在 1978 年初,他看上了当时迪吉多新发表的 VAX-11/780.好不容易,他联合了其它的部门才凑足购买 VAX的经费。刚开始时,机器原本安装的是 VMS操作系统。不过别的成员要执行 UNIX 操作系统,于是 Fateman安装上了 V32. 但问题来了,V32 并不支持虚拟内存,Fateman 便找上了 Domenico Ferrari 教授,希望他与他的研究小组能为 UNIX 加上这项功能。当时一位学生叫 Ozalp Babaoglu ,他想到了一些解决的方法似乎可行,但因为牵涉到 VAX硬件与 UNIX kernal的问题,于是他找上了 Joy帮忙。
就在只有一台 VAX的状况下,他们努力奋战着。1979年 1月,在 VAX上支持虚拟内存的UNIX版本终于诞生,V32 从此走入历史。紧接着 Peter Kessler与 Marshall Kirk McKusick 为他加上了Pascal;Joy 则动手将 2BSD 上的 ex、vi、C shell 等工具转移了过来。这个版本就是 3BSD.一个首次支持虚拟内存、demand paging 和 page eplacement 的 UNIX OS.


400) {this.resized=true; this.width=400; this.alt='Click here to open new window';}" onmouseover="if(this.resized) this.style.cursor='hand';" onclick="window.open('/upimg/20070420/11M1035161F53004.jpg');" border="0">


400) {this.resized=true; this.width=400; this.alt='Click here to open new window';}" onmouseover="if(this.resized) this.style.cursor='hand';" onclick="window.open('/upimg/20070420/11M1035164Z63303.jpg');" border="0">
UNIX与 DARPA交会
1970年代末,美国国防部先进研究计划机构(Defense Advanced Research Projects Agency ——简称 DARPA)正在为 AI (Artificial Intelligence ),VLSI及计算器视觉等研究(vision research )找寻一个可共通作业的计算机环境。硬件方面的首选是迪吉多的 VAX主机。配合的操作系统是 VMS. 这样的组合因拥有相当接近 DARPA 需求的功能被列入优先的考量,但在 DARPA与 DEC商谈对于 VMS的支持事宜之后,DARPA 并没有得到满意的答案。这迫使他们考虑朝向UNIX发展。但当时 UNIX OS(指的就是32V )搭配 VAX,最大的缺憾就是没有支持虚拟内存;但此时已经有人克服了。
当时,Bob Fabry 教授写了一份建议书给 DARPA,建议他们以柏克莱支持虚拟内存的 3BSD 为基础,发展成为计划所需。这份企划书引起了 DARPA的高度兴趣。随后 3BSD 也实际获得了 DARPA相关计划成员们的良好风评,也因此最后柏克莱大学打败了卡奈基梅隆大学与 BBN(Bolt Baranek & Newman , Inc. ),让 Bob Fabry成功地获得了 DARPA的资助合约。这份合约开始于 1980 年 4月,为期 18 月。此后的 DARPA便以 UNIX OS为标准操作系统。 Bob Fabry 教授在取得 DARPA合约后,依约成立了一个支持机构,也就是 Computer Systems Research Group简称 CSRG.Bob Fabry找上了 Bill Joy 来负责软件开发。Joy 迅速地以先前的 3BSD 为基础,整合新的功能。如 Job Contro l (作者是 Jim Kulp )、auto reboot 、1K block file system. 同时也整合入Pascal compiler 、Franz Lisp system、enhanced mail handling system.这就是在 1980 年所发表的 4BSD.没多久她便被安装在将近 500台VAX 上。
DARPA 采用了这个版本作为当时 DARPA的标准 UNIX 操作系统。
树大招风,当时,有位在 Stanford Research Institute的仁兄叫 David Kashtan,写了一份关于 VMS与 BSD UNIX在 VAX上的执行效率评估。该份报告指出 BSD UNIX 在效率上不如 VMS来的好。Joy 知道这件事之后,花了不到一个星期的时间,重新调整 UNIX kernal. 然后也写了一份报告,证明他们的BSD 在 VAX上要比 VMS优越多多。 1981年 6月,这个 Joy调整过的系统,加上了 Robert Elz 写的 auto configuration ,以 4.1BSD 的版本发表了。
当时的 DARPA对柏克莱 4.1BSD 的表现相当满意,于是续签了两年的新约,金额更是先前合约的 5倍。其中有一半的金额用在资助柏克莱继续发展 BSD UNIX . 钱多的相对代价就是要求高。当时,DARPA 对 UNIX 的期望开出了明确的目标;更迅速、更有效率的档案系统、支持程序可执行地址达 multi-gigabyte 、提供弹性的解译沟通能力、具整合支持网络能力。
在此同时,为了达到计划的目标,DARPA 成立的一个指导委员会;主要的成员有柏克莱的 Bob Fabry, Bill Joy ,Sam Leffler 、BBN 公司的 Alan Nemeth and Rob Gurwitz、贝尔实验室的 Dennis Ritchie 、史丹佛大学的 Keith Lantz、卡内基。梅伦大学 Rick Rashid、麻省理工学院 Bert Halstead、信息科学协会 Dan Lynch、DARPA 的 Duane Adams and Bob Baker以及加州。洛杉矶大学的 Jerry Popek.
不久,Joy 便开始整合早先 BBN的 Rob Gurwitz所发表的 TCP/IP protocols ,不过他对 BBN这些程序的执行效率并不满意,于是 Joy与 Sam Leffler重新写的一版自己的程序。
另外,并加入了一些支持网络的工具 rcp,rsh , rlogin ,rwho. 他们称她为 4.1aBSD,这个版本并没有正式发表,在1982年 4月开始供内部使用。虽是如此,在 4.2BSD 未正式发表之前,她还是繁殖的到处都是。6 月, 4.1aBSD kernal加上了新完成的档案系统,版本更新为 4.1bBSD.
rcp , rsh, rlogin , rwho 这群指令。因安全机制上的理由,逐渐被另一群新的指令群所取代,新的指令群叫 SSH(Secure Shell)。SHH 相关网址(http://www.ssh.org)。
1982年的春季末,已厌倦了在柏克莱环境的 Bill Joy ,答应受邀加入当年刚创办的 Sun Microsystems , Inc. ,成为 SUN的第四号创办人。那年的整个夏季他就在两地奔走。之后他对修改中的弹性解译沟通机制及改写 UNIX kernal到一个段落之后,由 Leffler接手了他的工作。由于合约期限的因素,Leffler 在1983年 4月发表了 4.1cBSD,提供给参予 DARPA各项相关计划的成员试用。6 月,DARPA 的指导委员会第二次会议招开,验收与检讨最新版的 BSD 成果。继续整合 UNIX 系统的 Leffler,在 1983 年 8月,发表了 4.2BSD.她达到了DARPA 的预定的需求;足以应付 CAD/CAM影像处理与 AI 研究的高速的档案系统及扩展强化的虚拟内存功能;提供能分散处理的解译沟通机制;支持56-Kbit 的 ARPA Internet网络连结,以及 10-Mbit/s Ethernet 的局域网络;还有经过重组架构已模块化的 kernal code ,提供更有效率的计算机平台移植。
SUN 以生产 RISC 架构的工作站计算机为主,使用的正是以 BSD为基础所的UNIX OS.在当时以不逊色于大型计算机的多人多任务、具网络沟通功能的UNIX OS 、加上价格低廉的硬件(相对于 mini 级计算机而言),广获得工程界的青睐,而mini级大计算机的命运自此注定开始逐渐式微。计算机软件的应用因为有了网络于是也开始朝向 Client-Server的架构发展。
1982年,SUN 有了自己的操作系统—— SunOS 1.0——承袭自 4.1BSD.一直到 1990 年11月,发表 SunOS 4.1.1 版同时冠上 Solaris 1.0时,SUN 才算开始向 System V 版本靠拢。
SunOS 4.1.1 可算是以 BSD为主体再附加上 System V 工具的 UNIX 混血儿。但这其实是个商业考量的过渡性做法(后文会加以说明)。
而 SunOS 4.1.x版的字眼也仅延续到 1994 年的 SunOS 4.1.4为止,她后继的版本是 Solaris 1.3. 真正延续到今日的 Solaris版本,则是始于 1992 年 7月的Solaris 2.0 (SUN OS 5.0)。
在商业有所成就的 SUN Microsystems 对 UNIX OS的发展倒也做了些重大贡献;如 1984 年发表的 NFS(Network File System )与其后在 1986 年发表的PC- NFS.
商业化的不平坦历程—— UNIX 版本的战争
UNIX商业化实质上即意味着将产生各种独立化的 UNIX 版本,这点大概是最显而易见的事实。如果以商品要具备独特性与独占性的利益来做考量的话,其实一点也不意外。因此 UNIX 开始衍生的相当多的版本。这种现象,对使用者以开发应用程序的厂商而言,已经造成了某成程度上困惑。然而,一种无所适从的无力感其实才刚开始。
1984年 1月 1日, AT&T 这个拥有 1495 亿美元资产、1 ,009 ,000 位员工的庞大巨兽,终于被格林法官(Harold H. Greene)以反扥拉斯法(antitrust ) 强制拆解成七家 RBOCs(Regional Bell Operating Companies ) . AT&T 也因而在一夕间解体成为区域性网络公司,从此失去了长途电话的垄断性地位。这种时空的转变让 AT&T 对 UNIX 的态度有了 180度的转变(其实,农夫我指的是收费的态度)。
先前已经提过 70 年代初期的 AT&T ,已经在长途电话市场上占有绝对垄断的优势,因而被美国政府的限制不得涉足与从事计算机与其它行业,也正因而造就了UNIX发展初期的自由开放。直到 1979 年,AT&T才宣布要将 UNIX 商业化的计划。1981年 11 月,AT&T属下的USG 发表了 System III.次年又更新为System IV.稍后于 1983 年,AT&T 将 CRG, USG合并成立了 UNIX System Development Lab. 一般简称为 USL,从其名称就不难清楚她将要扮演的角色。该年 System V 上市了。此时 AT&T 发觉每次版本更新都得花不少宣传费,实在不划算,所以决定在 System V 以后,名字就不再做变动了。1984年,System V Release 2发表,简称为 SVR2.在这个版本中,才终于看到来自 BSD 版本的 Virtual memory 功能,农夫我不得不惊叹 AT&T 的稳健作风。SVR3则是到了 1986 年才发表,随后 1987 年又发表了 SVR3.2.
1987年,在工作站市场上已占有一席之地的 SUN,找上了 AT&T ,打算将System V与 BSD这两大版本归为一统。 1988年初,双方更签订了合作合约,AT&T取得 SUN的一席董事,同时亦有权买下 SUN百分之二十的股份。这项合作计划,原本有机会整合当时版本纷乱的 UNIX OS. 但那是理想。实际上这个计划反而让 UNIX 族群里的其它成员恐慌万分,特别是 IBM、DEC 、HP这几个产业龙头。为了抵制这项行动,他们组织了一个反对联盟。因此「开放软件基金会」也就是 Open Software Foundation 简称 OSF在 1988 年正式诞生;成员除了前面的三巨头外,尚有多达三十几家计算机硬件制造厂商与系统咨询顾问公司,也相继以行动投入到此反对的行列中。然而 AT&T 与 SUN也不示弱地组织了 UNIX International ,也就是UNIX国际公司,成员数量虽然不比 OSF阵营来的多,但如果她是 Intel、 Toshiba 、Unisys、Motorola、Fujitsu ,这几个大块头,那也是很够看头的。
企业自身的利益在现实世界里始终是以个体的考量为优先,所以这两大阵营始终没能再达成任何共识,就连当时所制定的 UNIX 统一标准规格,严格来说也从不曾被实现过。这种企业利益上的冲突与矛盾其实也存在于同一个阵营中不同的成员之间。两大阵营对峙,可以说是 UNIX 有史以来最重大的产业冲突事件。
由于商业利益的政治考量大过技术问题的考量,也因此奠定了 UNIX 将继续分裂下去的命运。 AT&T 在 1989 年发表了 SVR4 ,SUN 在日后也将她的 SunOS 4.1. 1 开始冠上 Solaris的字眼,以行动靠拢 SVR4.OSF 则是在 1990 年发表了OSF/1.UNIX版本的问题因而更加混乱了。但有趣且可笑的是,开放系统——Open System ,这个双方都标榜的理念与观念却因此在计算机产业界引起了回响,这点倒是原先所始料未及的。
不久 AT&T 撤销了对 SUN的投资,同一个阵营的成员彼此也因而劳燕分飞。
USL 在 1991 年正式转变了一家独立的商业公司。但 UNIX 在商业市场上的价值却出现了变化……
让 UNIX 自由—— Networking Release 2
自从 UNIX 走出贝尔实验室后,研究机构与学术界就扮演了继承与发展的双重角色。在1979到 1984 年这段期间,UNIX的拥有者 AT&T ,对于学术界的授权政策尚可用「大方」来形容;同时也对学术界做某种程度的资助与合作。当时的学术界,得助于 AT&T 的大方授权与分享程序原始码,研习 UNIX 这个分时操作系统开始在学术界蔚为一股风气,甚至可以说是一种潮流或一种流行。其中,像柏克莱 BSD对 UNIX 的贡献,就是一个公开的事实。但早期的 BSD使用者,是必需向 AT&T 支付授权金的。这点,从产业界资助学术界的角度来看是一点也不值得惊讶的。因为资金的援助为了就是取得其成果。所以当时基于 AT&T 原始码所发展的成果,均归属 AT&T 所有。也因而 AT&T 掌控了 UNIX 的所有权。到了1984年以后,AT&T开始更积极地保护 UNIX 的原始码;AT&T甚至还要求各大学的使用人员签订保密条约,想藉此防堵 UNIX 的原始码从学术单位流出,以影响到商业利益。
在 DARPA资助柏克莱从事 BSD OS 发展的过程中,诞生了 TCP/IP 这项广泛影响现今计算机与因特网的通讯协议。由于 DARPA对于资助开发的软件项目有明文规定接受资助者必须无条件地释出程序的原始码,所以 TCP/IP 的原始码与程序的版权并不属于 AT&T 所有。这点在现今看来其意义是不凡的。也正因为有此一条件,柏克莱的 CSRG (Computer System Research Group)因应 BSD Vendors需求,在 1989 年 6月发表了 Networking Release 1 ,她包含了TCP/IP source code以及一些工具,提供给当时正开始起步发展的个人计算机制造业者使用。Networking Release 1 授权收费仅 1000 美元,而且不需要 T&T的商业授权,取而代之的是柏克莱大学的开放式授权。
农夫我看柏克莱授权方式,几乎可以说是一种良心式授权方式,在实质的运用上她完全没有限制。她允许原始码或执行档在任何情况下修改并且允许将修改后的程序 从事商业行为而无须任何回馈,当然也没有绝对要求开发者必须要释出原始码。如果你改都不改地加以贩售,她也没有意见。但有一点不可违反的限制,就是必须在 衍生物的版权声明上提到柏克莱的贡献。这种做法在日后,也没有多少改变,而这样的授权方式也成为了柏克莱的授权精神。
Keith Bostic由于 Networking Release 1 所得到的响应实在远超过 CSRG 成员的预估。
这个不算差的成果,让柏克莱的 CSRG 觉得有必要释出更多属于 BSD的程序原始码。于是激发 CSRG 的成员 Keith Bostic开始组织志愿工作者从事一项就算不能够惊天也足以动地的程序写作计划。计划的主要目的在当时还真让人感到有点" 乌扥邦".农夫我个人喜欢戏称她为「解放 UNIX 计划」。
Marshall Kirk McKusick这项计划大体上分成两个部分,操作系统工具(Utility )
与核心(kernal)。而且参与人员必须在完全没有参考 AT&T UNIX source code的情况下进行撰写程序的工作。因为只有在这种条件下,写出来的程序代码,才能摆脱 AT&T 的着作权束缚。当然这也绝对不是一件容易的事。Keith Bostic四处奔走,组织了超过四百名热心的软件工程师,经过了长达十八个月的奋战之后,操作系统主要的工具与链接库才算改写完成。Marshall Kirk McKusick负责改写当时的核心程序。但系统核心的部分,由于长期以来柏克莱与 AT&T 一直就彼此分享 UNIX 原始码,所以各自所加上去的程序代码早已混杂难分了。为了彻底的厘清双方各自撰写的部分,他们下决心进行逐行比对。首先花了好几个月的时间,将核心程序每 一行每一个档案都建立转换比对的数据库。然后接着进行移除来自 AT&T 32V 的程序代码并改写她们。即使是如此,仍旧有 6只程序让他们束手无策,因而无法将核心程序彻底完整地改写。最后,他们还是决定将他们所做的所有成果发表。授权的方式沿用 Networking Release 1 的授权方式,授权的磁带依旧是 1000 美金。这个版本就是 Networking Release 2 ,也有人称她为 4.3BSD NET/2.发表的时间在 1991 年 6月。虽然这是个不完整的操作系统。
但,在今日看来,却有着划时代的意义—— UNIX OS自由了。
谁是" 老大哥" ——侵权诉讼
AT&T的 USL在 1991 年正式转变了一家公司。当然,这意味着她将更重视UNIX在商业上的利益。当时的 UNIX OS早以称霸高阶的计算机市场;从 Cray 超级计算机、IBM 的大型计算机主机、迷你级计算机到工作站,均是 UNIX 的天下(这一点,直到现在21世纪,仍旧没有多大的改变)。即使在 80 年代中期后开始迅速发展的个人计算机,虽然当时被戏称为是玩具计算机,但也仍旧有像XENIX[注1], Interactive UNIX[注2]等几种向 AT&T 缴过税的商业化版本。
UNIX简直就是 AT&T 的一棵摇钱树。
但这一切在 Networking Release 2 (以后简写为 Net/2)出现之后,起了变化!
首先,一位 i386 处理器的玩家名叫 Bill Jolitz,在拿到 Net/2之后,很快地就将 Net/2 kernal 缺少的程序补齐了。BSD kernal这时可算是大功告成了。
当时 Bill Jolitz将他们放在因特网与其它人共享他的原始码,并且得到了不少正面的响应。由于这个版本是使用在 i386 微处理器的个人计算机上,所以就命名为386BSD,在 1992 年 2月正式发表。这该算是 BSD首度功能完整且版权独立的版本。Bill Jolitz 是当时唯一的 kernal 维护者。在他离开这个计划之后,继起的 BSD玩家们延续了这个版本,日后衍生了 FreeBSD,然后又从其中分支出裂NetBSD版本。
另一个将 Net/2完整化的是一家叫 Berkeley Software Design ,Incorporated的公司,简称 BSDI[注3]. 由于 Net/2的版权声明中,宣称其源文件的合法性,并且允许使用者,从事衍生物的商业行为,所以 BSDI 将他们修改后的系统命名为 BSD/386. 他们并将成果打包,刊登广告以 995美金的售价贩售 BSD/386,而且含原始码,而且还提供免费服务电话的咨询,电号号码是"1-800-ITS-Unix". 时间大约是在 1992 年 1月。当时,USL 的 System V 含 source code的价格大约是 BSD/386价格的一百倍左右。这可惊动了老大哥 AT&T.并且正式地书面严重警告 BSDI 违反的注册商标法(电话号码里有Unix的字眼),并公开宣称 AT&T 拥有 UNIX 的注册商标。BSDI再次刊登广告公开反击 AT&T ,声明她的商业行为完全合法。果不期然,BSDI的博命演出让双方手牵手走上法庭。
AT&T的 USL控告 BSDI 剽窃他的 UNIX 原始码,要求法官还他公道。在听证会上,BSDI祭出早已准备好的法宝;自己在无任何 AT&T source code 的条件下写出的合法档案,以及来自于 BSD授权的 Net/2 source code. 前面的证据足以让 BSDI 立于不败之地,后者让 BSDI 置身在暴风圈外。BSDI的辨证获得了法官的采信。但 At&T 岂会就此罢手,他们将焦点转移到 Net/2的 BSD授权上面,并且重新提出控诉,被告的对象变成了 BSDI 与柏克莱大学;同时 AT&T 还申请法庭禁止 BSDI 一切的 BSD/386销售行为。就这样,柏克莱大学也对号入座了。
农夫我认为,毕竟 AT&T 是营利企业,她得维护她的商业利益,这点是天经地义的事。
虽然柏克莱大学与 AT&T 在 UNIX 发展上有着非比寻常的关系,但商业利益是现实的。企业资助学术界的研究计划,多半是基于商业上的考量;我相信,学术界的少数高层在寻求奥援时不会不明白这 一点,即使这有可能让大部分的学术人士无法接受或不愿接受。不管如何,这一记醒棍倒再次挑起了这一点事实。
成为被告的柏克莱大学,只好无奈地面对这场无情的商业诉讼。但他们也同样不甘示弱地对 AT&T 的 Systerm V 着作权提出质疑,因为在 AT&T 的 UNIX 授权声明中完全没有提及柏克莱的贡献。所以柏克莱反控 AT&T 违反 BSD 的授权条款。柏克莱的反击让战况越演越烈,诉讼案一路从 AT&T 的老家新泽西州的联邦法庭打到柏克莱大学的所在地加州法院,但依旧没有结果。
到了 1993 年,官司还在进行中,但 AT&T 却已经打包 USL准备以一亿美元的价格找寻买主了。最后 AT&T 将 USL 以八千万美元代价的卖给了 Novell.而新买主也当仁不让地加入了这场混战。但却也因此,战况露出了一线平息的曙光。
诉讼案在 1994 年 1月宣告终结,以庭外和解收场。实际的协议内容仅有当事人知情。
如果从胜负的角度来看这场诉讼,或许柏克莱与 BSDI 是胜利的一方。但如果从UNIX发展的脚步来看这场诉讼,就可能根本没有任何一方是胜利者了。
事件平息后的 1994 年 6月,柏克莱的 CSRG 风光地发表了 BSD 4.4 Lite.在这个版本中,有 70 个档案引用的一份新修改的版权声明,阐述的 AT&T 与 BSD双方的贡献,并明确地给予档案自由散播的权利。但不知为何,应该有能力完整发表的 BSD 4.4 Lite 还是缺少了三的档案。当时,农夫我也很高兴地买了一本BSD4.4-Lite CD-ROM Companion ,含一张光盘,现在拿在手上,看来总觉得有点呆。
掌握 UNIX source code 以及 UNIX 商标的 Novell ,将 UNIX 商标交给X/open管理,自己则发展了一套命名为 UNIXWave 的操作系统。推出后市场的反应并不热络。不久,Novell与 SCO接头,在 SCO保证继续支持UNIXWare 的条件下,UNIX在 1995 年二次易主,新主人是SCO[注4].
备注:*1 Intel在 1978 年发表 4.77 MHz 的 8086 微处理器。1980年,Microsfot 便以 V7 为基础,发表了在微处理器(microprocessor-based computers)上执行的版本也就是 XENIX. 到了 1982 年,一家成立于 1979 年的软件公司 Santa Cruz Operation ,成为微软的合作开发厂商。之后她这家公司便一直致力于这个领域里延续到今日,缩写就是今日的 SCO.
*2 Interactive IS/1 (以 V6 为主体)。这个版本后来演化为比较让人熟知的名字—— Interactive UNIX. 后来因为 Sun Microsystems 致力发展 Solaris for X86,被财力雄厚的 Sun Microsystems 合并了,如今已经不见踪迹了。
*3就在我反复修改这段文稿的时候,BSDI这家公司已经被 Wind River 合并了,改名为iXsystems.2001/05/03
*4 2001 年 5月 4日,Caldera International , Inc. 正式并购了 SCO的服务器软件部及SCO 专业服务部这两个部门,新的控股公司名为 Caldera, Inc


400) {this.resized=true; this.width=400; this.alt='Click here to open new window';}" onmouseover="if(this.resized) this.style.cursor='hand';" onclick="window.open('/upimg/20070420/11M10351DZN248.jpg');" border="0">


400) {this.resized=true; this.width=400; this.alt='Click here to open new window';}" onmouseover="if(this.resized) this.style.cursor='hand';" onclick="window.open('/upimg/20070420/11M10351HPY959.jpg');" border="0">
GNU 计划——开启了新大道
在 1983 年 9月 27 日,麻省理工学院人工智能实验室(MIT Artificial Intelligence Lab )的 Richard M. Stallman(以下简称为 RMS),在net.unix-wizards以及net.usoft 的 newsgroups 贴上了一份标题为 "new UNIX implementation" 的讯息。这就是如今广为人知的 GNU计划的开始。在那则被视为「GNU 宣言」草稿的讯息中,RMS 阐述个人的理念与计划的目的——完成一个命名为 GNU的 "Free UNIX"操作系统,希望藉此寻唤理念想同者共襄盛举。
「如果我喜欢一个程序的话,那我就应该分享给其它喜欢这个程序的人」,这是RMS 的座右铭。此点也似乎正是促使其决心运作 GNU计划的原动力。当时的RMS 是想写出一套免费的操作系统。能够让每个人如空气般地自由的取得与使用。
选择“UNIX兼容”为设计的主要原因是;RMS 表明,UNIX并非他个人理想中的操作系统;他仅阅读一些相关数据,但未曾使用过(MIT 使用操作系统是"ITS——Incompatible Timesharing System");但他认为 UNIX 操作系统具有优良的本质特性。他相信如果 GUN与 UNIX 兼容将更容易令人接受。所以 RMS承袭 MIT用递归缩写字命名的传统为 GNU释译界定 Gnu is Not Unix.
1984年 1月,RMS 为了展开他的理想而决心离开已经待了十几年的 MIT AI Lab.。当他向他老板 Patrick Winston 辞职时,Winston 试图挽留地说:「你还是要辞职?」。RMS 不为所动的回答:「是」。Winston 显然得到预料中的答案,于是接着说出了思绪里关怀:「你想要保留你的钥匙吗?」。于是 RMS就从此开始专心地" 失业" 在他的老东家。一个人窝在他原来的旧办公室中,规划着如何开始他的 GNU计划。但想开发一套新的 UNIX 兼容的操作系统,即使是财力、人力资源雄厚的顶级计算机公司,也绝对不是一件说想做就能够做到的事。
当拟妥他的「GNU 宣言」之后,他正式向全世界呼唤、表明其将所为。种子落地了。
GNU 计划的第一只程序要算是孤军奋战的 RMS在 1984 年 9月开始撰写的Emacs 编辑器。
1985年初,Emacs 已进入可用的阶段。于是 RMS将她放在pre.ai.mit.edu这台机器的 FTP server 上,免费地让 amonymous的到访者自由下载使用。不久后,Emacs 强扞的功能引发了一些玩家们的注意,由于附上了 source code,玩家们能自己动手为它添加新的功能或除错,很快地,Emacs 获得了相当热烈的回响。随着名声渐播,开始有人相继地加入 GNU计划的程序写作阵营。" 此道不孤" 让 RMS倍感振奋与喜悦。
当时的因特网并未十分普及。所以有不少人虽然对 Emacs程序有兴趣,却没办法经由 FTP的管道取得,因而有人透过其它管道向 RMS询问能如何取得时,这可让当时处在失业状态的RMS 看到能够支持他继续奋战下去的资金来源——贩售" 自由软件".
一个人、一个独立的个人,要想在现实中实行自己的理念,最先得接受" 现实".唯有接收它是事实,实行理念的道路,才获得比较稳固的起点与开始。 ——网络农夫如是说。
想着、写着,脑中突然掠过一丝感受(所以顺便记录在这个地方)。不管如何,RMS 真的开始以一卷磁带 150 块美金的代价,服务有需要的人。也因为基于这个开始与基础,RMS 当年便创立了自由软件基金会—— Free Software Foundation(以后简称为FSF )。这对GNU 计划而言,意味着它已跨越个人化理念的构思阶段,并进入了有群体组织化的运作阶段。
同时,RMS 也制定出了属于GNU 计划的软件版权。RMS 使用 "copyleft" 用来形容她,其实就是与着作版权(copyright ) " 对立" 之意。这也就是 GPL—— General Purpose License(通用公共授权)。
GNU 计划的种子,就这样生根发芽了。
从贩卖 GNU自由软件扩展到其它的相关软件与参考手册,提供软件技术支持,并接受计算机器材与资金的捐助(捐助者依法享有一定额度的减税),为企业代训软件人 才。FSF 努力地开辟财源却仍旧是运作资金捉襟见肘。RMS 本人并不支薪。而FSF 聘请软件工程师的待遇,也仅是软件业界薪资水平的一半。但这绝不表示GNU 计划的软件水准是半桶水。GCC 编译器是 GNU计划在 1987 年 3月开始发表的免费编译器,当时的版本是 0.9测试版。如今最新的版本则是 3.0. 这个编译器可以说是今日自由软件写作的基石。GCC 所解译的机器码,其可靠度绝对不逊于商业化的编译器产品,甚至可以说是优越过商业编译器。
90年代初,GNU 计划暨已完成了质量与数量均十分可观的系统工具。这些工具被广泛的使用在当时各种工作站的 UNIX 系统上。虽然已有如此的成果,但仍称不上是完整的操作系统。他们缺少一支属于自己的" 核心程序(kernal)".
UNIX在 4.2BSD 之后,越写越大 kernal 开始带来一些不便与问题。因而当时便开始有另一个写作理念逐渐在发展——微核心(microkernal )理念。
1985年,卡内基大学(Carnegie Mellon University简称 CMU)暨以 4.3BSD 为发展基础,将之一拆为二,分成 micro kernal 与 single server两个部分。
该计划的名称为"Mach". 这个计划成了微核心发展的技术先河。GNU 原本有意直接采用"Mach"计划的成果。但无奈,这一等,从80年代中等到了90年代初,在几经商量之后,他们打算采用微核心的写法,成立自己的计划, 名称叫"Hurd". 这项计划,如今仍在奋战中,虽然 microkernal的做法让他们吃了不少苦头;但可喜的是,0.2 , 0.3 测试版本已经发表。
直到 21 世纪的今日,RMS 依旧努力不懈地耕耘着他的梦土。尽管他本人认为还尚未完全地实现他的「GNU 宣言」;但他执着于理念的行动,已凝聚了相当数量的自由软件写作族群们,在这些人与群体的努力下,一条新的大道其实已经被开拓出来了,她通往一个新的世 界。大道旁,枝叶已然繁茂的树荫下,可口果实一如礼物般地为所有的人成熟。人们称她—— Linux.
新世代的焦点—— Linux
1990年代中期,因特网因出现 World Wide Web , HTML 这种新型态的应用,而开始迅速的延烧全世界。一夕间,架设因特网主机的需求激增。这时有一套可以免费取得,并且能让 x86计算机升格成 UNIX 级主机的免费操作系统,开始了吸引全世界目光。在传媒与计算机工程师们的竞相走告下成为了这个新世代的焦点,这个新的名字就是 Linux.
Linus Benedict Torvalds 当然,这套媒体吹捧的当红炸子鸡,可非一人之功,一夕即成的。Linux 是一套版权彻彻底底与 AT&T 无关的 UNIX-like OS.原始核心程序的创作者是芬兰籍的 Linus Benedict Torvalds(现今他仍旧是核心程序的维护者)。操作系统里大部分的系统工具,来自于 RMS行之多年的 GNU计划成果,以及其它的自由软件写作计划产生的软件,如 X Windows、KDE 、Gnome 等窗口接口。由于构成操作系统的主要部分均奉行 GPL 版权,所以市面上有相当多样的安装套件,目前较广为人知的有 RedHat 、Slackware 、SuSE、Debian GNU/Linux ……。也因此,这套操作系统,可说是包含了无数字自由软件写作者的共同心血。
如此的一套操作系统其实也就是 RMS多年来想要达成的宿愿—— "Free UNIX". 所以,RMS 本人总认为该将名称改做"GNU/Linux".因此,也有人用 GNU/Linux来称呼这个操作系统。
Torvalds打从十岁出头当他外公的" 键盘手" 开始,到了中学就已成了不折不扣的计算机迷。1990年,当他就读赫尔辛基大学(University of Helsinki) 信息系二年级,选修一门「C 语言与 UNIX 操作系统」的课程,因而疯狂地迷恋上了UNIX操作系统。那年正好赫尔辛基大学正好添购的一台 VAX,安装 Ultrix 操作系统。连接了 16 台终端机供授课师生使用。有所限制的计算机资源,对一位计算机迷来说是极痛苦忍受的。
Torvalds开始作梦想" 搞" 一套可以在自己计算机上跑的 UNIX.
1991年 1月,Torvalds利用 "学生贷款" 加上去年的 "耶诞红包" ,以分期付款方式买了一台 386 DX33 个人计算机(他的第三台计算机)。他选择安装的操作系统则是在学术界颇负盛名的 Minix[ 注5]. 在几番奋战下,就绪运作的 Minix OS 功能性却多方面无法满足Torvalds的需求,因而激发了他重头来的欲念。于是 Torvalds 在他的 386 DX33 上逐步探索并撰写出他自己的核心程序。他网络上释放的第一个版本是 1991 年 9月 17 日的 0.01 版。虽然她是个简陋的开始,但由于 Torvalds 本人持续维护与网友回馈贡献,原本一个人所撰写的核心程序竟在不知不觉中逐渐转化成 "虚拟团队" 的运作模式。
然而,一般计算机使用者,需要的是可安装运作的操作系统(农夫我习惯以" 安装套件" 称之),而非单一的操作系统核心。当时英国的曼彻斯特电算中心(Manchester Computer Center,简称 MCC)便根据 0.12 版核心程序制作了一套名为 MCC Imterin的安装套件。随后各地的安装套件有如雨后春笋般地出现;如美国德州 Dave Safford 的 TAMU (Texas A&M University)版、Martin Junius 的 MJ 版、Peter McDonald的 SLS(Softlanding Linux Sustem)版等非商业安装套件的出现。在安装需求日增的情况下,Linux 安装套件创造出了一块新的需求市场。这一线商机,让非商业安装套件的也开始出现在商业市场上。Slackware 大概可算是最早出现的商业安装套件了。到如今,商业与非商业的安装套件则已多得数不清了。
随着使用人数激增,核心程序的版本与功能也开始加速演化,但仍不失于稳健。
1994年 3月 13 日,核心程序 1.0正式发表。其安装套件在功能上的整合已急起直追当时商业版的 UNIX OS. 此时的 Linux OS 已拥有数十万名使用者。当时赫尔辛基大学还以此为由举办了一场名为"Linux首度正式发表会". 就在芬兰电视台与众多传媒的郑重其事的报导下,Torvalds成了芬兰人的自豪,Linux OS宛如刚诞生的" 超新星" ,闪闪发亮地展现在众人眼前。
早期的 Linux核心程序曾被 Andrew Tanenbaum 指出,过度紧密地与 x86处理器结合,所以他认为 Linux核心程序将无法移植到别的处理器上。这点显然与UNIX OS 的可移植性大不相同。当时的情况的确是如此,这或多或少与Torvalds本人受限于拥有的硬件资源有关。
但当 Linux的使用族群拓展开来之后,便开始有人主动地将她移植到不同的平台上。像 Dave Miller即以不下于Torvalds狂热与学习精神将 Linux成功地移植到 SUN的 SPARC工作站上。
此外如 Amiga、Atari 、PowerPc 、MIPS R4000也陆续见到 Linux的身影。
这些移植严格地从技术的角度来看,仅能说是" 个案".但这已激发 Torvalds 的兴趣。
真正撼动 Linux核心的移植是对 Alpha处理器。
1994年 5月,在 DEC使用者协会上,Digital 的工程师 John Hall(外号Maddog) 碰上了 Torvalds ,双方一见如故。Maddog力劝 Torvalds 将Linux 移植到 Alpha芯片上,并主动提供了一台 Alpha 计算机供 Torvalds 研究使用。当年可说是全世界最快的 64-bits Alpha芯片是 DEC引以为豪的一项成就,其架构与功能均优越过同一时期的 Intel 32-bits处理器。这种技术性的挑战吸引了 Torvalds 的投入。这项移植,但这对原先以 x86微处理器为写作基础的 Linux核心程序而言,实在不是一件小工程。在 Torvalds 与 DEC相关人员的将近一年奋战后,Linux 核心程序脱胎换骨,成功地移植到 Alpha处理器上(与 x86处理器使用同一套程序代码)。1995年 3月,被戏谑是 Linux'95 的1.2 版核心程序正式发表,支持Intel x86 、DEC Alpha 、SUN SPARC 、MIPS等处理器。
1996年 6月,核心程序版本由 1.3直接跃升为 2.0版。Torvalds本人正式钦定了一只" 企鹅" 作为 Linux的标志。同时也开始支持对称式多重处理器(Symmetric Multi-Processing,简称 SMP)架构的计算机;而支持的处理器则又多了 Motorola 68k 和 PowerPc. 在自由软件团体们的努力与计算机产业业界的支持投入之下,Linux 具备的功能逼近商业版 UNIX OS. 当然,Linux 要达到" 成熟" 与" 稳定" ,实际上还有好长的一段路要走。
时至今日,散播在全球各地的 Linux虚拟发展团体,仍旧持续地发展中。能维持到什么时候?这在将来的历史自有答案。但至少在现今,一个 RMS奋斗的目标——可自由分享程序代码的操作系统,已可贵地呈现在我们的眼前。
备注:*5 Minix是 Andrew Tanenbaum 教授为教学目的而撰写的操作系统。
在教育界可算是一套学习 UNIX 基础的好范本。


400) {this.resized=true; this.width=400; this.alt='Click here to open new window';}" onmouseover="if(this.resized) this.style.cursor='hand';" onclick="window.open('/upimg/20070420/11M10351K6092622.jpg');" border="0">


400) {this.resized=true; this.width=400; this.alt='Click here to open new window';}" onmouseover="if(this.resized) this.style.cursor='hand';" onclick="window.open('/upimg/20070420/11M10351N20109221.jpg');" border="0">

新文明世纪自由共享
到此,这一段关于 UNIX 发展的文字,已从过去的历史当中走回到了今日…
… 21 世纪的今日。本文也接近尾声了。请诸位原谅农夫将以极为自身的历史感受,来作为本文的结语。
阅读与探究历史,是农夫个人在年轻时即有的一点小癖好。通常我无法忍受对自己喜好事物的缘由一无所知。所以我会想办法去探究她由谁所创、因何而生与发展的沿革。也正因为如此,我才会为 UNIX 这个当初我没能在英文字典上找的怪字,写了这么一篇文字。
然而在 UNIX 的发展过程当中,我惊讶地发现了一项有别于我探索 20 世纪历史的东西。
我相信诸君应该清楚,20世纪是人类文明史上最为血腥残暴的一段岁月。在其间,多数民族的上个世代所遭逢的苦难,都是空前的。哲学家柏林(Isaiah Berlin )回顾 20 世纪的感受,说了以下这样的一段话。
「我的一生——我一定得这么说一句——经历了二十世纪,却不曾遭逢个人苦难。
然而在我的记忆之中,它却是西方史上最可怕的一个世纪。」
的确,每当我阅读 20 世纪的相关史料,我就更能加倍地感受到这份莫名的幸运。我生长在台湾,这块回顾其历史仅能以" 悲土" 称之的岛上,她的苦难直至今日亦尚未完全结束。
尽管多数年轻的一代已然淡忘,来自何方,归往何处。
身为一个中国人,站立在这块似乎仍将被同胞武力相向的孤岛上……我已不清楚历史伤口会因得到同胞的爱而痊愈,还是再次因人类残暴掠夺的天性而迸裂……
抱歉,离题了。
我想说的是,在 20 世纪未的因特网时代中,我感受到了令人喜悦地,根源于心、跨越既有疆界藩篱的自由共享文明。这相较于 20 世纪初将" 战争" 视作为文明象征的人类而言,实属无价可贵的进展。即使这文明仍仅是刚播下的种子。
但我相信,她将如贝聿铭所言:
「你永无法明确知道你已播种的东西何时可以收割;或许只有一次收成,或许可重复收成。你也许遗忘曾播种了些什么,一种经验,一种感受,与某人的关系,抑或一种哲学及一项传统。然后,忽然间就开花了,被全然不同的环境所唤醒。这种盛开可以冲破藩篱及整个时代。」
多希望亲眼看到,几个世代后的某日,人类彼此掠夺的行为如天花一般地在人类社会中绝迹;而,共享已成为人类整体奉行的道德公理。如果这样的一个社会是我们今日所企求的;那么,这个方向与希望,就值得你我花一生的精力去努力。
当然,这仅只是一个个人的希望,我也清楚这世间并非如此美好。但,如果因假设一件事物不可能做到,而决定不去做;那是假设得到胜利,而非真实的事实。
或许过去的历史,曾经证实正义、公理、平等与理想的胜利,不过是短暂的昙花一现;那又如何。只要我们不放弃希望,希望就有机会成为真实。今日,所有的美好均因此得来,明日也是。
这几年来,我已看到不少因特网上诸君们的努力。我也相信这崭新文明的种子,有朝一日将展现出令人赞叹、愉悦的美景。未来存在我们尚未发现的国度。
我相信,我们能发现未曾走过的通道,打开不曾打开的门,进入玫瑰园中……那会是一个崭新的文明。


摘自:http://www.oklinux.cn/html/other/unix/20070421/21330.html

posted @ 2009-11-15 15:56 石头@ 阅读(2123) | 评论 (0)编辑 收藏

测试你的C语言掌握程度

字符串 
学习时间:1.5W(“W”周,下同)
知识点checklist
strlen()函数的返回值是什么类型的?
字符串strlen()的值,是否和他占据的内存空间相同?
你是否知道strcpy函数存在的潜在风险?如何避免?
如果一个字符串没有字符串结束符,而调用str开头的库函数,会发生什么?
Strcpy(),strcat(),strcmp(),strncpy(),strncat(),strncmp()内部到底是如何运行的?这些函数到底对源字符串和目标字符串做了些什么?你是否观察过它们运行时两个字符串内存的变化?
上面这些函数使用时,各有哪些需要注意的地方?
你会几种字符串查找操作?
c语言中有字符串这个数据类型吗?
对字符串进行操作的时候,是否为字符串结尾符预留存储位置?不然的话容易造成非常访问内存。

数组
学习时间:2W
知识点checklist
你肯定知道,定义“int a[10];”,a[10]这个元素是无效的。
你知道几种数组初始化的方法?
数组和指针有千丝万缕的联系而又不同,你是否对他们在不同情况下的使用进行过详细的总结?
“int calendar[10][20];”,这是一个什么样的数组?它拥有10数组类型的元素,还是20个?
“int a[10];”,数组名a在本质上是一个什么?你是否打印过a的值?
你知道几种获取数组某元素的方法?
指针和数组相同吗?什么时候相同?什么时候不同?
用指针和下标访问数组元素,那种方式更快?

结构体
学习时间:1W
知识点checklist
你知道什么是位域结构体吗?如何定义它?如何使用它?
你知道字节对齐对结构体占用内存空间大小的影响吗?如何计算结构体占用内存的大小?


学习时间:1W
知识点checklist
你知道宏的本质是什么吗?函数?语句?类型定义?或者其他?
你知道语言设计者为什么设计宏吗?这些原因目前是否仍然成立?
你会设计带有参数的宏吗?
你知道使用宏的参数的的时候的注意事项吗?
你会设计带有可变参数的宏吗?
你知道使用宏有什么劣势吗?
你有没有更好的替代方案?


枚举
学习时间:0.5W
知识点checklist
是否可以指定枚举中各项的值?
如果不指定值,枚举的第一个值是多少?
枚举的值是否可以是负数?
定义枚举的时候,你是否专门定义了枚举的最小值和最大值?


Switch
学习时间:0.5W
知识点checklist
switch(c)中的c的数据类型有哪些?
你是否在所有的switch中都加了default语句?
是否在所有的case中都加了break语句(一般情况的做法)?如果你不加break,将会发生什么?


Static
学习时间:1W
知识点checklist
static的三个主要作用是什么?
static的修饰的局部变量是保存在什么地方的?全局变量哪?
static修饰的全局变量和函数,在其他的文件中是否可以访问?如何访问?
你知道static是c语言中实现封装和隐藏的利器吗?你是否经常使用?
定义在不同源文件中的static全局变量,编译器是否允许他们的变量名称相同?他们在内存中的地址是否相同?函数那?


const
学习时间:1W
知识点checklist
你是否经常使用const来表明不能够被更改的变量?
你是否经常使用const常量来代替宏?
下面四种情况,你知道是各表示什么意思吗?
int  i_value= 10;
const  int* pvalue = &i_value
int  const *pvalue = &i_valueint*  const  pvalue= &i_value
const  int* const  pvalue = &i_value
你知道const常量如何初始化吗?


Sizeof
学习时间:1W
知识点checklist
对于字符数组,strlen和sizeof的值是否相同?
Sizeof本质上是函数还是宏?
Sizeof的返回值是什么类型?


指针
学习时间:3W
知识点checklist
“int *p;”&p,p,*p他们的值分别表示什么含义?
你定义的指针初始化了没?
你理解指针的指针的概念吗?你会使用吗?
“int *pi_value; pi_value = 0x100000;” pi_value + 1的值是是多少?
你会定义函数指针吗?
你会使用函数指针调用函数吗?
关于指针和数组,请参见知识点数组。


动态分配内存
学习时间:1W
知识点checklist
动态分配的内存是保存在什么地方的?
什么情况下使用动态分配内存?
动态申请内存一定要释放,否则会内存泄露。你是否使用过内存检测工具?


函数
学习时间:1W
知识点checklist
如何查看函数在内存中的地址?
如何给一个函数指针赋值?
你是否会定义可变入参函数
你是否可以区分函数的形参与实参?
如何定义函数名,以准确的表达函数的用途?
你是否使用const来修饰函数入参和返回值,以表的特定的含义?
递归如何使用?

变量
学习时间:1W
知识点checklist
全局变量,局部变量,常量分别保存在内存中的什么地方?
不同类型的变量,你是否知道其作用域?
全局变量和局部变量是否可以重名?你是否在这样做?
局部变量在函数退出后是否有效,为什么?
全局变量为什么不允许定义在头文件中?有何危害?

链接(linux)
学习时间:1W
知识点checklist
链接位于编译过程的那个阶段?
动态链接库和静态链接库使用时有何区别?
如何对动态链接库进行动态加载(不用重启程序而加载链接库)?
动态链接有何优点?
动态链接库中是否定义了非static的全局变量?你是否知道这是一个非常危险的动作?
动态库中的全局变量(非static)和函数(非static)是否可以和上层全局变量和函数重名?重名后会发生什么事情?


运行时的数据结构(linux)
学习时间:1W
知识点checklist
你知道什么是段的概念吗?
可执行程序可以分为几个段?每个段保存的是什么内容?
如何查看可执行程序各个段的大小?
当函数被调用时发生了什么?
你有没有试过程序的栈空间最大有多大?程序超过此大小会发生什么?
你使用的系统的栈是向下生长的,还是向上生长的?

Include
学习时间:0.5W
知识点checklist
1、如何避免对同一头文件的多次include?


声明
学习时间:1W
知识点checklist
什么是声明,什么是定义?
你是否会运用c语言声明的优先级规则?


关于复杂度:
软件的首要技术使命是管理复杂度。
优秀程序员的一个特质是将复杂的事情简单化,而非将简单的问题复杂化。所以,他们一般会选择简单的解决方案。
极尽机巧,复杂的解决方案,除了将新手搞得晕头转向之外,别无他用。
阅读优秀程序员的代码,是一种享受,你很少遇到思维的阻力,你可以尽情的享受简单之美。
所以,对难以理解的语言特性,要慎用、少用,最好不用,而以简单的解决方案替代之。但是,在做这些之前,你必须对这些知识点理解深刻。

如果你发现有什么错误,请和我联系。
如果这些知识点你90%以上都不知道,或者理解不深刻——我希望你可以加入DS计划,共同学习。
如果这些知识点你90%以上都知道,并且理解深刻——我希望你也可以加入DS计划,成为知识点专家,对新手进行指导。
如果你知道的比上面列出的还要多,或者还有你认为非常重要的,建议你也分享出来,对上面列举的内容进行优化。

原文地址:http://blog.csdn.net/chgaowei/archive/2009/10/27/4731498.aspx
DS计划加入方式:
1、 方式1 :加入 QQ 群: 93684322 。
2、 方式2 :加入 CSDN 群组: DS计划 。 

一位网友的建议

对《C方向项目详细计划》的一点建议
作者:陈新
原文: http://hi.csdn.net/space-1568678-do-thread-id-990.html
首先自己介绍一下,我已经工作多年,目前半管理半开发,主要使用PHP和C语言,对于C语言有过一定研究,有一些经验。
我很少上CSDN,虽然已经注册了很长时间,今天心血来潮进来看看,就发现了常高伟的的帖子《深入学习C语言知识点checklist——测试你掌握C的程度》,仔细看了一遍,觉得还不错,这年头还执着于技术细节的人很少了,可见作者还是下了不少功夫的。
接着就看到了“读S计划”,觉得有点意思,看完之后就有了写这个建议的冲动,希望对大家有所帮助。

关于c语言知识点本身,还是挺全面的,如果一个人大部分问题都能详细解答,说明这个人对C语言的了解还是很不错的。
不过我还是有几点建议:
1、知识点组织得不是很好,显得有些凌乱,有些相关知识点被分割到了多个地方,有些不够全面,从学习的角度来将,不是非常好。
例如开始就从字符串操作讲起,我觉得不是很好。原因是字符串操作只是库函数,对于c语言的字符串,我们开始只要知道是0结束就够了,函数后面在慢慢学习。了解字符串函数最好的办法,就是自己实现这些函数,然后跟源代码进行比较,找出差距。
例如宏和Include,不应该分开,而应该作为预处理统一学习。预处理主要包括宏替换、文件包含和条件编译三部分,另外的一些慢慢再了解就可以了。
此外,我觉得应该把static、const这些限定词和变量结合在一起学习,顺便把其它限定词auto、extern、register、 volatile、restrict、inline等整合在一起,从变量的类型(存储格式)、生命周期、作用域、可视性、存储分配等各种角度出发进行说明。
2、有些提问不是很恰当。
例如sizeof本质上是函数还是宏?因为sizeof既不是函数,也不是宏,这么提问容易让人产生误解。要想弄明白sizeof具体是什么,至少要明白编译的整个过程,弄明白编译时和运行时的概念。
例如数组提到的定义int a[10]; a[10] 这个元素是无效的。这种说法并不完全正确,a[10]并非无效,如果真弄明白了具体含义,完全是可以这么使用的(当然一般不推荐)。
3、学习时间的安排
像Switch、枚举之类的,如果有人讲解,一天就足够了。而数组应该和指针放在一起,由于指针是c语言的难点之一,恐怕3周的时间都不一定足够。
4、应该把c语言的学习当作当作一个系统,分成多个阶段。
个人觉得分为三个阶段比较合适:
第一阶段是c语言本身,主要是类型、操作符、表达式、语法结构、函数、指针、数组、结构等,想完全弄清楚这些其实很不容易。入门可以参照谭浩强的那本教科书,不过这本书只适合了解一下,不深入,而且里面有些地方和例子都不是很好。还是推荐K&R的《The C Programming Language》,最好是英文原版的。这阶段可以同时学习《数据结构》,尝试实现一些链表、树的操作。
第二阶段是结合着实际情况,加深对函数以及相关知识的认识,试着编写一些小软件,实现一些小功能。可以和《APUE》一起学习,里面讲到的例子都可以自己写一下。
第三阶段是深入学习编译原理、操作系统等知识,了解代码是如何从文本文件一步一步变成可执行文件的,知道栈、堆分别是什么,清楚程序的存储空间布局,库函数和系统调用的区别等。这阶段可以在某个方面深入下去,编写一个比较大的软件,例如一个简单的网络程序、数据库系统或者编译器等。
因此知识点中的链接、运行时的数据结构、结构体中的内存对齐等和其它知识点放在一起并不是很好,毕竟大部分其它大部分题目都是c语言本身的知识,而这些知识点不少都是要看具体实现的,甚至有些并没有标准答案。

另外,还有一些题外话:
1、现在已经比较少使用c语言开发软件了,c语言对开发者的要求比较高,c语言不是一天两天就能掌握的,因此首先要弄清楚自己是否真的对技术感兴趣,对技术有种刨根问底的冲动,而且愿意为此花功夫。如果仅仅是想搞搞应用,要快速实现某个功能,而不追求效率,不在乎具体实现方式,最好还是去学习更高级的语言。
2、 c和c++不是一个语言,所谓c++是c语言的超集也是不正确的,如果当初c++的名称是d语言之类的,可能就不会有这么多麻烦了。最主要两者的指导思想是不一样的,c语言默认其使用者什么都懂,所以将一切的控制都交给开发者自己去完成,语言本身不作太多限制,给开发者最大的自由度。这么做的好处和坏处都是非常明显的,没有谁比谁好的问题,只有是否适用的问题。
3、语言本身只是一个工具,将我们了解的计算机知识发挥、展示出来的工具,但基础知识远远比语言本身更重要。如果认为学好了一门语言,就是所谓的高手了,那是不切合实际的。当然语言本身也需要我们花费很大精力,毕竟掌握好一个工具,更能让我们的工作事半功倍。


摘自:http://topic.csdn.net/u/20091027/22/0573CFB5-F1BF-4CF2-8E60-13D907301A8E.html

posted @ 2009-10-31 13:10 石头@ 阅读(548) | 评论 (0)编辑 收藏

看看吧! 朋友。


成功经验宝典100则
1、王宗立说:每天早上游泳(输入正面潜意识)是他成为亿万富豪的关键。在游泳过程中,输入正面潜意识,使其每天都保持巅峰状态。
2、最重要的是要养成习惯,立即行动。感动之后是行动。一点总比没有好,晚做总比不做好。
3、 要养成运动的习惯,要养成早起的习惯。运动能激发无限的魅力,会使一个人感觉起来非常自信。所以我要自己保持持续的运动状态。让自己一早起来就很巅峰的状 态。很多情况是越文明,生活越糜烂。而你看王永庆,台湾的经营之神,虽然年龄高达86岁,但还是每天5点半起床,跑5000公尺,多年来一直坚持。朝气 ——POWER.能量就是魅力,气宇非凡。早起,不要为自己找理由,什么我没休息够,我昨天好累啊,等等。
4、仅仅知道还不够,关键是要不断地训练。训既是教育,练既是练习。
5、学校不教两件事情,一是不教谈恋爱,怎样找个好老婆怎样嫁个好老公。二是学校不教怎样**,学校给人的教育是追求金钱意味着罪恶,人为财死,鸟为食亡,财富是万恶之源。
6、成功者与失败者的差别在于时间管理,运用时间的方法。
7、你可以主宰你自己的命运!!!下定决心争取过自己想要的生活。清楚自己的生活目的。你需要拥有自己的梦想。
一 部电影,《楚门秀》,楚门伯班(金凯瑞饰)老是觉得他一直受到监视。他没想到这竟然是真的。从他呱呱落地开始的三十年来,楚门伯班就是史上播映最久、最受 欢迎的记录片肥皂剧的主角,他居住的理想小镇海景镇居然是一个庞大的摄影棚,而他的亲朋好友和他每天碰到的人全都是职业演员。他生命中的一举一动分秒都曝 露在隐藏在各处的摄影镜头面前。这就是「楚门的世界」,全球上亿观众都注意着他的一举一动,而他自己却不自知。
然后经过三十年的浑噩生活后,楚门 终于感到他的生活有点不对劲,当他发现他就像是活在玻璃罐里的蝴蝶时,他决定要不计代价地逃离海景镇。但是他必须面对「楚门的世界」的创始人、制作人和导 演克里斯托,并且克服他内心最大的恐惧,才能突破藩篱,获得自由他在内心对自己说,NO! I DONT WANT!(不!我不要过这种生活,我不要过这种受别人操纵的生活!)王宗立借这个例子是想说明,一个人的命运是没有人能够操纵的,只要他下定决心,而且 用生命去争取,他就可以去争取他想要的东西,过他想要的生活。你也有一合录影带,1天24小时,记录你一生,你的导演是谁呢,你是也在过一种别人操纵的生 活呢?你的生活是否是在于达成别人的目的的一种工具而已呢,而不是在过你想要的生活的做对的事情,起而行动,下定决心,用生命去争取!
你满不满意你自己的剧本,你敢不敢梦想5年后的你?
亚洲首富孙正义有句名言——最初所拥有的只是梦想和毫无根据的自信而已,但是所有的一切都从这里开始。
8、销售是世界上最赚钱的工作。
王宗立,21岁,财富达300亿,选择业务工作。
这个世界上收入最高的工作就是业务。他说:说服任何人,帮我做任何事。
销售,什么是销售,就是说明、教育、帮助别人作决定。需要三大能力:开发客户,网罗干部,缔结业务。
21岁,16个月的时间赚了300万,然后4个月赔光22岁赚了700万,半年赔光,销售房子,帮助别人做决定。人喜欢别人帮他做决定。不管是选衣服,交异性朋友还是选吃什么东西,你都希望别人替你做决定。
一个女人如果有两个男朋友,她该选择哪一个?如果你是其中之一,你要帮她下决定,你该如何说服她要她选择你?
二次创业失败,失败了没关系,重要的是学到了东西没有。成功就是交学费,早交晚交而已。越早交就交得越少。
在人生中必须得有一个自己又爱又敬又怕的人。他的这个又爱又敬又怕的人是他父亲。
我赔过近千万的钱,最重要的教训——千万别随便转换跑道。我见过太多的转型(转行)失败的人。扩张是另一种形态的转型(转行)。
9、人要成功需有三本——本人,本钱,本事。本人是指要亲自去了解你所做的业务(产品和服务,甚至具体到每一个细节),本钱就是要有资本,本事是指你要有你的核心专长,核心的竞争力。
一个人要成功,要有很多的贵人。 8位数字与9位数字相差一万倍。
亿万富翁靠经营管理,靠大智慧,靠忍。
老板的大忌:全天下的男人都会犯下的错误是色,英雄难过美人关。很多人有钱到一半,就会享受,开始酒池肉林,百花丛中有花就堪折,这样很快就会财富消散,因为赚钱不是加减法而是乘除法,来得快去得也会更快。所以做领导还要有忧患意识。
10、人生不在于机会而在于选择。人生的命运就取决于你一刹那所做的决定。
我做了哪些选择,以致于有我辉煌的成就——23岁月入百万,26岁成为亿万富翁,28岁收购成功杂志,两岸三地不同形态的业务?首先要选个好的工作和职业。
(1)、 宁为牛后,不为鸡首。1993年24岁时,日子非常不错,在忠孝东路有900平米的办公楼,销售房地产,遇到事业瓶颈,因为无法copy销售模式,好象个 人打拼一样,没有未来愿景。而会**的人都有一套模式。象麦当劳,只要按照他的这套模式,copy一下,就能赚很多很多的钱,或者有一套模式让下属 ALONG依循就可以赚钱了。必须要有一个KNOW HOW历史学家分析说,日本之所以会成功是因为明治维新和大化革新。所以学会**比现在**更重要。
(2)、 底子比面子更重要,收入比头衔更重要,实务经验比虚名更重要,识时务者为俊杰。看得到的结果比幻想的未来更重要。幻想的未来是假的。怎样销售?说服?怎样 卖东西?卖咖啡是在卖感觉,卖那种走在咖啡厅外面就问到浓浓的香味,进去之后看到那些摆设和文化气息,卖咖啡是在卖文化。说的是星巴克咖啡厅。
其 次要找个好的伴侣。他说他娶了一个好老婆。你要做应该做的事而不是你喜欢做的事情。我老婆很会欣赏我的优点,很会崇拜我看你的眼神就让你找到自信。 演讲后会很正面的评价我没有人不喜欢赞美,人的肯定来自于很多人的肯定,你想要别人赞美你你也要去赞美别人。我老婆的优点就是会鼓励、赞美、肯定和欣赏我 同时她是节省的女人。失败的婚姻会让人处于低潮,所以选老婆要选能助夫荫子的人。不要找一个勉强的老婆(老公),这种婚姻是不会幸福的,他(或者她)绝对 会带给你人生的负面的东西。你所爱的人,你要感觉到他(她)也很爱你。她爱你的程度甚于你或至少与你相当。你也许只是so so喜欢她,她却要very much喜欢你,不要找自己一相情愿喜欢的女人,否则你不会高枕无忧。
再次,关键是要激发潜能,忠于原主。他自己的例子。95年,他的原来的老 板,议员落选,新闻传媒的消息,造成很多负面的影响,属下的61家中60家都众叛亲离,只有王宗立他没有,因为他说他实在找不出更好的理由离开,经营状况 很不错, 使那个老板很感动,要他立即承诺如果能马上开出12张支票共计 7.2亿的单子,将给非常优厚的利润,……
这样呢,他说人生就是算和赌,他觉得自己算准了,虽然心理也不是非常有把握,但觉得非常值得赌一把,这样他的财富一下由千万富翁变成亿万富翁。那段时间的压力非常大,但是,要创造压力,享受压力。这样才能成功!
11、均衡式的发展。训练很贵,不训练更贵。
12、 改变命运很重要的三个关键。其中之一是选择好的老师非常重要。众人生死全看你,力挽狂澜只一人。要想人前显贵,必先人后受罪。霸王别姬,甘之如饴。少年得 志大不幸。乐极生悲。5000年来的魔咒。骄傲就会停止学习,要高而不危。每个人都有4张A,只是有些人幸运早翻到而已,而道路很漫长,要时常停下来思 考,不要跨太大的步骤,地雷。他作过3个重要的决策。良师有很多包括负面的,要从负面的东西看到学习到,从失败的人的经历里也能学习到很多东西,意见值多 少钱?不可限量。衷心的劝告。人不会永远都有好运气。
齐恒公,管仲,好酒会使寡人亡国吗,好色会使寡人亡国吗,好郊游会使寡人亡国吗,管仲说都不会,只有远贤臣近小人才会使你亡国。
13、要心怀一颗感恩的心。
14、怎么系统运用潜意识?马修史维的方法。
15、 欧那西斯的方法。看到任何人,经历任何事,每天晚上用本子记下。以决定下一次怎样花时间在他身上。这个不象学校教的有教无类,不能以貌取人,而真理是 say no,懂得拒绝。待人处世一定要因人而异,要学会拒绝否则会浪费时间,要交你应该交的朋友而不是你喜欢交的朋友。
欧那西斯说,要成功需要盟友,要非常大的成功就需要敌人,战友。康熙敬三碗酒,第三杯是向他的敌人敬的。他说如果没有这些人,就不会成就的大事业。所以说益友可能是竞争对手,要学会向竞争对手学习很多的东西。
16、功课不重要,一定要灵活。因为交际手腕高的人会更成功。
17、 如何分辨朋友,选择朋友?选择战友,选择敌人?如何选择环境,创造环境?他讲了他的三个女朋友。第一个非常爱玩,第二个非常情绪化,多愁善感,负面的情绪 非常多的人。第三个女朋友是说相信他会大富大贵,有非凡前途的人。崇拜,鼓励,相信他的人。我相信我就能看见18、会学习比肯学习愿意学习来得更重要。前 车之鉴,后车之履。要试着去教别人你想要学的东西。
19、每一个决定不是离成功越来越远就是离成功越来越近。思想决定态度,态度决定语言,语言决定行为,行为养成习惯,习惯形成性格,性格决定命运。
20、苦并不可怕,怕就怕苦得没有代价。
21、如何做领导统御?科学家是把简单的东西复杂化,企业家是把复杂的东西简单化。管理团队就是连锁人,大量copy,东方不败的葵花宝典,木兰诗背下来,销售房地产的脚本交战手册,实战手册。
领导统御的秘诀——四句话,开发,复制,管理,交换。
开发客户,公司来做,教业务员去做。复制:让每一个人都会做。管理:统一的去管理,团队成功。一个企业里有三种人,攻城者,开疆辟域。守城者,守天下。教练者,教育部长,复制的工作。管理就是整合不同类型的人。交换就是资源共享,集体学习,绝不否认每一个个体的价值。
22、如何选项目?要看适合不适合你。你的核心专长,核心竞争力是什么?
怎样融资?借钱?银行的钱是借给有钱的人而不是需要钱的人。天上下雨地上滑,自己跌倒自己爬。所以你要塑造自己被利用的价值,你的可被利用的价值是什么?保——呆人。
23、 如何管理好人才?识才,留才,养才,用才。识才——不要找一个完美无缺的人,没有这种人。留才——心静而后定,心定而后安,心安而后求知求财。养才——舍 得对你的员工投资,投资!把员工当作你的资产。员工是最宝贵的资产,人是无价之宝。外国企业平均花3-5%去培训他的员工,而中国的企业平均只花 0.03 -0.05%用来培训员工。用才——就是要把人才摆在适当的位置。
24、不管做什么都要有销售通路。
25、任何企业都有穷人,成功的企业家不应该停止不前。
26、行善与行孝——这是人生的两件不能等待的事情。
27、为什么要成功比怎样成功更重要!!!
28、世界上没有笨人,笨人都是骂出来的。所以一个赞美鼓励的家庭很重要。
如何选择环境?一等人创造环境,二等人跟随环境,三等人抱怨环境。要输入正面积极的关于环境的潜意识信息。所有与我有关的一切都必将欣欣向荣,不论白天与夜晚,所有与我有关的一切都必将欣欣向荣。用潜意识营造一个积极的环境,一个特别的know how.
每一天都有86400秒,如果你把每天的86400秒换算成86400块钱,如果没有用掉的话,会蒸发掉的,你会不会珍惜这些时间?王永庆一分钟赚6万块。年龄不能代表一切。激发潜能既是有效运用时间的最佳方法。安东尼罗宾说你每分每秒都要做最有生产力的事情。
29、我使用人才的方法是,他有10分才能,不会给他7分的活,而要相反,这样才能激发他的潜能。
30、一日之计在于昨晚。做最重要的事情。所谓的最重要的事情是指非自己亲自出马不可的事情,要思考3次,不要去做那些仅仅是因为自己喜欢做的事情。每天晚上安排6件重要的事情。缔造高度的压力。辛苦不可怕,关键是辛苦要值得。要创造压力并享受压力。
31、每周一星。稀有性,不可替代性。
32、学习催眠最重要的方法是as if(假装)。
33、 一个人与自己人性对抗的力量越强就越能取得成功。晚起床,熬夜,吃宵夜,吸烟等都是坏习惯。一定要养成运动的好习惯。慢跑或游泳都很好。会让你两眼炯炯有 神。使你每天都是热情效益有力量的一天。每天起床之后对自己说:生命多美好暗示性的语言:我喜欢健康,我喜欢保持优美的身材,我知道我追求成功……34、 当你有足够的理由,你就会作出不可思议的事情。每个人都要自问:我现在为了自己成功的人生,可以作出什么样的决定?
35、人才最难找!
36、四到——知道、悟到、做到、得到。
37、要做那些危险而享受的事情。红色代表赚钱、竞争、占有欲和掌控性。兰色代表人群、party、放松等等。绿色代表证据、数据、精确性。黄色代表使命感、义工、帮助人。
38、学习——为自己,为身边的人,为千千万万。
39、你为什么能赚10万美金?原因有三个。第一是你的习惯让你的收入没办法提升。包括决策的习惯、时间管理的习惯等等。第二是你所交的朋友,要交比你强的人。第三提升你核心圈的人的品质如你管理的团队的品质。
40、知道不够多,复习很重要。学习的秘诀在于所谓的六圈哲学:100%——50%——25%——12%——6%——3%,任何人不能成功是因为没人跟100%的人学习。所以我们要尽量的跟100%的人学习,跟最优秀的学习。接近那个100%的人。
41、台基集团的企业文化——孝顺,感恩,存钱,竞争。早会,演讲竞赛,每日一星。欧那西斯说一个人要获得巨大的成功必须有敌人,需要竞争才行。
42、成功的法则是拿来记住的。
43、教育训练者是使命传播者。
44、 人不可能永远处在颠峰状态,那么怎样克服低潮沮丧和消极的心态呢?当你遇到挑战时,你要想你是在高速飞行,从而才会遇到不可或缺的空气的阻力,从南京到北 京,你尽可以走路慢悠悠的走去,那样不会遇到象飞机高速飞行一样遇到的阻力,但是你的速度很慢很慢。恐怕要花半年时间才能到达目的地。
45、不遭人忌是庸才。
46、 好的环境是鼓风炉。POWER能量。当你走出去,你会遇到挑战,你会遇到拒绝,会有泼冷水的,虽然你开始还象720度的烧得通红的木炭,但一遇到冷水又会 逐渐降温。只有你内心的力量使你自己变成一个鼓风炉,你才又会慢慢升温到100度,200度,300度,500度,最后又达到甚至750度的火红的木炭。 你应该如何作到这一点呢???你要一遇到这些挑战,一遇到沮丧的时候,你要马上在心中说,I AM& nbspFIRE ,你牺牲了自己,照亮了别人。你想别人赞美,就要赞美别人,你想别人鼓励,就要鼓励别人,你想别人帮助,就帮助别人。
47、心理学家的实验。一只 狗,被穷追,不断的被追,直到倒在地上,嘴冒白沫,然后抽取其血液,有疲劳毒素在里面,用这些毒素注射在一只刚吃饱的活蹦乱跳的狼狗身上,立即要昏昏欲 睡,为什么?因为血液总是会疲劳的。人有两个器官是永远不会痛的,一个是头发和指甲另一个是肝脏,如果肝脏会痛这人肯定完了。
48、惟有坚持百忍,才能无所不能。
49、 天下有两难,登天难求人更难;世间有两苦,黄连苦,贫穷更苦;世上有两险,江湖险人心更险。所以要做最坏的打算。水能载舟亦能覆舟。一切都要能看得开,只 有你自己不会背叛你自己,所以要投资你自己。你要爱你自己,要爱跟你有血缘关系的亲人。世上还有两薄:春冰薄,人情更保所以要塑造自己永不被替代的价值, 永远被利用的价值。不要怪别人背叛你,你要怪自己没有创造自己被利用的环境。但你真的要坚持百忍才能立于不败之地,才能无所不能……处于低潮时,我会想, 如果是王永庆他会怎么做?知其难,忍其苦,测其险,耐其薄,可处世也。
50、感恩,精进,严谨。
51、记住别人任何的压力都不会压跨你,只有自己的压力会毁灭你自己。你要自己去调试自己的心灵。方法中,音乐电影的方法对于调试的帮助很大。用音乐治疗自己的痛苦。
52、人一定要克服自己的沮丧。
53、没有不景气,只有不争气。巧克力精神——巧妙地克服阻力。
54、OPT与OPM——运用别人的时间与金钱。
55、 王宗立的座右铭有三条。1、在生命的历程中要告诉自己,软弱的是时候要坚强,恐惧的是时候要勇敢,迷惑的时候要明智,抓不住的时候就要放手,真正的胜利是 活在自己的心中。2、冷静地面对一切问题,积极不断地超越自我,惜福永不消极怠惰,活在当下就是最美。3、上帝赐给我镇定和沉着,让我接受不可改变的事 情;上帝赐给我勇气和力量,让我改变我有能力改变的事情;上帝赐给我智慧,让我去分辨哪些事情是我有能力改变的,哪些事情是我无法改变的。
56、为什么要冷静?做业务很辛苦的,要很善于处理危机的。
57、做业务的三大法宝——走出去,说出来,把钱收回来。
58、可怜之人必有可恨之处。
59、什么是大智慧,就是怎样运用心灵的智慧,心灵的力量。哀莫大于心死。大部分人都会很沮丧。
60、寒冰不能断流水,枯木也能再逢春。
61、要善于运用心灵的力量。有了它,跌倒了再爬起来,失败了再成功。
62、罗伯特清崎的投资理财,四象限理论。E,S,B,I.穷爸爸——公家机关,最讲排场,请最多人,花最多的钱,讲气派。富爸爸——企业,私人企业。企业是花最少的钱要创造最大的效益,没有获利的企业是最大的罪恶。因为没有获利的企业会造成很多问题家庭。
63、并不是读书读得很多就会很有钱。
64、 过安定的生活有两种办法一种是在30岁之前赚了足够的钱,比如说30个亿,然后把这些钱放在银行,投资基金等。第二种是永远不要冒险,安心做一个雇员, 有职业保障但是真的有职业保障吗?没有!!!那些所谓的有职业保障的人只不过是在做钱的黑奴。你是否一辈子在为钱做奴隶。为钱而工作?
65、你是为生活而工作还是为工作而生活?如果你认为你的工作是享受,那么你就是在为工作而生活,否则的话,你是在为生活而工作。你要为了生活而工作?NO!
66、你所拥有的就是最好的。只要是你的就是最好的。
67、S象限里是自由职业者。是做业务,赚奖金收入的人。刚开始时建立通路。
王想建立的事业。把消费者变成销售者,把销售者变成领导者,管理者。如果不会销售就不会赚钱。
68、怎样学会销售?走出去,说出来,把钱收回来。
69、销售的重点是开发客户,缔结业务。这就需要1、专业知识,关于产品和服务的知识。2、要知道顾客购买我的产品的至少5大理由?把这些理由背得很熟很熟。3、要提供证据,提供见证者。4、要知道CLOSE的技巧。敢于帮助别人下决定。
70、客户说NO是很正常的,业务最大的困难在于胆量,接下来的开场白,产品介绍等等等。万般草木皆兵器,资源,看到人在走路就如同钱在向你招手。
71、B,利用别人的时间来帮你赚钱。人有四种,消费者——销售者——管理者——领导者。销售者是说明教育帮助顾客下决定的人。领导者是解说者。
72、怎样说服顾客,当你把产品形容得并使客户相信使得客户认为价值超过价格时,就成交了。价值超过价格就不贵。
73、要立大志才能做大事。领导者就是说服,说明,教育,帮助别人下决定的人。
74、 I象限的人,是投资者资本家。利用钱来赚钱的人。投资致富法则,沃伦巴菲特的秘诀——第一个法则,绝对不能赔钱。就是说不能在股票价格低于你当初的买入价 时抛出。一定要等最好的时机。逆向思考法则。没有投资智慧,只有理财EQ.那么怎么作到处变不惊?少赔就好。第二条,绝对不要忘记第一个法则。切记切记切 记!
75、世界上最恐怖的力量是复利。世界上没有聪明不聪明之分,只有懂与不懂。
76、如何增加人生效率?
77、一定不能满足于现状,要巨观而不是微观。
78、老板发现员工剽窃了他的智慧,资产等时怎么办?他不要想不开,你也可以挖别的企业的人才。网罗别人的员工,学习别人的智慧。创造你公司的不可被替代性。对于夫妻来说也是如此,要创造你在你老婆(老公)心目中不可被替代性。而不是一双玉臂钱人枕,半点朱唇万人尝。
79、人生最痛苦的事情莫过于开创和从低潮走向高潮。调整的方法是不要钻牛角尖,而是用另外一个来代替。用催眠录音带,马修史维的方法。
80、放松,放松,毫不批判的接受成功者的指令。
81、 时间管理,成功者成功的原因之一就是很会管理时间。把事情分为四类,A——很重要又很急的,B——很重要但不很急,如运动,健康检查,看书学习,上课等, C——很急但不重要,因人而异,如女朋友要我下班接她等等。这些也许可以要别人去替你做。D——既不着急也不重要。关键点是如何区分B和C类的事情。急或 重要是针对目标和价值观而言的。把第二天自己要做的事情6大项,在每晚做好计划。王宗立做中层管理者一般有以下6大件事情:1、召集员工激励员工。2、邀 约一组客户,去拜访说服,如果没有至少要去做问卷调查一组CASE.3、帮助我的干部CLOSE一个客户。4、帮助我的干部救一个客户。救要退货的。5、 有些情绪不好的员工要鼓励激发他。6、在公司亲自演示一个产品说明会。培训示范作用。身系公司生死一线之间。
82、如果一天做6件重要的事,那么一个月就能做180件重要的事情,一年能做2190件事情,你能不成功吗?
83、养成两个习惯。准备好两个小本子,一个专门用于记那些你当天你遇到的人,和事情。另一个用于记你明天要做的6件事情。
84、一点总比没有好,晚做总比不做好。要做最重要的事情。
85、 关于时间管理的,是安东尼罗宾的老师亚伯拉罕的课程。人有三种时间:Focus day焦点日,专门用于处理与实现最重要的目标有关的事情。在焦点日不做任何事除了最重要的事情之外。Buffer day:准备日:不怕没有机会,就怕没有准备。准备日是比如说去上课,去培训,去交一些朋友。等等。不是去缔结业务去收钱,但是去做之前的准备工作。 Free& nbspday:自由日,休息,与家人在一起。奖励,平衡等。
86、人有四种,人物,人才,人手,人渣。
87、全天下最长的距离是别人的钱包到你的钱包的距离。
88、马修史维:只要是正面的,有力量的对你有帮助的,那么DO IT NOW!
89、行善行孝感恩这三件事情都不能等,不然就没有机会了。
90、当别人泼你冷水时,轻视你,嘲笑你,侮辱你,打击你,为难你时,你不但不要骂他,责怪他,相反你要感谢他,因为他不仅在你沮丧时,在你的油箱里加满了油,让你一路勇往直前冲到底。
91、凡事没有任何意义,除非你赋予它定义。
92、人人都不是在推销产品,而是在推销自己。
93、投资大脑,回报率最高。
94、完美主义会杀人。不要等准备好了再说,差不多就要去做。完美主义会打断习惯。凡事最怕开头,有了开头就会继续,有继续就会养成习惯,习惯就会成自然,自然就是美。
95、相信就会看见。一般人是看见了才相信。所以信念很重要。
96、人无法成功的原因只有两个:懒惰和惧怕。人有三大最怕:火,高处往下跳,在公众面前演讲。
97、不要自己挣不到钱,就希望别人也破产。要创造好的环境,要做正面的暗示:无论白天与夜晚,所有与我有关的一切都必将欣欣向荣。
98、一等人创造环境,二等人跟随环境,三等人抱怨环境。
99、如果你有足够的理由,当你遇到令你兴奋得发抖的机会,你体内的火山就会自动爆发,你心灵的巨人就会被唤醒。
100、凡事皆正面,能量永不减。

posted @ 2009-08-24 21:45 石头@ 阅读(239) | 评论 (0)编辑 收藏

经典开源项目集

操作系统

Linux

项目主页:http://www.linux.org/

数据库

MySQL

项目主页:http://www.mysql.org/

HSQLDB(Hypersonic SQL)

项目主页:http://hsqldb.sourceforge.net/

Apache Derby

项目主页:http://db.apache.org/derby/

Excel JDBC Driver

项目主页:http://nilostep.com

Web开发框架

WebWork

WebWork是由OpenSymphony组织开发的,致力于组件化和代码重用的拉出式MVC模式J2EE Web框架。

项目主页:http://opensymphony.com/webwork/

Struts

Struts是一个基于Sun J2EE平台的MVC框架,主要是采用Servlet和JSP技术来实现的。

项目主页:http://struts.apache.org/

Spring MVC

Spring MVC是结构最清晰的MVC Model 2实现

项目主页:http://www.springframework.org/

EasyJWeb

EasyJWeb是基于java技术,应用于WEB应用程序快速开发的MVC框架,框架设计构思来源于国内众多项目实践,框架充分借签了当前主要流 行的开源Web框架(Struts、JSF、Tapestry 、Webwork),吸取了其优点及精华,利用Velocity作为模板页面引擎,是一个实现了页面及代码完全分离的MVC开发框架。是一个能实现中小型 Web应用系统快速开发的简易Web框架。

项目主页:http://www.easyjf.com/easyjweb/

JavaServer(TM) Faces(JSF)

JavaServer(TM) Faces技术简化了JavaServer应用程序用户界面的开发.各种技术水平的开发者都能够快速创建web应用程序通过在一个页面中装配一些可重复使 用UI组件;并可把这些组件与应用程序的数据源连接起来;也可把客户端产生的事件与服务端事件处理者连接起来.这个项目是Sun对JSF技术规范的最完整 实现。

项目主页:https://javaserverfaces.dev.java.net/

OpenBlueLab

OpenBlueLab是一个用于构建Web2.0 Portal系统的快速开发框架。其主页就是采用该框架开发的一个Demo。Portal布局可以通过UI进行配置。Widget将自动组装,在运行期不 需要编写任何数据库交互代码就能够使它们自动实现数据感知。基于Ajax与HTML的form也将从XML widget定义自动构建。XML widget定义可以从描述信息系统设计的UML模型快速生成。这个框架让你只需关注信息系统的设计,而form和portal的系统架构将自动生成。

项目主页:http://www.openbluelab.org/

JSP标签

Displytag

项目主页:http://displaytag.sourceforge.net/11/

AJAX框架

DWR

项目主页:http://www.getahead.ltd.uk/dwr/

应用服务器

Jakarta Tomcat

项目主页:http://jakarta.apache.org/tomcat/index.html

JBoss

项目主页:http://www.jboss.org

GlassFish

项目主页:https://glassfish.dev.java.net/

Caucho Resin

项目主页:http://www.caucho.com/

Java开发工具

Eclipse

项目主页:http://www.eclipse.org

NetBeans

项目主页:http://www.netbeans.org

EasyEclipse

项目主页:http://www.easyeclipse.org/

Jedit

项目主页:http://www.jedit.org/

UML建模工具

ArgoUML

项目主页:http://argouml.tigris.org/

Alma

项目主页:http://www.memoire.com/guillaume-desnoix/alma/

源码管理工具

SVNKit

项目主页:http://svnkit.com/

JCVS

项目主页:http://www.jcvs.org/

JSVN

项目主页:http://www.alternatecomputing.com/jsvn/index.php3

团队协作工具

Mindquarry

项目主页:http://www.mindquarry.com/

Java Enterprise TeamWork

项目主页:http://jeteam.sourceforge.net/

Coefficient

项目主页:http://coefficient.sourceforge.net/

Open-Xchange

项目主页:http://mirror.open-xchange.org/ox/EN/community/

项目管理工具

Memoranda

项目主页:http://memoranda.sourceforge.net/

Open Workbench

项目主页:http://www.openworkbench.org/

Onepoint Project

项目主页:http://www.onepoint.at/?action=setLanguage&language=en

OpenProj

项目主页:http://sourceforge.net/projects/openproj

Project

项目主页:http://www.project.net/

发布打包工具

JSmooth

项目主页:http://jsmooth.sourceforge.net/

Launch4j

项目主页:http://launch4j.sourceforge.net

VAInstall

项目主页:http://vainstall.sourceforge.net/


摘自:http://hi.baidu.com/computertao/blog/item/b06285335a45f8fc1a4cff6d.html

posted @ 2009-08-21 19:21 石头@ 阅读(1096) | 评论 (0)编辑 收藏

做java最起码掌握的十项技术

一个Java程序员应该掌握的10项技能

1、语法:必须比较熟悉,在写代码的时候IDE的编辑器对某一行报错应该能够根据报错信息知道是什么样的语法错误并且知道任何修正。
2、命令:必须熟悉JDK带的一些常用命令及其常用选项,命令至少需要熟悉:appletviewer、 HtmlConverter、jar、 java、javac、javadoc、javap、javaw、native2ascii、serialver,如果这些命令你没有全部使用过,那么你 对java实际上还很不了解。
3、工具:必须至少熟练使用一种IDE的开发工具,例如Eclipse、Netbeans、JBuilder、Jdeveloper、IDEA、JCreator或者Workshop,包括进行工程管理、常用选项的设置、插件的安装配置以及进行调试。
4、API:Java的核心API是非常庞大的,但是有一些内容笔者认为是必须熟悉的,否则不可能熟练的运用Java,包括:
◆java.lang包下的80%以上的类的功能的灵活运用。
◆java.util包下的80%以上的类的灵活运用,特别是集合类体系、规则表达式、zip、以及时间、随机数、属性、资源和Timer.
◆java.io包下的60%以上的类的使用,理解IO体系的基于管道模型的设计思路以及常用IO类的特性和使用场合。
◆java.math包下的100%的内容。
◆java.net包下的60%以上的内容,对各个类的功能比较熟悉。
◆java.text包下的60%以上的内容,特别是各种格式化类。
◆熟练运用JDBC. 8)、java.security包下40%以上的内容,如果对于安全没有接触的话根本就不可能掌握java.
◆AWT的基本内容,包括各种组件事件、监听器、布局管理器、常用组件、打印。
◆Swing的基本内容,和AWT的要求类似。
◆XML处理,熟悉SAX、DOM以及JDOM的优缺点并且能够使用其中的一种完成XML的解析及内容处理。
5、测试:必须熟悉使用junit编写测试用例完成代码的自动测试。
6、管理:必须熟悉使用ant完成工程管理的常用任务,例如工程编译、生成javadoc、生成jar、版本控制、自动测试。
7、排错:应该可以根据异常信息比较快速的定位问题的原因和大致位置。
8、思想:必须掌握OOP的主要要求,这样使用Java开发的系统才能是真正的Java系统。
9、规范:编写的代码必须符合流行的编码规范,例如类名首字母大写,成员和方法名首字母小写,方法名的第一个单词一般是动词,包名全部小写等,这样程序的可读性才比较好。
10、博学:掌握J2EE 、Oracle 、WebLogic、Jboss、Spring、Struts、Hibernate 等流行技术,掌握软件架构设计思想、搜索引擎优化、缓存系统设计、网站负载均衡、系统性能调优等实用技术。
本文摘自:http://hi.baidu.com/st_sen/blog/item/85333209ae157e2d6b60fbc9.html

posted @ 2009-08-09 18:16 石头@ 阅读(1168) | 评论 (4)编辑 收藏

很有哲理的一些话!

泪的存在,是为了证明悲伤不是一场幻觉。

  两人相爱时,渴求无限甜蜜的吻,但为何在争吵时,却要用接吻的嘴互相伤害呢?    

  爱其实就像打计程车。第一,不像公共汽车,只需等待就会自动来到你的面前,而需要你先向 它招手才停;第二,如果你碰到的是空车,那就是你的幸运,但往往车上已经有人了。这时你只能搭便车,只有先到的乘客下了车后,才能去你想去的地方;第三, 走了多少距离就要付出多少代价。    

  当你认为被抛弃的时候,受损失的其实是对方;因为他失去了一个真正喜欢的人,而你只不过少了一个不爱你的人。 

  要做的事情总找得出时间和机会,不要做的事情总找得出借口。    

  令人不能自拔的,除了牙齿还有爱情.    

  你以为最酸的感觉是吃醋吗?不是的,最酸溜溜的感觉是没权吃醋,根本就轮不到你吃醋,那就是最酸最酸的。    

  青春有限,可以骄傲的时候,尽管骄傲吧。有一天,当你死心塌地地爱上一个人的时候,你也许无法在骄傲。    

  宠和爱是不同的两件事,宠可以没有交流,而爱则不能。    

  一个人有生就有死,但只要你活着,就要以最好的方式活下去。    

  思恋一个人的滋味就像喝了一大杯冰水,然后用很长很长的时间流成热泪。    

  幸福像掉到沙发下面的一粒纽扣-----你专心找,怎么也找不到,等你淡忘了,它自己就滚出来了。    

  快乐就像香水,洒在别人身上的同时,自己也会沾上一点。    

  一只脚踩在紫罗兰上它却将香味留在了你的脚上------这就叫宽容。    

  离开我就别安慰我,要知道每一次缝补,那颗心都会遭遇穿刺的痛。    

  人生好比一只杯子,杯中的水满了就得施一半给人,待杯里又满了,再施一半。只有不断地进,不断地出,这只杯子里才会是活水,才会有价值。    

  人生试题一共有四道题目:学业.事业.婚姻.家庭.平均分高才能及格,切莫花太多的时间和精力在任一题目上。    

  因为懂得,所以慈悲。    

  爱情就像一双袜子,越是瞧起来不顺眼的袜子,越有可能永远陪在你身边,越是喜欢的漂亮袜子经常会少一只.    

  微小的幸福就在身边,容易满足就是天堂。    

  只有向后才能理解生活;但要生活好,则必须向前看。    

  对于你来说,我的出现只是你生命中的100+1=101;但对于我来说,你的出现在我的生命中却是0+1=1的算式。    

  世界上没有不伤人心的感情,或多或少,或大或小,它都会在你的灵魂上留下伤痕。以伤痕为代价换得感情的喜悦,以感情的喜悦作为伤痕的回报。    

  没有人因水的平淡而厌倦饮水,也没有人因生活的平淡而摒弃生活。    

  一片空白中两条细细的直线,它们从遥远的两头隐隐现出,急急忙忙地在彼此的身体上留下一个点,然后再次展向无限制的远方,一去不复返。    

  爱情的开始可能是友谊,可能是利用,可能是欺骗,也可能是需要或寂寞,甚至可能是报复,可那又有什么关系呢?只要最后的结果是演变成了爱情。    

  伤害你的人不是比你强大就是比你弱小。如果他比你弱小,宽恕他;如果他比你强大,宽恕自己。     

  我能从一千个从我身边经过的人中听出你的脚步,因为那999个人的脚是踏在地上,只有你的脚步声是踏在我的心上。    

  我喜欢你,可是我不敢说;我怕说了,我会死去;我不怕死,但是我怕死了以后,再也没有人会像我一样喜欢你。    

  得不到你所爱的,就爱你所得的。    

  眼泪的温度有530℃,只是因为外面的世界太冷,流出来的时候才会降到53℃。    

爱一个人就是在拨通电话时忽然不知道说什么好,原来只是想听听那熟悉的声音,真正想拨通的只是自己心底的一根弦

posted @ 2009-08-05 17:34 石头@ 阅读(403) | 评论 (0)编辑 收藏

java推荐读物

http://blog.csdn.net/sqw131/archive/2009/06/22/4287749.aspx

posted @ 2009-07-30 19:25 石头@ 阅读(430) | 评论 (0)编辑 收藏

初级程序员与高级程序员的做事

一般对于一个问题,初级程序员和高级程序员考虑问题的方法绝对是不同的。比如,在初级程序员阶段时,他会觉得VB也能做出应用来,且看起来也不错。

但到了中级程序员时,他可能就不会选择VB了,可能会用MFC,这时,也能做出效果不错的程序。

到高级程序员时,他绝对不是首先选择以上工具,VB也好,VC也好,这些都不是他考虑的问题。这时考虑的绝对是什么才是具有最快效率、最稳定性能的解决问题的方法。

软件和别的产品不同。比如,在软件中要达到某个目标,有n种方法,但是在n种方法中,只有一种方法或两种方法是最好的,其他的都很次。所以,要做一个好的系统,是很需要耐心的。如果没有耐心,就不会有细活,有细活的东西才是好东西。我觉得做软件是这样,做任何事情也是这样的,一定要投入。

 

程序员到达最高境界的时候,想的就是“我就是程序,程序就是我”。这时候我要做一个软件,不会有自己主观的思路,而是以机器的思路来考虑问题,也就是说,就是以程序的思考方式来思考程序,而不是以我去设计程序的方式去思考程序。这一点如果不到比较高的层次是不能明白的。

你设计程序不就是你思考问题,然后按自己的思路去做程序吗?

其实不是的。在我设计这个程序的时候,相当于我“钻”入这个程序里面去了。这时候没有我自己的任何思维,我的所有思维都是这个程序,这步该怎么走,下步该怎么走,它可能会出现什么情况。我动这个部分的时候,别的部分是否要干扰,也许会动一发而牵全身,它们之间是怎么相互影响的?

也只有到达这个境界,你的程序才能真正地写好,绝对不是做个什么可视化。可视化本身就是“我去设计这个程序”,而真正的程序高手是“我就是程序”,这两种方法绝对是不同的。比如,我要用VB去设计一个程序,和我本身就是一个程序的思维方式,是不一样的。别人也许觉得操作系统很深奥,很复杂,其实,如果你到达高手状态,你就是操作系统,你就能做任何程序。

对待软件要有一个全面的分析方法,光说理论是没有用的。如果你没有经过第一、第二、第三、第四这四个阶段,则永远到达不了高境界。因为空中楼阁的理论没有用,而这些必须是一步一步地去做出来。

一 个高级程序员应该具备开放性思维,从里到外的所有的知识都能了解。然后,看到世界最新技术就能马上掌握,马上了解。实际上,技术到达最高的境界后,是没有 分别的。任何东西都是相通的,只要你到达这个境界以后,什么问题一看就能明白,一看就能抓住最核心的问题,最根本的根本,而不会被其他的枝叶或表象所迷 惑,做到这一步后才算比较成功。

从 程序员本身来说,如果它到达这一步以后,他就已经形成了开阔的思维。他有这种开放性思维的话,他就能做战略决策,这对他将来做任何事情都有好处。事实上, 会做程序后,就会有一种分析问题的方法,学会怎么样把问题的表象剖开,看到它的本质。这时你碰到任何具体的问题,只要给点时间,都能轻而易举地解决。实际 上,对开发计算机软件来说,没有什么做不了的软件,所有的软件都能做,只是看你有没有时间,有没有耐心,有没有资金做支撑。

这几年,尤其是这两三年,估计到2005年前,中国软件这个行业里面大的软件公司就能形成。现在就已经在形成,例如用友,它上市后,地位就更加稳固了。其他大的软件企业会在这几年内迅速长大。这时候,包括流通渠道、经销商的渠道也会迅速长大。也就是说,到2005年以后,中国软件这个行业的门槛比现在还要高很多,与美国不会有太大的差别。此时,中国软件才真正体现出它的威力来。如果你是这些威力中的一员,就已经很厉害了。

别 人可能知道比尔·盖茨是个谈判的高手,是卖东西的高手,其实,比尔·盖茨从根本上来说是个程序高手,这是他根本中的根本。他对所有的技术都非常敏感,一眼 就看到本质,而且他本身也能做程序,时常在看程序。现在他不做董事长,而做首席设计师,这时他就更加接近程序的本质。因为他本身就有很开阔的思维,又深入 到技术的本身,所以他就知道技术的方向。这对于一个公司,对他这样的人来说,是非常重要的。

如果他判断错误一步,那公司以后再回头就很难了。计算机的竞争是非常激烈的,不能走错半步。很多公司以前看上去很火,后来就

销声匿迹了,就是因为它走错一步,然后就不行了。为什么它会走错?因为他不了解技术的本质在哪里,技术的发展方向在哪里。

比尔·盖茨因为父母是学法律的,所以他本身就很能“侃”,很有说服力,而他又是做技术的,就非常清楚技术的方向在哪里,所以他才能把方向把握得很准确,公司越来越大。而别的公司只一阵子,他却火了还会再火。就算微软再庞大,你如果不把握好软件技术的最前沿,一样也会玩完。就像Intel时刻把握着CPU的最新技术,才能保证自己是行业老大。技术决定它的将来。

 

所以,程序员要能达到这样的目标,就要有非常强的耐心和非常好的机遇才有可能。事实上,现在的机会挺好的,2005年 以前机会都非常大,以后机会会比较小。但是,如果有耐心的话,你还是会有机会的,机会都是出在耐心里。我记得有句话说“雄心的一半是耐心”,我认为雄心的 三分之二都是耐心。如果你越有野心,你就越要有耐心,你的野心才有可能实现。如果你有野心而没有耐心,那都是胡思乱想,别人一眼就能看穿。最后在竞争中, 对手一眼就看到你的意图,那你还有什么可竞争的?



转自:http://blog.pfan.cn/vagrant/31151.html

posted @ 2009-07-27 21:04 石头@ 阅读(788) | 评论 (0)编辑 收藏