PHP And Socket

书名: 《PHP Game Programming》
作者: Matt Rutledget
翻译: heiyeluren <heiyeluren_gmail_com>

◇ Socket基础
◇ 产生一个服务器
◇  产生一个客户端

在这一章里你将了解到迷人而又让人容易糊涂的套接字(Sockets)。Sockets在PHP中是没有充分利用的功能。今天你将看到产生一个能使用客户端连接的服务器,并在客户端使用socket进行连接,服务器端将详细的处理信息发送给客户端。
当你看到完整的socket过程,那么你将会在以后的程序开发中使用它。这个服务器是一个能让你连接的HTTP服务器,客户端是一个Web浏览器,这是一个单一的 客户端/服务器 的关系。

◆ Socket 基础

PHP 使用Berkley的socket库来创建它的连接。你可以知道socket只不过是一个数据结构。你使用这个socket数据结构去开始一个客户端和服务器之间的会话。这个服务器是一直在监听准备产生一个新的会话。当一个客户端连接服务器,它就打开服务器正在进行监听的一个端口进行会话。这时,服务器端接受客户端的连接请求,那么就进行一次循环。现在这个客户端就能够发送信息到服务器,服务器也能发送信息给客户端。
产生一个Socket,你需要三个变量:一个协议、一个socket类型和一个公共协议类型。产生一个socket有三种协议供选择,继续看下面的内容来获取详细的协议内容。
定义一个公共的协议类型是进行连接一个必不可少的元素。下面的表我们看看有那些公共的协议类型。

表一:协议
名字/常量     描述
AF_INET   这是大多数用来产生socket的协议,使用TCP或UDP来传输,用在IPv4的地址
AF_INET6     与上面类似,不过是来用在IPv6的地址
AF_UNIX   本地协议,使用在Unix和Linux系统上,它很少使用,一般都是当客户端和服务器在同一台及其上的时候使用
表二:Socket类型
名字/常量     描述
SOCK_STREAM   这个协议是按照顺序的、可靠的、数据完整的基于字节流的连接。这是一个使用最多的socket类型,这个socket是使用TCP来进行传输。
SOCK_DGRAM   这个协议是无连接的、固定长度的传输调用。该协议是不可靠的,使用UDP来进行它的连接。
SOCK_SEQPACKET   这个协议是双线路的、可靠的连接,发送固定长度的数据包进行传输。必须把这个包完整的接受才能进行读取。
SOCK_RAW   这个socket类型提供单一的网络访问,这个socket类型使用ICMP公共协议。(ping、traceroute使用该协议)
SOCK_RDM   这个类型是很少使用的,在大部分的操作系统上没有实现,它是提供给数据链路层使用,不保证数据包的顺序

表三:公共协议
名字/常量     描述
ICMP   互联网控制消息协议,主要使用在网关和主机上,用来检查网络状况和报告错误信息
UDP    用户数据报文协议,它是一个无连接,不可靠的传输协议
TCP 传输控制协议,这是一个使用最多的可靠的公共协议,它能保证数据包能够到达接受者那儿,如果在传输过程中发生错误,那么它将重新发送出错数据包。

现 在你知道了产生一个socket的三个元素,那么我们就在php中使用socket_create()函数来产生一个socket。这个 socket_create()函数需要三个参数:一个协议、一个socket类型、一个公共协议。socket_create()函数运行成功返回一个包含socket的资源类型,如果没有成功则返回false。
Resourece socket_create(int protocol, int socketType, int commonProtocol);

现在你产生一个socket,然后呢?php提供了几个操纵socket的函数。你能够绑定socket到一个IP,监听一个socket的通信,接受一个socket;现在我们来看一个例子,了解函数是如何产生、接受和监听一个socket。

<?php
$commonProtocol = getprotobyname(“tcp”);
$socket = socket_create(AF_INET, SOCK_STREAM, $commonProtocol);
socket_bind($socket, ‘localhost’, 1337);
socket_listen($socket);
// More socket functionality to come
?>

上面这个例子产生一个你自己的服务器端。例子第一行,
$commonProtocol = getprotobyname(“tcp”);
使用公共协议名字来获取一个协议类型。在这里使用的是TCP公共协议,如果你想使用UDP或者ICMP协议,那么你应该把getprotobyname() 函数的参数改为“udp”或“icmp”。还有一个可选的办法是不使用getprotobyname()函数而是指定SOL_TCP或SOL_UDP在 socket_create()函数中。
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
例子的第二行是产生一个socket并且返回一个socket资源的实例。在你有了一个socket资源的实例以后,你就必须把socket绑定到一个IP地址和某一个端口上。
socket_bind($socket, ‘localhost’, 1337);
在这里你绑定socket到本地计算机(127.0.0.1)和绑定socket到你的1337端口。然后你就需要监听所有进来的socket连接。
socket_listen($socket);
在第四行以后,你就需要了解所有的socket函数和他们的使用。

