<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[阿Tim日志]]></title> 
<link>https://atim.cn/index.php</link> 
<description><![CDATA[专业的php开发者.开发团队的带队人]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[阿Tim日志]]></copyright>
<item>
<link>https://atim.cn/acme-dns-create-cert/</link>
<title><![CDATA[使用dns申请Let’s Encrypt的证书]]></title> 
<author>bkkkd &lt;partybase@gmail.com&gt;</author>
<category><![CDATA[Web 技术 ]]></category>
<pubDate>Mon, 26 Apr 2021 14:34:54 +0000</pubDate> 
<guid>https://atim.cn/acme-dns-create-cert/</guid> 
<description>
<![CDATA[ 
	一般情况下使用certbot来申请证书,但使用动态域名的时候,不能使用80和443端口.所以一直没有申请下来.<br/>只能使用aliyun或者腾讯云的证书来申请.<br/>但这样每年处理一下.而且时间长了.也不一定记得去更换.就算记得更新的过程也是挺麻烦的.<br/><br/>最好能像阿里那样使用dns来验证域名这样就可以一劳永逸了.<br/><br/>acme.sh可以使用创建泛域名的证书<br/><br/><div class="code"><br/>curl https://get.acme.sh &#124; sh -s email=tim@atim.cn<br/>source ~/.bashrc<br/>acme.sh --issue --dns -d *.ddns.atim.cn --yes-I-know-dns-manual-mode-enough-go-ahead-please<br/></div><br/><br/>到这里出会报错,提示找不到dns定义的txt值.<br/><div class="code"><br/>&#91;Mon 26 Apr 2021 10:29:11 PM CST&#93; Using CA: https://acme-v02.api.letsencrypt.org/directory<br/>&#91;Mon 26 Apr 2021 10:29:11 PM CST&#93; Creating domain key<br/>&#91;Mon 26 Apr 2021 10:29:11 PM CST&#93; The domain key is here: /root/.acme.sh/a.alpicool.com/ddns.atim.cnkey<br/>&#91;Mon 26 Apr 2021 10:29:11 PM CST&#93; Single domain=&#039;ddns.atim.cn&#039;<br/>&#91;Mon 26 Apr 2021 10:29:11 PM CST&#93; Getting domain auth token for each domain<br/>&#91;Mon 26 Apr 2021 10:29:14 PM CST&#93; Getting webroot for domain=&#039;ddns.atim.cn&#039;<br/>&#91;Mon 26 Apr 2021 10:29:14 PM CST&#93; Add the following TXT record:<br/>&#91;Mon 26 Apr 2021 10:29:14 PM CST&#93; Domain: &#039;_acme-challenge.ddns.atim.cn&#039;<br/>&#91;Mon 26 Apr 2021 10:29:14 PM CST&#93; TXT value: &#039;xxxxxxxxxxx&#039;<br/>&#91;Mon 26 Apr 2021 10:29:14 PM CST&#93; Please be aware that you prepend _acme-challenge. before your domain<br/>&#91;Mon 26 Apr 2021 10:29:14 PM CST&#93; so the resulting subdomain will be: _acme-challenge.ddns.atim.cn<br/>&#91;Mon 26 Apr 2021 10:29:14 PM CST&#93; Please add the TXT records to the domains, and re-run with --renew.<br/>&#91;Mon 26 Apr 2021 10:29:14 PM CST&#93; Please add &#039;--debug&#039; or &#039;--log&#039; to check more details.<br/>&#91;Mon 26 Apr 2021 10:29:14 PM CST&#93; See: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh<br/><br/></div><br/>然后手动到域名里添加域名记录:<br/>域名为:<span style="color: #DC143C;">_acme-challenge.ddns</span>.atim.cn<br/>值为:<span style="color: #DC143C;">xxxxxxxxxxx</span><br/><br/>添加完成后重新验证<br/><div class="code"><br/>acme.sh --renew --dns -d *.ddns.atim.cn<br/></div><br/>然后把对nginx或者apache里配置证书.就可以正常使用,可以参考<<a href="https://atim.cn/certbot-case/" target="_blank">使用certbot自动生成证书</a>><br/>
]]>
</description>
</item><item>
<link>https://atim.cn/post/1050/</link>
<title><![CDATA[优化Linux的内核参数来提高服务器并发处理能力]]></title> 
<author>bkkkd &lt;partybase@gmail.com&gt;</author>
<category><![CDATA[Web 技术 ]]></category>
<pubDate>Thu, 09 Aug 2012 09:52:08 +0000</pubDate> 
<guid>https://atim.cn/post/1050/</guid> 
<description>
<![CDATA[ 
	<br/>PS：在服务器硬件资源额定有限的情况下，最大的压榨服务器的性能，提高服务器的并发处理能力，是很多运维技术人员思考的问题。要提高Linux系统下的负载能力，可以使用nginx等原生并发处理能力就很强的web服务器，如果使用Apache的可以启用其Worker模式，来提高其并发处理能力。除此之外，在考虑节省成本的情况下，可以修改Linux的内核相关TCP参数，来最大的提高服务器性能。当然，最基础的提高负载问题，还是升级服务器硬件了，这是最根本的。<br/><br/>Linux系统下，TCP连接断开后，会以TIME_WAIT状态保留一定的时间，然后才会释放端口。当并发请求过多的时候，就会产生大量的TIME_WAIT状态的连接，无法及时断开的话，会占用大量的端口资源和服务器资源。这个时候我们可以优化TCP的内核参数，来及时将TIME_WAIT状态的端口清理掉。<br/><br/>本文介绍的方法只对拥有大量TIME_WAIT状态的连接导致系统资源消耗有效，如果不是这种情况下，效果可能不明显。可以使用netstat命令去查TIME_WAIT状态的连接状态，输入下面的组合命令，查看当前TCP连接的状态和对应的连接数量：<br/>#netstat -n &#124; awk ‘/^tcp/ &#123;++S[$NF]&#125; END &#123;for(a in S) print a, S[a]&#125;’<br/>这个命令会输出类似下面的结果：<br/>LAST_ACK 16<br/>SYN_RECV 348<br/>ESTABLISHED 70<br/>FIN_WAIT1 229<br/>FIN_WAIT2 30<br/>CLOSING 33<br/>TIME_WAIT 18098<br/>我们只用关心TIME_WAIT的个数，在这里可以看到，有18000多个TIME_WAIT，这样就占用了18000多个端口。要知道端口的数量只有65535个，占用一个少一个，会严重的影响到后继的新连接。这种情况下，我们就有必要调整下Linux的TCP内核参数，让系统更快的释放TIME_WAIT连接。<br/><br/>用vim打开配置文件：#vim /etc/sysctl.conf<br/><br/>在这个文件中，加入下面的几行内容：<br/>net.ipv4.tcp_syncookies = 1<br/>net.ipv4.tcp_tw_reuse = 1<br/>net.ipv4.tcp_tw_recycle = 1<br/>net.ipv4.tcp_fin_timeout = 30<br/><br/>输入下面的命令，让内核参数生效：#sysctl -p<br/><br/>简单的说明上面的参数的含义：<br/><br/>net.ipv4.tcp_syncookies = 1<br/>#表示开启SYN Cookies。当出现SYN等待队列溢出时，启用cookies来处理，可防范少量SYN攻击，默认为0，表示关闭；<br/>net.ipv4.tcp_tw_reuse = 1<br/>#表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接，默认为0，表示关闭；<br/>net.ipv4.tcp_tw_recycle = 1<br/>#表示开启TCP连接中TIME-WAIT sockets的快速回收，默认为0，表示关闭；<br/>net.ipv4.tcp_fin_timeout<br/>#修改系統默认的 TIMEOUT 时间。<br/><br/>在经过这样的调整之后，除了会进一步提升服务器的负载能力之外，还能够防御小流量程度的DoS、CC和SYN攻击。<br/><br/>此外，如果你的连接数本身就很多，我们可以再优化一下TCP的可使用端口范围，进一步提升服务器的并发能力。依然是往上面的参数文件中，加入下面这些配置：<br/>net.ipv4.tcp_keepalive_time = 1200<br/>net.ipv4.ip_local_port_range = 10000 65000<br/>net.ipv4.tcp_max_syn_backlog = 8192<br/>net.ipv4.tcp_max_tw_buckets = 5000<br/>#这几个参数，建议只在流量非常大的服务器上开启，会有显著的效果。一般的流量小的服务器上，没有必要去设置这几个参数。<br/><br/>net.ipv4.tcp_keepalive_time = 1200<br/>#表示当keepalive起用的时候，TCP发送keepalive消息的频度。缺省是2小时，改为20分钟。<br/>net.ipv4.ip_local_port_range = 10000 65000<br/>#表示用于向外连接的端口范围。缺省情况下很小：32768到61000，改为10000到65000。（注意：这里不要将最低值设的太低，否则可能会占用掉正常的端口！）<br/>net.ipv4.tcp_max_syn_backlog = 8192<br/>#表示SYN队列的长度，默认为1024，加大队列长度为8192，可以容纳更多等待连接的网络连接数。<br/>net.ipv4.tcp_max_tw_buckets = 6000<br/>#表示系统同时保持TIME_WAIT的最大数量，如果超过这个数字，TIME_WAIT将立刻被清除并打印警告信息。默 认为180000，改为6000。对于Apache、Nginx等服务器，上几行的参数可以很好地减少TIME_WAIT套接字数量，但是对于 Squid，效果却不大。此项参数可以控制TIME_WAIT的最大数量，避免Squid服务器被大量的TIME_WAIT拖死。<br/><br/>内核其他TCP参数说明：<br/>net.ipv4.tcp_max_syn_backlog = 65536<br/>#记录的那些尚未收到客户端确认信息的连接请求的最大值。对于有128M内存的系统而言，缺省值是1024，小内存的系统则是128。<br/>net.core.netdev_max_backlog = 32768<br/>#每个网络接口接收数据包的速率比内核处理这些包的速率快时，允许送到队列的数据包的最大数目。<br/>net.core.somaxconn = 32768<br/>#web应用中listen函数的backlog默认会给我们内核参数的net.core.somaxconn限制到128，而nginx定义的NGX_LISTEN_BACKLOG默认为511，所以有必要调整这个值。<br/><br/>net.core.wmem_default = 8388608<br/>net.core.rmem_default = 8388608<br/>net.core.rmem_max = 16777216&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #最大socket读buffer,可参考的优化值:873200<br/>net.core.wmem_max = 16777216&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #最大socket写buffer,可参考的优化值:873200<br/>net.ipv4.tcp_timestsmps = 0<br/>#时间戳可以避免序列号的卷绕。一个1Gbps的链路肯定会遇到以前用过的序列号。时间戳能够让内核接受这种“异常”的数据包。这里需要将其关掉。<br/>net.ipv4.tcp_synack_retries = 2<br/>#为了打开对端的连接，内核需要发送一个SYN并附带一个回应前面一个SYN的ACK。也就是所谓三次握手中的第二次握手。这个设置决定了内核放弃连接之前发送SYN+ACK包的数量。<br/>net.ipv4.tcp_syn_retries = 2<br/>#在内核放弃建立连接之前发送SYN包的数量。<br/>#net.ipv4.tcp_tw_len = 1<br/>net.ipv4.tcp_tw_reuse = 1<br/># 开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接。<br/><br/>net.ipv4.tcp_wmem = 8192 436600 873200<br/># TCP写buffer,可参考的优化值: 8192 436600 873200<br/>net.ipv4.tcp_rmem&nbsp;&nbsp;= 32768 436600 873200<br/># TCP读buffer,可参考的优化值: 32768 436600 873200<br/>net.ipv4.tcp_mem = 94500000 91500000 92700000<br/># 同样有3个值,意思是:<br/>net.ipv4.tcp_mem[0]:低于此值，TCP没有内存压力。<br/>net.ipv4.tcp_mem[1]:在此值下，进入内存压力阶段。<br/>net.ipv4.tcp_mem[2]:高于此值，TCP拒绝分配socket。<br/>上述内存单位是页，而不是字节。可参考的优化值是:786432 1048576 1572864<br/><br/>net.ipv4.tcp_max_orphans = 3276800<br/>#系统中最多有多少个TCP套接字不被关联到任何一个用户文件句柄上。<br/>如果超过这个数字，连接将即刻被复位并打印出警告信息。<br/>这个限制仅仅是为了防止简单的DoS攻击，不能过分依靠它或者人为地减小这个值，<br/>更应该增加这个值(如果增加了内存之后)。<br/>net.ipv4.tcp_fin_timeout = 30<br/>#如果套接字由本端要求关闭，这个参数决定了它保持在FIN-WAIT-2状态的时间。对端可以出错并永远不关闭连接，甚至意外当机。缺省值是60秒。2.2 内核的通常值是180秒，你可以按这个设置，但要记住的是，即使你的机器是一个轻载的WEB服务器，也有因为大量的死套接字而内存溢出的风险，FIN- WAIT-2的危险性比FIN-WAIT-1要小，因为它最多只能吃掉1.5K内存，但是它们的生存期长些。<br/><br/>经过这样的优化配置之后，你的服务器的TCP并发处理能力会显著提高。以上配置仅供参考，用于生产环境请根据自己的实际情况。<br/>
]]>
</description>
</item><item>
<link>https://atim.cn/post/1044/</link>
<title><![CDATA[什么是ActiveRecord]]></title> 
<author>bkkkd &lt;partybase@gmail.com&gt;</author>
<category><![CDATA[Web 技术 ]]></category>
<pubDate>Thu, 22 Mar 2012 05:56:33 +0000</pubDate> 
<guid>https://atim.cn/post/1044/</guid> 
<description>
<![CDATA[ 
	ActiveRecord是什么:<br/>1. 每一个数据库表对应创建一个类.类的每一个对象实例对应于数据库中表的一行记录; 通常表的每个字段在类中都有相应的Field;<br/>2. ActiveRecord同时负责把自己持久化. 在ActiveRecord中封装了对数据库的访问, 即CRUD;<br/>3. ActiveRecord是一种领域模型(Domain Model), 封装了部分业务逻辑;<br/>ActiveRecord不是什么:<br/><br/>1. Row Data Gateway<br/>Row Data Gateway模式中每个对象也封装了数据库记录的状态和持久化到数据库的访问方法; 这两个有时候很难区分. 细微的区别在于Row Data Gateway不封装任何业务逻辑;<br/><br/>2. TableGateway<br/>TableGateway是一种数据访问模式, 对每个表有一个类, 类的方法封装了对单个表的数据操作, 如CRUD; 方法的接受表字段的值作为参数;<br/>比如说对表Person有DAOPerson, 有以下方法:<br/>int Create(string name, bool isMale)<br/>DataSet Find(int personId)<br/>void Delete(int personId)<br/>void Update(int personId, string name, bool isMale)<br/>微软的很多代码示例中使用了此模式;<br/><br/>ActiveRecord的区别在于ActiveRecord的对象中保持了记录的值, 是有状态的, 而TableGateway是没有状态的, 只是一系列数据库访问方法的集合;<br/><br/>3. Table Module<br/>Table Module是一种领域逻辑模式, 一个类对应于数据库中的一个表; Table Module通常和Table Gateway合作, 前者负责基本的业务逻辑, 后者负责数据库访问, 以达到逻辑层和持久化层的隔离; 微软的实例代码经常使用这两者, 如对表Person, 通常会定义两个类, PersonBL和PersonDB, 在PersonBL中处理验证等逻辑, 并调用PersonDB访问数据库, 层间调用使用DataSet或自定义数据传输对象传输数据<br/><br/>在业务逻辑比较简单并且有和表的一一对应时, ActiveRecord相对来说更简单, 因为它在一个类中包括了业务逻辑对象和数据访问, 而且不需要数据传输对象, 减少了维护的工作量;<br/>和Table Module比较起来, ActiveRecord与数据库耦合更紧;<br/><br/>ActiveRecord适用于:<br/>1. 业务逻辑比较简单;当你的类基本上和数据库中的表一一对应时, ActiveRecord是非常方便的, 即你的业务逻辑大多数是对单表操作;<br/><br/>2. 当发生跨表的操作时, 往往会配合使用事务脚本(Transaction Script), 把跨表事务提升到事务脚本中;<br/><br/>3. ActiveRecord最大优点是简单, 直观; 一个类就包括了数据访问和业务逻辑. 如果配合代码生成器使用就更方便了;<br/><br/>4. 这些优点使ActiveRecord特别适合web快速开发, 而正是快速开发框架ROR采用了ActiveRecord, 并且很多类ROR框架如Castle的纷纷效仿才使ActiveRecord重新进入大家视线;<br/>我想这也是为什么Martin Fowler在PoEAA中早就提出了这个模式, 但是直到最近两三年ActiveRecord才热起来可能就是这个原因;<br/><br/>ActiveRecord不适合于<br/>1. ActiveRecord虽然有业务逻辑, 但基本上都是基于单表的. 跨表逻辑一般会放到当发生跨表的操作时, 往往会配合使用事务脚本(Transaction Script)中. 如果对象间的关联越来越多, 你的事务脚本越来越庞大, 重复的代码越来越多, 你就要考虑Domain Model + O/R Mapper了;<br/><br/>2. ActiveRecord保存了数据, 使它有时候看上去像数据传输对象(DTO). 但是ActiveRecord有数据库访问能力, 不要把它当DTO用. 尤其在跨越进程边界调用的时候, 不能传递ActiveRecord对象;<br/><br/>来源：http://www.cnblogs.com/kuber/archive/2008/05/09/1188463.html
]]>
</description>
</item><item>
<link>https://atim.cn/post/1042/</link>
<title><![CDATA[Windows Socket 网络编程(二) —— 套接字编程原理]]></title> 
<author>bkkkd &lt;partybase@gmail.com&gt;</author>
<category><![CDATA[Web 技术 ]]></category>
<pubDate>Fri, 10 Feb 2012 09:20:29 +0000</pubDate> 
<guid>https://atim.cn/post/1042/</guid> 
<description>
<![CDATA[ 
	一、客户机/服务器模式<br/>在TCP/IP网络中两个进程间的相互作用的主机模式是客户机/服务器模式(Client/Server model)。该模式的建立基于以下两点：1、非对等作用；2、通信完全是异步的。客户机/服务器模式在操作过程中采取的是主动请示方式：<br/><br/>首先服务器方要先启动，并根据请示提供相应服务：（过程如下）<br/>1、打开一通信通道并告知本地主机，它愿意在某一个公认地址上接收客户请求。<br/>2、等待客户请求到达该端口。<br/>3、接收到重复服务请求，处理该请求并发送应答信号。<br/>4、返回第二步，等待另一客户请求<br/>5、关闭服务器。<br/>客户方：<br/>1、打开一通信通道，并连接到服务器所在主机的特定端口。<br/>2、向服务器发送服务请求报文，等待并接收应答；继续提出请求……<br/>3、请求结束后关闭通信通道并终止。<br/><br/>二、基本套接字<br/>为了更好说明套接字编程原理，给出几个基本的套接字，在以后的篇幅中会给出更详细的使用说明。<br/>1、创建套接字——socket()<br/>功能：使用前创建一个新的套接字<br/>格式：SOCKET PASCAL FAR socket(int af,int type,int procotol);<br/>参数：af: 通信发生的区域<br/>type: 要建立的套接字类型<br/>procotol: 使用的特定协议<br/><br/>2、指定本地地址——bind()<br/>功能：将套接字地址与所创建的套接字号联系起来。<br/>格式：int PASCAL FAR bind(SOCKET s,const struct sockaddr FAR * name,int namelen);<br/>参数：s: 是由socket()调用返回的并且未作连接的套接字描述符（套接字号）。<br/>其它：没有错误，bind()返回0，否则SOCKET_ERROR<br/>地址结构说明：<br/>struct sockaddr_in<br/>&#123;<br/>short sin_family;//AF_INET<br/>u_short sin_port;//16位端口号，网络字节顺序<br/>struct in_addr sin_addr;//32位IP地址，网络字节顺序<br/>char sin_zero[8];//保留<br/>&#125;<br/><br/>3、建立套接字连接——connect()和accept()<br/>功能：共同完成连接工作<br/>格式：int PASCAL FAR connect(SOCKET s,const struct sockaddr FAR * name,int namelen);<br/>SOCKET PASCAL FAR accept(SOCKET s,struct sockaddr FAR * name,int FAR * addrlen);<br/>参数：同上<br/><br/>4、监听连接——listen()<br/>功能：用于面向连接服务器，表明它愿意接收连接。<br/>格式：int PASCAL FAR listen(SOCKET s, int backlog);<br/><br/>5、数据传输——send()与recv()<br/>功能：数据的发送与接收<br/>格式：int PASCAL FAR send(SOCKET s,const char FAR * buf,int len,int flags);<br/>int PASCAL FAR recv(SOCKET s,const char FAR * buf,int len,int flags);<br/>参数：buf:指向存有传输数据的缓冲区的指针。<br/><br/>6、多路复用——select()<br/>功能：用来检测一个或多个套接字状态。<br/>格式：int PASCAL FAR select(int nfds,fd_set FAR * readfds,fd_set FAR * writefds,<br/>fd_set FAR * exceptfds,const struct timeval FAR * timeout);<br/>参数：readfds:指向要做读检测的指针<br/>writefds:指向要做写检测的指针<br/>exceptfds:指向要检测是否出错的指针<br/>timeout:最大等待时间<br/><br/>7、关闭套接字——closesocket()<br/>功能：关闭套接字s<br/>格式：BOOL PASCAL FAR closesocket(SOCKET s);<br/><br/>三、典型过程图<br/>2.1 面向连接的套接字的系统调用时序图<br/><br/><a href="https://atim.cn/attachment.php?fid=38" target="_blank"><img src="https://atim.cn/attachment.php?fid=38" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>2.2 无连接协议的套接字调用时序图<br/><br/><a href="https://atim.cn/attachment.php?fid=39" target="_blank"><img src="https://atim.cn/attachment.php?fid=39" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>2.3 面向连接的应用程序流程图<br/><a href="https://atim.cn/attachment.php?fid=40" target="_blank"><img src="https://atim.cn/attachment.php?fid=40" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/>原文地址: http://www.vckbase.com/document/viewdoc/?id=484
]]>
</description>
</item><item>
<link>https://atim.cn/post/1013/</link>
<title><![CDATA[linux ulimit max open files]]></title> 
<author>bkkkd &lt;partybase@gmail.com&gt;</author>
<category><![CDATA[Web 技术 ]]></category>
<pubDate>Wed, 27 Apr 2011 04:01:05 +0000</pubDate> 
<guid>https://atim.cn/post/1013/</guid> 
<description>
<![CDATA[ 
	有时候在程序里面需要打开多个文件，进行分析，系统一般默认数量是1024，（用ulimit -a可以看到）对于正常使用是够了，但是对于程序来讲，就太少了。<br/>修改办法：<br/>重启就OK<br/>修改2个文件。<br/>1./etc/security/limits.conf<br/>vi /etc/security/limits.conf<br/>加上：<br/>* soft nofile 8192<br/>* hard nofile 20480<br/><br/>2./etc/pam.d/login<br/>session&nbsp;&nbsp;&nbsp;&nbsp;required&nbsp;&nbsp;&nbsp;&nbsp; /lib/security/pam_limits.so<br/><br/><br/>ulimit -a查看 下 OK<br/><br/>另一篇：ulimit值(Linux文件句柄数量)在Centos5(RHEL5)中的调整<br/><br/>http://www.crazylemon.net/linux/173.html<br/><br/>在Linux下面部署应用的时候，有时候会遇上Socket/File: Can’t open so many files的问题，比如还有Squid做代理,当文件打开数到900多时速能就非常快的下降，有可能打不开网页.<br/>其实Linux是有文件句柄限制的，而且Linux默认不是很高，一般都是1024，生产服务器用其实很容易就达到这个数量.<br/><br/>查看方法<br/><br/>我们可以用ulimit -a来查看所有限制值<br/><br/>[root@centos5 ~]# ulimit -a<br/>core file size (blocks, -c) 0<br/>data seg size (kbytes, -d) unlimited<br/>max nice (-e) 0<br/>file size (blocks, -f) unlimited<br/>pending signals (-i) 4096<br/>max locked memory (kbytes, -l) 32<br/>max memory size (kbytes, -m) unlimited<br/>open files (-n) 1024<br/>pipe size (512 bytes, -p) 8<br/>POSIX message queues (bytes, -q) 819200<br/>max rt priority (-r) 0<br/>stack size (kbytes, -s) 10240<br/>cpu time (seconds, -t) unlimited<br/>max user processes (-u) 4096<br/>virtual memory (kbytes, -v) unlimited<br/>file locks (-x) unlimited&#124;&#124;<<br/><br/>其中 "open files (-n) 1024 "是Linux操作系统对一个进程打开的文件句柄数量的限制(也包含打开的SOCKET数量,可影响MySQL的并发连接数目).这个值可用ulimit命令来修改,但ulimit命令修改的数值只对当前登录用户的目前使用环境有效,系统重启或者用户退出后就会失效.<br/><br/>系统总限制是在这里，/proc/sys/fs/file-max.可以通过cat查看目前的值，修改/etc/sysctl.conf 中也可以控制.<br/><br/>另外还有一个，/proc/sys/fs/file-nr，可以看到整个系统目前使用的文件句柄数量<br/><br/>查找文件句柄问题的时候，还有一个很实用的程序lsof.可以很方便看到某个进程开了那些句柄.也可以看到某个文件/目录被什么进程占用了.<br/><br/>修改方法<br/>若要令修改ulimits的数值永久生效,则必须修改配置文档,可以给ulimit修改命令放入/etc/profile里面，这个方法实在是不方便,还 有一个方法是修改/etc/sysctl.conf .我修改了，测试过,但对用户的ulimits -a 是不会改变的。只是/proc/sys/fs/file-max的值变了.(我给命令放到rc.local中失败)<br/><br/>我认为正确的做法，应该是修改/etc/security/limits.conf<br/>里面有很详细的注释，比如<br/><br/>* soft nofile 32768<br/>* hard nofile 65536<br/><br/>也可以直接运行下面这个shell。直接copy到你的终端中运行就好了.<br/>echo -ne "<br/>* soft nofile 65536<br/>* hard nofile 65536<br/>" >>/etc/security/limits.conf<br/><br/>就可以将文件句柄限制统一改成软32768，硬65536.配置文件最前面的是指domain，设置为星号代表全局，另外你也可以针对不同的用户做出不同的限制<br/><br/>注意.这个当中的硬限制是实际的限制，而软限制，是warnning限制，只会做出warning.其实ulimit命令本身就有分软硬设置，加-H就是硬，加-S就是软<br/>默认显示的是软限制，如果运行ulimit命令修改的时候没有加上的话，就是两个参数一起改变.<br/><br/>生效<br/><br/>修改完重新登录就可以见到.(我的系统是Centos5.1.修改了，重新登录后就立刻生效.可以用ulimit -a 查看确认.)<br/><br/>如果你使用squid的话,你要在/etc/init.d/squid的文件加入ulimit -HSn 65535.另外,在squid.conf中也要加入max_filedesc 16384<br/><br/>注：上面这种方式只是改变了用户登陆系统后的文件打开数，对于/etc/init.d/nginxphp这种的启动脚本并不起作用，像这种启动脚本，需要在脚本内加一行：<br/><br/>ulimit -HSn 65535<br/><br/>才行。<br/>
]]>
</description>
</item><item>
<link>https://atim.cn/post/1002/</link>
<title><![CDATA[facebook是如何管理代码的]]></title> 
<author>bkkkd &lt;partybase@gmail.com&gt;</author>
<category><![CDATA[Web 技术 ]]></category>
<pubDate>Sun, 06 Feb 2011 22:59:01 +0000</pubDate> 
<guid>https://atim.cn/post/1002/</guid> 
<description>
<![CDATA[ 
	<a href="http://framethink.wordpress.com/2011/01/17/how-facebook-ships-code/" target="_blank">原文在此</a>，看完之后，终于明白为什么优秀的工程师都去了/想去facebook，因为那里是工程师们的天堂。<br/><br/>译文:<br/><br/>我对facebook的运转着迷。这是一个很独特的环境，不容易被复制（他们的体系并不适合所有的公司，即使他们努力尝试过）。下面是我和facebook的朋友们关于他们如何开发和管理项目的记录。<br/><br/>现在距离我收集的这些信息又过去6个月了，我相信facebook肯定又对他们的项目开发实践进行了改进。所以这些记录可能会有点过时。同时facebook的工程师驱动文化也越来越为大众所知。非常感谢那些帮助我整理这篇文章的facebook的朋友们。<br/><br/>记录：<br/><br/>截止到2010年6月，facebook有将近2000名员工，10个月前只有1100名，一年之间差不多翻了一番。<br/>两个最大的部门是工程师和运维，每个部门大概都是400-500人。这两个部门人数大约占了公司的一半。<br/>产品经理与工程师的比例大约为1-7到1-10。<br/>每个工程师入职时，都要接收4-6周的培训，通过修补bugs和听高级开发工程师的课程来熟悉facebook。<br/>培训结束后，每个工程师都可以接触线上的数据库(更大的权力意味着更大的责任，也有一份"勿做清单"，不然可能会被开，比如共享用户的隐私数据)。<br/>有非常牢靠的安全体系，以免有人不小心/故意做了些不好的事。<br/>每个工程师可以修改facebook的任何代码，随时可以迁入。<br/>浓厚的工程师驱动文化。"产品经理基本可以被忽略"，这是facebook一名员工的话。工程师可以修改流程的细节，重新安排工作任务，随时植入自己的想法。<br/>在每月的跨部门会议上，由工程师来汇报工作进度，市场部和产品经理会出席会议，也可以做些简短的发言，但如果说得太多，很可能就会被打小报告。他们确实想让工程师来主导产品的开发，对自己的产品负责。<br/>项目需要的资源都是自愿的<br/>一个产品经理把工程师们召集到一起，让他们对他的想法产生兴趣。<br/>工程师们决定开发那些让他们感兴趣的特性。<br/>工程师跟他们的经理说："我下周想开发这5个新特性"。<br/>经理会让工程师独立开发，可能有时会让他优先完成一些特性。<br/>工程师独立完成所有的特性——前端/后端/数据库，等等所有相关的部分。如果需要得到设计人员的帮助，需要先让设计人员对你的想法产生兴趣。其他如架构之类的也一样。但总体来说，工程师要独立完成所有的任务。<br/>对于某个特性是否值得开发的争论，通常是这么解决的：花一个星期的时间完成他，并在小部分人群中(如1%)进行测试。<br/>工程师常常希望解决难题，这能获得声望和尊敬。他们很难对前端项目或UI设计产生太大的兴趣。这跟其他公司可能正好相反。在facebook，后端任务，比如新的feed算法，广告投放算法，memcache优化等等，是工程师真正感兴趣的。<br/>所有的代码修改都要进行审核(通过一个或多个工程师)，但News Feed是个例外，因为太重要了，Zuckerberg会亲自review。<br/>所有的修改至少要被一个人审核，而且这个系统可以让任何人很方便地审核其他人的代码，即使你没有邀请他<br/>工程师负责测试，代码修复，和维护自己的项目。<br/>每个办公室或通过VPN连接的员工会使用下一版的facebook，这个版本的facebook会经常更新，通常比公开的早1-12小时。所有的员工被强烈建议提交bugs，而且通常会很快被修复。<br/>很奇怪只有很少的QA或自动测试——"大部分工程师都能写出基本没有bug的代码，只是在其他公司他们不需要这么做。如果有QA部门，他们只要把代码写完，扔给他们就行了"<br/>[针对上一条]我们有自动测试，代码发布前必须要通过测试。我们不相信"所有的工程师都能写出没有bug的代码"，毕竟这是一个商业公司。<br/>很奇怪，缺少产品经理的影响和控制——产品经理是很独立的和自由的。产生影响力的关键是与工程师和工程师的领导们们搞好关系。需要大致了解技术，不要提一些愚蠢的想法。<br/>所有提交的代码每周二打包一次。<br/>只要多一分努力，终于一天会发生改变。<br/>星期二的代码发布，需要所有的提交过代码的工程师在场。<br/>代码打包前，工程师必须在一个特殊的IRC channel上。<br/>运维执行打包过程<br/>facebook有大约60000台服务器<br/>有9个代码发布级别<br/>最小的级别只有6台服务器<br/>星期二的代码发布会先发布到6台服务器上，运维组会检测这6台服务器的反应，保证代码正常工作，然后再提交到下一级<br/>如果发布出现了一些问题（如报错等等），那么就停止下一级的部署，提交出错代码的工程师负责修复问题，然后从头继续发布。<br/>所以一次发布可能会经历几次重复：1-2-3-fix. 回到1. 1-2-3-4-5-fix. 回到1. 1-2-3-4-5-6-7-8-9<br/>运维组是受过严格训练，倍受尊敬，而且有商业意识的。他们的工作包括分析错误日志，负载和内存状态等等。还包括用户行为。<br/>代码发布期间，运维组使用IRC-based页面系统，可以通过facebook/email/irc/im/sms ping每一个工程师，如果需要他们注意的话。对运维组不做回应是一件很羞愧的事。<br/>代码一旦发布到第9级，并且稳定运行，就算发布成功了。<br/>如果一个特性没有按时完成，也没什么大不了的，下次完成时一并发布即可。<br/>如果被svn-blamed,public shamed或工作经常疏忽就很可能被开除。"这是一个高效的文化"。不够高效或者不够聪明的员工会被剔除。管理层会在6个月的时间里观察你表现，如果不合格，只能说再见。每一级都是这个待遇，即使是C级别和VP级别，如果不够高效，也会被开除。<br/>被责骂不会导致解雇。我们特别尊重别人，原谅别人。大部分高级工程师都或多或少犯过一些严重的错误，包括我。但没有人因此被解雇。<br/>我也没有遇到过因为上面提到过的犯错误而被解雇。有些人犯了错，他们会非常努力地去修复，也让其他人得到了学习。<br/><br/><a href="http://blog.leezhong.com/translate/2011/01/18/how-facebook-ships-code.html" target="_blank">原文地址</a>
]]>
</description>
</item><item>
<link>https://atim.cn/post/474/</link>
<title><![CDATA[[转载]让ubuntu直接启动到文本模式]]></title> 
<author>bkkkd &lt;partybase@gmail.com&gt;</author>
<category><![CDATA[Web 技术 ]]></category>
<pubDate>Mon, 15 Dec 2008 14:37:45 +0000</pubDate> 
<guid>https://atim.cn/post/474/</guid> 
<description>
<![CDATA[ 
	init和inittab<br/>=============<br/>Linux下为什么会要有个init？用过 windows 9.x的人应该知道有个批处理文件autoexec.bat，用过windows NT/2000系统的人应该在控制面板中见过system service工具，它们的目的是相同的。只是比较起来windows下的这些东西功能太弱（当然用法也更简单）。<br/>init是Linux启动的最后一步，它帮助用户完成每次启动系统都必须完成的一些重复性任务，如加载文件系统、各类网络服务等等程序；它还有一个重要用途，让用户自定义系统运行环境，只启动需要的进程，关闭不用的进程，释放内存和处理器资源，让系统运行得更快更稳。<br/><br/>init 会按任务表执行我们下的命令，这个任务表就是/etc/inittab文件。我们可以为系统制定多个运行环境以满足不同任务的需要，在inittab中称之为运行等级（runlevel）。例如，计算机要用来完成一种联网编译任务（与其它系统共享CPU周期，合作编译软件），这样情况需占用大量CPU能力和内存，所以当计算机用作这种用途时，其他程序的运行要尽可能少。可设置一个运行等级（如：runlevel 4），把其它程序包括X Window全关闭，只启动联网编译进程；其他时段，你的计算机要与Windows系统共享文件，需要启动Samba，可以再定义一个运行等级（如： runlevel 2）。<br/>现在当你要进行联网编译时可运行init 4，而不用手工去关闭每个暂不需要的进程；要与Windows系统共享文件可运行init 2。<br/><br/>Debian系统对某些运行等级进行了预先配置（而且是无法修改的）<br/><br/>runlevel 0：它的任务就是关闭所有程序，关机。如果计算机及内核支持APM，系统电源可自动切断。<br/><br/>runlevel 1：为单用户模式保留的。在这个运行等级下，除了一个root shell外，没有其它程序运行。除了root文件系统以只读方式安装外，不安装其它文件系统。该运行等级通常在恢复系统时用。<br/><br/>runlevel 6：与runlevel 0非常相似，只是它是重启系统而不是关闭系统。<br/><br/>runlevel 2、3、4、5：Debian系统对它们没有具体规定，通常可自由进行定制，它们都属于多用户模式。其中runlevel 3是Debian使用的默认运行等级。启动Debian系统时，用的就是这个运行等级。<br/><br/>下面是inittab文件的例子<br/><br/># /etc/inittab: init(8) configuration.<br/># $Id: inittab,v 1.91 2002/01/25 13:35:21 miquels Exp $<br/><br/># The default runlevel.<br/>id:2:initdefault:<br/><br/># Boot-time system configuration/initialization script.<br/># This is run first except when booting in emergency (-b) mode.<br/>si::sysinit:/etc/init.d/rcS<br/><br/># What to do in single-user mode.<br/>~~:S:wait:/sbin/sulogin<br/><br/># /etc/init.d executes the S and K scripts upon change<br/># of runlevel.<br/>#<br/># Runlevel 0 is halt.<br/># Runlevel 1 is single-user.<br/># Runlevels 2-5 are multi-user.<br/># Runlevel 6 is reboot.<br/><br/>l0:0:wait:/etc/init.d/rc 0<br/>l1:1:wait:/etc/init.d/rc 1<br/>l2:2:wait:/etc/init.d/rc 2<br/>l3:3:wait:/etc/init.d/rc 3<br/>l4:4:wait:/etc/init.d/rc 4<br/>l5:5:wait:/etc/init.d/rc 5<br/>l6:6:wait:/etc/init.d/rc 6<br/># Normally not reached, but fallthrough in case of emergency.<br/>z6:6:respawn:/sbin/sulogin<br/><br/># What to do when CTRL-ALT-DEL is pressed.<br/>ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now<br/><br/># Action on special keypress (ALT-UpArrow).<br/>#kb::kbrequest:/bin/echo "Keyboard Request--edit /etc/inittab to let this work."<br/><br/># What to do when the power fails/returns.<br/>pf::powerwait:/etc/init.d/powerfail start<br/>pn::powerfailnow:/etc/init.d/powerfail now<br/>po::powerokwait:/etc/init.d/powerfail stop<br/><br/># /sbin/getty invocations for the runlevels.<br/>#<br/># The "id" field MUST be the same as the last<br/># characters of the device (after "tty").<br/>#<br/># Format:<br/># <id>:<runlevels>:<action>:<process><br/>#<br/># Note that on most Debian systems tty7 is used by the X Window System,<br/># so if you want to add more getty's go ahead but skip tty7 if you run X.<br/>#<br/>1:2345:respawn:/sbin/getty 38400 tty1<br/>2:23:respawn:/sbin/getty 38400 tty2<br/>3:23:respawn:/sbin/getty 38400 tty3<br/>4:23:respawn:/sbin/getty 38400 tty4<br/>5:23:respawn:/sbin/getty 38400 tty5<br/>6:23:respawn:/sbin/getty 38400 tty6<br/><br/># Example how to put a getty on a serial line (for a terminal)<br/>#<br/>#T0:23:respawn:/sbin/getty -L ttyS0 9600 vt100<br/>#T1:23:respawn:/sbin/getty -L ttyS1 9600 vt100<br/><br/># Example how to put a getty on a modem line.<br/>#<br/>#T3:23:respawn:/sbin/mgetty -x0 -s 57600 ttyS3<br/><br/>该文件有一个基本类型的指令，它们指定命令行，命令行所采取的动作，在何种运行等级下激活命令。这引起命令行的格式大体如下：<br/><br/>id:runlevels:action:command<br/><br/>id是任意一个名称（具体是什么并不重要），runlevels是一个数字串（代表运行等级），action描述何时执行命令，command指定执行的实际命令。拿启动getty的命令行举例：<br/><br/>1:2345:respawn:/sbin/getty 38400 tty1<br/><br/>该命令告诉init，它应该在引导后以运行等级2-5运行命令/sbin/getty 38400 tty1。动作标记respawn表示命令在退出时重新运行（当用户在shell输入exit的时候）。<br/><br/>从方面的文件中可以看到，运行等级2和3有六个活动的gettys，而等级4和5只有一个。假设运行等级4下有三个shell运行在虚拟控制台。你在ID为2和3的命令行的运行等级字段添加了数字4，也就是说你将<br/><br/>2:23:respawn:/sbin/getty 38400 tty2<br/>3:23:respawn:/sbin/getty 38400 tty3<br/><br/>替换成<br/><br/>2:234:respawn:/sbin/getty 38400 tty2<br/>3:234:respawn:/sbin/getty 38400 tty3<br/><br/>然后重启或执行以下命令：<br/><br/>telinit q<br/><br/>对inittab进行修改。telinit q命令指示init重新加载它的配置。参阅telinit(8)。<br/><br/>/etc/inittab的其它行看起来比较复杂，我们先看看还有哪些动作标记：<br/><br/>·respawn：启动命令并监视命令的执行，当进程退出时，再次执行该命令（通常用于虚拟终端设备上的登录提示）。 ·wait：进入指定运行等级时，启动进程。init会停下来，直到执行完成。这个标记用于设置特定等级下软件的启动。<br/>·once：进入指定的任一运行等级时，启动一次进程。<br/>·boot：该命令在系统引导时运行。这种类型的指令忽略运行等级。<br/>·bootwait：该命令在系统引导时运行，init等到它退出后才能继续做别的事。<br/>·off：禁用所有运行等级下的某个命令。<br/>·initdefault：这种类型的项指定在系统引导时进入哪个运行等级。<br/>·powerwait：这类指令给出在电源不足时需要执行的命令。init直到进程完成后才继续工作。<br/>·powerfail：与powerwait类似，但init不等待进程完成。<br/>·powerworkwait：电源正常后执行。init暂停，直到进程结束。<br/>·powerfailnow：当便携机电池或外部UPS电池电量不足时执行。<br/>·ctrlaltdel：指定init在捕获ctrl+alt+del组合键时执行的命令。<br/>·kbdrequest：把特殊动作映射到特定的按键。Debian中的是alt+UpArrow。<br/><br/>现在再看上面的文件是不是清楚了许多？<br/><br/>更强大的sysvinit<br/>================<br/>inittab 的主要功能是描述引导及正常操作时，应该在何种运行等级下启动什么程序，每个运行等级的具体项目完全可以通常/etc/inittab来定义，但 Debian有一个更健壮的方案sysvinit，它被认为是init最强大的应用程序之一。Debian组织inittab的方式是把运行等级的大部分定义从inittab中移出来，移到一个脚本层次中去。惟一直接从inittab启动的程序只有getty，它用于虚拟设备上启动登录提示符，保留它因为它们要求特殊处理，在inittab之外处理要困难得多。<br/><br/>inittab来启动所有软件当然是可能的，但将所有配置写在同一个文件既不方便查看也不方便维护，所以文件里会加上这许多行：<br/><br/>l0:0:wait:/etc/init.d/rc 0<br/>l1:1:wait:/etc/init.d/rc 1<br/>l2:2:wait:/etc/init.d/rc 2<br/>l3:3:wait:/etc/init.d/rc 3<br/>l4:4:wait:/etc/init.d/rc 4<br/>l5:5:wait:/etc/init.d/rc 5<br/>l6:6:wait:/etc/init.d/rc 6<br/><br/>这些行实际决定了系统在各个运行等级下的行为。它们如何做到的也许并不明显，但至少我们知道主要意思：首先每行都有个符号ID lx，lx表示runlevel x；其次，每行只在一个运行等级下激活，该运行等级对应着符号ID中的数字x。命令执行时，init停下来，直到进程结束。最后，每个命令行调用一个脚本 /etc/init.d/rc x，这里x代表当前运行等级的数字。显然各运行等级的具体任务在/etc/init.d/rc脚本中安排。<br/><br/>Debian init设置的核心在/etc/init.d目录。该目录包含了启动或停止重要软件的脚本，为了简化操作，规定每个脚本都使用相同的一套参数——start或stop。个别软件包维护者为用户着想，往这些脚本中加了其他功能，但init不会去调用它们。<br/>举个例子，可调用：#/etc/init.d/apache start来启动Apache，调用：#/etc/init.d/apache stop来关闭它。<br/>作为一个用户工具，这是非常有用的，它让用户轻松启动和关闭Debian所带的复杂程序，不过在考虑如何启动程序前，先检查/etc/init.d，看看是不是已经有脚本可以做这件事了。借助于这种机制，可以按自己的需求来调整运行等级，/etc/init.d/rc可以把系统引入所需的运行等级。 /etc/rcx.d是一组指向/etc/init.d的符号链接。进行运行等级时，rc在运行等级目录中按逻辑顺序处理每个脚本。首先前缀为K的每个文件都以参数stop（按字母和数字顺序）执行；其次，以S为前缀的每个脚本都以参数start（按字母和数字顺序）执行。<br/>了解了工作原理，下面试着自己来构造一个运行等级。我们使用运行等级5和与之相关的rc目录/etc/rc5.d。首先，看看该目录下的内容：找出每个符号链接所做的工作；查看文件，判断它来自哪个文件。经过仔细查看，找出启动无用程序的S打头的脚本，把它们删掉，在/etc/init.d中找出需要运行但未包括在内的脚本，例如假设你想在运行等级5下启动Samba，执行命令：<br/><br/>ln -s /etc/init.d/samba /etc/rc5.d/S20samba<br/><br/>看到这里是不是对init有了新的了解，那么来测试一下学习成果：关闭Debian默认安装时加载的gdm/xdm/kdm进程，让Debian启动到命令行终端而不是X。<br/><br/><br/><br/>http://www.real-blog.com/linux-bsd-notes/49<br/>以文字模式啟動 Ubuntu<br/><br/>January 31, 2006 @ 11:00 pm · Filed under Linux / BSD 筆記<br/><br/>如果想 Ubuntu 在每次啟動到 command prompt ，可以輸入以下指令:<br/><br/>$echo “false” &#124; sudo tee /etc/X11/default-display-manager<br/><br/>當下次開機時，就會以指令模式啟動，如果想變回啟動 x window，可以輸入:<br/><br/>$echo “/usr/bin/gdm” &#124; sudo tee /etc/X11/default-display-manager<br/><br/>P.S. 如果不是用 gdm 作為，以上指令需要根據你的環境作出更改，例如 kdm 或 xdm。 
]]>
</description>
</item><item>
<link>https://atim.cn/post/472/</link>
<title><![CDATA[详细讲解Ubuntu Server安装过程]]></title> 
<author>bkkkd &lt;partybase@gmail.com&gt;</author>
<category><![CDATA[Web 技术 ]]></category>
<pubDate>Sun, 14 Dec 2008 14:02:43 +0000</pubDate> 
<guid>https://atim.cn/post/472/</guid> 
<description>
<![CDATA[ 
	系统软件：Ubuntu 7.04 内核，Fluxbox桌面管理，firefox浏览器，openoffice办公软件，xfe文件管理器<br/><br/>Step1:安装Ubuntu 7.04 Server<br/><br/>a、Server安装画面，按F6，在 -- 之前添加 "irqpoll" 选项; 按F4，选择屏幕分辨率为1024×768 32<br/><br/>b、语言选择English<br/><br/>c、当安装自动设定 DHCP 时，选择 “Cancel”节省系统安装时间<br/><br/>d、手动硬盘分区，创建一个65Mb的分区，并将其挂载点设定为 /boot,bootable选项设定为True,如不这么设定，系统安装完无法启动<br/><br/>e、Server 安装类型、选择LAMP<br/><br/>f、安装过程约15分钟<br/><br/>Step 2：设定网络<br/><br/>a、动态ip：<br/><br/>sudo nano /etc/network/interfaces 在文件的最后加入<br/><br/>iface eth0 inet dhcp<br/><br/>auto eth0<br/><br/>b、静态ip：(加快启动速度)<br/><br/>iface eth0 inet static<br/><br/>address 192.168.0.3<br/><br/>netmask 255.255.255.0<br/><br/>gateway 192.168.0.1<br/><br/>auto eth0<br/><br/>注：ip地址设定为192.168.0.3，子网掩码：255.255.255.0，网关：192.168.0.1<br/><br/>按 Ctrl+o 保存文件，按Ctrl+x退出<br/><br/>设定DNS(动态ip不需)<br/><br/>sudo nano /etc/resolv.conf 在文件加入<br/><br/>nameserver 192.168.0.1<br/><br/>注：192.168.0.1 是DNS的ip地址<br/><br/>按 Ctrl+o 保存文件，按Ctrl+x退出<br/><br/>Step 3、重启系统网络<br/><br/>sudo /etc/init.d/networking restart<br/><br/>Step 4、修改 源<br/><br/>从网上获得一个复制文件 或 手工修改<br/><br/>a、从网上获得一个源复制文件<br/><br/>wget http://www.topmiracle.net/sources.list<br/><br/>sudo cp ./sources.list /etc/apt<br/><br/>b、手工修改<br/><br/>sudo nano /etc/apt/sources.list 设定 源 为<br/><br/>deb http://cn.archive.ubuntu.com/ubuntu feisty main restricted universe multiverse<br/><br/>deb http://cn.archive.ubuntu.com/ubuntu feisty-security main restricted universe multiverse<br/><br/>deb http://cn.archive.ubuntu.com/ubuntu feisty-updates main restricted universe multiverse<br/><br/>deb http://cn.archive.ubuntu.com/ubuntu feisty-backports main restricted universe multiverse<br/><br/>deb http://cn.archive.ubuntu.com/ubuntu feisty-proposed main restricted universe multiverse<br/><br/>deb-src http://cn.archive.ubuntu.com/ubuntu feisty main restricted universe multiverse<br/><br/>deb-src http://cn.archive.ubuntu.com/ubuntu feisty-security main restricted universe multiverse<br/><br/>deb-src http://cn.archive.ubuntu.com/ubuntu feisty-updates main restricted universe multiverse<br/><br/>deb-src http://cn.archive.ubuntu.com/ubuntu feisty-backports main restricted universe multiverse<br/><br/>deb-src http://cn.archive.ubuntu.com/ubuntu feisty-proposed main restricted universe multiverse<br/><br/>Step 5、更新 源软件包 和 更新系统软件<br/><br/>sudo aptitude update<br/><br/>sudo aptitude upgrade<br/><br/>Step 6、安装Xorg,Fluxbox,Synaptic<br/><br/>sudo aptitude install xorg fluxbox synaptic<br/><br/>Step 7、安装英文和中文包<br/><br/>sudo aptitude install language-pack-en language-pack-en-base language-pack-zh language-pack-zh-base language-selector language-selector-common<br/><br/>Step 8、在英文界面输入中文<br/><br/>sudo fontconfig-voodoo -f zh_CN<br/><br/>Step 9、安装fcitx中文输入<br/><br/>sudo aptitude install fcitx<br/><br/>im-switch -s fcitx<br/><br/>sudo nano /etc/gtk-2.0/gtk.immodules<br/><br/>找到下面这个部份<br/><br/>"/usr/lib/gtk-2.0/2.10.0/immodules/im-xim.so"<br/>"xim" "X Input Method" "gtk20" "/usr/share/locale" "ko:ja:th:zh"<br/><br/>更改为<br/><br/>"/usr/lib/gtk-2.0/2.10.0/immodules/im-xim.so"<br/>"xim" "X Input Method" "gtk20" "/usr/share/locale" "en:ko:ja:th:zh"<br/><br/>Set 10、设定中文输入，系统环境<br/><br/>sudo nano /etc/environment 在文件PATH后添加以下内容LC_CTYPE="zh_CN.UTF-8"<br/><br/>LANG="en_US.UTF-8"<br/><br/>Step 11、安装中文字体<br/><br/>sudo aptitude install xfonts-wqy<br/><br/>Setp 12、设定系统启用中文字体<br/><br/>从网上复制一个配置文件 或者 手工创建<br/><br/>a、从网上复制一个配置文件<br/><br/>wget http://www.topmiracle.net/language-selector.conf<br/><br/>sudo cp ./language-selector.conf /etc/fonts<br/><br/>b、手工创建<br/><br/>sudo nano /etc/fonts/language-selector.conf 文件内容为<br/><br/><fontconfig> <br/>&nbsp;&nbsp;&nbsp;&nbsp;<alias> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<family>serif</family> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<prefer> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<family>Bitstream Vera Serif</family> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<family>DejaVu Serif</family> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<family>AR PL ShanHeiSun Uni</family> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<family>WenQuanYi Bitmap Song</family> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<family>AR PL ZenKai Uni</family> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</prefer> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</alias> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<alias> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<family>sans-serif</family> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<prefer> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<family>Bitstream Vera Sans</family> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<family>DejaVu Sans</family> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<family>AR PL ShanHeiSun Uni</family> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<family>WenQuanYi Bitmap Song</family> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<family>AR PL ZenKai Uni</family> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</prefer> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</alias> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<alias> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<family>monospace</family> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<prefer> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<family>Bitstream Vera Sans Mono</family> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<family>DejaVu Sans Mono</family> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<family>AR PL ShanHeiSun Uni</family> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<family>WenQuanYi Bitmap Song</family> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<family>AR PL ZenKai Uni</family> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</prefer> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</alias> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<match target="font" > <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<test name="family" compare="contains" > <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<string>Song</string> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<string>Sun</string> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<string>Kai</string> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<string>Ming</string> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</test>&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<!-- check to see if the font is just regular --> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<test name="weight" compare="less_eq"> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<int>100</int> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</test> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<test compare="more_eq" target="pattern" name="weight" > <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<int>180</int> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</test> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<edit mode="assign" name="embolden" > <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<bool>true</bool> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</edit> <br/>&nbsp;&nbsp;&nbsp;&nbsp;</match> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<match target="font" > <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<test name="family" compare="contains" > <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<string>Song</string> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<string>Sun</string> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<string>Kai</string> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<string>Ming</string> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</test>&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<edit name="globaladvance"> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<bool>false</bool> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</edit> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<edit name="spacing"> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<int>0</int> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</edit> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<edit name="hinting"> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<bool>true</bool> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</edit> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<edit name="autohint"> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<bool>false</bool> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</edit> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<edit name="antialias" mode="assign"> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<bool>true</bool> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</edit> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<test name="pixelsize" compare="less_eq"> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<int>18</int> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</test> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<edit name="antialias" mode="assign" > <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<bool>false</bool> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</edit> <br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</match> <br/></fontconfig><br/><br/>Step 13、确认系统拥有zh_CN.UTF8<br/><br/>sudo dpkg-reconfigure locales<br/><br/>Step 14、安装firefox,openoffice,sun-java6-jre<br/><br/>sudo aptitude install firefox moxilla-firefox-locale-zh-cn openoffice.org sun-java6-jre<br/><br/>Step 15、卸载Server默认安装的nfs(网络共享用samba, 以后安装)<br/><br/>sudo aptitude remove nfs<br/><br/>Step 16、重启电脑<br/><br/>sudo reboot (sudo poweroff是关闭电脑)<br/><br/>Step 17、Login后享受Ubuntu+Fluxbox的惊人速度<br/><br/>startx<br/><br/>Step 18、安装xfe文件管理器<br/><br/>xfe是一个功能强大，耗能极少，速度极快的文件管理器，xfe 0.98版以后支持UTF8，安装前请确认版本号大于0.98目前(2007年4月)最新版是0.99-1,可到<br/><br/>http://sourceforge.net/project/showfiles.php?group_id=64835 下载deb包(xfe主页http://sourceforge.net/projects/xfe)<br/><br/>下载后先安装libfox-1.6-0<br/><br/>sudo aptitude install libfox-1.6-0<br/><br/>安装xfe(deb包)<br/><br/>sudo dpkg -i xfe_0.99-1_i386.deb<br/><br/>其他参考：<br/><br/>https://help.ubuntu.com/community/Installation/LowMemorySystems<br/><br/>http://fluxbox.sourceforge.net/
]]>
</description>
</item><item>
<link>https://atim.cn/post/469/</link>
<title><![CDATA[part of Hypertext Transfer Protocol -- HTTP/1.1]]></title> 
<author>bkkkd &lt;partybase@gmail.com&gt;</author>
<category><![CDATA[Web 技术 ]]></category>
<pubDate>Tue, 02 Dec 2008 01:52:03 +0000</pubDate> 
<guid>https://atim.cn/post/469/</guid> 
<description>
<![CDATA[ 
	<br/>RFC 2616 Fielding, et al.<br/>10 Status Code Definitions<br/><br/>Each Status-Code is described below, including a description of which method(s) it can follow and any metainformation required in the response.<br/>10.1 Informational 1xx<br/><br/>This class of status code indicates a provisional response, consisting only of the Status-Line and optional headers, and is terminated by an empty line. There are no required headers for this class of status code. Since HTTP/1.0 did not define any 1xx status codes, servers MUST NOT send a 1xx response to an HTTP/1.0 client except under experimental conditions.<br/><br/>A client MUST be prepared to accept one or more 1xx status responses prior to a regular response, even if the client does not expect a 100 (Continue) status message. Unexpected 1xx status responses MAY be ignored by a user agent.<br/><br/>Proxies MUST forward 1xx responses, unless the connection between the proxy and its client has been closed, or unless the proxy itself requested the generation of the 1xx response. (For example, if a<br/><br/>proxy adds a "Expect: 100-continue" field when it forwards a request, then it need not forward the corresponding 100 (Continue) response(s).)<br/>10.1.1 100 Continue<br/><br/>The client SHOULD continue with its request. This interim response is used to inform the client that the initial part of the request has been received and has not yet been rejected by the server. The client SHOULD continue by sending the remainder of the request or, if the request has already been completed, ignore this response. The server MUST send a final response after the request has been completed. See section 8.2.3 for detailed discussion of the use and handling of this status code.<br/>10.1.2 101 Switching Protocols<br/><br/>The server understands and is willing to comply with the client's request, via the Upgrade message header field (section 14.42), for a change in the application protocol being used on this connection. The server will switch protocols to those defined by the response's Upgrade header field immediately after the empty line which terminates the 101 response.<br/><br/>The protocol SHOULD be switched only when it is advantageous to do so. For example, switching to a newer version of HTTP is advantageous over older versions, and switching to a real-time, synchronous protocol might be advantageous when delivering resources that use such features.<br/>10.2 Successful 2xx<br/><br/>This class of status code indicates that the client's request was successfully received, understood, and accepted.<br/>10.2.1 200 OK<br/><br/>The request has succeeded. The information returned with the response is dependent on the method used in the request, for example:<br/><br/>GET an entity corresponding to the requested resource is sent in the response;<br/><br/>HEAD the entity-header fields corresponding to the requested resource are sent in the response without any message-body;<br/><br/>POST an entity describing or containing the result of the action;<br/><br/>TRACE an entity containing the request message as received by the end server.<br/>10.2.2 201 Created<br/><br/>The request has been fulfilled and resulted in a new resource being created. The newly created resource can be referenced by the URI(s) returned in the entity of the response, with the most specific URI for the resource given by a Location header field. The response SHOULD include an entity containing a list of resource characteristics and location(s) from which the user or user agent can choose the one most appropriate. The entity format is specified by the media type given in the Content-Type header field. The origin server MUST create the resource before returning the 201 status code. If the action cannot be carried out immediately, the server SHOULD respond with 202 (Accepted) response instead.<br/><br/>A 201 response MAY contain an ETag response header field indicating the current value of the entity tag for the requested variant just created, see section 14.19.<br/>10.2.3 202 Accepted<br/><br/>The request has been accepted for processing, but the processing has not been completed. The request might or might not eventually be acted upon, as it might be disallowed when processing actually takes place. There is no facility for re-sending a status code from an asynchronous operation such as this.<br/><br/>The 202 response is intentionally non-committal. Its purpose is to allow a server to accept a request for some other process (perhaps a batch-oriented process that is only run once per day) without requiring that the user agent's connection to the server persist until the process is completed. The entity returned with this response SHOULD include an indication of the request's current status and either a pointer to a status monitor or some estimate of when the user can expect the request to be fulfilled.<br/>10.2.4 203 Non-Authoritative Information<br/><br/>The returned metainformation in the entity-header is not the definitive set as available from the origin server, but is gathered from a local or a third-party copy. The set presented MAY be a subset or superset of the original version. For example, including local annotation information about the resource might result in a superset of the metainformation known by the origin server. Use of this response code is not required and is only appropriate when the response would otherwise be 200 (OK).<br/>10.2.5 204 No Content<br/><br/>The server has fulfilled the request but does not need to return an entity-body, and might want to return updated metainformation. The response MAY include new or updated metainformation in the form of entity-headers, which if present SHOULD be associated with the requested variant.<br/><br/>If the client is a user agent, it SHOULD NOT change its document view from that which caused the request to be sent. This response is primarily intended to allow input for actions to take place without causing a change to the user agent's active document view, although any new or updated metainformation SHOULD be applied to the document currently in the user agent's active view.<br/><br/>The 204 response MUST NOT include a message-body, and thus is always terminated by the first empty line after the header fields.<br/>10.2.6 205 Reset Content<br/><br/>The server has fulfilled the request and the user agent SHOULD reset the document view which caused the request to be sent. This response is primarily intended to allow input for actions to take place via user input, followed by a clearing of the form in which the input is given so that the user can easily initiate another input action. The response MUST NOT include an entity.<br/>10.2.7 206 Partial Content<br/><br/>The server has fulfilled the partial GET request for the resource. The request MUST have included a Range header field (section 14.35) indicating the desired range, and MAY have included an If-Range header field (section 14.27) to make the request conditional.<br/><br/>The response MUST include the following header fields:<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- Either a Content-Range header field (section 14.16) indicating<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;the range included with this response, or a multipart/byteranges<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Content-Type including Content-Range fields for each part. If a<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Content-Length header field is present in the response, its<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value MUST match the actual number of OCTETs transmitted in the<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message-body.<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- Date<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- ETag and/or Content-Location, if the header would have been sent<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;in a 200 response to the same request<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- Expires, Cache-Control, and/or Vary, if the field-value might<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;differ from that sent in any previous response for the same<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;variant<br/><br/>If the 206 response is the result of an If-Range request that used a strong cache validator (see section 13.3.3), the response SHOULD NOT include other entity-headers. If the response is the result of an If-Range request that used a weak validator, the response MUST NOT include other entity-headers; this prevents inconsistencies between cached entity-bodies and updated headers. Otherwise, the response MUST include all of the entity-headers that would have been returned with a 200 (OK) response to the same request.<br/><br/>A cache MUST NOT combine a 206 response with other previously cached content if the ETag or Last-Modified headers do not match exactly, see 13.5.4.<br/><br/>A cache that does not support the Range and Content-Range headers MUST NOT cache 206 (Partial) responses.<br/>10.3 Redirection 3xx<br/><br/>This class of status code indicates that further action needs to be taken by the user agent in order to fulfill the request. The action required MAY be carried out by the user agent without interaction with the user if and only if the method used in the second request is GET or HEAD. A client SHOULD detect infinite redirection loops, since such loops generate network traffic for each redirection.<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Note: previous versions of this specification recommended a<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maximum of five redirections. Content developers should be aware<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;that there might be clients that implement such a fixed<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;limitation.<br/><br/>10.3.1 300 Multiple Choices<br/><br/>The requested resource corresponds to any one of a set of representations, each with its own specific location, and agent- driven negotiation information (section 12) is being provided so that the user (or user agent) can select a preferred representation and redirect its request to that location.<br/><br/>Unless it was a HEAD request, the response SHOULD include an entity containing a list of resource characteristics and location(s) from which the user or user agent can choose the one most appropriate. The entity format is specified by the media type given in the Content- Type header field. Depending upon the format and the capabilities of<br/><br/>the user agent, selection of the most appropriate choice MAY be performed automatically. However, this specification does not define any standard for such automatic selection.<br/><br/>If the server has a preferred choice of representation, it SHOULD include the specific URI for that representation in the Location field; user agents MAY use the Location field value for automatic redirection. This response is cacheable unless indicated otherwise.<br/>10.3.2 301 Moved Permanently<br/><br/>The requested resource has been assigned a new permanent URI and any future references to this resource SHOULD use one of the returned URIs. Clients with link editing capabilities ought to automatically re-link references to the Request-URI to one or more of the new references returned by the server, where possible. This response is cacheable unless indicated otherwise.<br/><br/>The new permanent URI SHOULD be given by the Location field in the response. Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s).<br/><br/>If the 301 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Note: When automatically redirecting a POST request after<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;receiving a 301 status code, some existing HTTP/1.0 user agents<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;will erroneously change it into a GET request.<br/><br/>10.3.3 302 Found<br/><br/>The requested resource resides temporarily under a different URI. Since the redirection might be altered on occasion, the client SHOULD continue to use the Request-URI for future requests. This response is only cacheable if indicated by a Cache-Control or Expires header field.<br/><br/>The temporary URI SHOULD be given by the Location field in the response. Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s).<br/><br/>If the 302 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Note: RFC 1945 and RFC 2068 specify that the client is not allowed<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;to change the method on the redirected request.&nbsp;&nbsp;However, most<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;existing user agent implementations treat 302 as if it were a 303<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;response, performing a GET on the Location field-value regardless<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;of the original request method. The status codes 303 and 307 have<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;been added for servers that wish to make unambiguously clear which<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;kind of reaction is expected of the client.<br/><br/>10.3.4 303 See Other<br/><br/>The response to the request can be found under a different URI and SHOULD be retrieved using a GET method on that resource. This method exists primarily to allow the output of a POST-activated script to redirect the user agent to a selected resource. The new URI is not a substitute reference for the originally requested resource. The 303 response MUST NOT be cached, but the response to the second (redirected) request might be cacheable.<br/><br/>The different URI SHOULD be given by the Location field in the response. Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s).<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Note: Many pre-HTTP/1.1 user agents do not understand the 303<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status. When interoperability with such clients is a concern, the<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;302 status code may be used instead, since most user agents react<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;to a 302 response as described here for 303.<br/><br/>10.3.5 304 Not Modified<br/><br/>If the client has performed a conditional GET request and access is allowed, but the document has not been modified, the server SHOULD respond with this status code. The 304 response MUST NOT contain a message-body, and thus is always terminated by the first empty line after the header fields.<br/><br/>The response MUST include the following header fields:<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- Date, unless its omission is required by section 14.18.1<br/><br/>If a clockless origin server obeys these rules, and proxies and clients add their own Date to any response received without one (as already specified by [RFC 2068], section 14.19), caches will operate correctly.<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- ETag and/or Content-Location, if the header would have been sent<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;in a 200 response to the same request<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- Expires, Cache-Control, and/or Vary, if the field-value might<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;differ from that sent in any previous response for the same<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;variant<br/><br/>If the conditional GET used a strong cache validator (see section 13.3.3), the response SHOULD NOT include other entity-headers. Otherwise (i.e., the conditional GET used a weak validator), the response MUST NOT include other entity-headers; this prevents inconsistencies between cached entity-bodies and updated headers.<br/><br/>If a 304 response indicates an entity not currently cached, then the cache MUST disregard the response and repeat the request without the conditional.<br/><br/>If a cache uses a received 304 response to update a cache entry, the cache MUST update the entry to reflect any new field values given in the response.<br/>10.3.6 305 Use Proxy<br/><br/>The requested resource MUST be accessed through the proxy given by the Location field. The Location field gives the URI of the proxy. The recipient is expected to repeat this single request via the proxy. 305 responses MUST only be generated by origin servers.<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Note: RFC 2068 was not clear that 305 was intended to redirect a<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;single request, and to be generated by origin servers only.&nbsp;&nbsp;Not<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;observing these limitations has significant security consequences.<br/><br/>10.3.7 306 (Unused)<br/><br/>The 306 status code was used in a previous version of the specification, is no longer used, and the code is reserved.<br/>10.3.8 307 Temporary Redirect<br/><br/>The requested resource resides temporarily under a different URI. Since the redirection MAY be altered on occasion, the client SHOULD continue to use the Request-URI for future requests. This response is only cacheable if indicated by a Cache-Control or Expires header field.<br/><br/>The temporary URI SHOULD be given by the Location field in the response. Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s) , since many pre-HTTP/1.1 user agents do not understand the 307 status. Therefore, the note SHOULD contain the information necessary for a user to repeat the original request on the new URI.<br/><br/>If the 307 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.<br/>10.4 Client Error 4xx<br/><br/>The 4xx class of status code is intended for cases in which the client seems to have erred. Except when responding to a HEAD request, the server SHOULD include an entity containing an explanation of the error situation, and whether it is a temporary or permanent condition. These status codes are applicable to any request method. User agents SHOULD display any included entity to the user.<br/><br/>If the client is sending data, a server implementation using TCP SHOULD be careful to ensure that the client acknowledges receipt of the packet(s) containing the response, before the server closes the input connection. If the client continues sending data to the server after the close, the server's TCP stack will send a reset packet to the client, which may erase the client's unacknowledged input buffers before they can be read and interpreted by the HTTP application.<br/>10.4.1 400 Bad Request<br/><br/>The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repeat the request without modifications.<br/>10.4.2 401 Unauthorized<br/><br/>The request requires user authentication. The response MUST include a WWW-Authenticate header field (section 14.47) containing a challenge applicable to the requested resource. The client MAY repeat the request with a suitable Authorization header field (section 14.8). If the request already included Authorization credentials, then the 401 response indicates that authorization has been refused for those credentials. If the 401 response contains the same challenge as the prior response, and the user agent has already attempted authentication at least once, then the user SHOULD be presented the entity that was given in the response, since that entity might include relevant diagnostic information. HTTP access authentication is explained in "HTTP Authentication: Basic and Digest Access Authentication" [43].<br/>10.4.3 402 Payment Required<br/><br/>This code is reserved for future use.<br/>10.4.4 403 Forbidden<br/><br/>The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. If the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead.<br/>10.4.5 404 Not Found<br/><br/>The server has not found anything matching the Request-URI. No indication is given of whether the condition is temporary or permanent. The 410 (Gone) status code SHOULD be used if the server knows, through some internally configurable mechanism, that an old resource is permanently unavailable and has no forwarding address. This status code is commonly used when the server does not wish to reveal exactly why the request has been refused, or when no other response is applicable.<br/>10.4.6 405 Method Not Allowed<br/><br/>The method specified in the Request-Line is not allowed for the resource identified by the Request-URI. The response MUST include an Allow header containing a list of valid methods for the requested resource.<br/>10.4.7 406 Not Acceptable<br/><br/>The resource identified by the request is only capable of generating response entities which have content characteristics not acceptable according to the accept headers sent in the request.<br/><br/>Unless it was a HEAD request, the response SHOULD include an entity containing a list of available entity characteristics and location(s) from which the user or user agent can choose the one most appropriate. The entity format is specified by the media type given in the Content-Type header field. Depending upon the format and the capabilities of the user agent, selection of the most appropriate choice MAY be performed automatically. However, this specification does not define any standard for such automatic selection.<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Note: HTTP/1.1 servers are allowed to return responses which are<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;not acceptable according to the accept headers sent in the<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;request. In some cases, this may even be preferable to sending a<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;406 response. User agents are encouraged to inspect the headers of<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;an incoming response to determine if it is acceptable.<br/><br/>If the response could be unacceptable, a user agent SHOULD temporarily stop receipt of more data and query the user for a decision on further actions.<br/>10.4.8 407 Proxy Authentication Required<br/><br/>This code is similar to 401 (Unauthorized), but indicates that the client must first authenticate itself with the proxy. The proxy MUST return a Proxy-Authenticate header field (section 14.33) containing a challenge applicable to the proxy for the requested resource. The client MAY repeat the request with a suitable Proxy-Authorization header field (section 14.34). HTTP access authentication is explained in "HTTP Authentication: Basic and Digest Access Authentication" [43].<br/>10.4.9 408 Request Timeout<br/><br/>The client did not produce a request within the time that the server was prepared to wait. The client MAY repeat the request without modifications at any later time.<br/>10.4.10 409 Conflict<br/><br/>The request could not be completed due to a conflict with the current state of the resource. This code is only allowed in situations where it is expected that the user might be able to resolve the conflict and resubmit the request. The response body SHOULD include enough<br/><br/>information for the user to recognize the source of the conflict. Ideally, the response entity would include enough information for the user or user agent to fix the problem; however, that might not be possible and is not required.<br/><br/>Conflicts are most likely to occur in response to a PUT request. For example, if versioning were being used and the entity being PUT included changes to a resource which conflict with those made by an earlier (third-party) request, the server might use the 409 response to indicate that it can't complete the request. In this case, the response entity would likely contain a list of the differences between the two versions in a format defined by the response Content-Type.<br/>10.4.11 410 Gone<br/><br/>The requested resource is no longer available at the server and no forwarding address is known. This condition is expected to be considered permanent. Clients with link editing capabilities SHOULD delete references to the Request-URI after user approval. If the server does not know, or has no facility to determine, whether or not the condition is permanent, the status code 404 (Not Found) SHOULD be used instead. This response is cacheable unless indicated otherwise.<br/><br/>The 410 response is primarily intended to assist the task of web maintenance by notifying the recipient that the resource is intentionally unavailable and that the server owners desire that remote links to that resource be removed. Such an event is common for limited-time, promotional services and for resources belonging to individuals no longer working at the server's site. It is not necessary to mark all permanently unavailable resources as "gone" or to keep the mark for any length of time -- that is left to the discretion of the server owner.<br/>10.4.12 411 Length Required<br/><br/>The server refuses to accept the request without a defined Content- Length. The client MAY repeat the request if it adds a valid Content-Length header field containing the length of the message-body in the request message.<br/>10.4.13 412 Precondition Failed<br/><br/>The precondition given in one or more of the request-header fields evaluated to false when it was tested on the server. This response code allows the client to place preconditions on the current resource metainformation (header field data) and thus prevent the requested method from being applied to a resource other than the one intended.<br/>10.4.14 413 Request Entity Too Large<br/><br/>The server is refusing to process a request because the request entity is larger than the server is willing or able to process. The server MAY close the connection to prevent the client from continuing the request.<br/><br/>If the condition is temporary, the server SHOULD include a Retry- After header field to indicate that it is temporary and after what time the client MAY try again.<br/>10.4.15 414 Request-URI Too Long<br/><br/>The server is refusing to service the request because the Request-URI is longer than the server is willing to interpret. This rare condition is only likely to occur when a client has improperly converted a POST request to a GET request with long query information, when the client has descended into a URI "black hole" of redirection (e.g., a redirected URI prefix that points to a suffix of itself), or when the server is under attack by a client attempting to exploit security holes present in some servers using fixed-length buffers for reading or manipulating the Request-URI.<br/>10.4.16 415 Unsupported Media Type<br/><br/>The server is refusing to service the request because the entity of the request is in a format not supported by the requested resource for the requested method.<br/>10.4.17 416 Requested Range Not Satisfiable<br/><br/>A server SHOULD return a response with this status code if a request included a Range request-header field (section 14.35), and none of the range-specifier values in this field overlap the current extent of the selected resource, and the request did not include an If-Range request-header field. (For byte-ranges, this means that the first- byte-pos of all of the byte-range-spec values were greater than the current length of the selected resource.)<br/><br/>When this status code is returned for a byte-range request, the response SHOULD include a Content-Range entity-header field specifying the current length of the selected resource (see section 14.16). This response MUST NOT use the multipart/byteranges content- type.<br/>10.4.18 417 Expectation Failed<br/><br/>The expectation given in an Expect request-header field (see section 14.20) could not be met by this server, or, if the server is a proxy, the server has unambiguous evidence that the request could not be met by the next-hop server.<br/>10.5 Server Error 5xx<br/><br/>Response status codes beginning with the digit "5" indicate cases in which the server is aware that it has erred or is incapable of performing the request. Except when responding to a HEAD request, the server SHOULD include an entity containing an explanation of the error situation, and whether it is a temporary or permanent condition. User agents SHOULD display any included entity to the user. These response codes are applicable to any request method.<br/>10.5.1 500 Internal Server Error<br/><br/>The server encountered an unexpected condition which prevented it from fulfilling the request.<br/>10.5.2 501 Not Implemented<br/><br/>The server does not support the functionality required to fulfill the request. This is the appropriate response when the server does not recognize the request method and is not capable of supporting it for any resource.<br/>10.5.3 502 Bad Gateway<br/><br/>The server, while acting as a gateway or proxy, received an invalid response from the upstream server it accessed in attempting to fulfill the request.<br/>10.5.4 503 Service Unavailable<br/><br/>The server is currently unable to handle the request due to a temporary overloading or maintenance of the server. The implication is that this is a temporary condition which will be alleviated after some delay. If known, the length of the delay MAY be indicated in a Retry-After header. If no Retry-After is given, the client SHOULD handle the response as it would for a 500 response.<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Note: The existence of the 503 status code does not imply that a<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;server must use it when becoming overloaded. Some servers may wish<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;to simply refuse the connection.<br/><br/>10.5.5 504 Gateway Timeout<br/><br/>The server, while acting as a gateway or proxy, did not receive a timely response from the upstream server specified by the URI (e.g. HTTP, FTP, LDAP) or some other auxiliary server (e.g. DNS) it needed to access in attempting to complete the request.<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Note: Note to implementors: some deployed proxies are known to<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 400 or 500 when DNS lookups time out.<br/><br/>10.5.6 505 HTTP Version Not Supported<br/><br/>The server does not support, or refuses to support, the HTTP protocol version that was used in the request message. The server is indicating that it is unable or unwilling to complete the request using the same major version as the client, as described in section 3.1, other than with this error message. The response SHOULD contain an entity describing why that version is not supported and what other protocols are supported by that server.<br/>
]]>
</description>
</item><item>
<link>https://atim.cn/post/467/</link>
<title><![CDATA[[转载]php编码问题:PHP开发中的中文编码问题]]></title> 
<author>bkkkd &lt;partybase@gmail.com&gt;</author>
<category><![CDATA[Web 技术 ]]></category>
<pubDate>Wed, 26 Nov 2008 23:35:39 +0000</pubDate> 
<guid>https://atim.cn/post/467/</guid> 
<description>
<![CDATA[ 
	一：首先介绍问题起源<br/>每个国家（或区域）都规定了计算机信息交换用的字符编码集，如美国的扩展 ASCII码, 中国的 GB2312-80，日本的 JIS 等，作为该国家/区域内信息处理的基础，有着统一编码的重要作用。字符编码集按长度分为 SBCS（单字节字符集），DBCS（双字节字符集）两大类。早期的软件（尤其是操作系统），为了解决本地字符信息的计算机处理，出现了各种本地化版本（L10N），为了区分，引进了 LANG, Codepage 等概念。但是由于各个本地字符集代码范围重叠，相互间信息交换困难；软件各个本地化版本独立维护成本较高。因此有必要将本地化工作中的共性抽取出来，作一致处理，将特别的本地化处理内容降低到最少。这也就是所谓的国际化（I18N）。各种语言信息被进一步规范为 Locale 信息。处理的底层字符集变成了几乎包含了所有字形的 Unicode。现在大部分具有国际化特征的软件核心字符处理都是以 Unicode 为基础的，在软件运行时根据当时的 Locale/Lang/Codepage 设置<br/>确定相应的本地字符编码设置，并依此处理本地字符。在处理过程中需要实现 Unicode 和本地字符集的相互转换，甚或以 Unicode 为中间的两个不同本地字符集的相互转换。这种方式在网络环境下被进一步延伸，任何网络两端的字符信息也需要根据字符集的设置转换成可接受的内容。<br/><br/>三：数据库读写时的 encoding 问题<br/><br/>1) 流行的关系数据库系统都支持数据库 encoding，也就是说在创建数据库时可以指定它自己的字符集设置，数据库的数据以指定的编码形式存储。当应用程序访问数据时，在入口和出口处都会有 encoding 转换。对于中文数据，数据库字符编码的设置应当保证数据的完整性. GB2312，GBK，UTF-8 等都是可选的数据库 encoding；也可以选择 ISO8859-1 (8-bit)，那么应用程序在写数据之前须将 16Bit 的一个汉字或 Unicode 拆分成两个8-bit 的字符，读数据之后则需将两个字节合并起来，同时还要判别其中的 SBCS 字符。没有充分利用数据库 encoding 的作用，反而增加了编程的复杂度，ISO8859-1不是推荐的数据库 encoding。编程时，可以先用数据库管理系统提供的管理功能检查其中的中文数据是否正确。<br/>2) PHP 程序在查询数据库之前，首先执行 mysql_query("SET NAMES xxxx");其中 xxxx 是你网页的编码(charset=xxxx)，如果网页中 charset=utf8，则 xxxx=utf8，如果网页中 charset=gb2312，则xxxx=gb2312，几乎所有WEB程序，都有一段连接数据库的公共代码，放在一个文件里，在这文件里，加入 mysql_query("set names")就可以了。SET NAMES 显示客户端发送的 SQL 语句中使用什么字符集。因此，SET NAMES 'utf-8'语句告诉服务器"将来从这个客户端传来的信息采用字符集utf-8"。它还为服务器发送回客户端的结果指定了字符集。（例如，如果你使用一个SELECT语句，它表示列值使用了什么字符集。）<br/><br/>四：定位问题时常用的技巧<br/>定位中文encoding问题通常采用最笨的也是最有效的办法――在你认为有嫌疑的程序处理后打印字符串的内码。通过打印字符串的内码，你可以发现什么时候中文字符被转换成Unicode，什么时候Unicode被转回中文内码，什么时候一个中文字成了两个 Unicode字符，什么时候中文字符串被转成了一串问号，什么时候中文字符串的高位被截掉了……取用合适的样本字符串也有助于区分问题的类型。如："aa啊aa?@aa" 等中英相间、GB、GBK特征字符均有的字符串。一般来说，英文字符无论怎么转换或处理，都不会失真（如果遇到了，可以尝试着增加连续的英文字母长度）。<br/><br/>五：解决各种应用的乱码问题<br/>首先掌握页面编码设置规则<br/>1. 使用 <META http-equiv="content-type" c> 标签设置页面编码这个标签的作用是声明客户端的浏览器用什么字符集编码显示该页面，xxx可以为GB2312，GBK，UTF-8（和MySQL不同，MySQL是 UTF8）等等。因此，大部分页面可以采用这种方式来告诉浏览器显示这个页面的时候采用什么编码，这样才不会造成编码错误而产生乱码。但是有的时候我们会发现有了这句还是不行，不管xxx是哪一种，浏览器采用的始终都是一种编码，这个情况我后面会谈到。请注意，<meta>是属于html信息的，仅仅是一个声明，它起作用表明服务器已经把HTML信息传到了浏览器。<br/>2. header("content-type:text/html; charset=xxx");<br/>这个函数header()的作用是把括号里面的信息发到http标头。<br/>如果括号里面的内容为文中所说那样，那作用和<META>标签基本相同，大家对照第一个看发现字符都差不多的。但是不同的是如果有这段函数，浏览器就会永远采用你所要求的xxx编码，绝对不会不听话，因此这个函数是很有用的。为什么会这样呢？那就得说说HTTPS标头和HTML信息的差别了：https标头是服务器以HTTP协议传送HTML信息到浏览器前所送出的字串。因为meta标签是属于html信息的，所以header()发送的内容先到达浏览器，通俗点就是header()的优先级高于meta（不知道可不可以这样讲）。加入一个php页面既有header("content- type:text/html; charset=xxx")，又有<META http-equiv="content-type" c>，浏览器就只认前者http标头而不认meta了。当然这个函数只能在php页面内使用。同样也留有一个问题，为什么前者就绝对起作用，而后者有时候就不行呢？这就是接下来要谈的Apache的原因了。<br/>3. AddDefaultCharset<br/>Apache 根目录的 conf 文件夹里，有整个Apache的配置文档httpd.conf。<br/>用文本编辑器打开httpd.conf，第708行（不同版本可能不同）有AddDefaultCharset xxx，xxx为编码名称。这行代码的意思：设置整个服务器内的网页文件https标头里的字符集为你默认的xxx字符集。有这行，就相当于给每个文件都加了一行header("content-type:text/html; charset=xxx")。这下就明白为什么明明meta设置了是utf-8，可浏览器始终采用gb2312的原因。如果网页里有 header("content-type:text/html; charset=xxx")，就把默认的字符集改为你设置的字符集，所以这个函数永远有用。如果把AddDefaultCharset xxx前面加个"#"，注释掉这句，而且页面里不含header("content-type…")，那这个时候就轮到<br/>meta标签起作用了。<br/>下面列出以上的优先顺序：<br/>1>---header("content-type:text/html; charset=utf-8")<br/>2>---AddDefaultCharset xxx<br/>3>---<META http-equiv="content-type" c><br/>如果你是web程序员，给你的每个页面都加个header("content-type:text/html; charset=utf-8")，保证它在任何服务器都能正确显 示，可移植性强。<br/><br/>结束语<br/>其实 php开发中的中文encoding 并没有想像的那么复杂，虽然定位和解决问题没有定规，各种运行环境也各不尽然，但后面的原理是一样的。了解字符集的知识是解决字符问题的基础。不过，随着中文字符集的变化，不仅仅是 php编程，中文信息处理中的问题还是会存在一段时间的。<br/><br/>补充：<br/>定义php的默认语言.<br/>php.ini中： <br/><br/>From: PHPChina
]]>
</description>
</item><item>
<link>https://atim.cn/post/456/</link>
<title><![CDATA[[转]PPPoE作NAT共享上网]]></title> 
<author>bkkkd &lt;partybase@gmail.com&gt;</author>
<category><![CDATA[Web 技术 ]]></category>
<pubDate>Tue, 11 Nov 2008 16:21:36 +0000</pubDate> 
<guid>https://atim.cn/post/456/</guid> 
<description>
<![CDATA[ 
	<br/>OpenBSD4.1设PPPoE作NAT共享上网首先安装好OpenBSD4.1,我的机器有两个网卡：一个是pcn0是作为连接ADSL MODEL的，一个是pcn1是作为连接内网的。<br/><br/>其中下面全部配置中的pcn0是我的连接ADSL MODEL的网卡名，你要更改成你定际的网卡名。pcn1同样也要改成连接你内网的网卡名。<br/><br/>1) 连接ADSL MODEL的网卡不需要有IP,所以用 vi /etc/hostname.pcn0 编辑网卡配置文件。将里面的内容全部清空。<br/><br/>2)将/etc/mygate中的全部内容也删除。这样就没有设缺省网关了。<br/><br/>3)配置内网网卡的IP.<br/>&nbsp;&nbsp;vi /etc/hostname.pcn1<br/>在里面加上以下内容：<br/>inet 192.168.188.1 255.255.255.0 192.168.188.255<br/><br/>4)在/etc/resolv.conf 中加入下面的内容，以设定DNS<br/>lookup file bind<br/>nameserver&nbsp;&nbsp;&nbsp;&nbsp;202.96.128.166 202.96.128.86<br/><br/>5)运行sh /etc/netstart使所作的ip配置生效。这时，<br/>在你内网的电脑可以ping 192.168.188.1来试下你的内网<br/>网卡有没设错。<br/><br/><br/>6)配置PPPoE需要用到的ppp拔号配置文件<br/>vi /etc/ppp/ppp.conf<br/>加入下面的内容,注意大小写和将我的pcn0网卡名换成你的:<br/><br/>default:<br/>&nbsp;&nbsp;&nbsp;&nbsp; set log Phase Chat LCP IPCP CCP tun command<br/>&nbsp;&nbsp;&nbsp;&nbsp; set timeout 0<br/>&nbsp;&nbsp;&nbsp;&nbsp; set redial 15 0<br/>&nbsp;&nbsp;&nbsp;&nbsp; set reconnect 15 10000<br/>&nbsp;&nbsp;&nbsp;&nbsp; set server /var/run/ppp.sock "" 0177<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;pppoe:<br/>&nbsp;&nbsp;&nbsp;&nbsp; set device "!/usr/sbin/pppoe -i pcn0"<br/>&nbsp;&nbsp;&nbsp;&nbsp; set mtu max 1492<br/>&nbsp;&nbsp;&nbsp;&nbsp; set mru max 1492<br/>&nbsp;&nbsp;&nbsp;&nbsp; set speed sync<br/>&nbsp;&nbsp;&nbsp;&nbsp; enable lqr<br/>&nbsp;&nbsp;&nbsp;&nbsp; disable acfcomp protocomp<br/>&nbsp;&nbsp;&nbsp;&nbsp; deny acfcomp<br/>&nbsp;&nbsp;&nbsp;&nbsp; add! default HISADDR<br/>&nbsp;&nbsp;&nbsp;&nbsp; set authname "你的ADSL账号名"<br/>&nbsp;&nbsp;&nbsp;&nbsp; set authkey "你的ADSL密码"<br/>现在可以试试你设的PPPoE是否正确<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;sh /sbin/ifconfig pcn0 up<br/>&nbsp;&nbsp;&nbsp;&nbsp;sh /usr/sbin/ppp -ddial pppoe<br/>命令中的-ddial是接断线后不断重拔。连接上了后，你可以用ifconfig<br/>看到新加了一个网络设备tun0。你还可以ping一下google.com，看网络是不是真的通了。<br/>再在/etc/rc.local中中入以下内容，使它下次开机自动拔号上网。<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;/sbin/ifconfig pcn0 up<br/>&nbsp;&nbsp;&nbsp;&nbsp;/usr/sbin/ppp -ddial pppoe<br/><br/><br/>7) 运行sysctl net.inet.ip.fowarding=1 ，<br/>你可以看到屏幕显示 net.inet.ip.forwarding: 0 -> 1<br/><br/>这表示IP转发开启了，想要在下次开机后自动开启，<br/>vi /etc/sysctl.conf<br/>将#net.inet.ip.forwarding=1 中的最前面的#号删除<br/><br/>8)下面我们来配置package filter配置文件,将以下内容加在/etc/pf.conf中<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;ext_if="tun0"<br/>&nbsp;&nbsp;&nbsp;&nbsp;int_if="pcn1"<br/>&nbsp;&nbsp;&nbsp;&nbsp;internal_net="192.168.188.0/24"<br/>&nbsp;&nbsp;&nbsp;&nbsp;scrub in all<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;# for NAT<br/>&nbsp;&nbsp;&nbsp;&nbsp;nat on $ext_if from $internal_net to any -> ($ext_if)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;# for firewall<br/>&nbsp;&nbsp;&nbsp;&nbsp;block in all<br/>&nbsp;&nbsp;&nbsp;&nbsp;block out all<br/>&nbsp;&nbsp;&nbsp;&nbsp;pass quick on lo0 all<br/>&nbsp;&nbsp;&nbsp;&nbsp;pass out on $ext_if proto tcp all modulate state flags S/SA<br/>&nbsp;&nbsp;&nbsp;&nbsp;pass out on $ext_if proto &#123; udp, icmp &#125; all keep state<br/>&nbsp;&nbsp;&nbsp;&nbsp;pass in on $int_if from $internal_net to any<br/>&nbsp;&nbsp;&nbsp;&nbsp;pass out on $int_if from any to $internal_net<br/>其中的tun0是pppoe拔号连接上后系统自动新加的虚拟网卡，pcn1是我的内网网卡，<br/>192.168.188.0/24是我的内网网段。<br/><br/>现在运行 pfctl -e 来运行package filter.<br/>屏幕上会显示 pf enabled 。<br/>这时，你内网的电脑就可以上网了。<br/><br/>最后将/etc/rc.conf中的pf=NO修改为<br/>pf=YES<br/>使下次开机自动运行package filter.<br/><br/>====================================<br/>使Openbsd的网络更加安全，更加快<br/>vi /etc/inetd.conf<br/>在<br/>ident&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stream&nbsp;&nbsp;&nbsp;&nbsp;tcp&nbsp;&nbsp;&nbsp;&nbsp;nowait&nbsp;&nbsp;&nbsp;&nbsp;_identd&nbsp;&nbsp;&nbsp;&nbsp;/usr/libexec/identd&nbsp;&nbsp;&nbsp;&nbsp;identd -el<br/>ident&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stream&nbsp;&nbsp;&nbsp;&nbsp;tcp6&nbsp;&nbsp;&nbsp;&nbsp;nowait&nbsp;&nbsp;&nbsp;&nbsp;_identd&nbsp;&nbsp;&nbsp;&nbsp;/usr/libexec/identd&nbsp;&nbsp;&nbsp;&nbsp;identd -el<br/>这两行前加上#号，让系统开机不自动运行ident网络服务。<br/><br/>同样，对comsat的两行也同样加上#号，禁止自动运行comsat网络服务。<br/>127.0.0.1:comsat dgram&nbsp;&nbsp;&nbsp;&nbsp;udp&nbsp;&nbsp;&nbsp;&nbsp;wait&nbsp;&nbsp;&nbsp;&nbsp;root&nbsp;&nbsp;&nbsp;&nbsp;/usr/libexec/comsat&nbsp;&nbsp;&nbsp;&nbsp;comsat<br/>[::1]:comsat&nbsp;&nbsp;&nbsp;&nbsp;dgram&nbsp;&nbsp;&nbsp;&nbsp;udp6&nbsp;&nbsp;&nbsp;&nbsp;wait&nbsp;&nbsp;&nbsp;&nbsp;root&nbsp;&nbsp;&nbsp;&nbsp;/usr/libexec/comsat&nbsp;&nbsp;&nbsp;&nbsp;comsat<br/><br/>同样，对daytime和time网络服务作同样禁止处理。&nbsp;&nbsp; <br/>daytime&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stream&nbsp;&nbsp;&nbsp;&nbsp;tcp&nbsp;&nbsp;&nbsp;&nbsp;nowait&nbsp;&nbsp;&nbsp;&nbsp;root&nbsp;&nbsp;&nbsp;&nbsp;internal<br/>daytime&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stream&nbsp;&nbsp;&nbsp;&nbsp;tcp6&nbsp;&nbsp;&nbsp;&nbsp;nowait&nbsp;&nbsp;&nbsp;&nbsp;root&nbsp;&nbsp;&nbsp;&nbsp;internal<br/>time&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stream&nbsp;&nbsp;&nbsp;&nbsp;tcp&nbsp;&nbsp;&nbsp;&nbsp;nowait&nbsp;&nbsp;&nbsp;&nbsp;root&nbsp;&nbsp;&nbsp;&nbsp;internal<br/>time&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stream&nbsp;&nbsp;&nbsp;&nbsp;tcp6&nbsp;&nbsp;&nbsp;&nbsp;nowait&nbsp;&nbsp;&nbsp;&nbsp;root&nbsp;&nbsp;&nbsp;&nbsp;internal<br/><br/>--------------------------------------------------------------------------------------<br/><br/>vi /etc/rc.conf&nbsp;&nbsp;设置<br/>sendmail_flags=NO<br/>关闭sendmail.<br/><br/>再来vi /var/cron/tabs/root<br/>将其中sendmail的一部分修改,加上一个#号，让sendmail不开机自动运行。<br/>*/30&nbsp;&nbsp; *&nbsp;&nbsp; *&nbsp;&nbsp; *&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;/usr/sbin/sendmail -L sm-msp-queue -Ac -q<br/><br/>而sshd就看是不是需要远程ssh连接过来，要的话，就保持它<br/>sshd_flags=""<br/>不需要的话，就vi /etc/rc.conf,修改<br/>sshd_flags=NO<br/>------------------------------------------------------------------------------------<br/><br/>vi /etc/sysctl.conf 在文件中开启swap分区加密<br/>vm.swapencrypt.enable=1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 1=Encrypt pages that go to swap<br/><br/>-----------------------------------------------------------------------------------<br/>加以下内容到/etc/sysctl.conf中，使增加wan口上的tcp性能。<br/># 1. Path MTU discovery: enabled by default<br/># 2. TCP Extension (RFC1323): enabled by default<br/># 3. Increase TCP Window size for increase in network performance<br/>net.inet.tcp.recvspace=65535<br/>net.inet.tcp.sendspace=65535<br/># 4. SACK (RFC2018): enabled by default<br/><br/><br/>完。<br/>参考了网上找的这个资料。特别是pf.conf的配置。<br/>===========================================<br/><br/>I've been using an OpenBSD box for NAT/firewall at home (with Verizon DSL) for a while now. I switched to OpenBSD after Red Hat dropped their non-enterprise version (don't get me wrong, I still use Fedora on desktop machines). The installation/setup is actually quite simple. Here are some notes.<br/>Update(20040708): The notes have been updated for OpenBSD 3.5.<br/><br/>&nbsp;&nbsp; 1. My internal and external network interfaces are fxp0 and fxp1, respectively. Note that after PPPoE is done, fxp1 will be represented by tun0.<br/><br/>&nbsp;&nbsp; 2. Follow this to install OpenBSD 3.5 and configure the internal interface during the installation. After the installation, modify configuration files as follows.<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Note: Section 4.5.2 of the installation guide says "It is important that the first partition skips the first track of the disk, in this case, starting on sector 63". However, I'm using the first partition for OpenBSD, and I had to make the partition start on sector 0 (otherwise, it seems that the bootloader won't be installed correctly). Of course, YMMV.<br/><br/>&nbsp;&nbsp; 3. /etc/rc.conf: make sure "pf=NO" (will start pf after the DSL link is up).<br/><br/>&nbsp;&nbsp; 4. /etc/rc.local: put the following lines at the end to bring up the external interface and start ppp.<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/sbin/ifconfig fxp1 up<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/usr/sbin/ppp -ddial pppoe<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/><br/>&nbsp;&nbsp; 5. /etc/sysctl.conf: make sure "net.inet.ip.forwarding=1" (enable IP forwarding).<br/><br/>&nbsp;&nbsp; 6. My /etc/ppp/ppp.conf is as follows:<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;default:<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set log Phase Chat LCP IPCP CCP tun command<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set timeout 0<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set redial 15 0<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set reconnect 15 10000<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set server /var/run/ppp.sock "" 0177<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pppoe:<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set device "!/usr/sbin/pppoe -i fxp1"<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set mtu max 1492<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set mru max 1492<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set speed sync<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enable lqr<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; disable acfcomp protocomp<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; deny acfcomp<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; add! default HISADDR<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set authname <your_user_name><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set authkey <your_password><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Note: you can remove "LCP" from the first line of "default" if it's generating too many log messages.<br/><br/>&nbsp;&nbsp; 7. My /etc/ppp/ppp.linkup is as follows:<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MYADDR:<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;! sh -c "/sbin/pfctl -e -f /etc/pf.conf"<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;This will start pf after the link is up.<br/><br/>&nbsp;&nbsp; 8. Finally, the NAT/firewall rules are specified in /etc/pf.conf (for more information about the rules, see here):<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ext_if="tun0"<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int_if="fxp0"<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;internal_net="192.168.0.0/24"<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scrub in all<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# for NAT<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nat on $ext_if from $internal_net to any -> ($ext_if)<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# for firewall<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;block in all<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;block out all<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pass quick on lo0 all<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pass out on $ext_if proto tcp all modulate<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; state flags S/SA<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pass out on $ext_if proto &#123; udp, icmp &#125; all keep<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; state<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pass in on $int_if from $internal_net to any<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pass out on $int_if from any to $internal_net<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/><br/>These are based on several online documents I've read. Please let me know if you find something I missed. Thanks! 
]]>
</description>
</item><item>
<link>https://atim.cn/post/425/</link>
<title><![CDATA[[转载]UTF-8编码的详细讲解]]></title> 
<author>bkkkd &lt;partybase@gmail.com&gt;</author>
<category><![CDATA[Web 技术 ]]></category>
<pubDate>Wed, 27 Aug 2008 23:29:05 +0000</pubDate> 
<guid>https://atim.cn/post/425/</guid> 
<description>
<![CDATA[ 
	UTF-8 and Unicode FAQ <br/>by Markus Kuhn&nbsp;&nbsp;<br/><br/>中国LINUX论坛翻译小组 xLoneStar[译] 2000年2月&nbsp;&nbsp;<br/>这篇文章说明了在 POSIX 系统 (Linux,Unix) 上使用 Unicode/UTF-8 所需要的信息. 在将来不远的几年里, Unicode 已经很接近于取代 ASCII 与 Latin-1 编码的位置了. 它不仅允许你处理处理事实上存在于地球上的任何语言文字, 而且提供了一个全面的数学与技术符号集, 因此可以简化科学信息交换. <br/><br/>UTF-8 编码提供了一种简便而向后兼容的方法, 使得那种完全围绕 ASCII 设计的操作系统, 比如 Unix, 也可以使用 Unicode. UTF-8 就是 Unix, Linux 已经类似的系统使用 Unicode 的方式. 现在是你了解它的时候了. <br/><br/>什么是 UCS 和 ISO 10646? <br/>国际标准 ISO 10646 定义了 通用字符集 (Universal Character Set, UCS). UCS 是所有其他字符集标准的一个超集. 它保证与其他字符集是双向兼容的. 就是说, 如果你将任何文本字符串翻译到 UCS格式, 然后再翻译回原编码, 你不会丢失任何信息. <br/><br/>UCS 包含了用于表达所有已知语言的字符. 不仅包括拉丁语,希腊语, 斯拉夫语,希伯来语,阿拉伯语,亚美尼亚语和乔治亚语的描述, 还包括中文, 日文和韩文这样的象形文字, 以及 平假名, 片假名, 孟加拉语, 旁遮普语果鲁穆奇字符(Gurmukhi), 泰米尔语, 印.埃纳德语 (Kannada), Malayalam, 泰国语, 老挝语, 汉语拼音 (Bopomofo), Hangul, Devangari, Gujarati, Oriya, Telugu 以及其他数也数不清的语. 对于还没有加入的语言, 由于正在研究怎样在计算机中最好地编码它们, 因而最终它们都将被加入. 这些语言包括 Tibetian, 高棉语, Runic(古代北欧文字), 埃塞俄比亚语, 其他象形文字, 以及各种各样的印-欧语系的语言, 还包括挑选出来的艺术语言比如 Tengwar, Cirth 和 克林贡语(Klingon). UCS 还包括大量的图形的, 印刷用的, 数学用的和科学用的符号, 包括所有由 TeX, Postscript, MS-DOS，MS-Windows, Macintosh, OCR 字体, 以及许多其他字处理和出版系统提供的字符. <br/><br/>ISO 10646 定义了一个 31 位的字符集. 然而, 在这巨大的编码空间中, 迄今为止只分配了前 65534 个码位 (0x0000 到 0xFFFD). 这个 UCS 的 16位子集称为 基本多语言面 (Basic Multilingual Plane, BMP). 将被编码在 16 位 BMP 以外的字符都属于非常特殊的字符(比如象形文字), 且只有专家在历史和科学领域里才会用到它们. 按当前的计划, 将来也许再也不会有字符被分配到从 0x000000 到 0x10FFFF 这个覆盖了超过 100 万个潜在的未来字符的 21 位的编码空间以外去了. ISO 10646-1 标准第一次发表于 1993 年, 定义了字符集与 BMP 中内容的架构. 定义 BMP 以外的字符编码的第二部分 ISO 10646-2 正在准备中, 但也许要过好几年才能完成. 新的字符仍源源不断地加入到 BMP 中, 但已经存在的字符是稳定的且不会再改变了. <br/><br/>UCS 不仅给每个字符分配一个代码, 而且赋予了一个正式的名字. 表示一个 UCS 或 Unicode 值的十六进制数, 通常在前面加上 "U+", 就象 U+0041 代表字符"拉丁大写字母 A". UCS 字符 U+0000 到 U+007F 与 US-ASCII(ISO 646) 是一致的, U+0000 到 U+00FF 与 ISO 8859-1(Latin-1) 也是一致的. 从 U+E000 到 U+F8FF, 已经 BMP 以外的大范围的编码是为私用保留的. <br/><br/>什么是组合字符? <br/>UCS里有些编码点分配给了 组合字符.它们类似于打字机上的无间隔重音键. 单个的组合字符不是一个完整的字符. 它是一个类似于重音符或其他指示标记, 加在前一个字符后面. 因而, 重音符可以加在任何字符后面. 那些最重要的被加重的字符, 就象普通语言的正字法(orthographies of common languages)里用到的那种, 在 UCS 里都有自己的位置, 以确保同老的字符集的向后兼容性. 既有自己的编码位置, 又可以表示为一个普通字符跟随一个组合字符的被加重字符, 被称为 预作字符(precomposed characters). UCS 里的预作字符是为了同没有预作字符的旧编码, 比如 ISO 8859, 保持向后兼容性而设的. 组合字符机制允许在任何字符后加上重音符或其他指示标记, 这在科学符号中特别有用, 比如数学方程式和国际音标字母, 可能会需要在一个基本字符后组合上一个或多个指示标记.<br/><br/>组合字符跟随着被修饰的字符. 比如, 德语中的元音变音字符 ("拉丁大写字母A 加上分音符"), 既可以表示为 UCS 码 U+00C4 的预作字符, 也可以表示成一个普通 "拉丁大写字母A" 跟着一个"组合分音符":U+0041 U+0308 这样的组合. 当需要堆叠多个重音符, 或在一个基本字符的上面和下面都要加上组合标记时, 可以使用多个组合字符. 比如在泰国文中, 一个基本字符最多可加上两个组合字符. <br/><br/>什么是 UCS 实现级别? <br/>不是所有的系统都需要支持象组合字符这样的 UCS 里所有的先进机制. 因此 ISO 10646 指定了下列三种实现级别:&nbsp;&nbsp;<br/><br/>级别1&nbsp;&nbsp;<br/>不支持组合字符和 Hangul Jamo 字符 (一种特别的, 更加复杂的韩国文的编码, 使用两个或三个子字符来编码一个韩文音节)&nbsp;&nbsp;<br/>级别2&nbsp;&nbsp;<br/>类似于级别1, 但在某些文字中, 允许一列固定的组合字符 (例如, 希伯来文, 阿拉伯文, Devangari, 孟加拉语, 果鲁穆奇语, Gujarati, Oriya, 泰米尔语, Telugo, 印.埃纳德语, Malayalam, 泰国语和老挝语). 如果没有这最起码的几个组合字符, UCS 就不能完整地表达这些语言.&nbsp;&nbsp;<br/>级别3&nbsp;&nbsp;<br/>支持所有的 UCS 字符, 例如数学家可以在任意一个字符上加上一个 tilde(颚化符号,西班牙语字母上面的～)或一个箭头(或两者都加).&nbsp;&nbsp;<br/>什么是 Unicode? <br/>历史上, 有两个独立的, 创立单一字符集的尝试. 一个是国际标准化组织(ISO)的 ISO 10646 项目, 另一个是由(一开始大多是美国的)多语言软件制造商组成的协会组织的 Unicode 项目. 幸运的是, 1991年前后, 两个项目的参与者都认识到, 世界不需要两个不同的单一字符集. 它们合并双方的工作成果, 并为创立一个单一编码表而协同工作. 两个项目仍都存在并独立地公布各自的标准, 但 Unicode 协会和 ISO/IEC JTC1/SC2 都同意保持 Unicode 和 ISO 10646 标准的码表兼容, 并紧密地共同调整任何未来的扩展. <br/><br/>那么 Unicode 和 ISO 10646 不同在什么地方? <br/>Unicode 协会公布的 Unicode 标准 严密地包含了 ISO 10646-1 实现级别3的基本多语言面. 在两个标准里所有的字符都在相同的位置并且有相同的名字. <br/><br/>Unicode 标准额外定义了许多与字符有关的语义符号学, 一般而言是对于实现高质量的印刷出版系统的更好的参考. Unicode 详细说明了绘制某些语言(比如阿拉伯语)表达形式的算法, 处理双向文字(比如拉丁与希伯来文混合文字)的算法和 排序与字符串比较 所需的算法, 以及其他许多东西. <br/><br/>另一方面, ISO 10646 标准, 就象广为人知的 ISO 8859 标准一样, 只不过是一个简单的字符集表. 它指定了一些与标准有关的术语, 定义了一些编码的别名, 并包括了规范说明, 指定了怎样使用 UCS 连接其他 ISO 标准的实现, 比如 ISO 6429 和 ISO 2022. 还有一些与 ISO 紧密相关的, 比如 ISO 14651 是关于 UCS 字符串排序的. <br/><br/>考虑到 Unicode 标准有一个易记的名字, 且在任何好的书店里的 Addison-Wesley 里有, 只花费 ISO 版本的一小部分, 且包括更多的辅助信息, 因而它成为使用广泛得多的参考也就不足为奇了. 然而, 一般认为, 用于打印 ISO 10646-1 标准的字体在某些方面的质量要高于用于打印 Unicode 2.0的. 专业字体设计者总是被建议说要两个标准都实现, 但一些提供的样例字形有显著的区别. ISO 10646-1 标准同样使用四种不同的风格变体来显示表意文字如中文, 日文和韩文 (CJK), 而 Unicode 2.0 的表里只有中文的变体. 这导致了普遍的认为 Unicode 对日本用户来说是不可接收的传说, 尽管是错误的. <br/><br/>什么是 UTF-8? <br/>首先 UCS 和 Unicode 只是分配整数给字符的编码表. 现在存在好几种将一串字符表示为一串字节的方法. 最显而易见的两种方法是将 Unicode 文本存储为 2 个 或 4 个字节序列的串. 这两种方法的正式名称分别为 UCS-2 和 UCS-4. 除非另外指定, 否则大多数的字节都是这样的(Bigendian convention). 将一个 ASCII 或 Latin-1 的文件转换成 UCS-2 只需简单地在每个 ASCII 字节前插入 0x00. 如果要转换成 UCS-4, 则必须在每个 ASCII 字节前插入三个 0x00.<br/><br/>在 Unix 下使用 UCS-2 (或 UCS-4) 会导致非常严重的问题. 用这些编码的字符串会包含一些特殊的字符, 比如 ’&#92;0’ 或 ’/’, 它们在 文件名和其他 C 库函数参数里都有特别的含义. 另外, 大多数使用 ASCII 文件的 UNIX 下的工具, 如果不进行重大修改是无法读取 16 位的字符的. 基于这些原因, 在文件名, 文本文件, 环境变量等地方, UCS-2 不适合作为 Unicode 的外部编码. <br/><br/>在 ISO 10646-1 Annex R 和 RFC 2279 里定义的 UTF-8 编码没有这些问题. 它是在 Unix 风格的操作系统下使用 Unicode 的明显的方法. <br/><br/>UTF-8 有一下特性:&nbsp;&nbsp;<br/><br/>UCS 字符 U+0000 到 U+007F (ASCII) 被编码为字节 0x00 到 0x7F (ASCII 兼容). 这意味着只包含 7 位 ASCII 字符的文件在 ASCII 和 UTF-8 两种编码方式下是一样的.&nbsp;&nbsp;<br/>所有 >U+007F 的 UCS 字符被编码为一个多个字节的串, 每个字节都有标记位集. 因此, ASCII 字节 (0x00-0x7F) 不可能作为任何其他字符的一部分.&nbsp;&nbsp;<br/>表示非 ASCII 字符的多字节串的第一个字节总是在 0xC0 到 0xFD 的范围里, 并指出这个字符包含多少个字节. 多字节串的其余字节都在 0x80 到 0xBF 范围里. 这使得重新同步非常容易, 并使编码无国界, 且很少受丢失字节的影响.&nbsp;&nbsp;<br/>可以编入所有可能的 231个 UCS 代码&nbsp;&nbsp;<br/>UTF-8 编码字符理论上可以最多到 6 个字节长, 然而 16 位 BMP 字符最多只用到 3 字节长.&nbsp;&nbsp;<br/>Bigendian UCS-4 字节串的排列顺序是预定的.&nbsp;&nbsp;<br/>字节 0xFE 和 0xFF 在 UTF-8 编码中从未用到.&nbsp;&nbsp;<br/>下列字节串用来表示一个字符. 用到哪个串取决于该字符在 Unicode 中的序号. <br/><br/>U-00000000 - U-0000007F: 0xxxxxxx&nbsp;&nbsp;<br/>U-00000080 - U-000007FF: 110xxxxx 10xxxxxx&nbsp;&nbsp;<br/>U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx&nbsp;&nbsp;<br/>U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx&nbsp;&nbsp;<br/>U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx&nbsp;&nbsp;<br/>U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx&nbsp;&nbsp;<br/><br/>xxx 的位置由字符编码数的二进制表示的位填入. 越靠右的 x 具有越少的特殊意义. 只用最短的那个足够表达一个字符编码数的多字节串. 注意在多字节串中, 第一个字节的开头"1"的数目就是整个串中字节的数目. <br/><br/>例如: Unicode 字符 U+00A9 = 1010 1001 (版权符号) 在 UTF-8 里的编码为: <br/><br/>11000010 10101001 = 0xC2 0xA9 <br/><br/>而字符 U+2260 = 0010 0010 0110 0000 (不等于) 编码为: <br/><br/>11100010 10001001 10100000 = 0xE2 0x89 0xA0 <br/><br/>这种编码的官方名字拼写为 UTF-8, 其中 UTF 代表 UCS Transformation Format. 请勿在任何文档中用其他名字 (比如 utf8 或 UTF_8) 来表示 UTF-8, 当然除非你指的是一个变量名而不是这种编码本身. <br/><br/>什么编程语言支持 Unicode? <br/>在大约 1993 年之后开发的大多数现代编程语言都有一个特别的数据类型, 叫做 Unicode/ISO 10646-1 字符. 在 Ada95 中叫 Wide_Character, 在 Java 中叫 char. <br/><br/>ISO C 也详细说明了处理多字节编码和宽字符 (wide characters) 的机制, 1994 年 9 月 Amendment 1 to ISO C 发表时又加入了更多. 这些机制主要是为各类东亚编码而设计的, 它们比处理 UCS 所需的要健壮得多. UTF-8 是 ISO C 标准调用多字节字符串的编码的一个例子, wchar_t 类型可以用来存放 Unicode 字符. <br/><br/>在 Linux 下该如何使用 Unicode? <br/>在 UTF-8 之前, 不同地区的 Linux 用户使用各种各样的 ASCII 扩展. 最普遍的欧洲编码是 ISO 8859-1 和 ISO 8859-2, 希腊编码 ISO 8859-7, 俄国编码 KOI-8, 日本编码 EUC 和 Shift-JIS, 等等. 这使得 文件的交换非常困难, 且应用软件必须特别关心这些编码的不同之处. <br/><br/>最终, Unicode 将取代所有这些编码, 主要通过 UTF-8 的形式. UTF-8 将应用在&nbsp;&nbsp;<br/><br/>文本文件 (源代码, HTML 文件, email 消息, 等等)&nbsp;&nbsp;<br/><br/>文件名&nbsp;&nbsp;<br/>标准输入与标准输出, 管道&nbsp;&nbsp;<br/>环境变量&nbsp;&nbsp;<br/>剪切与粘贴选择缓冲区&nbsp;&nbsp;<br/>telnet, modem 和到终端模拟器的串口连接&nbsp;&nbsp;<br/>以及其他地方以前用ASCII来表示的字节串&nbsp;&nbsp;<br/>在 UTF- 8 模式下, 终端模拟器, 比如 xterm 或 Linux console driver, 将每次按键转换成相应的 UTF-8 串, 然后发送到前台进程的 stdin 里. 类似的, 任何进程在 stdout 上的输出都将发送到终端模拟器, 在那里用一个 UTF-8 解码器进行处理, 之后再用一种 16 位的字体显示出来. <br/><br/>只有在功能完善的多语言字处理器包里才可能有完全的 Unicode 功能支持. 而广泛用在 Linux 里用于取代 ASCII 和其他 8 位字符集的方案则要简单得多. 第一步, Linux 终端模拟器和命令行工具将只是转变到 UTF-8. 这意味着只用到 级别1 的 ISO 10646-1 实现 (没有组合字符), 且只支持那些不需要更多处理的语言象 拉丁, 希腊, 斯拉夫 和许多科学用符号. 在这个级别上, UCS 支持与 ISO 8859 支持类似, 唯一显著的区别是现在我们有几千种字符可以用了, 其中的字符可以用多字节串来表示. <br/><br/>总有一天 Linux 会当然地支持组合字符, 但即便如此, 对于组合字符串, 预作字符 (如何可用的话)仍将是首选的. 更正式地, 在 Linux 下用 Unicode 对文本编码的首选的方法应该是定义在 Unicode Technical Report #15 里的 Normalization Form C. <br/><br/>在今后的一个阶段, 人们可以考虑增加在日文和中文里用到的双字节字符的支持 (他们相对比较简单), 组合字符支持, 甚至也许对从右至左书写的语言如希伯来文 (他们可不是那么简单的) 的支持. 但对这些高级功能的支持不应该阻碍简单的平板 UTF-8 在 拉丁, 希腊, 斯拉夫和科学用符号方面的快速应用, 以取代大量的欧洲 8 位编码, 并提供一个象样的科学用符号集. <br/><br/>我该怎样修改我的软件? <br/>有两种途径可以支持 UTF-8, 我称之为软转换与硬转换. 软转换时, 各处的数据均保存为 UTF-8 形式, 因而需要修改的软件很少. 在硬转换时, 程序将读入的 UTF-8 数据转换成宽字符数组, 以在应用程序内部处理. 在输出时, 再把字符串转换回 UTF-8 形式. <br/><br/>大多数应用程序只用软转换就可以工作得很好了. 这使得将 UTF-8 引入 Unix 成为切实可行的. 例如, 象 cat 和 echo 这样的程序根本不需要修改. 他们仍然可以对输入输出的是 ISO 8859-2 还是 UTF-8 一无所知, 因为它们只是搬运字节流而没有处理它们. 它们只能识别 ASCII 字符和象 ’&#92;n’ 这样的控制码, 而这在 UTF-8 下也没有任何改变. 因此, 这些应用程序的 UTF-8 编码与解码将完全在终端模拟器里完成. <br/><br/>而那些通过数字节数来获知字符数量的程序则需要一些小修改. 在 UTF-8 模式下, 它们必须不数入 0x80 到 0xBF 范围内的字节, 因为这些只是跟随字节, 它们本身并不是字符. 例如, ls 程序就必须要修改, 因为它通过数文件名中字符数来排放给用户的目录表格布局. 类似地, 所有的假定其输出为定宽字体, 并因此而格式化它们的程序, 必须学会怎样数 UTF-8 文本中的字符数. 编辑器的功能, 如删除单个字符, 必须要作轻微的修改, 以删除可能属于该字符的所有字节. 受影响有编辑器 (vi,emacs, 等等)以及使用 ncurses 库的程序. <br/><br/>Linux 核心使用软转换也可以工作得很好, 只需要非常微小的修改以支持 UTF-8. 大多数处理字符串的核心功能 (例如: 文件名, 环境变量, 等等) 都不受影响. 下列地方也许必须修改:&nbsp;&nbsp;<br/><br/>控制台显示与键盘驱动程序 (另一个 VT100 模拟器) 必须能编码和解码 UTF-8, 必须要起码支持 Unicode 字符集的几个子集. 从 Linux 1.2 起这些功能已经有了.&nbsp;&nbsp;<br/>外部文件系统驱动程序, 例如 VFAT 和 WinNT 必须转换文件名字符编码. UTF-8 已经加入可用的转换选项的列表里了, 因此 mount 命令必须告诉核心驱动程序用户进程希望看到 UTF-8 文件名. 既然 VFAT 和 WinNT 无论如何至少已经用了 Unicode了, 那么 UTF-8 在这里就可以发挥其优势, 以保证转换中无信息损失. <br/><br/>POSIX 系统的 tty 驱动程序支持一种 "cooked" 模式, 有一些原始的行编辑功能. 为了让字符删除功能工作正常, stty 必须在 tty 驱动程序里设置 UTF-8 模式, 因此它就不会把 0x80 到 0xBF 范围内的跟随字符也数进去了. Bruno Haible 那里已经有了一些 stty 和核心 tty 驱动 程序的 Linux 补丁 了.&nbsp;&nbsp;<br/>C 对 Unicode 和 UTF-8 的支持 <br/>从 GNU glibc 2.1 开始, wchar_t 类型已经正式定为只存放独立于当前 locale 的, 32位的 ISO 10646 值. glibc 2.2 开始将完全支持 ISO C 中的多字节转换函数 (wprintf(),mbstowcs(),等等), 这些函数可以用于在 wchar_t 和包括 UTF- 8 在内的任何依赖于 locale 的多字节编码间进行转换. <br/><br/>例如, 你可以写 <br/><br/>wprintf(L"Sch鰊e Gre!&#92;n"); <br/>然后, 你的软件将按照你的用户在环境变量 LC_CTYPE (例如, en_US.UTF-8 或 de_DE.ISO_8859-1) 中选择的 locale 所指定的编码来打印这段文字. 你的编译器必须运行在与该 C 源文件所用编码相应的 locale 中, 在目标文件中以上的宽字符串将改为 wchar_t 字符串存储. 在输出时, 运行时库将把 wchar_t 字符串转换回与程序执行时的 locale 相应的编码. <br/><br/>注意, 类似这样的操作: <br/><br/>char c = L"a";&nbsp;&nbsp;<br/>只允许从 U+0000 到 U+007F (7 位 ASCII) 范围里的字符. 对于非 ASCII 字符, 不能直接从 wchar_t 到 char 转换. <br/><br/>现在, 象 readline() 这样的函数在 UTF-8 locale 下也能工作了. <br/><br/>怎样激活 UTF-8 模式? <br/>如果你的应用程序既支持 8 位字符集 (ISO 8859-*,KOI-8,等等), 也支持 UTF-8, 那么它必须通过某种方法以得知是否应使用 UTF-8 模式. 幸运的是, 在未来的几年里, 人们将只使用 UTF-8, 因此你可以将它作为默认, 但即使如此, 你还是得既支持传统 8 位字符集, 也支持 UTF-8. <br/><br/>当前的应用程序使用许许多多的不同的命令行开关来激活它们各自的 UTF-8 模式, 例如:&nbsp;&nbsp;<br/><br/>xterm 命令行选项 "-u8" 和 X resource "XTerm*utf8:1"&nbsp;&nbsp;<br/>gnat/gcc 命令行选项 "-gnatW8"&nbsp;&nbsp;<br/>stty 命令行选项 "iutf8"&nbsp;&nbsp;<br/>mined 命令行选项 "-U"&nbsp;&nbsp;<br/>xemacs elisp 包裹 以在 UTF-8 和内部使用的 MULE 编码间转换&nbsp;&nbsp;<br/>vim ’fileencoding’ 选项&nbsp;&nbsp;<br/>less 环境变量 LESSCHARSET=utf-8&nbsp;&nbsp;<br/>记住每一个应用程序的命令行选项或其他配置方法是非常单调乏味的, 因此急需某种标准方法. <br/><br/>如果你在你的应用程序里使用硬转换, 并使用某种特定的 C 库函数来处理外部字符编码和内部使用的 wchar_t 编码的转换工作, 那么 C 库会帮你处理模式切换的问题. 你只需将环境变量 LC_CTYPE 设为正确的 locale, 例如, 如果你使用 UTF-8, 那就是en.UTF- 8, 而如果是 Latin-1, 并需要英语的转换, 则设为 en.ISO_8859-1. <br/><br/>然而, 大多数现存软件的维护者选择用软转换来代替, 而不使用 libc 的宽字符函数, 不仅因为它们还未得到广泛应用, 还因为这会使得软件进行大规模修改. 在这种情况下, 你的应用程序必须自己来获知何时使用 UTF-8 模式. 一种方式是做以下工作: <br/><br/>按照环境变量 LC_ALL, LC_CTYPE, LANG 的顺序, 寻找第一个有值的变量. 如果该值包含 UTF-8 子串 (也许是小写或没有"-") 则默认为 UTF-8 模式 (仍然可以用命令行开关来重设), 因为这个值可靠又恰当地指示了 C 库应该使用一种 UTF- 8 locale. <br/><br/>提供一个命令行选项 (或者如果是 X 客户程序则用 X resource 的值) 将仍然是有用的, 可以用来重设由 LC_CTYPE 等环境变量指定的默认值. <br/><br/>我怎样才能得到 UTF-8 版本的 xterm? <br/>在 XFree86 里带的 xterm 版本最近已经由 Thomas E. Dickey 加入了支持 UTF-8 的扩展. 使用方法是, 获取 xterm patch #119 (1999-10-16) 或更新版本, 用 "./configure --enable-wide- chars ; make" 来编译, 然后用命令行选项 -u8 来调用 xterm, 使它将输入输出转换为 UTF-8. 在 UTF-8 模式里使用一个 *-ISO10646-1 字体. 当你在 ISO 8859-1 模式里时也可以使用 *-ISO10646-1 字体, 因为 ISO 10646-1 字体与 ISO 8859-1 字体是完全向后兼容的. <br/><br/>新的支持 UTF-8 的 xterm 版本, 以及一些 ISO 10646-1 字体, 将被收录入 XFree86 4.0 版里. <br/><br/>xterm 支持组合字符吗? <br/>Xterm 当前只支持级别1的 ISO 10646-1, 就是说, 不提供组合字符的支持. 当前, 组合字符将被当作空格字符对待. xterm 将来的修订版很有可能加入某些简单的组合字符支持, 就是仅仅将那个有一个或多个组合字符的基字符加粗 (logical OR-ing). 对于在基线以下的和在小字符上方的重音符来说, 这样处理的结果还是可以接受的. 对于象泰国文字体那样使用特别设计的加粗字符的文字, 这样处理也能工作的很好. 然而, 对于某些字体里, 在较高的字符上方组合上的重音符, 特别是对于 "fixed" 字体族, 产生的结果就不完全令人满意了. 因此, 在可用的地方, 应该继续优先使用预作字符. <br/><br/>xterm 支持半宽与全宽 CJK 字体吗? <br/>Xterm 当前只支持那种所有字形都等宽的 cell-spaced 的字体. 将来的修订版很有可能为 CJK 语言加入半宽与全宽字符支持, 类似于 kterm 提供的那种. 如果选择的普通字体是 X×Y 象素大小, 且宽字符模式是打开的, 那么 xterm 会试图装入另外的一个 2X×Y 象素大小的字体 (同样的 XLFD, 只是 AVERAGE_WIDTH 属性的值翻倍). 它会用这个字体来显示所有在 Unicode Technical Report #11 里被分配了 East Asian Wide (W) 或 East Asian FullWidth (F) 宽度属性的 Unicode 字符. 下面这个 C 函数用来测试一个 Unicode 字符是否是宽字符并需要用覆盖两个字符单元的字形来显示: <br/><br/>/* This function tests, whether the ISO 10646/Unicode character code <br/>&nbsp;&nbsp;* ucs belongs into the East Asian Wide (W) or East Asian FullWidth <br/>&nbsp;&nbsp;* (F) category as defined in Unicode Technical Report #11. In this <br/>&nbsp;&nbsp;* case, the terminal emulator should represent the character using a <br/>&nbsp;&nbsp;* a glyph from a double-wide font that covers two normal (Latin) <br/>&nbsp;&nbsp;* character cells. */ <br/><br/>int iswide(int ucs) <br/>&#123; <br/>&nbsp;&nbsp;if (ucs < 0x1100) <br/>&nbsp;&nbsp;&nbsp;&nbsp;return 0; <br/><br/>&nbsp;&nbsp;return <br/>&nbsp;&nbsp;&nbsp;&nbsp;(ucs >= 0x1100 && ucs <= 0x115f) &#124;&#124; /* Hangul Jamo */ <br/>&nbsp;&nbsp;&nbsp;&nbsp;(ucs >= 0x2e80 && ucs <= 0xa4cf && (ucs & ~0x0011) != 0x300a && <br/>&nbsp;&nbsp;&nbsp;&nbsp;ucs != 0x303f) &#124;&#124;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* CJK ... Yi */ <br/>&nbsp;&nbsp;&nbsp;&nbsp;(ucs >= 0xac00 && ucs <= 0xd7a3) &#124;&#124; /* Hangul Syllables */ <br/>&nbsp;&nbsp;&nbsp;&nbsp;(ucs >= 0xf900 && ucs <= 0xfaff) &#124;&#124; /* CJK Compatibility Ideographs */ <br/>&nbsp;&nbsp;&nbsp;&nbsp;(ucs >= 0xfe30 && ucs <= 0xfe6f) &#124;&#124; /* CJK Compatibility Forms */ <br/>&nbsp;&nbsp;&nbsp;&nbsp;(ucs >= 0xff00 && ucs <= 0xff5f) &#124;&#124; /* Fullwidth Forms */ <br/>&nbsp;&nbsp;&nbsp;&nbsp;(ucs >= 0xffe0 && ucs <= 0xffe6); <br/>&#125; <br/>某些 C 库也提供了函数 <br/><br/>#include <wchar.h> <br/>int wcwidth(wchar_t wc); <br/>int wcswidth(const wchar_t *pwcs, size_t n); <br/>用来测定该宽字符 wc 或由 pwcs 指向的字符串中的 n 个宽字符码 (或者少于 n 个宽字符码, 如果在 n 个宽字符码之前遇到一个空宽字符的话) 所要求的列位置的数量. 这些函数定义在 Open Group 的 Single UNIX Specification 里. 一个拉丁/希腊/斯拉夫/等等的字符要求一个列位置, 一个 CJK 象形文字要求两个, 而一个组合字符要求零个. <br/><br/>最终 xterm 是否会支持从右到左的书写? <br/>此刻还没有给 xterm 增加从右到左功能的计划. 希伯来与阿拉伯用户因此不得不靠应用程序在将希伯来文与阿拉伯文字符串送到终端前按左方向翻转它们, 换句话说, 双向处理必须在应用程序里完成, 而不是在 xterm 里. 至少, 希伯来与阿拉伯文在预作字形的可用性的形式上, 以及提示表格上的支持, 比 ISO 8859 要有所改进. 现在还远没有决定 xterm 是否支持双向文字以及该怎样工作. ISO 6429 = ECMA- 48 和 Unicode bidi algorithm 都提供了可供选择的开始点. 也可以参考 ECMA Technical <br/>Report TR/53. Xterm 也不处理阿拉伯文, Hangul 或 印度文本的格式化算法, 而且现在还不太清楚在 VT100 模拟器里处理是否可行和值得, 或者应该留给应用软件去处理. 如果你打算在你的应用程序里支持双向文字输出, 看一下 FriBidi, Dov Grobgeld 的 Unicode 双向算法的自由实现.<br/><br/>我在哪儿能找到 ISO 10646-1 X11 字体? <br/>在过去的几个月里出现了相当多的 X11 的 Unicode 字体, 并且还在快速增多.&nbsp;&nbsp;<br/><br/>Markus Kuhn 正和其他许多志愿者一起工作于手动将旧的 -misc-fixed-*-iso8859-1 字体扩展到覆盖所有的欧洲字符表 (拉丁, 希腊, 斯拉夫, 国际音标字母表. 数学与技术符号, 某些字体里甚至有亚美尼亚语, 乔治亚语, 片假名等). 更多信息请参考 Unicode fonts and tools for X11 页. 这些字体将与 XFree86 一起分发. 例如字体&nbsp;&nbsp;<br/>-misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso10646-1 <br/><br/>(旧的 xterm 的 fixed 缺省字体的一个扩展, 包括超过 3000 个字符) 已经是 XFree86 3.9 snapshot 的一部分了. <br/><br/>Markus 也做好了 X11R6.4 distribution 里所有的 Adobe 和 B&H BDF 字体的 ISO 10646 版本. 这些字体已经包含了全部 Postscript 字体表 (大约 30 个额外的字符, 大部分也被 CP1252 MS-Windows 使用, 如 smart quotes, dashes 等), 在 ISO 8859-1 编码下是没有的. 它们在 ISO 10646-1 版本里是完全可用的.&nbsp;&nbsp;<br/>XFree86 4.0 将携带一个集成的 TrueType 字体引擎, 这使得你的 X 应用程序可以将任何 Apple/Microsoft 字体用于 ISO 10646-1 编码.&nbsp;&nbsp;<br/>将来的 XFree86 版本很有可能从分发版中去除大多数旧的 BDF 字体, 取而代之的是 ISO 10646-1 编码的版本. X 服务器则会增加一个自动编码转换器, 只有当旧的 8 位软件请求一个类似于 ISO 8859-* 编码的字体时, 才虚拟地从 ISO 10646-1 字体文件中创建一个这样的字体. 现代软件应该优先地直接使用 ISO 10646-1 字体编码.&nbsp;&nbsp;<br/>ClearlyU (cu12) 是一个非常有用的 X11 的 12 点阵, 100 dpi 的 proportional ISO 10646-1 BDF 字体, 包含超过 3700 个字符, 由 Mark Leisher 提供 (样例图象).&nbsp;&nbsp;<br/>Roman Czyborra 的 GNU Unicode font 项目工作于收集一个完整的与免费的 8×16/16×16 pixel Unicode 字体. 目前已经覆盖了 34000 个字符.&nbsp;&nbsp;<br/>etl-unicode 是一个 ISO 10646-1 BDF 字体, 由 Primoz Peterlin 提供.&nbsp;&nbsp;<br/>Unicode X11 字体名字以 -ISO10646-1 结尾. 这个 X 逻辑字体描述器 (X Logical Font Descriptor, XLFD) 的 CHARSET_REGISTRY 和 CHARSET_ENCODING 域里的值已经为所有 Unicode 和 ISO 10646-1 的 16 位字体而正式地注册了. 每个 *-ISO10646-1 字体都包含了整个 Unicode 字符集里的某几个子集, 而用户必须弄清楚他们选择的字体覆盖哪几个他们需要的字符子集. <br/><br/>*-ISO10646-1 字体通常也指定一个 DEFAULT_CHAR 值, 指向一个非 Unicode 字形, 用来表示所有在该字体里不可用的字符 (通常是一个虚线框, 一个 H 的大小, 位于 0x1F 或 0xFFFE). 这使得用户至少能知道这儿有一个不支持的字符. xterm 用的小的定宽字体比如 6x13 等, 将永远无法覆盖所有的 Unicode, 因为许多文字比如日本汉字只能用比欧洲用户广泛使用的大的象素尺寸才能表示. 欧洲使用的典型的 Unicode 字体将只包含大约 1000 到 3000 个字符的子集. <br/><br/>我怎样才能找出一个 X 字体里有哪些字形? <br/>X 协议无法让一个应用程序方便地找出一个 cell-spaced 字体提供哪些字形, 它没有为字体提供这样的量度. 因此 Mark Leisher 和 Erik van de Poel (Netscape) 指定了一个新的 _XFREE86_GLYPH_RANGES BDF 属性, 告诉应用程序该 BDF 字体实现了哪个 Unicode 子集. Mark Leisher 提供了一些样例代码以产生并扫描这个属性, 而 Xmbdfed 3.9 以及更高版本将自动将其加入到由它产生的每个 BDF 文件里. <br/><br/>与 UTF-8 终端模拟器相关的问题是什么? <br/>VT100 终端模拟器接受 ISO 2022 (=ECMA-35) ESC 序列, 用于在不同的字符集间切换. <br/><br/>UTF- 8 在 ISO 2022 的意义里是一个 "其他编码系统" (参考 ECMA 35 的 15.4 节). UTF-8 是在 ISO 2022 SS2/SS3/G0/G1/G2/G3 世界之外的, 因此如果你从 ISO 2022 切换到 UTF-8, 所有的 SS2 /SS3/G0/G1/G2/G3 状态都变得没有意义了, 直到你离开 UTF-8 并切换回 ISO 2022. UTF-8 是一个没有国家的编码, 也就是一个自我终结的短字节序列完全决定了它代表什么字符, 独立于任何国家的切换. G0 与 G1 在 ISO 10646 里与在 ISO 8859-1 里相同, 而 G2/G3 在 ISO 10646 里不存在, 因为任何字符都有固定的位置, 因而不会发声切换. 在 UTF-8 模式下, 你的终端不会因为你偶然地装入一个二进制文件而切换入一种奇怪图形字符模式. 这使得一个终端在 UTF-8 模式下比在 ISO 2022 模式下要健壮得多, 而且因此可以有办法将终端锁在 UTF-8 模式里, 而不会偶然地回到 ISO 2022 世界里.<br/><br/>ISO 2022 标准指定了一系列的 ESC % 序列, 以离开 ISO 2022 世界 (指定其他的编码系统, DOCS), 用于 UTF- 8 的许多这样的序列已经注册进了 ISO 2375 International Register of Coded Character Sets:&nbsp;&nbsp;<br/><br/>ESC %G 从 ISO 2022 里激活一个未指定实现级别的 UTF-8 模式且允许再返回 ISO 2022.&nbsp;&nbsp;<br/>ESC %@ 从 UTF-8 回到 ISO 2022, 条件是通过 ESC %G 进入的 UTF-8&nbsp;&nbsp;<br/>ESC %/G 切换进 UTF-8 级别 1 且不返回.&nbsp;&nbsp;<br/>ESC %/H 切换进 UTF-8 级别 2 且不返回.&nbsp;&nbsp;<br/>ESC %/I 切换进 UTF-8 级别 3 且不返回.&nbsp;&nbsp;<br/>当一个终端模拟器在 UTF-8 模式时, 任何 ISO 2022 逃脱码序列例如用于切换 G2/G3 等的都被忽略. 一个在 UTF-8 模式下的终端模拟器唯一会执行的 ISO 2022 序列是 ESC %@ 以从 UTF-8 返回 ISO 2022 方案. <br/><br/>UTF-8 仍然允许你使用象 CSI 这样的 C1 控制字符, 尽管 UTF-8 也使用 0x80-0x9F 范围里的字节. 重要的是必须理解在 UTF- 8 模式下的终端模拟器必须在执行任何控制字符前对收到的字节流运用 UTF-8 解码器. C1 字符与其他任何大于 U+007F 的字符一样需先经过 UTF-8 解码. <br/><br/>已经有哪些支持 UTF-8 的应用程序了? <br/>Yudit 是 Gaspar Sinai 的自由 X11 Unicode 编辑器&nbsp;&nbsp;<br/>Mined 98 由 Thomas Wolff 提供, 是一个可以处理 UTF-8 的文本编辑器.&nbsp;&nbsp;<br/>less 版本 346 或更高, 支持 UTF-8&nbsp;&nbsp;<br/>C-Kermit 7.0 在传输, 终端, 及文件字符集方面支持 UTF-8.&nbsp;&nbsp;<br/>Sam 是 Plan9 的 UTF-8 编辑器, 类似于 vi, 也可用于 Linux 和 Win32. (Plan9 是第一个完全转向 UTF-8, 将其作为字符编码的操作系统.)&nbsp;&nbsp;<br/>9term 由 Matty Farrow 提供, 是一个 Plan9 操作系统的 Unicode/UTF-8 终端模拟器的 Unix 移植.&nbsp;&nbsp;<br/>Wily 是一个 Plan9 Acme 编辑器的 Unix 实现.&nbsp;&nbsp;<br/>ucm-0.1 是 Juliusz Chroboczek 的 Unicode 字符映射表, 一个小工具, 使你可以选中任何一个 Unicode 字符并粘贴进你的应用程序.&nbsp;&nbsp;<br/>有哪些用于改善 UTF-8 支持的补丁? <br/>Robert Brady 提供了一个 patch for less 340 (现在已经合并进了 less 344)&nbsp;&nbsp;<br/>Bruno Haible 提供了用于 stty, Linux 核心 tty 等的 多个补丁.&nbsp;&nbsp;<br/>Otfried Cheong 编写了 Unicode encoding for GNU Emacs 工具箱, 使 Mule 能够处理 UTF-8 文件.&nbsp;&nbsp;<br/>Postscript 字形的名字与 UCS 代码是怎么关联的? <br/>参考 Adobe 的 Unicode and Glyph Names 指南.&nbsp;&nbsp;<br/><br/>X11 的剪切与粘贴工作在 UTF-8 时是如何完成的? <br/>参考 Juliusz Chroboczek 的 客户机间 Unicode 文本的交换 草案, 对 ICCCM 的一个扩充的建议, 用一个新的可用于属性类型(property type)和选中(selection)目标的原子 UTF8_STRING 来处理 UTF-8 的选中. <br/><br/>现在有没有用于处理 Unicode 的免费的库? <br/>IBM Classes for Unicode&nbsp;&nbsp;<br/>Mark Leisher 的 UCData Unicode 字符属性库和 wchar_t 支持测试码.&nbsp;&nbsp;<br/>各种 X widget 对 Unicode 支持的现状如何? <br/>GScript - Unicode 与复杂文本处理 是一个为 GTK+ 增加全功能的 Unicode 支持的项目.&nbsp;&nbsp;<br/>Qt 2.0 现在支持使用 *-ISO10646-1 字体了.&nbsp;&nbsp;<br/>FriBidi 是 Dov Grobgeld 的 Unicode 双向算法的免费实现.&nbsp;&nbsp;<br/>有什么关于这个话题的好的邮件列表? <br/>你确实应该订阅的是 unicode@unicode.org 邮件列表, 这是发现标准的作者和其他许多领袖的话语的最好办法. 订阅方法是, 用 "subscribe" 作为标题, "subscribe YOUR@EMAIL.ADDRESS unicode" 作为正文, 发一条消息到 unicode-request@unicode.org. <br/><br/>也有一个专注与改进通常用于 GNU/Linux 系统上应用程序的 UTF-8 支持的邮件列表 linux-utf8@nl.linux.org. 订阅方法是, 以 "subscribe linux-utf8" 为内容, 发送消息到 majordomo@nl.linux.org. 你也可以浏览 linux-utf8 archive <br/><br/>其他相关的还有 XFree86 组的 "字体" 与 "i18n" 列表, 但你必须成为一名正式的开发者才能订阅. <br/><br/>更多参考 <br/>Bruno Haible ’s Unicode HOWTO.&nbsp;&nbsp;<br/>The Unicode Standard, Version 2.0&nbsp;&nbsp;<br/>Unicode Technical Reports&nbsp;&nbsp;<br/>Mark Davis’ Unicode FAQ&nbsp;&nbsp;<br/>ISO/IEC 10646-1:1993&nbsp;&nbsp;<br/>Frank Tang’s I?t?rnati?nàliz?ti?n Secrets&nbsp;&nbsp;<br/>Unicode Support in the Solaris 7 Operating Environment&nbsp;&nbsp;<br/>The USENIX paper by Rob Pike and Ken Thompson on the introduction of UTF-8 under Plan9 reports about the first operating system that migrated already in 1992 completely to UTF-8 (which was at the time still called UTF-2).&nbsp;&nbsp;<br/>Li18nux is a project initiated by several Linux distributors to enhance Unicode support for Linux.&nbsp;&nbsp;<br/>The Online Single Unix Specification contains definitions of all the ISO C Amendment 1 function, plus extensions such as wcwidth().&nbsp;&nbsp;<br/>The Open Group’s summary of ISO C Amendment 1.&nbsp;&nbsp;<br/>GNU libc&nbsp;&nbsp;<br/>The Linux Console Tools&nbsp;&nbsp;<br/>The Unicode Consortium character database and character set conversion tables are an essential resource for anyone developping Unicode related tools.&nbsp;&nbsp;<br/>Other conversion tables are available from Microsoft and Keld Simonsen’s WG15 archive.&nbsp;&nbsp;<br/>Michael Everson’s ISO10646-1 archive contains online versions of many of the more recent ISO 10646-1 amendments, plus many other goodies. See also his Roadmaps to the Universal Character Set.&nbsp;&nbsp;<br/>An introduction into The Universal Character Set (UCS).&nbsp;&nbsp;<br/>Otfried Cheong’s essey on Han Unification in Unicode&nbsp;&nbsp;<br/>The AMS STIX project is working on revising and extending the mathematical characters for Unicode 4.0 and ISO 10646-2.&nbsp;&nbsp;<br/>Jukka Korpela’s Soft hyphen (SHY) - a hard problem? is an excellent discussion of the controversy surrounding U+00AD.&nbsp;&nbsp;<br/>James Briggs’ Perl, Unicode and I18N FAQ.&nbsp;&nbsp;<br/>我不断地将新的材料加入这份文档, 因此请定期来查看. 欢迎所有关于改进的建议, 以及自由软件社区里关于改善 UTF-8 支持的广告. UTF-8 用在 Linux 里是新近的事, 因此我们在将来的几个月里可以见到大量的进展. <br/><br/>特别感谢 Ulrich Drepper 和 Bruno Haible 的有价值的注解 
]]>
</description>
</item><item>
<link>https://atim.cn/post/422/</link>
<title><![CDATA[什么是 RSS?]]></title> 
<author>bkkkd &lt;partybase@gmail.com&gt;</author>
<category><![CDATA[Web 技术 ]]></category>
<pubDate>Sat, 23 Aug 2008 13:09:57 +0000</pubDate> 
<guid>https://atim.cn/post/422/</guid> 
<description>
<![CDATA[ 
	什么是 RSS?<br/>RSS 是一种站点内容聚合的格式。<br/><br/>它的名字是Really Simple Syndication 的的简写。<br/>RSS是XML的一种。所有的RSS文档都遵循 XML 1.0规范, 该规范发布在W3C网站上。<br/>这里是RSS版本历史的一个概要。<br/><br/>在一个RSS文档中，最外层是一个<rss>元素，这个元素必须规定version属性，该属性明确了本文档遵从何种RSS版本规范。如果一个RSS文档以这个规范来表示，那么它的version属性就必须是2.0。<br/><rss>元素只有一个子元素<channel>，包含了关于这个频道(元数据)和它的内容的一些信息。<br/><br/>样本文件<br/><br/>这里有一些RSS样本文件： RSS 0.91, 0.92 和 2.0。<br/><br/>注意这些样本文件所指向的链接地址和服务器可能已经不再存在。在撰写0.91文档的时候，这个0.91的样本文件就已经创建了。维护一个样本文件的历史也许是一个不错的主意。<br/><br/>关于本文档<br/><br/>本文档完成于2002年秋天，版本为 2.0.1。<br/><br/>它包含从 RSS 0.91 规范(2000年)开始的所有的修改和添加，以及包含在RSS 0.92 （2000年12月）和RSS 0.94（2002年8月）中的新的特性。<br/><br/>详细的文档历史纪录请参阅这里。<br/><br/>本文档中首先介绍必须的和可选的频道元素；接着介绍了<item>的子元素。最后回答了一些经常碰到的问题，并提供了未来的发展路线和RSS扩展的指导方针。<br/><br/>必需的频道元素<br/><br/>下面是一个必须包含的频道(channel)元素的列表，每一个都有一个简单的描述、一个例子、应该出现的位置和更详细描述的链接地址。<br/>01.●　title&nbsp;&nbsp; <br/>名称：title&nbsp;&nbsp;<br/>描述：频道的名称。它表明别人如何访问你的服务。如果你有一个与你的RSS文件内容一致的HTML网站，你的title元素值应该与你的网站的标题相同。&nbsp;&nbsp;<br/>例子：GoUpstate.com 的新闻大字标题。&nbsp;&nbsp;<br/>02.●　link&nbsp;&nbsp; <br/>名称：link&nbsp;&nbsp;<br/>描述：对应频道的网站的URL链接地址。&nbsp;&nbsp;<br/>例子：http://www.goupstate.com/ 。&nbsp;&nbsp;<br/>03.●　description&nbsp;&nbsp; <br/>名称：description&nbsp;&nbsp;<br/>描述：关于频道的描述。&nbsp;&nbsp;<br/>例子：The latest news from GoUpstate.com, a Spartanburg Herald-Journal Web site。<br/>可选的频道元素<br/><br/>下面是一个可选的频道(channel)元素的列表。&nbsp;&nbsp;<br/>01.●　language<br/>名称：language<br/>描述：频道使用的语言。比如，在一个网站上，允许聚合所有的意大利语站点到相应的分组。对于这个元素，可使用的值，参阅 Netscape提供的清单。或者可以参阅W3C定义的 清单。&nbsp;&nbsp;<br/>例子：en-us。&nbsp;&nbsp;<br/>02.●　copyright<br/>名称：copyright<br/>描述：频道内容的版权声明。&nbsp;&nbsp;<br/>例子：Copyright 2002, Spartanburg Herald-Journal&nbsp;&nbsp;<br/>03.●　managingEditor<br/>名称：managingEditor<br/>描述：频道内容责任编辑的电子邮件地址。&nbsp;&nbsp;<br/>例子：geo@herald.com (George Matesky)&nbsp;&nbsp;<br/>04.●　webMaster<br/>名称：webMaster<br/>描述：频道技术支持人员的电子邮件地址。&nbsp;&nbsp;<br/>例子：betty@herald.com (Betty Guernsey)&nbsp;&nbsp;<br/>05.●　pubDate<br/>名称：pubDate<br/>描述：频道内容发布的日期。所有的日期和时间都必须遵循 RFC 822规范, 但年份可以用２个或４个字母表示(首选４个字母)。&nbsp;&nbsp;<br/>例子：Sat, 07 Sep 2002 00:00:01 GMT&nbsp;&nbsp;<br/>06.●　lastBuildDate<br/>名称：lastBuildDate<br/>描述：频道内容的最后修改时间。&nbsp;&nbsp;<br/>例子：Sat, 07 Sep 2002 09:42:31 GMT&nbsp;&nbsp;<br/>07.●　category<br/>名称：category&nbsp;&nbsp;<br/>描述：指定频道所属的一个或多个分类。遵循与item级category元素相同的规则。详见这里。&nbsp;&nbsp;<br/>例子：<category>Newspapers</category>&nbsp;&nbsp;<br/>08.●　generator<br/>名称：generator&nbsp;&nbsp;<br/>描述：表明生成频道的程序名称的字符串。&nbsp;&nbsp;<br/>例子：MightyInHouse Content System v2.3&nbsp;&nbsp;<br/>09.●　docs<br/>名称：docs<br/>描述：指向该RSS文件所用格式说明文档的URL链接地址。&nbsp;&nbsp;<br/>例子：http://blogs.law.harvard.edu/tech/rss。&nbsp;&nbsp;<br/>10.●　cloud<br/>名称：cloud<br/>描述：允许通过注册一个cloud来处理获得频道的更新通知，并为rss种子实现一个轻量级的发布订阅协议，详见这里。&nbsp;&nbsp;<br/>例子：<cloud domain="rpc.sys.com" port="80" path="/RPC2" registerProcedure="pingMe" protocol="soap"/>&nbsp;&nbsp;<br/>11.●　ttl<br/>名称：ttl&nbsp;&nbsp;<br/>描述：ttl是Time to live的缩写，表示生存时间。它表示频道从源更新之前可以缓存的时间。详见 这里。&nbsp;&nbsp;<br/>例子：<ttl>60</ttl>。&nbsp;&nbsp;<br/>12.●　image<br/>名称：image<br/>描述：指定一个可以在频道中显示的GIF、JPEG或者 PNG 图像。详见这里。&nbsp;&nbsp;<br/>例子：。<br/>13.●　rating<br/>名称：rating<br/>描述：频道的 PICS 内容分级信息。&nbsp;&nbsp;<br/>例子： 。<br/>14.●　textInput<br/>名称：textInput<br/>描述：指定一个可以在频道中显示的文本输入框。详见这里。<br/>例子：。&nbsp;&nbsp;<br/>15.●　skipHours<br/>名称：skipHours<br/>描述：提示聚合器，可以跳过那些小时的时间段。详见这里。<br/>例子：。&nbsp;&nbsp;<br/>16.●　skipDays<br/>名称：skipDays<br/>描述：提示聚合器，可以跳过那些天的时间段。详见这里。&nbsp;&nbsp;<br/>例子：。&nbsp;&nbsp;<br/><channel>的子元素<image>&nbsp;&nbsp;<br/><br/><image> 是 <channel>的一个可选子元素, 它本身包含了三个必须的和三个可选的子元素。<br/><url>是一个GIF、JPEG或PNG图像文件的URL链接地址，该图像代表整个频道。<br/><title>用于描述上面的图像，当频道在HTML中显示时，用于HTML语言中的<img>的alt属性。<br/><link>是要连接的站点的url，当显示频道时，图像的连接指向该站点。(在实际中，<title>和<link>应该与频道的<title>和<link>有相同的值)。<br/>可选的元素包括<width>和<height>，它们是数字类型，指定图像的宽度和高度，单位为像素。<br/><description>就是link的TITLE属性中文本，它将在调用网页时显示出来。&nbsp;&nbsp;<br/><br/>图像宽度的最大值为144，默认值为88 。<br/>图像高度的最大值为400，默认值为31 。<br/><br/><channel>的子元素<cloud><br/><br/><cloud> 是 <channel>的一个可选子元素。<br/>它指定一个可以支持rssCloud接口的web服务，rssCloud接口可以在HTTP-POST、XML-RPC或SOAP1.1中实现。<br/>它的目的是允许通过注册一个cloud来处理获得频道的更新通知，从而为RSS feeds实现一个轻量级的发布订阅协议.<br/><cloud domain="rpc.sys.com" port="80" path="/RPC2" registerProcedure="myCloud.rssPleaseNotify" protocol="xml-rpc" /><br/><br/>在这个例子中，为了请求频道通知，你需要发送一个XML-RPC消息到rpc.sys.com的80端口，路径为/RPC2。调用的程序为为myCloud.rssPleaseNotify。&nbsp;&nbsp;<br/>这个元素的详细说明和 rssCloud 接口说明请参阅 这里。<br/><br/><channel>子元素<ttl><br/><br/><ttl><channel>的一个可选子元素。<br/>ttl是Time to live的缩写，表示生存时间。它表示频道从源重新更新之前可以缓存的时间。这使得rss源可以被一个支持文件共享的网络所管理，例如Gnutella。<br/><br/>例子: <ttl>60</ttl><br/><br/><channel>的子元素<textInput><br/>频道可以选择包含一个<textInput>子元素，它本身包含了四个必须的子元素。<br/><title>--文本输入区域提交按钮的标签。<br/><description>--文本输入区域的描述。<br/><name>--文本输入区域中文本对象的名称。<br/><link>--处理文本输入请求的CGI脚本的URL链接地址。<br/>使用<textInput>元素的目的看起来有些神秘。你可以用它提供一个搜索引擎输入框，或让读者提供反馈信息。许多聚合器忽略该元素。<br/><item>的元素<br/><br/>一个频道可以包含许多<item>元素。一个项目可以代表一个"故事" ——比如说一份报纸或杂志上的故事；如果是这样的话，那么项目的描述则是故事的摘要，项目的链接则指向整个故事的链接位置。一个项目也可以本身是完整的，如果是这样的话，项目的描述就包含了文本(整体以HTML格式编码是可以的；参见例子)，而链接和标题可以省略。项目的所有元素都是可选的，但是至少要包含一个标题(title)或描述(description)。&nbsp;&nbsp;<br/>01.●　title<br/>名称：title<br/>描述：item的标题。&nbsp;&nbsp;<br/>例子：Venice Film Festival Tries to Quit Sinking&nbsp;&nbsp;<br/>02.●　link<br/>名称：link<br/>描述：item的URL链接地址。&nbsp;&nbsp;<br/>例子：http://nytimes.com/2004/12/07FEST.html<br/>03.●　description&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>名称：description&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>描述：item的摘要。&nbsp;&nbsp;<br/>例子：Some of the most heated chatter at the Venice Film Festival this week was about the way that the arrival of the stars at the Palazzo del Cinema was being staged.&nbsp;&nbsp;<br/>04.●　author<br/>名称：author<br/>描述：item作者的电子邮件地址。详见这里。<br/>例子：。&nbsp;&nbsp;<br/>05.●　category<br/>名称：category<br/>描述：包含item在一个或多个分类中。详见这里。&nbsp;&nbsp;<br/>例子：。&nbsp;&nbsp;<br/>06.●　comments<br/>名称：comments<br/>描述：与item相关的评论的URL链接地址。详见 这里。&nbsp;&nbsp;<br/>例子：。&nbsp;&nbsp;<br/>07.●　enclosure<br/>名称：enclosure<br/>描述：item附加的媒体对象。详见这里。<br/>例子：。&nbsp;&nbsp;<br/>08.●　guid<br/>名称：guid<br/>描述：可以唯一确定item身份的字符串。详见 这里。<br/>例子：。&nbsp;&nbsp;<br/>09.●　pubDate<br/>名称：pubDate<br/>描述：item发布的时间。详见 这里。<br/>例子：。&nbsp;&nbsp;<br/>10.●　source<br/>名称：source<br/>描述：rss频道来源。详见 这里。<br/>例子：。&nbsp;&nbsp;<br/><item>的子元素<source><br/><br/><source>是<item>的一个可选子元素。<br/><br/>它的值是item所属rss频道的名称，从title衍生而来。它有一个必须包含的属性url, 该属性链接到XML序列化源。<br/><source url="http://www.tomalak.org/links2.xml">Tomalak’s Realm</source><br/><br/>该元素的作用是提高链接的声望，从而进一步推广新闻项目的源头。它可以用在聚合器的Post命令中。当从聚合器中通过一个webblog编辑工具提交一个item时，<source>应该能够被自动生成。<br/><br/><item>的子元素<enclosure><br/><br/><enclosure>是<item>的一个可选子元素。<br/>它有三个必须的属性。url属性表明enclosure的位置，length属性表明它的字节大小，而type属性则指出它的标准MIME类型。<br/>这里的url必须为一个http url。&nbsp;&nbsp;<br/><br/><enclosure url="http://www.scripting.com/mp3s/weatherReportSuite.mp3" length="12216320" type="audio/mpeg" /><br/><br/>它的 use-case 说明请参见这里。<br/><br/><item>的子元素<category><br/><br/><category>是<item>的一个可选子元素。<br/>它有一个可选属性domain，该属性是一个用来定义分类法的字符串。&nbsp;&nbsp;<br/>该节点的值是一个斜杠分割的字符串，它用来表明在指定的分类法中的层次位置。处理器可以为分类的识别建立协定。以下是两个例子：&nbsp;&nbsp;<br/><br/><category>Grateful Dead</category><br/><br/><category domain="http://www.fool.com/cusips">MSFT</category><br/><br/>你可以根据需要为不同的域包含很多<category>元素，并且可以在相同域的不同部分拥有一个交叉引用的item。&nbsp;&nbsp;<br/><br/><item>的子元素<pubDate><br/><br/><pubDate> 是<item>的一个可选子元素。<br/>它的值是一个 日期, 表明项目发布的时间。如果它是一个将来的日期，则聚合器在日期到达之前可以选择不显示该项目。&nbsp;&nbsp;<br/><br/><pubDate>Sun, 19 May 2002 15:21:36 GMT</pubDate><br/><br/><item>的子元素<guid>&nbsp;&nbsp;<br/><br/><guid>是<item>的一个可选子元素。<br/>guid 是 globally unique identifier的缩写。它是一个可以唯一识别这个<item>的字符串。在发布之后，聚合器可以选择使用该字符串判断这个<item>是否是新的。&nbsp;&nbsp;<br/><guid>http://some.server.com/weblogItem3207</guid><br/><br/>guid没有特定的语法规则。聚合器必须将它们当作一个字符串来处理。生成具有唯一性的字符串guid取决于种子的源头。&nbsp;&nbsp;<br/>如果guid元素有isPermaLink属性，并且值为真，解释器就会认为它是item的permalink。permalink是一个可在web浏览器中打开的url链接，它指向<item>节点所描述的完整item。 例如：<br/><guid isPermaLink="true">http://inessential.com/2002/09/01.php#a2</guid>&nbsp;&nbsp;<br/>isPermaLink是可选属性，默认值为真。如果值为假，guid将不会被认为是一个url或指向任何对象的url。&nbsp;&nbsp;<br/><br/><item>的子元素<comments><br/><br/><comments>是<item>的一个可选子元素。<br/>如果出现，它指向与item相关的评论的url。<br/><br/><comments>http://ekzemplo.com/entry/4403/comments</comments><br/><br/>更多信息，请参阅 这里。<br/><br/><item>的子元素<author>&nbsp;&nbsp;<br/><br/><author>是<item>的一个可选子元素。<br/>它是item作者的电子邮件地址l。对于通过rss传播的报纸和杂志，作者可能是写该item所描述的文章的人。对于聚集型webblogs，作者可能不是责任编辑或站长。对于个人维护的webblog，忽略<author>节点是有意义的。<br/><author>lawyer@boyer.net (Lawyer Boyer)</author><br/><br/>注释<br/><br/>RSS限制<link> 和 <url>元素的数据首字母为非空格字符。这些元素的数据必须以IANA-registered URI方案规定的格式开始，如http://, https://, news://, mailto:和 ftp://等。在RSS2.0规范之前，RSS规范只允许http:// 和 ftp://，然而在实践中，其他的URI方案被内容开发者广泛使用，并被聚合器所支持。聚合器也许对它们支持的URI方案有一些限制，而内容开发者不应该假定所有的聚合器都支持所有的URI方案。<br/>在 RSS 0.91规范中，各种元素都被限制为500或100个字符。在一个符合0.91规范的频道中，不能超过15个 <item> 元素。在RSS 0.92和以后的规范中，不再有这些字符长度或者XML级别的限制。处理器也许强加一些它们自己的限制，产生者也许有自己的一些参数选择，它们可以规定在一个频道中，不超过一定数目的<item>元素，或者字符串都限制在一定的长度。&nbsp;&nbsp;<br/>如上所述，在 RSS 2.0规范中，对于一个目录系统，当链接一个频道到它的标识中时，使用基于频道级别的分类特征。例如，如果链接一个频道到它的Syndic8 标识，则将包括一个分类元素作为频道的子元素，它有域“Syndic8”属性，同时在Syndic8 数据库中为你的频道确定这个标识。正确的分类元素脚本应该是 <category domain="Syndic8">1765</category>。<br/><br/>一个经常被问到的问题是关于<guid> 如何和 <link>进行区别。它们指的是相同的事情吗？在一些内容系统中是，但在别的内容系统中可能不是。在一些系统中，<link> 是一个网络日志项的永久链接。然后在别的系统中，每一个<item>都是一个较长文章的摘要，<link>指向这篇文章，而 <guid>则是这个网络日志入口的永久链接。在所有的情况下，建议提供<guid>,如果可能的话，并使它成为一个永久链接。这使聚合着在内容发生变化时，也不会出现重复项目成为可能。<br/>如果你对RSS 2.0规范的格式有任何问题，请向由Sjoerd Visscher维护的电子邮件列表RSS2-Support发送邮件。这个邮件列表不是一个技术辩论的列表，而是一个针对作者和开发人员在创建和使用RSS 2.0格式的内容时提供技术支持的列表。<br/>RSS的扩展<br/><br/>RSS起源于1999年，目标是成为一个简单、易于理解的数据格式。在它逐渐成为一种流行格式之后，开发者想在一个名字空间中使用模块对它进行扩展，正像W3C定义的那样。&nbsp;&nbsp;<br/>RSS遵循简单的规则，增加了它的能力。一个RSS feed 可以包含不是在本页中描述的内容，而只是在一个名字空间中定义的那些元素。<br/><br/>本文档中定义的元素不是一个名字空间本省的元素，因此， RSS2.0从某种意义上来讲，和原来的版本是兼容的，即一个 0.91 或者 0.92 版本的文件也是一个有效的 2.0 版本文件。如果RSS2.0的元素是在一个名字空间中，那么这种约束将被打破，即 一个0.9x 版本的文件不可能是一个有效的2.0 版本的文件。<br/><br/>发展方向&nbsp;&nbsp;<br/><br/>RSS决不是一个完美的格式，但是它现在已经非常流行，并得到广泛的支持。要成为一个固定的规范，RSS需要很长的一段时间。这项工作的目的是帮助RSS 成为一个固定的事情，同时促进和培育围绕它进行的开发的市场的增长，并为新的聚合格式铺平道路。因此，为了实用的目的，RSS规范将被冻结在2.0.2版本。我们可以预期的可能的2.0.2 或者 2.0.3等版本，都只是出于澄清规范的目的，而不是在格式上增加新的特征。后续的工作应该集中在模块化、名字空间的使用和在完全新的聚合格式中用新的名字等方面。<br/>许可协议和作者<br/><br/>RSS 2.0 是在遵循i the Attribution/Share Alike Creative Commons 许可协议 的基础上由 the Berkman Center for Internet & Society at Harvard Law School 提供。本文档的作者是 Dave Winer，UserLand software的创始人，也是 Berkman Center 的员工。
]]>
</description>
</item><item>
<link>https://atim.cn/post/337/</link>
<title><![CDATA[DOMDocument 属性和方法 ]]></title> 
<author>bkkkd &lt;partybase@gmail.com&gt;</author>
<category><![CDATA[Web 技术 ]]></category>
<pubDate>Sat, 29 Sep 2007 17:01:47 +0000</pubDate> 
<guid>https://atim.cn/post/337/</guid> 
<description>
<![CDATA[ 
	 &nbsp;最近发现DOMDocument对象很重要,还有XMLHTTP也很重要<br/><br/>注意大小写一定不能弄错.<br/><br/>属性:<br/><br/> <br/><br/> 1Attributes &nbsp; &nbsp; 存储节点的属性列表(只读)<br/> 2childNodes &nbsp; &nbsp; 存储节点的子节点列表(只读)<br/> 3dataType &nbsp; &nbsp; 返回此节点的数据类型<br/> 4Definition &nbsp; &nbsp; 以DTD或XML模式给出的节点的定义(只读)<br/> 5Doctype &nbsp; &nbsp; 指定文档类型节点(只读)<br/> 6documentElement &nbsp; &nbsp; 返回文档的根元素(可读写)<br/> 7firstChild &nbsp; &nbsp; 返回当前节点的第一个子节点(只读)<br/> 8Implementation &nbsp; &nbsp; 返回XMLDOMImplementation对象<br/> 9lastChild &nbsp; &nbsp; 返回当前节点最后一个子节点(只读)<br/>10nextSibling &nbsp; &nbsp; 返回当前节点的下一个兄弟节点(只读)<br/>11nodeName &nbsp; &nbsp; 返回节点的名字(只读)<br/>12nodeType &nbsp; &nbsp; 返回节点的类型(只读)<br/>13nodeTypedValue &nbsp; &nbsp; 存储节点值(可读写)<br/>14nodeValue &nbsp; &nbsp; 返回节点的文本(可读写)<br/>15ownerDocument &nbsp; &nbsp; 返回包含此节点的根文档(只读)<br/>16parentNode &nbsp; &nbsp; 返回父节点(只读)<br/>17Parsed &nbsp; &nbsp; 返回此节点及其子节点是否已经被解析(只读)<br/>18Prefix &nbsp; &nbsp; 返回名称空间前缀(只读)<br/>19preserveWhiteSpace &nbsp; &nbsp; 指定是否保留空白(可读写)<br/>20previousSibling &nbsp; &nbsp; 返回此节点的前一个兄弟节点(只读)<br/>21Text &nbsp; &nbsp; 返回此节点及其后代的文本内容(可读写)<br/>22url &nbsp; &nbsp; 返回最近载入的XML文档的URL(只读)<br/>23Xml &nbsp; &nbsp; 返回节点及其后代的XML表示(只读)<br/><br/>方法:<br/><br/> 1appendChild &nbsp; &nbsp; 为当前节点添加一个新的子节点,放在最后的子节点后<br/> 2cloneNode &nbsp; &nbsp; 返回当前节点的拷贝<br/> 3createAttribute &nbsp; &nbsp; 创建新的属性<br/> 4createCDATASection &nbsp; &nbsp; 创建包括给定数据的CDATA段<br/> 5createComment &nbsp; &nbsp; 创建一个注释节点<br/> 6createDocumentFragment &nbsp; &nbsp; 创建DocumentFragment对象<br/> 7createElement &nbsp; &nbsp; 创建一个元素节点<br/> 8createEntityReference &nbsp; &nbsp; 创建EntityReference对象<br/> 9createNode &nbsp; &nbsp; 创建给定类型,名字和命名空间的节点<br/>10createPorcessingInstruction &nbsp; &nbsp; 创建操作指令节点<br/>11createTextNode &nbsp; &nbsp; 创建包括给定数据的文本节点<br/>12getElementsByTagName &nbsp; &nbsp; 返回指定名字的元素集合<br/>13hasChildNodes &nbsp; &nbsp; 返回当前节点是否有子节点<br/>14insertBefore &nbsp; &nbsp; 在指定节点前插入子节点<br/>15Load &nbsp; &nbsp; 导入指定位置的XML文档<br/>16loadXML &nbsp; &nbsp; 导入指定字符串的XML文档<br/>17removeChild &nbsp; &nbsp; 从子结点列表中删除指定的子节点<br/>18replaceChild &nbsp; &nbsp; 从子节点列表中替换指定的子节点<br/>19Save &nbsp; &nbsp; 把XML文件存到指定节点<br/>20selectNodes &nbsp; &nbsp; 对节点进行指定的匹配,并返回匹配节点列表<br/>21selectSingleNode &nbsp; &nbsp; 对节点进行指定的匹配,并返回第一个匹配节点<br/>22transformNode &nbsp; &nbsp; 使用指定的样式表对节点及其后代进行转换<br/>23transformNodeToObject &nbsp; &nbsp; 使用指定的样式表将节点及其后代转换为对象<br/><br/><br/>*************************************************************************************************************************<br/><br/><br/>DOM(文档对象模型)<br/>DOM(文档对象模型)概念的推出,这个API使HTML如虎添翼,但是有些学DHTML的朋友还是有些困挠,只是因为目前的手册的书写不太科学,是按字母<br/><br/>来分的,不便查阅.其实DOM中最关键是要掌握节点与节点之间的关系(between node andnode),想学习DHTML中的DOM千万不要从头到尾地看遍所<br/><br/>有的属性和方法,你有三国时张松的"过目不忘"的本领吗?没有吧,那就听我分析一下：<br/><br/>其实DOM教给我们的就是一个层次结构，你可以理解为一个树形结构，就像我们的目录一样，一个根目录，根目录下有子目录，子目录下还有子<br/><br/>目录……<br/><br/>根节点：<br/><br/><br/>DOM把层次中的每一个对象都称之为节点（NODE），以HTML超文本标记语言为例：整个文档的一个根就是< html >,在DOM中可以使用<br/><br/>document.documentElement来访问它，它就是整个节点树的根节点（ROOT）<br/><br/>子节点：<br/><br/>一般意义上的节点，根节点以下最大子节点就是主文档区< &nbsp;body >了，要访问到body标签，在脚本中应该写：<br/>document.body<br/>body区以内所有的文本及HTML标签都是文档的节点，分别称为文本节点、元素节点（或者叫标签节点），大家知道HTML说到底只是文本而矣，<br/><br/>不论怎么样的网页必然由这两个节点组成，也只能由这两个节点组成<br/><br/>节点之间的关系：<br/><br/>节点之间的关系也是DOM中最重要的一个关节，如何正确地引用到节点对象，一定要清楚节点树各个节点的相互描述方式，在DHTML里，<br/><br/>Javascript脚本就用了各个节点对象的一整套方法和属性去描述另外的节点对象。<br/><br/><br/>节点的绝对引用：<br/>返回文档的根节点<br/>document.documentElement<br/>返回当前文档中被击活的标签节点<br/>document.activeElement<br/>返回鼠标移出的源节点<br/>event.fromElement<br/>返回鼠标移入的源节点<br/>event.toElement<br/>返回激活事件的源节点<br/>event.srcElement<br/><br/>节点的相对引用：(设当前对节点为node)<br/>返回父节点<br/>node.parentNode<br/>node.parentElement<br/>返回子节点集合（包含文本节点及标签节点）<br/>node.childNodes<br/>返回子标签节点集合<br/>node.children<br/>返回子文本节点集合<br/>node.textNodes<br/>返回第一个子节点<br/>node.firstChild<br/>返回最后一个子节点<br/>node.lastChild<br/>返回同属下一个节点<br/>node.nextSibling<br/>返回同属上一个节点<br/>node.previousSibling<br/><br/>节点的各种操作：(设当前的节点为node)<br/><br/>新增标签节点句柄：<br/>document.createElement(sNode) //参数为要新添的节点标签名，例：newnode=document.createElement("div");<br/><br/>1、添加节点：<br/>追加子节点：<br/>node.appendChild(oNode) //oNode为生新增的节点句柄,例：node.appendChild(newnode)<br/>应用标签节点<br/>node.applyElment(oNode,sWhere)//oNode为生新增的节点句柄,sWhere有两个值：outside / inside，加在当前节点外面还是里面<br/>插入节点<br/>inode.insertBefore()<br/>node.insertAdjacentElement()<br/>node.replaceAdjacentText()<br/><br/>2、修改节点：<br/><br/>删除节点<br/>node.remove()<br/>node.removeChild()<br/>node.removeNode()<br/><br/>替换节点<br/>node.replaceChild()<br/>node.replaceNode()<br/>node.swapNode()<br/><br/><br/>2、复制节点：<br/>返回复制复制节点引用<br/>node.cloneNode(bAll)//bAll为布尔值，true / false 是否克隆该节点所有子节点<br/><br/>3、节点信息<br/>是否包含某节点<br/>node.contains()<br/>是否有子节点<br/>node.hasChildNodes()<br/><br/>************************************************************************************************************************<br/><br/>下面为javascript操作xml<br/><br/><div class="code">&lt;script language=&quot;JavaScript&quot;&gt;<br/>&lt;!--<br/>var doc = new ActiveXObject(&quot;Msxml2.DOMDocument&quot;); //ie5.5+,CreateObject(&quot;Microsoft.XMLDOM&quot;) <br/><br/><br/>//加载文档<br/>//doc.load(&quot;b.xml&quot;);<br/><br/>//创建文件头<br/>var p = doc.createProcessingInstruction(&quot;xml&quot;,&quot;version=&#039;1.0&#039; &nbsp;encoding=&#039;gb2312&#039;&quot;);<br/><br/> &nbsp; &nbsp;//添加文件头<br/> &nbsp; &nbsp;doc.appendChild(p);<br/><br/>//用于直接加载时获得根接点<br/>//var root = doc.documentElement;<br/><br/>//两种方式创建根接点<br/>// &nbsp; &nbsp;var root = doc.createElement(&quot;students&quot;);<br/> &nbsp; &nbsp;var root = doc.createNode(1,&quot;students&quot;,&quot;&quot;);<br/><br/> &nbsp; &nbsp;//创建子接点<br/> &nbsp; &nbsp;var n = doc.createNode(1,&quot;ttyp&quot;,&quot;&quot;);<br/><br/> &nbsp; &nbsp; &nbsp; &nbsp;//指定子接点文本<br/> &nbsp; &nbsp; &nbsp; &nbsp;//n.text = &quot; this is a test&quot;;<br/> &nbsp; &nbsp;<br/> &nbsp; &nbsp;//创建孙接点<br/> &nbsp; &nbsp;var o = doc.createElement(&quot;sex&quot;);<br/> &nbsp; &nbsp; &nbsp; &nbsp;o.text = &quot;男&quot;; &nbsp; &nbsp;//指定其文本<br/><br/> &nbsp; &nbsp;//创建属性<br/> &nbsp; &nbsp;var r = doc.createAttribute(&quot;id&quot;);<br/> &nbsp; &nbsp; &nbsp; &nbsp;r.value=&quot;test&quot;;<br/><br/> &nbsp; &nbsp; &nbsp; &nbsp;//添加属性<br/> &nbsp; &nbsp; &nbsp; &nbsp;n.setAttributeNode(r);<br/><br/> &nbsp; &nbsp;//创建第二个属性 &nbsp; &nbsp;<br/> &nbsp; &nbsp;var r1 = doc.createAttribute(&quot;class&quot;);<br/> &nbsp; &nbsp; &nbsp; &nbsp;r1.value=&quot;tt&quot;;<br/> &nbsp; &nbsp; &nbsp; &nbsp;<br/> &nbsp; &nbsp; &nbsp; &nbsp;//添加属性<br/> &nbsp; &nbsp; &nbsp; &nbsp;n.setAttributeNode(r1);<br/><br/> &nbsp; &nbsp; &nbsp; &nbsp;//删除第二个属性<br/> &nbsp; &nbsp; &nbsp; &nbsp;n.removeAttribute(&quot;class&quot;);<br/><br/> &nbsp; &nbsp; &nbsp; &nbsp;//添加孙接点<br/> &nbsp; &nbsp; &nbsp; &nbsp;n.appendChild(o);<br/><br/> &nbsp; &nbsp; &nbsp; &nbsp;//添加文本接点<br/> &nbsp; &nbsp; &nbsp; &nbsp;n.appendChild(doc.createTextNode(&quot;this is a text node.&quot;));<br/><br/> &nbsp; &nbsp; &nbsp; &nbsp;//添加注释<br/> &nbsp; &nbsp; &nbsp; &nbsp;n.appendChild(doc.createComment(&quot;this is a comment&amp;amp;#92;n&quot;));<br/> &nbsp; &nbsp;<br/> &nbsp; &nbsp; &nbsp; &nbsp;//添加子接点<br/> &nbsp; &nbsp; &nbsp; &nbsp;root.appendChild(n);<br/> &nbsp; &nbsp;<br/> &nbsp; &nbsp;//复制接点<br/> &nbsp; &nbsp;var m = n.cloneNode(true);<br/><br/> &nbsp; &nbsp; &nbsp; &nbsp;root.appendChild(m);<br/> &nbsp; &nbsp; &nbsp; &nbsp;<br/> &nbsp; &nbsp; &nbsp; &nbsp;//删除接点<br/> &nbsp; &nbsp; &nbsp; &nbsp;root.removeChild(root.childNodes(0));<br/><br/> &nbsp; &nbsp;//创建数据段<br/> &nbsp; &nbsp;var c = doc.createCDATASection(&quot;this is a cdata&quot;);<br/> &nbsp; &nbsp; &nbsp; &nbsp;c.text = &quot;hi,cdata&quot;;<br/> &nbsp; &nbsp; &nbsp; &nbsp;//添加数据段<br/> &nbsp; &nbsp; &nbsp; &nbsp;root.appendChild(c);<br/> &nbsp; &nbsp;<br/> &nbsp; &nbsp;//添加根接点<br/> &nbsp; &nbsp;doc.appendChild(root);<br/><br/> &nbsp; &nbsp;//查找接点<br/> &nbsp; &nbsp;var a = doc.getElementsByTagName(&quot;ttyp&quot;);<br/> &nbsp; &nbsp;//var a = doc.selectNodes(&quot;//ttyp&quot;);<br/><br/> &nbsp; &nbsp;//显示改接点的属性<br/> &nbsp; &nbsp;for(var i= 0;i&lt;a.length;i++)<br/> &nbsp; &nbsp; &nbsp;&#123;<br/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;alert(a&#91;i&#93;.xml);<br/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for(var j=0;j&lt;a&#91;i&#93;.attributes.length;j++)<br/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#123;<br/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;alert(a&#91;i&#93;.attributes&#91;j&#93;.name);<br/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#125;<br/> &nbsp; &nbsp; &nbsp;&#125;<br/><br/> &nbsp; &nbsp;//修改节点,利用XPATH定位节点<br/> &nbsp; &nbsp;var b = doc.selectSingleNode(&quot;//ttyp/sex&quot;);<br/> &nbsp; &nbsp;b.text = &quot;女&quot;;<br/><br/> &nbsp; &nbsp;//alert(doc.xml);<br/><br/> &nbsp; &nbsp;//XML保存（需要在服务端，客户端用FSO）<br/> &nbsp; &nbsp;//doc.save();<br/> &nbsp; &nbsp;<br/> &nbsp; &nbsp;//查看根接点XML<br/> &nbsp; &nbsp;if(n)<br/> &nbsp; &nbsp; &nbsp;&#123;<br/> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;alert(n.ownerDocument.xml);<br/> &nbsp; &nbsp; &nbsp;&#125;<br/><br/>//--&gt;<br/>&lt;/script&gt; </div><br/>
]]>
</description>
</item><item>
<link>https://atim.cn/post/305/</link>
<title><![CDATA[什么是CSS hack及写法]]></title> 
<author>bkkkd &lt;partybase@gmail.com&gt;</author>
<category><![CDATA[Web 技术 ]]></category>
<pubDate>Sat, 07 Jul 2007 06:50:42 +0000</pubDate> 
<guid>https://atim.cn/post/305/</guid> 
<description>
<![CDATA[ 
	来源：http://www.div-css.com <br/>什么是CSS hack<br/>由于不同的浏览器，比如Internet Explorer 6,Internet Explorer 7,Mozilla Firefox等，对CSS的解析认识不一样，因此会导致生成的页面效果不一样，得不到我们所需要的页面效果。<br/><br/>这个时候我们就需要针对不同的浏览器去写不同的CSS，让它能够同时兼容不同的浏览器，能在不同的浏览器中也能得到我们想要的页面效果。<br/><br/>这个针对不同的浏览器写不同的CSS code的过程，就叫CSS hack,也叫写CSS hack。<br/><br/>CSS Hack的原理是什么<br/>由于不同的浏览器对CSS的支持及解析结果不一样，还由于CSS中的优先级的关系。我们就可以根据这个来针对不同的浏览器来写不同的CSS。<br/><br/>比如 IE6能识别下划线_和星号*，IE7能识别星号*，当不能识别下划线_，而firefox两个都不能认识。等等<br/><br/>书写顺序，一般是将识别能力强的浏览器的CSS写在后面。下面如何写里面说得更详细些。<br/><br/>如何写CSS Hack<br/>比如要分辨IE6和firefox两种浏览器，可以这样写： <br/><div class="code"><br/>&lt;style&gt; &nbsp; <br/>div&#123; &nbsp; <br/> &nbsp; &nbsp;background:green; /* for firefox */ &nbsp; <br/> &nbsp; &nbsp;*background:red; &nbsp;/* for IE6 */ &nbsp; <br/>&#125; &nbsp; <br/>&lt;/style&gt; &nbsp; <br/><br/>&lt;div&gt;我在IE6中看到是红色的，在firefox中看到是绿色的。&lt;/div&gt; &nbsp;<br/>&lt;style&gt; div&#123; &nbsp; background:green; /* for firefox */ &nbsp; *background:red; &nbsp;/* for IE6 */ &#125; &lt;/style&gt; &lt;div&gt;我在IE6中看到是红色的，在firefox中看到是绿色的。&lt;/div&gt;<br/></div><br/>解释一下：<br/>上面的css在firefox中，它是认识不了后面的那个带星号*的东东是什么的，于是将它过滤掉，不予理睬，解析得到的结果是:div&#123;background:green&#125;,于是理所当然这个div的背景是绿色的。<br/>在IE6中呢，它两个background都能识别出来，它解析得到的结果是:div&#123;background:green;background:red;&#125;,于是根据优先级别，处在后面的red的优先级高，于是当然这个div的背景颜色就是红色的了。<br/><br/><br/><br/> <br/><br/>CSS hack:区分IE6，IE7，firefox区别不同浏览器，CSS hack写法：<br/><br/><br/>区别IE6与FF：<br/> &nbsp; &nbsp; &nbsp; background:orange;*background:blue;<br/><br/><br/>区别IE6与IE7：<br/> &nbsp; &nbsp; &nbsp; background:green !important;background:blue;<br/><br/><br/>区别IE7与FF：<br/> &nbsp; &nbsp; &nbsp; background:orange; *background:green;<br/><br/><br/>区别FF，IE7，IE6：<br/> &nbsp; &nbsp; &nbsp; background:orange;*background:green !important;*background:blue;<br/><br/><br/>注：IE都能识别*;标准浏览器(如FF)不能识别*；<br/>IE6能识别*，但不能识别 !important,<br/>IE7能识别*，也能识别!important;<br/>FF不能识别*，但能识别!important;<br/><a href="https://atim.cn/attachment/1183791030_0.gif" target="_blank"><img src="https://atim.cn/attachment/1183791030_0.gif" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a>
]]>
</description>
</item><item>
<link>https://atim.cn/post/234/</link>
<title><![CDATA[ 权限设计及算法]]></title> 
<author>bkkkd &lt;partybase@gmail.com&gt;</author>
<category><![CDATA[Web 技术 ]]></category>
<pubDate>Thu, 29 Mar 2007 03:25:02 +0000</pubDate> 
<guid>https://atim.cn/post/234/</guid> 
<description>
<![CDATA[ 
	权限设计<br/><br/>大概有这几种模式：<br/>用户+组+角色+权限<br/>用户+组+权限<br/>用户+角色+权限<br/>用户+权限<br/><br/><br/>最近看了别人的设计方法，大多以“整数”来表示权限值，如添加、浏览、删除和修改，分别用1、2、4、8这几个整数来代替，不过，各人的做法有所不同，举例如下：<br/><br/>1. 用2的n次幂组成权限值的集合，如1、2、4、8、16...，某用户的权限值为其子集中的整数之和，如 7=1+2+4，5=1+4。如果要从数据库检索包含某几种权限的用户，则先把这几种权限值相加，假设和为k，然后select * from table where 1 and 用户权限值 = 'k'；如果要判断某用户有哪些权限，则取出其权限值k，分别用k&1,K&2,K&4,k&16...,如果为真，则表示有值等于“&”右边整数的权限，例如，如果k&4为真，则此用户有权限表中值等于4的权限；<br/><br/>2.用质数2、3、5、 7、11...组成权限集合，某用户的权限为其子集中各整数的乘积，如 210 = 2*3*5*7,我觉得这种方法很有趣，难点在于如何分解质因数；但我有些不认同原作者的提法，他认为权限之间可能存在包含关系，如某用户有删除权限，则其一定有浏览权限，要不然就没法删除，事实确实是这样，不过我认为这样太复杂了，容易出错，我觉得权限最好是“原子”的，互不干扰，也就是说某用户有删除权限而没浏览权限则其无法进行删除操作，因为他看不到东西，解决这个矛盾的关键是在给用户赋权时，把浏览权限也赋给他；<br/><br/>3.不用整数，而是用“向量表”方法（也许我说的不一定对），把所有可能的权限按一定的顺序排列，如添加、浏览、修改、删除...，用户的权限值为固定100位长度的字符串，如100010100001....01，从左起每一位对应一种操作权限，如果有这种权限，则此位的值为1，反之，则为0，作者之所以把用户权限值固定为100位，我想是考虑到升级问题，但我认为这还不够科学，我认为用户的权限值长度应小于权限个数，举例如下：<br/>权限排列表：添加、浏览、修改、删除，用户A有添加和浏览的的权限，则其权限值为11，用户B有浏览和修改的权限则其权限值为011，用户C有浏览和删除的权限则其权限值为0101，这样设计的好处为：当权限表中增加别的权限时，不会影响用户表或角色表；<br/><br/>4. 我曾经的做法，在后台管理中把权限分为两大类：栏目权限和操作权限，每个栏目对应一个目录，操作权限细分为浏览、添加、修改和删除，用户进入系统后首先判断有没有栏目权限，然后判断有没有操作权限，判断栏目权限相对简单一些，首先获取访问页面的路径path，然后分解出目录，对应用户拥有的目录权限，如果此目录包含在用户有权管理的目录数组中（从数据库取出），则其有进入此目录的权限，否则，没有，然而，在判断操作权限好象有些麻烦，但突然想到添加、浏览、修改和删除与我的文件命名规则是基本是对应的，但有点不同的是，我把添加和删除的功能合并在一个文件中了，例如文件名为 proAddEdit.php，幸好意识到修改文件时多了个传递参数id，于是，我用正则解决了这个问题，今天看来，这种方法似乎过时了，因为不适应面向对象的思想和用框架体系来开发系统！
]]>
</description>
</item><item>
<link>https://atim.cn/post/208/</link>
<title><![CDATA[[转载]Meta标签详解]]></title> 
<author>bkkkd &lt;partybase@gmail.com&gt;</author>
<category><![CDATA[Web 技术 ]]></category>
<pubDate>Thu, 08 Mar 2007 01:41:15 +0000</pubDate> 
<guid>https://atim.cn/post/208/</guid> 
<description>
<![CDATA[ 
	<br/>Meta在GG等搜索引擎出现前是一个搜索友好的方法.<br/>但因为太多人通过meta作假,所以就很多搜索引擎都不以mate作为内容的标准<br/>但meta也有其它的作用.<br/><div class="quote"><div class="quote-title">引用</div><div class="quote-content"><br/>META标签是HTML语言HEAD区的一个辅助性标签，它位于HTML文档头部的<HEAD>标记和<TITLE>标记之间，它提供用户不可见的信息。meta标签通常用来为搜索引擎robots定义页面主题，或者是定义用户浏览器上的cookie；它可以用于鉴别作者，设定页面格式，标注内容提要和关键字；还可以设置页面使其可以根据你定义的时间间隔刷新自己,以及设置RASC内容等级，等等。 <br/><br/>详细介绍 <br/><br/>下面介绍一些有关 标记的例子及解释。 <br/><br/>META标签分两大部分：HTTP标题信息(HTTP-EQUIV)和页面描述信息(NAME)。 <br/><br/>★HTTP-EQUIV <br/><br/>HTTP-EQUIV类似于HTTP的头部协议，它回应给浏览器一些有用的信息，以帮助正确和精确地显示网页内容。常用的HTTP-EQUIV类型有： <br/><br/>1、Content-Type和Content-Language (显示字符集的设定) <br/><br/>说明：设定页面使用的字符集，用以说明主页制作所使用的文字已经语言，浏览器会根据此来调用相应的字符集显示page内容。 <br/><br/>用法：<Meta http-equiv="Content-Type" Content="text/html; Charset=gb2312"><br/><br/><Meta http-equiv="Content-Language" Content="zh-CN"> <br/><br/>注意：该META标签定义了HTML页面所使用的字符集为GB2132，就是国标汉字码。如果将其中的“charset=GB2312”替换成“BIG5”，则该页面所用的字符集就是繁体中文Big5码。当你浏览一些国外的站点时，IE浏览器会提示你要正确显示该页面需要下载xx语支持。这个功能就是通过读取HTML页面META标签的Content-Type属性而得知需要使用哪种字符集显示该页面的。如果系统里没有装相应的字符集，则IE就提示下载。其他的语言也对应不同的charset，比如日文的字符集是“iso-2022-jp ”，韩文的是“ks_c_5601”。<br/><br/>Content-Type的Content还可以是：text/xml等文档类型；<br/><br/>Charset选项：ISO-8859-1(英文)、BIG5、UTF-8、SHIFT-Jis、Euc、Koi8-2、us-ascii, x-mac-roman, iso-8859-2, x-mac-ce, iso-2022-jp, x-sjis, x-euc-jp,euc-kr, iso-2022-kr, gb2312, gb_2312-80, x-euc-tw, x-cns11643-1,x-cns11643-2等字符集；Content-Language的Content还可以是：EN、FR等语言代码。 <br/><br/>2、Refresh (刷新) <br/><br/>说明：让网页多长时间（秒）刷新自己，或在多长时间后让网页自动链接到其它网页。<br/><br/>用法：<Meta http-equiv="Refresh" Content="30"><br/><br/><Meta http-equiv="Refresh" Content="5; Url=http://www.downme.com"><br/><br/>注意：其中的5是指停留5秒钟后自动刷新到URL网址。 <br/><br/>3、Expires (期限) <br/><br/>说明：指定网页在缓存中的过期时间，一旦网页过期，必须到服务器上重新调阅。<br/><br/>用法：<Meta http-equiv="Expires" Content="0"><br/><br/><Meta http-equiv="Expires" Content="Wed, 26 Feb 1997 08:21:57 GMT"><br/><br/>注意：必须使用GMT的时间格式，或直接设为0(数字表示多少时间后过期)。 <br/><br/>4、Pragma (cach模式) <br/><br/>说明：禁止浏览器从本地机的缓存中调阅页面内容。<br/><br/>用法：<Meta http-equiv="Pragma" Content="No-cach"><br/><br/>注意：网页不保存在缓存中，每次访问都刷新页面。这样设定，访问者将无法脱机浏览。 <br/><br/>5、Set-Cookie (cookie设定) <br/><br/>说明：浏览器访问某个页面时会将它存在缓存中，下次再次访问时就可从缓存中读取，以提高速度。当你希望访问者每次都刷新你广告的图标，或每次都刷新你的计数器，就要禁用缓存了。通常HTML文件没有必要禁用缓存，对于ASP等页面，就可以使用禁用缓存，因为每次看到的页面都是在服务器动态生成的，缓存就失去意义。如果网页过期，那么存盘的cookie将被删除。<br/><br/>用法：<Meta http-equiv="Set-Cookie" Content="cookievalue=xxx; expires=Wednesday,<br/><br/>21-Oct-98 16:14:21 GMT; path=/"><br/><br/>注意：必须使用GMT的时间格式。 <br/><br/>6、Window-target (显示窗口的设定) <br/><br/>说明：强制页面在当前窗口以独立页面显示。<br/><br/>用法：<Meta http-equiv="Widow-target" Content="_top"><br/><br/>注意：这个属性是用来防止别人在框架里调用你的页面。Content选项：_blank、_top、_self、_parent。 <br/><br/>7、Pics-label (网页RSAC等级评定)<br/><br/>说明：在IE的Internet选项中有一项内容设置，可以防止浏览一些受限制的网站，而网站的限制级<br/><br/>别就是通过该参数来设置的。<br/><br/>用法：<META http-equiv="Pics-label" Contect=<br/><br/>"(PICS－1.1'http://www.rsac.org/ratingsv01.html'<br/><br/>I gen comment 'RSACi North America Sever' by 'inet@microsoft.com' <br/><br/>for 'http://www.microsoft.com' on '1997.06.30T14:21－0500' r(n0 s0 v0 l0))"> <br/><br/>注意：不要将级别设置的太高。RSAC的评估系统提供了一种用来评价Web站点内容的标准。用户可以设置Microsoft Internet Explorer（IE3.0以上）来排除包含有色情和暴力内容的站点。上面这个例子中的HTML取自Microsoft的主页。代码中的（n 0 s 0 v 0 l 0）表示该站点不包含不健康内容。级别的评定是由RSAC，即美国娱乐委员会的评级机构评定的，如果你想进一步了解RSAC评估系统的等级内容，或者你需要评价自己的网站，可以访问RSAC的站点：http://www.rsac.org/。 <br/><br/>8、Page-Enter、Page-Exit (进入与退出) <br/><br/>说明：这个是页面被载入和调出时的一些特效。<br/><br/>用法：<Meta http-equiv="Page-Enter" Content="blendTrans(Duration=0.5)"><br/><br/><Meta http-equiv="Page-Exit" Content="blendTrans(Duration=0.5)"><br/><br/>注意：blendTrans是动态滤镜的一种，产生渐隐效果。另一种动态滤镜RevealTrans也可以用于页面进入与退出效果: <br/><br/><Meta http-equiv="Page-Enter" Content="revealTrans(duration=x, transition=y)"><br/><br/><Meta http-equiv="Page-Exit" Content="revealTrans(duration=x, transition=y)"> <br/><br/>Duration表示滤镜特效的持续时间(单位：秒)<br/><br/>Transition滤镜类型。表示使用哪种特效，取值为0-23。 <br/><br/>0 矩形缩小<br/><br/>1 矩形扩大<br/><br/>2 圆形缩小<br/><br/>3 圆形扩大<br/><br/>4 下到上刷新<br/><br/>5 上到下刷新<br/><br/>6 左到右刷新<br/><br/>7 右到左刷新<br/><br/>8 竖百叶窗<br/><br/>9 横百叶窗<br/><br/>10 错位横百叶窗<br/><br/>11 错位竖百叶窗<br/><br/>12 点扩散<br/><br/>13 左右到中间刷新<br/><br/>14 中间到左右刷新<br/><br/>15 中间到上下<br/><br/>16 上下到中间<br/><br/>17 右下到左上<br/><br/>18 右上到左下<br/><br/>19 左上到右下<br/><br/>20 左下到右上<br/><br/>21 横条<br/><br/>22 竖条<br/><br/>23 以上22种随机选择一种 <br/><br/>9、MSThemeCompatible (XP主题)<br/><br/>说明：是否在IE中关闭 xp 的主题<br/><br/>用法：<Meta http-equiv="MSThemeCompatible" Content="Yes"><br/><br/>注意：关闭 xp 的蓝色立体按钮系统显示样式，从而和win2k 很象。 <br/><br/>10、IE6 (页面生成器)<br/><br/>说明：页面生成器generator，是ie6<br/><br/>用法：<Meta http-equiv="IE6" Content="Generator"><br/><br/>注意：用什么东西做的，类似商品出厂厂商。 <br/><br/>11、Content-scrīpt-Type (脚本相关)<br/><br/>说明：这是近来W3C的规范，指明页面中脚本的类型。<br/><br/>用法：<Meta http-equiv="Content-scrīpt-Type" Content="text/javascrīpt"><br/><br/>注意： <br/><br/>★NAME变量 <br/><br/>name是描述网页的，对应于Content（网页内容），以便于搜索引擎机器人查找、分类（目前几乎所有的搜索引擎都使用网上机器人自动查找meta值来给网页分类）。<br/><br/>name的value值（name=""）指定所提供信息的类型。有些值是已经定义好的。例如descrīption(说明)、keyword(关键字)、refresh(刷新)等。还可以指定其他任意值，如：creationdate(创建日期) 、<br/><br/>document ID(文档编号)和level(等级)等。<br/><br/>name的content指定实际内容。如：如果指定level(等级)为value(值)，则Content可能是beginner(初级)、intermediate(中级)、advanced(高级)。 <br/><br/>1、Keywords (关键字)<br/><br/>说明：为搜索引擎提供的关键字列表<br/><br/>用法：<Meta name="Keywords" Content="关键词1,关键词2，关键词3,关键词4,……"><br/><br/>注意：各关键词间用英文逗号“,”隔开。META的通常用处是指定搜索引擎用来提高搜索质量的关键词。当数个META元素提供文档语言从属信息时，搜索引擎会使用lang特性来过滤并通过用户的语言优先参照来显示搜索结果。例如：<br/><br/><Meta name="Kyewords" Lang="EN" Content="vacation,greece,sunshine"><br/><br/><Meta name="Kyewords" Lang="FR" Content="vacances,grè:ce,soleil"> <br/><br/>2、Descrīption (简介)<br/><br/>说明：Descrīption用来告诉搜索引擎你的网站主要内容。<br/><br/>用法：<Meta name="Descrīption" Content="你网页的简述"><br/><br/>注意： <br/><br/>3、Robots (机器人向导)<br/><br/>说明：Robots用来告诉搜索机器人哪些页面需要索引，哪些页面不需要索引。Content的参数有all、none、index、noindex、follow、nofollow。默认是all。<br/><br/>用法：<Meta name="Robots" Content="All&#124;None&#124;Index&#124;Noindex&#124;Follow&#124;Nofollow"><br/><br/>注意：许多搜索引擎都通过放出robot/spider搜索来登录网站，这些robot/spider就要用到meta元素的一些特性来决定怎样登录。 <br/><br/>all：文件将被检索，且页面上的链接可以被查询；<br/><br/>none：文件将不被检索，且页面上的链接不可以被查询；(和 "noindex, no follow" 起相同作用)<br/><br/>index：文件将被检索；（让robot/spider登录）<br/><br/>follow：页面上的链接可以被查询；<br/><br/>noindex：文件将不被检索，但页面上的链接可以被查询；(不让robot/spider登录)<br/><br/>nofollow：文件将不被检索，页面上的链接可以被查询。(不让robot/spider顺着此页的连接往下探找) <br/><br/>4、Author (作者)<br/><br/>说明：标注网页的作者或制作组<br/><br/>用法：<Meta name="Author" Content="张三，abc@163.com"><br/><br/>注意：Content可以是：你或你的制作组的名字,或Email <br/><br/>5、Copyright (版权)<br/><br/>说明：标注版权<br/><br/>用法：<Meta name="Copyright" Content="本页版权归网易学院所有。All Rights Reserved"><br/><br/>注意： <br/><br/>6、Generator (编辑器)<br/><br/>说明：编辑器的说明<br/><br/>用法：<Meta name="Generator" Content="PCDATA&#124;FrontPage&#124;"><br/><br/>注意：Content="你所用编辑器" <br/><br/>7、revisit-after (重访)<br/><br/>说明：<br/><br/>用法：<META name="revisit-after" CONTENT="7 days" ><br/><br/>注意： <br/><br/>★Head中的其它一些用法 <br/><br/>1、scheme (方案)<br/><br/>说明：scheme can be used when name is used to specify how the value of content should be interpreted.<br/><br/>用法：<meta scheme="ISBN" name="identifier" content="0-14-043205-1" /><br/><br/>注意： <br/><br/>2、Link (链接)<br/><br/>说明：链接到文件<br/><br/>用法：<Link href="soim.ico" rel="Shortcut Icon"><br/><br/>注意：很多网站如果你把她保存在收件夹中后，会发现它连带着一个小图标，如果再次点击进入之后还会发现地址栏中也有个小图标。现在只要在你的页头加上这段话，就能轻松实现这一功能。<LINK> 用来将目前文件与其它 URL 作连结，但不会有连结按钮，用於 <HEAD> 标记间， 格式如下： <br/><br/><link href="URL" rel="relationship"> <br/><br/><link href="URL" rev="relationship"> <br/><br/>3、Base (基链接)<br/><br/>说明：插入网页基链接属性<br/><br/>用法：<Base href="http://www.***.net/" target="_blank"><br/><br/>注意：你网页上的所有相对路径在链接时都将在前面加上“http://www.***.com/”。其中target="_blank"是链接文件在新的窗口中打开，你可以做其他设置。将“_blank”改为“_parent”是链接文件将在当前窗口的父级窗口中打开；改为“_self”链接文件在当前窗口（帧）中打开；改为“_top”链接文件全屏显示。 <br/><br/>以上是META标签的一些基本用法，其中最重要的就是：Keywords和Descrīption的设定。为什么呢？道理很简单，这两个语句可以让搜索引擎能准确的发现你，吸引更多的人访问你的站点!根据现在流行搜索引擎(Google，Lycos，AltaVista等)的工作原理，搜索引擎先派机器人自动在WWW上搜索，当发现新的网站时，便于检索页面中的Keywords和Descrīption，并将其加入到自己的数据库，然后再根据关键词的密度将网站排序。 <br/><br/>由此看来，我们必须记住添加Keywords和Descrīption的META标签，并尽可能写好关键字和简介。否则，<br/><br/>后果就会是：<br/><br/>●如果你的页面中根本没有Keywords和Descrīption的META标签，那么机器人是无法将你的站点加入数<br/><br/>据库，网友也就不可能搜索到你的站点。 <br/><br/>●如果你的关键字选的不好，关键字的密度不高，被排列在几十甚至几百万个站点的后面被点击的可<br/><br/>能性也是非常小的。 <br/><br/>写好Keywords(关键字)要注意以下几点： <br/><br/>●不要用常见词汇。例如www、homepage、net、web等。 <br/><br/>●不要用形容词，副词。例如最好的，最大的等。 <br/><br/>●不要用笼统的词汇，要尽量精确。例如“爱立信手机”，改用“T28SC”会更好。 <br/><br/>“三人之行，必有我师”，寻找合适关键词的技巧是：到Google、Lycos、Alta等著名搜索引擎，搜索与<br/><br/>你的网站内容相仿的网站，查看排名前十位的网站的META关键字，将它们用在你的网站上，效果可想而知了。 <br/><br/>★小窍门 <br/><br/>为了提高搜索点击率，这里还有一些“捷径”可以帮得到你： <br/><br/>●为了增加关键词的密度，将关键字隐藏在页面里(将文字颜色定义成与背景颜色一样)。 <br/><br/>●在图像的ALT注释语句中加入关键字。如：<IMG SRC="xxx.gif" Alt="Keywords"> <br/><br/>●利用HTML的注释语句，在页面代码里加入大量关键字。用法： <!-- 这里插入关键字 --> <br/></div></div>
]]>
</description>
</item><item>
<link>https://atim.cn/post/206/</link>
<title><![CDATA[如何编写PHP扩展]]></title> 
<author>bkkkd &lt;partybase@gmail.com&gt;</author>
<category><![CDATA[Web 技术 ]]></category>
<pubDate>Wed, 07 Mar 2007 05:36:04 +0000</pubDate> 
<guid>https://atim.cn/post/206/</guid> 
<description>
<![CDATA[ 
	http://blog.csdn.net/taft/archive/2006/02/10/596291.aspx
]]>
</description>
</item><item>
<link>https://atim.cn/post/205/</link>
<title><![CDATA[[转载]深入探讨PHP中的内存管理问题]]></title> 
<author>bkkkd &lt;partybase@gmail.com&gt;</author>
<category><![CDATA[Web 技术 ]]></category>
<pubDate>Wed, 07 Mar 2007 05:33:55 +0000</pubDate> 
<guid>https://atim.cn/post/205/</guid> 
<description>
<![CDATA[ 
	作者：朱先忠编译<br/><br/>　　摘要 内存管理对于长期运行的程序，例如服务器守护程序，是相当重要的影响；因此，理解PHP是如何分配与释放内存的对于创建这类程序极为重要。本文将重点探讨PHP的内存管理问题。<br/><br/>　　一、 内存<br/><br/>　　在PHP中，填充一个字符串变量相当简单，这只需要一个语句"＜?php $str = 'hello world '; ?＞"即可，并且该字符串能够被自由地修改、拷贝和移动。而在C语言中，尽管你能够编写例如"char *str = "hello world ";"这样的一个简单的静态字符串；但是，却不能修改该字符串，因为它生存于程序空间内。为了创建一个可操纵的字符串，你必须分配一个内存块，并且通过一个函数（例如strdup()）来复制其内容。<br/><div class="code"><br/>&#123;<br/>　char *str;<br/>　str = strdup(&quot;hello world&quot;);<br/>　if (!str) &#123;<br/>　　fprintf(stderr， &quot;Unable to allocate memory!&quot;);<br/>　&#125;<br/>&#125;<br/></div><br/>　　由于后面我们将分析的各种原因，传统型内存管理函数（例如malloc()，free()，strdup()，realloc()，calloc()，等等）几乎都不能直接为PHP源代码所使用。<br/><br/>　　二、 释放内存<br/><br/>　　在几乎所有的平台上，内存管理都是通过一种请求和释放模式实现的。首先，一个应用程序请求它下面的层(通常指"操作系统")："我想使用一些内存空间"。如果存在可用的空间，操作系统就会把它提供给该程序并且打上一个标记以便不会再把这部分内存分配给其它程序。<br/>当应用程序使用完这部分内存，它应该被返回到OS；这样以来，它就能够被继续分配给其它程序。如果该程序不返回这部分内存，那么OS无法知道是否这块内存不再使用并进而再分配给另一个进程。如果一个内存块没有释放，并且所有者应用程序丢失了它，那么，我们就说此应用程序"存在漏洞"，因为这部分内存无法再为其它程序可用。<br/><br/>　　在一个典型的客户端应用程序中，较小的不太经常的内存泄漏有时能够为OS所"容忍"，因为在这个进程稍后结束时该泄漏内存会被隐式返回到OS。这并没有什么，因为OS知道它把该内存分配给了哪个程序，并且它能够确信当该程序终止时不再需要该内存。<br/><br/>　　而对于长时间运行的服务器守护程序，包括象Apache这样的web服务器和扩展php模块来说，进程往往被设计为相当长时间一直运行。因为OS不能清理内存使用，所以，任何程序的泄漏-无论是多么小-都将导致重复操作并最终耗尽所有的系统资源。<br/><br/>　　现在，我们不妨考虑用户空间内的stristr()函数；为了使用大小写不敏感的搜索来查找一个字符串，它实际上创建了两个串的各自的一个小型副本，然后执行一个更传统型的大小写敏感的搜索来查找相对的偏移量。然而，在定位该字符串的偏移量之后，它不再使用这些小写版本的字符串。如果它不释放这些副本，那么，每一个使用stristr()的脚本在每次调用它时都将泄漏一些内存。最后，web服务器进程将拥有所有的系统内存，但却不能够使用它。<br/><br/>　　你可以理直气壮地说，理想的解决方案就是编写良好、干净的、一致的代码。这当然不错；但是，在一个象PHP解释器这样的环境中，这种观点仅对了一半。<br/><br/>　　三、 错误处理<br/><br/>　　为了实现"跳出"对用户空间脚本及其依赖的扩展函数的一个活动请求，需要使用一种方法来完全"跳出"一个活动请求。这是在Zend引擎内实现的：在一个请求的开始设置一个"跳出"地址，然后在任何die()或exit()调用或在遇到任何关键错误(E_ERROR)时执行一个longjmp()以跳转到该"跳出"地址。<br/><br/>　　尽管这个"跳出"进程能够简化程序执行的流程，但是，在绝大多数情况下，这会意味着将会跳过资源清除代码部分(例如free()调用)并最终导致出现内存漏洞。现在，让我们来考虑下面这个简化版本的处理函数调用的引擎代码：<br/><div class="code"><br/>void call_function(const char *fname， int fname_len TSRMLS_DC)&#123;<br/>　zend_function *fe;<br/>　char *lcase_fname;<br/>　/* PHP函数名是大小写不敏感的，<br/>　*为了简化在函数表中对它们的定位，<br/>　*所有函数名都隐含地翻译为小写的<br/>　*/<br/>　lcase_fname = estrndup(fname， fname_len);<br/>　zend_str_tolower(lcase_fname， fname_len);<br/>　if (zend_hash_find(EG(function_table)，lcase_fname， fname_len + 1， (void **)&amp;fe) == FAILURE) &#123;<br/>　　zend_execute(fe-＞op_array TSRMLS_CC);<br/>　&#125; else &#123;<br/>　　php_error_docref(NULL TSRMLS_CC， E_ERROR，&quot;Call to undefined function: %s()&quot;， fname);<br/>　&#125;<br/>　efree(lcase_fname);<br/>&#125;<br/></div><br/>　　当执行到php_error_docref()这一行时，内部错误处理器就会明白该错误级别是critical，并相应地调用longjmp()来中断当前程序流程并离开call_function()函数，甚至根本不会执行到efree(lcase_fname)这一行。你可能想把efree()代码行移动到zend_error()代码行的上面；但是，调用这个call_function()例程的代码行会怎么样呢？fname本身很可能就是一个分配的字符串，并且，在它被错误消息处理使用完之前，你根本不能释放它。<br/><br/>　　注意，这个php_error_docref()函数是trigger_error()函数的一个内部等价实现。它的第一个参数是一个将被添加到 docref的可选的文档引用。第三个参数可以是任何我们熟悉的E_*家族常量，用于指示错误的严重程度。第四个参数（最后一个）遵循printf()风格的格式化和变量参数列表式样。<br/>四、 Zend内存管理器<br/><br/>　　在上面的"跳出"请求期间解决内存泄漏的方案之一是：使用Zend内存管理(ZendMM)层。引擎的这一部分非常类似于操作系统的内存管理行为-分配内存给调用程序。区别在于，它处于进程空间中非常低的位置而且是"请求感知"的；这样以来，当一个请求结束时，它能够执行与OS在一个进程终止时相同的行为。也就是说，它会隐式地释放所有的为该请求所占用的内存。图1展示了ZendMM与OS以及PHP进程之间的关系。<br/><br/>网管必读深入探讨PHP中的内存管理问题(2)<br/><a href="https://atim.cn/attachment/1173245376_0.jpg" target="_blank"><img src="https://atim.cn/attachment/1173245376_0.jpg" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/>图1.Zend内存管理器代替系统调用来实现针对每一种请求的内存分配。<br/><br/>　　除了提供隐式内存清除功能之外，ZendMM还能够根据php.ini中memory_limit的设置控制每一种内存请求的用法。如果一个脚本试图请求比系统中可用内存更多的内存，或大于它每次应该请求的最大量，那么，ZendMM将自动地发出一个E_ERROR消息并且启动相应的"跳出"进程。这种方法的一个额外优点在于，大多数内存分配调用的返回值并不需要检查，因为如果失败的话将会导致立即跳转到引擎的退出部分。<br/><br/>　　把PHP内部代码和OS的实际的内存管理层"钩"在一起的原理并不复杂：所有内部分配的内存都要使用一组特定的可选函数实现。例如，PHP代码不是使用malloc (16)来分配一个16字节内存块而是使用了emalloc(16)。除了实现实际的内存分配任务外，ZendMM还会使用相应的绑定请求类型来标志该内存块；这样以来，当一个请求"跳出"时，ZendMM可以隐式地释放它。<br/><br/>　　经常情况下，内存一般都需要被分配比单个请求持续时间更长的一段时间。这种类型的分配（因其在一次请求结束之后仍然存在而被称为"永久性分配"），可以使用传统型内存分配器来实现，因为这些分配并不会添加 ZendMM使用的那些额外的相应于每种请求的信息。然而有时，直到运行时刻才会确定是否一个特定的分配需要永久性分配，因此ZendMM导出了一组帮助宏，其行为类似于其它的内存分配函数，但是使用最后一个额外参数来指示是否为永久性分配。<br/><br/>　　如果你确实想实现一个永久性分配，那么这个参数应该被设置为1；在这种情况下，请求是通过传统型malloc()分配器家族进行传递的。然而，如果运行时刻逻辑认为这个块不需要永久性分配；那么，这个参数可以被设置为零，并且调用将会被调整到针对每种请求的内存分配器函数。<br/><br/>　　例如，pemalloc(buffer_len，1)将映射到malloc(buffer_len)，而pemalloc(buffer_len，0)将被使用下列语句映射到emalloc(buffer_len)：<br/><div class="code"><br/>#define in Zend/zend_alloc.h:<br/>#define pemalloc(size， persistent) ((persistent)?malloc(size): emalloc(size))<br/><br/>　　所有这些在ZendMM中提供的分配器函数都能够从下表中找到其更传统的对应实现。<br/><br/>　　表格1展示了ZendMM支持下的每一个分配器函数以及它们的e/pe对应实现：<br/><br/>　　表格1.传统型相对于PHP特定的分配器。<br/><br/>分配器函数 &nbsp; e/pe对应实现<br/>void *malloc(size_t count); &nbsp; void *emalloc(size_t count);void *pemalloc(size_t count，char persistent);<br/>void *calloc(size_t count); &nbsp; void *ecalloc(size_t count);void *pecalloc(size_t count，char persistent);<br/>void *realloc(void *ptr，size_t count); &nbsp; void *erealloc(void *ptr，size_t count);<br/>void *perealloc(void *ptr，size_t count，char persistent);<br/>void *strdup(void *ptr); &nbsp; void *estrdup(void *ptr);void *pestrdup(void *ptr，char persistent);<br/>void free(void *ptr); &nbsp; void efree(void *ptr);<br/>void pefree(void *ptr，char persistent);<br/></div><br/>　　你可能会注意到，即使是pefree()函数也要求使用永久性标志。这是因为在调用pefree()时，它实际上并不知道是否ptr是一种永久性分配。针对一个非永久性分配调用free()能够导致双倍的空间释放，而针对一种永久性分配调用efree()有可能会导致一个段错误，因为内存管理器会试图查找并不存在的管理信息。因此，你的代码需要记住它分配的数据结构是否是永久性的。<br/><br/>　　除了分配器函数核心部分外，还存在其它一些非常方便的ZendMM特定的函数，例如：<br/><br/>void *estrndup(void *ptr，int len);<br/><br/>　　该函数能够分配len+1个字节的内存并且从ptr处复制len个字节到最新分配的块。这个estrndup()函数的行为可以大致描述如下：<br/><div class="code"><br/>void *estrndup(void *ptr， int len)<br/>&#123;<br/>　char *dst = emalloc(len + 1);<br/>　memcpy(dst， ptr， len);<br/>　dst&#91;len&#93; = 0;<br/>　return dst;<br/>&#125;<br/></div><br/>　　在此，被隐式放置在缓冲区最后的NULL字节可以确保任何使用estrndup()实现字符串复制操作的函数都不需要担心会把结果缓冲区传递给一个例如 printf()这样的希望以为NULL为结束符的函数。当使用estrndup()来复制非字符串数据时，最后一个字节实质上都浪费了，但其中的利明显大于弊。<br/><br/>void *safe_emalloc(size_t size， size_t count， size_t addtl);<br/>void *safe_pemalloc(size_t size， size_t count，size_t addtl，char persistent);<br/><br/>　　这些函数分配的内存空间最终大小是((size*count)+addtl)。你可以会问："为什么还要提供额外函数呢？为什么不使用一个 emalloc/pemalloc呢？"原因很简单：为了安全。尽管有时候可能性相当小，但是，正是这一"可能性相当小"的结果导致宿主平台的内存溢出。这可能会导致分配负数个数的字节空间，或更有甚者，会导致分配一个小于调用程序要求大小的字节空间。而safe_emalloc()能够避免这种类型的陷井-通过检查整数溢出并且在发生这样的溢出时显式地预以结束。<br/><br/>　　注意，并不是所有的内存分配例程都有一个相应的p*对等实现。例如，不存在pestrndup()，并且在PHP 5.1版本前也不存在safe_pemalloc()。<br/><br/>　　五、 引用计数<br/><br/>　　慎重的内存分配与释放对于PHP（它是一种多请求进程）的长期性能有极其重大的影响；但是，这还仅是问题的一半。为了使一个每秒处理上千次点击的服务器高效地运行，每一次请求都需要使用尽可能少的内存并且要尽可能减少不必要的数据复制操作。请考虑下列PHP代码片断：<br/><div class="code"><br/>＜?php<br/>$a = &#039;Hello World&#039;;<br/>$b = $a;<br/>unset($a);<br/>?＞<br/></div><br/>　　在第一次调用之后，只有一个变量被创建，并且一个12字节的内存块指派给它以便存储字符串"Hello World"，还包括一个结尾处的NULL字符。现在，让我们来观察后面的两行：$b被置为与变量$a相同的值，然后变量$a被释放。<br/><br/>　　如果PHP因每次变量赋值都要复制变量内容的话，那么，对于上例中要复制的字符串还需要复制额外的12个字节，并且在数据复制期间还要进行另外的处理器加载。这一行为乍看起来有点荒谬，因为当第三行代码出现时，原始变量被释放，从而使得整个数据复制显得完全不必要。其实，我们不妨再远一层考虑，让我们设想当一个10MB大小的文件的内容被装载到两个变量中时会发生什么。这将会占用20MB的空间，此时，10已经足够了。引擎会把那么多的时间和内存浪费在这样一种无用的努力上吗？<br/><br/>　　你应该知道，PHP的设计者早已深谙此理。<br/><br/>　　记住，在引擎中，变量名和它们的值实际上是两个不同的概念。值本身是一个无名的zval*存储体（在本例中，是一个字符串值），它被通过zend_hash_add()赋给变量$a。如果两个变量名都指向同一个值，会发生什么呢？<br/><div class="code"><br/>&#123;<br/>　zval *helloval;<br/>　MAKE_STD_ZVAL(helloval);<br/>　ZVAL_STRING(helloval， &quot;Hello World&quot;， 1);<br/>　zend_hash_add(EG(active_symbol_table)， &quot;a&quot;， sizeof(&quot;a&quot;)，&amp;helloval， sizeof(zval*)， NULL);<br/>　zend_hash_add(EG(active_symbol_table)， &quot;b&quot;， sizeof(&quot;b&quot;)，&amp;helloval， sizeof(zval*)， NULL);<br/>&#125;<br/></div><br/>　　此时，你可以实际地观察$a或$b，并且会看到它们都包含字符串"Hello World"。遗憾的是，接下来，你继续执行第三行代码"unset($a);"。此时，unset()并不知道$a变量指向的数据还被另一个变量所使用，因此它只是盲目地释放掉该内存。任何随后的对变量$b的存取都将被分析为已经释放的内存空间并因此导致引擎崩溃。<br/><br/>　　这个问题可以借助于zval（它有好几种形式）的第四个成员refcount加以解决。当一个变量被首次创建并赋值时，它的refcount被初始化为1，因为它被假定仅由最初创建它时相应的变量所使用。当你的代码片断开始把helloval赋给$b时，它需要把refcount的值增加为2；这样以来，现在该值被两个变量所引用：<br/><div class="code"><br/>&#123;<br/>　zval *helloval;<br/>　MAKE_STD_ZVAL(helloval);<br/>　ZVAL_STRING(helloval， &quot;Hello World&quot;， 1);<br/>　zend_hash_add(EG(active_symbol_table)， &quot;a&quot;， sizeof(&quot;a&quot;)，&amp;helloval， sizeof(zval*)， NULL);<br/>　ZVAL_ADDREF(helloval);<br/>　zend_hash_add(EG(active_symbol_table)， &quot;b&quot;， sizeof(&quot;b&quot;)，&amp;helloval，sizeof(zval*)，NULL);<br/>&#125;<br/></div><br/>　　现在，当unset()删除原变量的$a相应的副本时，它就能够从refcount参数中看到，还有另外其他人对该数据感兴趣；因此，它应该只是减少refcount的计数值，然后不再管它。<br/>六、 写复制（Copy on Write）<br/><br/>　　通过refcounting来节约内存的确是不错的主意，但是，当你仅想改变其中一个变量的值时情况会如何呢？为此，请考虑下面的代码片断：<br/><div class="code"><br/>＜?php<br/>$a = 1;<br/>$b = $a;<br/>$b += 5;<br/>?＞<br/></div><br/>　　通过上面的逻辑流程，你当然知道$a的值仍然等于1，而$b的值最后将是6。并且此时，你还知道，Zend在尽力节省内存-通过使$a和$b都引用相同的zval（见第二行代码）。那么，当执行到第三行并且必须改变$b变量的值时，会发生什么情况呢？<br/><br/>　　回答是，Zend要查看refcount的值，并且确保在它的值大于1时对之进行分离。在Zend引擎中，分离是破坏一个引用对的过程，正好与你刚才看到的过程相反：<br/><div class="code"><br/>zval *get_var_and_separate(char *varname， int varname_len TSRMLS_DC)<br/>&#123;<br/>　zval **varval， *varcopy;<br/>　if (zend_hash_find(EG(active_symbol_table)，varname， varname_len + 1， (void**)&amp;varval) == FAILURE) &#123;<br/>　　/* 变量根本并不存在-失败而导致退出*/<br/>　　return NULL;<br/>　&#125;<br/>　if ((*varval)-＞refcount ＜ 2) &#123;<br/>　　/* varname是唯一的实际引用，<br/>　　*不需要进行分离<br/>　　*/<br/>　　return *varval;<br/>　&#125;<br/>　/* 否则，再复制一份zval*的值*/<br/>　MAKE_STD_ZVAL(varcopy);<br/>　varcopy = *varval;<br/>　/* 复制任何在zval*内的已分配的结构*/<br/>　zval_copy_ctor(varcopy);<br/>　/*删除旧版本的varname<br/>　*这将减少该过程中varval的refcount的值<br/>　*/<br/>　zend_hash_del(EG(active_symbol_table)， varname， varname_len + 1);<br/>　/*初始化新创建的值的引用计数，并把它依附到<br/>　* varname变量<br/>　*/<br/>　varcopy-＞refcount = 1;<br/>　varcopy-＞is_ref = 0;<br/>　zend_hash_add(EG(active_symbol_table)， varname， varname_len + 1，&amp;varcopy， sizeof(zval*)， NULL);<br/>　/*返回新的zval* */<br/>　return varcopy;<br/>&#125;<br/></div><br/>　　现在，既然引擎有一个仅为变量$b所拥有的zval*（引擎能知道这一点），所以它能够把这个值转换成一个long型值并根据脚本的请求给它增加5。<br/><br/>　　七、 写改变（change-on-write）<br/><br/>　　引用计数概念的引入还导致了一个新的数据操作可能性，其形式从用户空间脚本管理器看来与"引用"有一定关系。请考虑下列的用户空间代码片断：<br/><div class="code"><br/>＜?php<br/>$a = 1;<br/>$b = &amp;$a;<br/>$b += 5;<br/>?＞<br/></div><br/>　　在上面的PHP代码中，你能看出$a的值现在为6，尽管它一开始为1并且从未(直接)发生变化。之所以会发生这种情况是因为当引擎开始把$b的值增加5 时，它注意到$b是一个对$a的引用并且认为"我可以改变该值而不必分离它，因为我想使所有的引用变量都能看到这一改变"。<br/><br/>　　但是，引擎是如何知道的呢？很简单，它只要查看一下zval结构的第四个和最后一个元素（is_ref）即可。这是一个简单的开/关位，它定义了该值是否实际上是一个用户空间风格引用集的一部分。在前面的代码片断中，当执行第一行时，为$a创建的值得到一个refcount为1，还有一个is_ref值为0，因为它仅为一个变量($a)所拥有并且没有其它变量对它产生写引用改变。在第二行，这个值的refcount元素被增加为2，除了这次is_ref元素被置为 1之外（因为脚本中包含了一个"&"符号以指示是完全引用）。<br/><br/>　　最后，在第三行，引擎再一次取出与变量$b相关的值并且检查是否有必要进行分离。这一次该值没有被分离，因为前面没有包括一个检查。下面是get_var_and_separate()函数中与refcount检查有关的部分代码：<br/><div class="code"><br/>if ((*varval)-＞is_ref &#124;&#124; (*varval)-＞refcount ＜ 2) &#123;<br/>　/* varname是唯一的实际引用，<br/>　* 或者它是对其它变量的一个完全引用<br/>　*任何一种方式：都没有进行分离<br/>　*/<br/>　return *varval;<br/>&#125;<br/></div><br/>　　这一次，尽管refcount为2，却没有实现分离，因为这个值是一个完全引用。引擎能够自由地修改它而不必关心其它变量值的变化。<br/>八、 分离问题<br/><br/>　　尽管已经存在上面讨论到的复制和引用技术，但是还存在一些不能通过is_ref和refcount操作来解决的问题。请考虑下面这个PHP代码块：<br/><div class="code"><br/>＜?php<br/>$a = 1;<br/>$b = $a;<br/>$c = &amp;$a;<br/>?＞<br/></div><br/>　　在此，你有一个需要与三个不同的变量相关联的值。其中，两个变量是使用了"change-on-write"完全引用方式，而第三个变量处于一种可分离的"copy-on-write"（写复制）上下文中。如果仅使用is_ref和refcount来描述这种关系，有哪些值能够工作呢？<br/><br/>　　回答是：没有一个能工作。在这种情况下，这个值必须被复制到两个分离的zval*中，尽管两者都包含完全相同的数据(见图2)。<br/><a href="https://atim.cn/attachment/1173245563_0.jpg" target="_blank"><img src="https://atim.cn/attachment/1173245563_0.jpg" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/>网管必读深入探讨PHP中的内存管理问题(4)<br/>图2.引用时强制分离<br/><br/>　　同样，下列代码块将引起相同的冲突并且强迫该值分离出一个副本(见图3)。<br/><a href="https://atim.cn/attachment/1173245563_1.jpg" target="_blank"><img src="https://atim.cn/attachment/1173245563_1.jpg" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/>网管必读深入探讨PHP中的内存管理问题(4)<br/>图3.复制时强制分离<br/><div class="code"><br/>＜?php<br/>$a = 1;<br/>$b = &amp;$a;<br/>$c = $a;<br/>?＞<br/></div><br/>　　注意，在这里的两种情况下，$b都与原始的zval对象相关联，因为在分离发生时引擎无法知道介于到该操作当中的第三个变量的名字。<br/><br/>　　九、 总结<br/><br/>　　PHP是一种托管语言。从普通用户角度来看，这种仔细地控制资源和内存的方式意味着更为容易地进行原型开发并导致出现更少的冲突。然而，当我们深入"内里"之后，一切的承诺似乎都不复存在，最终还要依赖于真正有责任心的开发者来维持整个运行时刻环境的一致性。
]]>
</description>
</item><item>
<link>https://atim.cn/post/10/</link>
<title><![CDATA[什么是c/s,b/s,什么是b2b,b2c]]></title> 
<author>bkkkd &lt;partybase@gmail.com&gt;</author>
<category><![CDATA[Web 技术 ]]></category>
<pubDate>Thu, 11 Jan 2007 02:10:48 +0000</pubDate> 
<guid>https://atim.cn/post/10/</guid> 
<description>
<![CDATA[ 
	c/s 指的是Client/server结构，是一个客户机/服务器结构，一般基于局域网开发工作。 <br/>b/s 指的是Browser/Server结构，是一个基于浏览器的结构，一般可用于基于广域网的开发工作。<br/>-------------------------------------------------------------------------------------------------------------<br/><br/>C/S 对应的传统软件开发模式，S：服务器，可以是数据库服务器；C：客户端程序，一般是一些数据库应用的前端界面程序。这种模式将业务逻辑放到客户端处理，尽管效率很高，但造成维护困难（每次升级需要将所有的客户端程序升级） <br/>B/S 是目前较流行的开发模式，是多层应用开发的一种。S：有两层，一层是DBS，即数据库服务器；另一层是AS，即应用服务器，例如WebSphere、WebLogic、Tomcat、JBoss等。B：客户端浏览器，一般是IE。这种模式的好处是，业务逻辑放在AS这一层，维护很方便，但效率上会有一些损失。 <br/>具体问题，具体分析，软件架构是为项目服务的，不必为了 B/S而B/S<br/>------------------------------------------------------------------------------------------------<br/>B2C是"企业对客户"的简称，指Internet电子商务中的零售部分。<br/>与之相对的是B2B，或称作"企业对企业"。
]]>
</description>
</item>
</channel>
</rss>