表四:Socket函数
函数名    描述
socket_accept() 接受一个Socket连接
socket_bind()     把socket绑定在一个IP地址和端口上
socket_clear_error() 清除socket的错误或者最后的错误代码
socket_close()     关闭一个socket资源
socket_connect() 开始一个socket连接
socket_create_listen() 在指定端口打开一个socket监听
socket_create_pair() 产生一对没有区别的socket到一个数组里
socket_create() 产生一个socket,相当于产生一个socket的数据结构
socket_get_option() 获取socket选项
socket_getpeername() 获取远程类似主机的ip地址
socket_getsockname() 获取本地socket的ip地址
socket_iovec_add() 添加一个新的向量到一个分散/聚合的数组
socket_iovec_alloc() 这个函数创建一个能够发送接收读写的iovec数据结构
socket_iovec_delete() 删除一个已经分配的iovec
socket_iovec_fetch() 返回指定的iovec资源的数据
socket_iovec_free() 释放一个iovec资源
socket_iovec_set() 设置iovec的数据新值
socket_last_error() 获取当前socket的最后错误代码
socket_listen()     监听由指定socket的所有连接
socket_read()     读取指定长度的数据
socket_readv()     读取从分散/聚合数组过来的数据
socket_recv()     从socket里结束数据到缓存
socket_recvfrom() 接受数据从指定的socket,如果没有指定则默认当前socket
socket_recvmsg() 从iovec里接受消息
socket_select()     多路选择
socket_send()     这个函数发送数据到已连接的socket
socket_sendmsg() 发送消息到socket
socket_sendto() 发送消息到指定地址的socket
socket_set_block() 在socket里设置为块模式
socket_set_nonblock() socket里设置为非块模式
socket_set_option() 设置socket选项
socket_shutdown() 这个函数允许你关闭读、写、或者指定的socket
socket_strerror() 返回指定错误号的详细错误
socket_write()     写数据到socket缓存
socket_writev() 写数据到分散/聚合数组

(注: 函数介绍删减了部分原文内容,函数详细使用建议参考英文原文,或者参考PHP手册)

以上所有的函数都是PHP中关于socket的,使用这些函数,你必须把你的socket打开,如果你没有打开,请编辑你的php.ini文件,去掉下面这行前面的注释:
extension=php_sockets.dll
如果你无法去掉注释,那么请使用下面的代码来加载扩展库:
<?php
if(!extension_loaded(‘sockets’))
{
if(strtoupper(substr(PHP_OS, 3)) == “WIN”)
{
dl(‘php_sockets.dll’);
}
else
{
dl(‘sockets.so’);
}
}
?>

如果你不知道你的socket是否打开,那么你可以使用phpinfo()函数来确定socket是否打开。你通过查看phpinfo信息了解socket是否打开。如下图:

查看phpinfo()关于socket的信息

◆ 产生一个服务器

现在我们把第一个例子进行完善。你需要监听一个指定的socket并且处理用户的连接。

<?php
$commonProtocol = getprotobyname("tcp");
$socket = socket_create(AF_INET, SOCK_STREAM, $commonProtocol);
socket_bind($socket, ‘localhost’, 1337);
socket_listen($socket);
// Accept any incoming connections to the server
$connection = socket_accept($socket);
if($connection)
{
socket_write($connection, "You have connected to the socket…\n\r");
}
?>

你应该使用你的命令提示符来运行这个例子。理由是因为这里将产生一个服务器,而不是一个Web页面。如果你尝试使用Web浏览器来运行这个脚本,那么很有可能它会超过30秒的限时。你可以使用下面的代码来设置一个无限的运行时间,但是还是建议使用命令提示符来运行。
set_time_limit(0);
在你的命令提示符中对这个脚本进行简单测试:
Php.exe example01_server.php
如果你没有在系统的环境变量中设置php解释器的路径,那么你将需要给php.exe指定详细的路径。当你运行这个服务器端的时候,你能够通过远程登陆(telnet)的方式连接到端口1337来测试这个服务器。如下图:

上面的服务器端有三个问题:1. 它不能接受多个连接。2. 它只完成唯一的一个命令。3. 你不能通过Web浏览器连接这个服务器。
这个第一个问题比较容易解决,你可以使用一个应用程序去每次都连接到服务器。但是后面的问题是你需要使用一个Web页面去连接这个服务器,这个比较困难。你可以让你的服务器接受连接,然后些数据到客户端(如果它一定要写的话),关闭连接并且等待下一个连接。
在上一个代码的基础上再改进,产生下面的代码来做你的新服务器端:

<?php
// Set up our socket
$commonProtocol = getprotobyname("tcp");
$socket = socket_create(AF_INET, SOCK_STREAM, $commonProtocol);
socket_bind($socket, ‘localhost’, 1337);
socket_listen($socket);
// Initialize the buffer
$buffer = "NO DATA";
while(true)
{
// Accept any connections coming in on this socket

$connection = socket_accept($socket);
printf("Socket connected\r\n");
// Check to see if there is anything in the buffer
if($buffer != "")
{
   printf("Something is in the buffer…sending data…\r\n");
   socket_write($connection, $buffer . "\r\n");
   printf("Wrote to socket\r\n");
}
else
{
   printf("No Data in the buffer\r\n");
}
// Get the input
while($data = socket_read($connection, 1024, PHP_NORMAL_READ))
{
   $buffer = $data;
   socket_write($connection, "Information Received\r\n");
   printf("Buffer: " . $buffer . "\r\n");
}
socket_close($connection);
printf("Closed the socket\r\n\r\n");
}
?>

这 个服务器端要做什么呢?它初始化一个socket并且打开一个缓存收发数据。它等待连接,一旦产生一个连接,它将打印“Socket connected”在服务器端的屏幕上。这个服务器检查缓冲区,如果缓冲区里有数据,它将把数据发送到连接过来的计算机。然后它发送这个数据的接受信息,一旦它接受了信息,就把信息保存到数据里,并且让连接的计算机知道这些信息,最后关闭连接。当连接关闭后,服务器又开始处理下一次连接。(翻译的烂,附上原文)
This is what the server does. It initializes the socket and the buffer that you use to receive
and send data. Then it waits for a connection. Once a connection is created it prints
“Socket connected” to the screen the server is running on. The server then checks to see if
there is anything in the buffer; if there is, it sends the data to the connected computer.
After it sends the data it waits to receive information. Once it receives information it stores
it in the data, lets the connected computer know that it has received the information, and
then closes the connection. After the connection is closed, the server starts the whole
process again.

◆ 产生一个客户端

处理第二个问题是很容易的。你需要产生一个php页连接一个socket,发送一些数据进它的缓存并处理它。然后你又个处理后的数据在还顿,你能够发送你的数据到服务器。在另外一台客户端连接,它将处理那些数据。
To solve the second problem is very easy. You need to create a PHP page that connects to
a socket, receive any data that is in the buffer, and process it. After you have processed the
data in the buffer you can send your data to the server. When another client connects, it
will process the data you sent and the client will send more data back to the server.

下面的例子示范了使用socket:

<?php
// Create the socket and connect
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
$connection = socket_connect($socket,’localhost’, 1337);
while($buffer = socket_read($socket, 1024, PHP_NORMAL_READ))
{
if($buffer == “NO DATA”)
{
echo(“<p>NO DATA</p>”);
break;
}
else
{
   // Do something with the data in the buffer
   echo(“<p>Buffer Data: “ . $buffer . “</p>”);
}
}
echo(“<p>Writing to Socket</p>”);
// Write some test data to our socket
if(!socket_write($socket, “SOME DATA\r\n”))
{
echo(“<p>Write failed</p>”);
}
// Read any response from the socket
while($buffer = socket_read($socket, 1024, PHP_NORMAL_READ))
{
echo(“<p>Data sent was: SOME DATA<br> Response was:” . $buffer . “</p>”);
}
echo(“<p>Done Reading from Socket</p>”);
?>

这 个例子的代码演示了客户端连接到服务器。客户端读取数据。如果这是第一时间到达这个循环的首次连接,这个服务器将发送“NO DATA”返回给客户端。如果情况发生了,这个客户端在连接之上。客户端发送它的数据到服务器,数据发送给服务器,客户端等待响应。一旦接受到响应,那么它将把响应写到屏幕上。

Lighttpd与PHP

作者:老王

Lighttpd和PHP的搭配现在越来越常见了。但是老实说,如非必要,我还是推荐你使用Apache和PHP的搭配方式,毕竟LAMP构架的成熟度和稳定度都是经过时间考验的。

那么什么时候Lighttpd和PHP的搭配更值得选择呢?可以从以下几点考虑:如果访问量比较大,硬件资源吃紧,那么Lighttpd适合你;如果和稳定相比,你倾向速度多一些,那么Lighttpd适合你。

题外话:NginX大有赶超Lighttpd的态势。

Lighttpd的安装,本文就不多说了,大家自己搜索一下就能找到大把大把的教程。这里我们着重讨论一下Lighttpd的配置。

安装好Lighttpd+PHP后,你的配置很可能是类似下面的代码:

fastcgi.server = ( ".php" =>
    (( "socket" => "/tmp/php-fastcgi.socket",
        "bin-path" => "/usr/bin/php-cgi",
        "max-procs" => 10,
        "bin-environment" => (
            "PHP_FCGI_CHILDREN" => "16",
            "PHP_FCGI_MAX_REQUESTS" => "1000"
        ),
        "broken-scriptfilename" => "enable"
    ))
)

其中,PHP_FCGI_MAX_REQUESTS的作用是在一个子进程工作一定次数后就干掉它,以免可能出现的问题连累系统,主进程会再创建一个相应的子进程来替补,保证子进程数一直是PHP_FCGI_CHILDREN个。

另外还有两个设置选项至关重要,分别是max-procs和PHP_FCGI_CHILDREN。如上所示的配置,系统将创建170个PHP-cgi的进程,它的计算公式如下:

num-procs = max-procs * ( 1 + PHP_FCGI_CHILDREN )

如果一个php-cgi进程占用十几兆内存的话,那么总计大约就要占用2G左右的内存。

我们先来看看max-procs的意思:从字面意思看,它似乎指得是最大进程数。实际它指的是Lighttpd一开始spawn多少个进程。

至于PHP_FCGI_CHILDREN的意思,和字面意思相同,指的就是每个主进程里产生多少个PHPFCGI子进程。

如果你的Lighttpd已经启动,你可以尝试执行一下命令:ps aux | grep php-cgi,将会看到大量的php-cgi进程:

nobody 10939 0.0 0.1 15556 4820 ? Ss 16:24 0:00 /usr/local/bin/php-cgi
nobody 11380 0.0 0.1 15452 5588 ? S 16:24 0:00 /usr/local/bin/php-cgi

仔细观察,你会发现这些php-cgi的状态不尽相同,有的是Ss,有的是S,通过man ps你能找到这些状态的含义:

S Interruptible sleep (waiting for an event to complete)
s is a session leader

也就是说,Ss状态的进程都是主进程(max-procs代表的那些进程),而S状态的进程都是子进程(PHP_FCGI_CHILDREN代表的那些进程)。如果不相信,你可以使用命令核实一下数量:

ps aux | grep php-cgi | grep Ss | grep -v grep | wc -l

确认了这些,我们再仔细看ps aux | grep php-cgi的结果,你还会发现主进程的内存占用(4840)和子进程的内存占用(5588)是不同的。这是因为主进程不处理实际的PHP请求,它唯一的工作就是看管好自己手下的子进程。而实际的PHP请求都是由子进程来完成的,所以子进程占用的内存要稍大一些。

如此,我们对max-procs和PHP_FCGI_CHILDREN的含义应该理解了吧,别急,还有一个问题:既然php-cgi的总进程数可以由上面的公式算出来,那么以下几个配置选项哪个好?

"max-procs" => 1,
"PHP_FCGI_CHILDREN" => "169",

"max-procs" => 2,
"PHP_FCGI_CHILDREN" => "84",

"max-procs" => 10,
"PHP_FCGI_CHILDREN" => "16",

以上三种配置产生的总进程数一样(都是170),我们如何判断配置的好坏呢?

如果使用了eAccelerator之类的PHP优化器,那么eAccelerator会为每一个主进程创建一个独立的缓存空间,这个时候如果你的max-procs是2的话,就会建立两个独立的缓存空间。一方面这浪费了一些内存,另一方面如果你的一个主进程挂了(它下面的子进程就失控了),至少你还有一个主进程可以保持正常运转。

总体来说,max-procs不宜为较小,否则没有容错性,在有PHP优化器的时候也不宜过大,否则会浪费很多内存做缓存空间,即便没有装PHP优化器,max-procs也不宜过大,因为主进程是不处理PHP请求的,过多的主进程自然就是一种浪费。确定了max-procs的值,剩下PHP_FCGI_CHILDREN的值就好说了。

另外:通过命令netstat -anp | grep php-cgi | wc -l可以得知当前有多少php-cgi处于连接状态,如果接近php-cgi的总进程数,就说明应该加大进程数了。

Lighttpd Web Server软件包多个远程拒绝服务漏洞

受影响系统:
LightTPD LightTPD 1.4.x
LightTPD LightTPD 1.3.x

不受影响系统:
LightTPD LightTPD 1.4.14

描述:
Lighttpd是一款轻型的开放源码Web Server软件包。

Lighttpd如果在解析/r/n/r/n期间连接中断的话,服务器就会陷入死循环,使用100%的CPU时间。攻击者可以反复利用这个漏洞,直至到达服务器的并行连接极限或到达文件描述符限制。

Lighttpd为mtime缓存所生成的字符串,缓存密钥默认值为0。这时字符串的指针仍为空,如果请求了mtime为0的文件就会试图访问空指针导致崩溃。利用这个漏洞要求恶意用户能够上传文件或操控文件的mtime。

厂商补丁:
LightTPD
目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:
http://www.lighttpd.net/assets/2007/4/13/lighttpd-1.4.x_crlf_parsing_dos.patch
http://www.lighttpd.net/assets/2007/4/13/lighttpd-1.4.x_zero_mtime_crash.patch

本篇文章来源于 黑客手册
原文链接:http://www.nohack.cn/bugs/other/20070419/42971.html

Lighttpd配置

了解了web服务器的基本架构之后,再配置web服务器都是很类似的了;

1. 配置基于名称的虚拟主机
看个实例吧:

$HTTP["host"] == "blog.cn" {
server.name = "blog.cn"
server.document-root = "d:/www/MyBlog"
}

可以简单到这等地步的,里面没有配置的选项将都和外面的一样

2. 配置redirect和rewrite

注意一定要打开对应的这两个模块:

"mod_redirect",
"mod_rewrite",

看个简单例子:
如果我在跟目录输入/st 就像重定向到:http://phpor.net/server-status ,可以这么写:
url.redirect = ( "^/st$" => "http://phpor.net/server-status" )

如果我在跟目录输入/s 就像rewrite到:/server-status ,可以这么写:
url.rewrite = ( "^/s$" => "/server-status" )

看起来这两种写法很相似,不过一定要注意:
redirect是客户端重定向,可以重定向到另外一个网站,浏览器需要再发一个请求,所以redirect时目的地址可以是完整的uri

rewrite是服务器端重定向,不能重定向到另外一个网站,浏览器不用重新发出请求,所以rewrite 时不能目的地址中含有域名

当然还有更多的使用正则来redirect和rewrite的用法,自己看看手册吧!

3. 绑定服务到指定ip和指定端口

因为一个机器可能有多块网卡,就算只有一块网卡,还有一个环回地址呢,所以只对指定的网卡提供服务就需要这种配置了,目前我用web仅仅是本机管理自己的资源用,很多信息是秘密的,不能公开的,但是我又不想每次打开管理系统就需要输入密码,所以我就把web绑定到127.0.0.1,不允许对外提供服务,这样就确保绝对安全了,这样来写:

server.bind = "127.0.0.1"
server.port = 81
# 绑定到指定端口

相关文章:http://lighttpd.banma.com/bbs/b_17.html

Linux 下查看网卡硬件信息

使用命令:ethtool
例:

[root@ljj ~]# ethtool -i eth0
driver: pcnet32
version: 1.31
firmware-version:
bus-info: 0000:00:11.0
[root@ljj ~]# ethtool -k eth0
Offload parameters for eth0:
Cannot get device rx csum settings: Operation not supported
rx-checksumming: off
tx-checksumming: off
scatter-gather: off
tcp segmentation offload: off
[root@ljj ~]# ethtool -g eth0
Ring parameters for eth0:
Pre-set maximums:
RX:             511
RX Mini:        0
RX Jumbo:       0
TX:             511
Current hardware settings:
RX:             31
RX Mini:        0
RX Jumbo:       0
TX:             15

[root@ljj ~]#

服务器相关知识:U的概念

机箱外观参数中的 1u.2u.3u.4u~8u 代表什么意思呢?

U是一种表示服务器外部尺寸的单位,是unit的缩略语,详细的尺寸由作为业界团体的美国电子工业协会(EIA)所决定。

之所以要规定服务器的尺寸,是为了使服务器保持适当的尺寸以便放在铁质或铝质的机架上。机架上有固定服务器的螺孔,以便它能与服务器的螺孔对上号,再用螺丝加以固定好,以方便安装每一部服务器所需要的空间。

规定的尺寸是服务器的宽(48.26cm=19英寸)与高(4.445cm的倍数)。由于宽为19英寸,所以有时也将满足这一规定的机架称为“19英寸机架”。厚度以4.445cm为基本单位。1U就是4.445cm,2U则是1U的2倍为8.89cm。

所谓“1U的PC服务器”,就是外形满足EIA规格、厚度为4.445cm的产品。设计为能放置到19英寸机柜的产品一般被称为机架服务器。

1U服务器就是一种高可用高密度的低成本服务器平台,是专门为特殊应用行业和高密度计算机环境设计的。它们可以通过本地硬盘启动自己的操作系统,如Windows NT/2000/2003、Linux、Solaris等等,类似于一个个独立的服务器。在这种模式下,每一个主板运行自己的系统,服务于指定的不同用户群,相互之间没有关联。不过我们还是可以用系统软件将这些主板集合成一个服务器集群。

目前我国的1U式服务器发展还处于起步阶段,国内的用户数量还不是很多,当前多以数据中心和科研机构应用的比较广泛。但是由于符合未来计算模式的发展方向,并且在我国网络日益普及的今天,网络技术的应用也越发频繁。针对个人的数据备份、网络游戏平台和中小型企业网站的实施与应用,都将可能采用这种服务器产品。

服务器硬件配置入门级参考

这是一篇关于WEB服务器选购的文章,希望对你能有点用处

说到服务器,目前最热门的应用无非就是做Web支持和网游平台,国内大部分采购服务器作为网游应用的都是私服,属于侵犯知识产权的行为,虽然短期内容易盈 利,但是是违法的,国内已经有架设私服被判刑的先例,所以不便多做讨论,今天想就我个人这几年架设WEB服务器的经验跟大家谈谈WEB服务器和服务器硬件 方面的搭配问题。
很多中小型企业的技术人员或者打算以网站、盈利的个人团体组织都经常提出这么一个疑问:究竟什么样的配置可以支持多大的流量?

其实这个问题不可能有准确答案,因为每个网站使用的Web系统都不一样,有些喜欢用IIS+ASP,有些则是用Apache+PHP,这在脚本的执行 效率上本身就存在很大的差异,另外,网页系统编写的复杂程度和优化程度也极大的影响着服务器能够承载的访问人数,大部分的新闻资讯、下载类网站都已经使用 了静态页面来减少Web系统对服务器处理能力的依赖,但是仍然有不少例如论坛、商城一类的系统需要大量动态代码的支持,所以笼统的去谈论一个服务器能够支 持多少访问量是没有实际意义的,还是需要具体的去分析:

首先说说CPU,我们知道,大部分的Web脚本为了安全起见都是在服务器端执行的(Javascript例外),而这些脚本就相当于我们用VB或者C ++编程时使用的高级语言,不同的是我们用VB这些软件编程,编辑软件最后会把我们的代码编译成执行效率更高的可执行软件,而我们的Web脚本在保存时是 不会被编译的,都是在用户请求访问这个页面时才被相关的编译器进行编译操作,这样一来,结果就是一个页面被访问N次,就得被编译N次,这样对系统资源的占 用是非常可怕的,虽然IIS已经对.NET进行优化,会将被访问过的页面编译后缓存起来,下次其他用户进行相同请求时不再需要对这个页面进行编译,但网页 脚本的复杂性和庞大性最终还是大量的占用系统资源尤其是处理器资源,这就是为什么热门论坛同时多人在线服务器会变得很慢。其实现在的服务器配置,大多是 P4 3.2G或者双路Xeon 3.0G,这样的配置对于动态论坛这种极度消耗资源的系统仍然没有足够的支持能力,根据我的经验,一个服务器上如果是纯粹一个动态论坛而没有其他应用,采 用P4 的处理器大概也就同时支持200-300人在线,如果是Web系统效率较高,脚本优化得好,还可以再多100~200人,如果是双路Xeon,千人在线也 差不多是极限了。所以,到目前位置,如果想做访问量、想做人气,选用性能比较强劲的CPU还是有足够理由的,个人比较推崇的还是采用Xeon 系统,P4 毕竟是入门级的配置,虽然双核 P4D 性能已经比以前大幅提升,但在多任务处理中,双路 Xeon 的表现还是遥遥领先,而且对于多客户访问的支持也更加稳定。

当然,有人可能会问:如果是静态页面为主的站点,是不是对处理器的要求就比较低了?答案是肯定的。静态页面不需要经过编译,基本就看网络带宽和网卡, 如果是图片多的网站,硬盘最好也换成SCSI,高转速高缓存的SCSI硬盘对于多而小的文件读取更有优势,而且稳定性更好,寿命也更长。

接下来说说内存,不管是静态页面的网址还是动态页面的网站,最好都尽量使用大容量内存,尤其是现在的服务器,内存的运行速度已经不是什么重要问题, DDR 333、DDR 400或者DDR2 其实区别都不大,最重要的只有两点:内存的容量和纠错(如ECC)。由于服务器有大量的数据需要临时缓存到内存里,所以访问量大的时候内存的占用也是较大 的,而当内存不够用的时候,虚拟内存的工作压力就非常大,其实就是磁盘工作压力会很大,而系统程序跟数据缓存操作不断的争抢内存资源时,当机的几率就高了 很多,如果你不希望你的服务器经常重启,配置大容量内存是非常必要的,除非是一天千位数IP的那种小型网站,不然还是建议大家使用 1GB 以上内存,即使有时候内存的使用率不会想我们想象的那么高,但是使用大内存对于降低虚拟内存的使用和减少重启次数都是有很大帮助的。而内存的纠错其实在服 务器上是非常必要的,首先很多服务器主板本身就要求搭配ECC REG内存,普通内存根本开不了机,另外,由于内存也是高速设备而且数据刷新频率非常高,所以加入纠错芯片的ECC内存可以有效的帮助系统减少由于数据信 息出错而产生的严重后果,另外,由于内存的校验操作都是内存上的独立智检芯片完成,所以不会占用CPU资源,一些用户担心内存纠错会造成系统性能的下降其 实是一种心理作用。

至于服务器的硬盘,现在大部分的入门级机型都使用性能出色价格低廉的SATA硬盘,其实这也无可厚非,只不过如果严格比较SATA跟SCSI的区别, 在稳定性方面和使用寿命方面SCSI还是有较大优势。我们知道,现在凭借较大的单碟容量,SATA硬盘的性能已经可以跟SCSI媲美,但是服务器这种分分 钟要接受用户访问,不断读取、改写磁盘数据的应用环境还是给硬盘带来很大的工作压力,尤其是多人访问以及长时间下载的时候,这样的高强度读写量绝对是桌面 级的硬盘无法承受的,哪怕是SATA硬盘,也只是在接口上做了调整,磁盘体和磁头的发热仍然会造成致命伤,而SCSI硬盘设计的时候就考虑到它的工作环 境,所以不会一味扩充容量,而是以安全为先决条件,这就是为什么很多二手市场淘汰下来的SCSI硬盘都仍然可以再用个几年。所以,做下载的站点如果资金允 许,还是应该尽量选用SCSI硬盘,如果用SATA,也应该定期检查服务器磁盘是否报错以便及时处理减少损失,这绝不是危言耸听,我做过的几个带有资源下 载的站点,SATA硬盘基本都是1年左右就开始报错了。

再说说主板吧,一些初级用户觉得用家用主板可以很好的节省成本,其实家用主板跟服务器主板根本就是两回事,为什么“泰安”和“超微”的主板会那么贵? 并不是没有道理的:首先是稳定。做服务器的,如果不稳定,一切性能都是空谈。服务器主板的内部总线在设计上要优于家用板,总线带宽够大,能够同时传输的数 据才多;另外,服务器主板的用料也非常严格,电容、电阻偷工减料的行为在服务器主板上是不能出现的,还有就是设计问题了,有能力做服务器主板的厂家,设计 产品的功力自然要高出一筹,电路设计的合理和优化也是影响主板稳定性的一个因素。最明显的一点:在访问量大的时候,如果是普通主板,不是卡的非常厉害就是 立刻罢工,而服务器主板则可以比较平稳的处理这些任务。另外,服务器主板上都会集成一张ATI的入门级显卡,一般是8M显存,显存也是直接集成主板上,为 什么这样?因为对服务器来说,显卡是个负担,只有在安装调试的时候才用到,其他时候服务器扔在机柜里面都是不接显示器的,全部通过远程管理,服务器最好没 有显卡,因为多一个显卡就多一个负担,需要CPU建立联系处理数据,而且服务器不能集成太强大的显卡,因为性能好的显卡还会发热、耗电,所以专业的服务器 主板都是内建一张ATI入门级显卡。

最后说说网卡。既然是服务器,肯定都是要接入网络来工作,而服务器访问量一般都很大,这时候专业网卡跟普通网卡的区别就非常明显!例如我们常用的30 元一块的普通10/100M网卡,或者是大多数主板集成的网卡,当然现在也有不少千兆的网卡卖到这个价或者集成在主板上,但是,这些都是个人上网使用的, 用了这样的网卡,服务器根本顶不住几百个人在线,因为网卡的线程到了极限,完全依赖CPU的处理,同时这些网卡用料比较省,寿命也不长,像服务器这样长时 间工作,这种网卡是最先挂掉的,我以前就见过有人在服务器上使用这种网卡最后网卡烧掉的。另外也有一些好一点的网卡,价格在60-180之间,其实这些也 不行,因为线程不存在瓶颈的时候吞吐量已经到了极限,大家不要简单的把吞吐量看成是数据流量,而是数据零碎的处理速度,举例来说,一个大力士一次搬动 100KG的东西,你搬10KG的,但是你速度快,你能搬的速度比他快10倍,那你说是你比较效率高。其实错了,因为你搬起和放下比他多9次,而且每次你 都用脑子去记录,他可以完全不动脑子,而脑子就是CPU。服务器必须使用专业网卡,例如3com、intel的,这些网卡单独出售价格都在几百到几千元, 不过服务器主板上一般都会集成有,这类网卡才是最适用的,因为基本不依赖CPU,能直接和内存沟通数据,有自己的很大的缓存区,甚至有的能直接分离垃圾数 据请求。我们个人平时使用,其实任何网卡都是一样,不过拿到服务器上,好的网卡和差的网卡,立刻分出区别。

说了这些,其实还是希望大家对服务器各个配件有一些了解,特别是现在很多人选择组装的方式构建服务器,就更应该用稳定和适用去衡量产品,而不要一味降低成本,结果弄出一台服务器拿到机房经常死机,后期维护起来让自己头疼。

Linux操作系统如何将应用程序添加到菜单

 

现在想把Ulipad添加到系统的“应用程序”菜单里,方法如下:

 

sudo gedit /usr/share/applications/Ulipad.desktop

 

然后在里面添加如下内容:

 

[Desktop Entry]

 

Name=Ulipad

 

Comment=a Python IDE

 

Exec=/home/zhao/ulipad/UliPad.py

 

Icon=/home/zhao/ulipad/Ulipad.png

 

Terminal=false

 

Type=Application

 

Categories=Application;Development;

 

保存后,Ulipad就会出现在:应用程序->编程菜单下面。

LDAP 的Windows安装

Windows下安装使用openldap
openldap 比起其他商业目录服务器(比如 IBM Directory Server),特别的轻巧,十分适合于本地开发测试用,在产品环境中的表现也很优秀。

openldap 软件在它的官方网站 http://www.openldap.org, 不过下载过来是源代码,并没有包含 win32 下的 Makefile 文件,只提供了在 Unix/Linux 下编译用的 Makefile。所以相应的在网上介绍在 windows 下安装使用 openldap 的资料比较少,而在 Unix/Linux 下应用文档却很丰富。

本文实践了在 Windows 下安装配 openldap,并添加一个条目,LdapBrowser 浏览,及 Java 程序连接 openldap 的全过程。

1. 下载安装 openldap for windows,当前版本2.2.29
    下载地址:http://download.bergmans.us/openldap/openldap-2.2.29/openldap-2.2.29-db-4.3.29-openssl-0.9.8a-win32_Setup.exe
    相关链接:http://lucas.bergmans.us/hacks/openldap/
   安装很简单,一路 next 即可,假设我们安装在 c:\openldap

2. 配置 openldap,编辑 sldap.conf 文件
   1) 打开 c:\openldap\sldap.conf,找到
    include  C:/openldap/etc/schema/core.schema,在它后面添加
    include  C:/openldap/etc/schema/cosine.schema
    include  C:/openldap/etc/schema/inetorgperson.schema

    接下来的例子只需要用到以上三个 schema,当然,如果你觉得需要的话,你可以把其他的 schema 全部添加进来
    include  C:/openldap/etc/schema/corba.schema
    include  C:/openldap/etc/schema/dyngroup.schema
    include  C:/openldap/etc/schema/java.schema
    include  C:/openldap/etc/schema/misc.schema
    include  C:/openldap/etc/schema/nis.schema
    include  C:/openldap/etc/schema/openldap.schema

   2) 还是在 sldap.conf 文件中,找到
    suffix  "dc=my-domain,dc=com"
    rootdn  "cn=Manager,dc=my-domain,dc=com"
    把这两行改为
    suffix "o=tcl,c=cn"  
    rootdn "cn=Manager,o=tcl,c=cn"

    suffix 就是看自己如何定义了,后面步骤的 ldif 文件就必须与它定义了。还要注意到这个配置文件中有一个 rootpw  secret,这个 secret 是 cn=Manager 的密码,以后会用到,不过这里是明文密码,你可以用命令: slappasswd -h {MD5} -s secret 算出加密的密码 {MD5}Xr4ilOzQ4PCOq3aQ0qbuaQ== 取代配置中的 secret。

3. 启动 openldap
    CMD 进入到 c:\openldap 下,运行命令 sldapd -d 1
    用可以看到控制台下打印一片信息,openldap 默认是用的 Berkeley DB 数据库存储目录数据的。

4. 建立条目,编辑导入 ldif 文件
   1) 新建一个 ldif(LDAP Data Interchanged Format) 文件(纯文本格式),例如 test.ldif,文件内容如下:
   
dn: o=tcl,c=cn
objectClass: dcObject
objectClass: organization
o: tcl
dc: com

dn: uid=Unmi, o=tcl,c=cn
uid: Unmi
objectClass: inetOrgPerson
mail: fantasia@sina.com
userPassword:: MTIzNDU2
labeledURI: http://unmi.blogcn.com
sn: Qiu
cn: 隔叶黄莺

   2) 执行命令:ldapadd -x -D "cn=manager,o=tcl,c=cn" -w secret -f test.ldif
    导入组织信息和一个用户 uid=Unmi

5. LdapBrowser 浏览
下载地址:http://www.blogjava.net/Files/Unmi/LdapBrowser282.rar     注:需要安装jre