php 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。

上面这个例子产生一个你自己的服务器端。例子第一行,
$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
如果你无法去掉注释,那么请使用下面的代码来加载扩展库:

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

查看phpinfo()关于socket的信息

◆ 产生一个服务器

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

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

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

这个服务器端要做什么呢?它初始化一个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(“

NO DATA

”);
break;
}
else
{
// Do something with the data in the buffer
echo(“

Buffer Data: “ . $buffer . “

”);
}
}
echo(“

Writing to Socket

”);
// Write some test data to our socket
if(!socket_write($socket, “SOME DATArn”))
{
echo(“

Write failed

”);
}
// Read any response from the socket
while($buffer = socket_read($socket, 1024, PHP_NORMAL_READ))
{
echo(“

Data sent was: SOME DATA
Response was:” . $buffer . “

”);
}
echo(“

Done Reading from Socket

”);
?>

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

结合Socket的坦克大战

(因为是描述游戏和socket结合,跟本文联系不大,所以不翻译,建议参考英文原文)

[ 题外话 ]

翻译文章的初衷是因为我个人对socket非常感兴趣,而且目前国内见php的文章比较少,除了php手册里面的部分内容,所以在我看了《PHP Game Programming》这本书里有关于socket的内容后毅然决定要翻译,我知道翻译出来的质量不行,还请见谅。

另外,我在《Core PHP Programming》Third Edition中也发现里面的Socket内容讲的不错,如果有空,我想也许我会把它也给翻译一下。这是我第一次翻译文章,花了我近五个小时,文章可以说是错误百出,如果翻译的不合理请见谅,如果有兴趣提高这个内容可以给我发邮件。这个凌晨时分,竟然无法入眠,不知道是不是在其他角落,也有人同我一样。

希望本文能够给向学习PHP Socket编程的朋友一点帮助,感谢你阅读这个错误百出的文章

Leave a comment

岂止是一篇IT评论

这篇文章写的真是不错,可以引发很多思考。

其实这种所谓遗传的限制又何止在Windows上存在。

====================================================================================

一个由虚拟设备文件而造成的限制,竟然能跨越三十多年,跨越CP/M、MS-DOS、Windows、OS/2和Windows NT五个架构而以相同的形式存在,这最后也许真是微软的一场悲剧。
1973年,一个名为CP/M的操作系统诞生了。CP/M的文件系统是单层目录结构,文件名限制为8.3字符。为了支持用户程序的输入输出,CP/M提供了虚拟文件 COM1, COM2, COM3, COM4, LPT1, LPT2, CON, AUX, PRN, 和 NUL。
1980年,西雅图电脑产品(Seattle Computer Product)山寨了一个CP/M,称为86-DOS。因此,它同样具有CP/M具有的那些虚拟文件,同样是单层目录结构和8.3字符。由于许多程序总是将文件带扩展名保存,所有以那些虚拟文件名为主文件名的文件,都被视为和那些虚拟文件等价。

1973年,一个名为CP/M的操作系统诞生了。CP/M的文件系统是单层目录结构,文件名限制为8.3字符。为了支持用户程序的输入输出,CP/M提供了虚拟文件 COM1, COM2, COM3, COM4, LPT1, LPT2, CON, AUX, PRN, 和 NUL。
1980年,西雅图电脑产品(Seattle Computer Product)山寨了一个CP/M,称为86-DOS。因此,它同样具有CP/M具有的那些虚拟文件,同样是单层目录结构和8.3字符。由于许多程序总是将文件带扩展名保存,所有以那些虚拟文件名为主文件名的文件,都被视为和那些虚拟文件等价。

1981年,微软买下了86-DOS,并将其以MS-DOS 1.0的名字发布给用户。

1983年,MS-DOS 2.0发布了,它加入了树形目录结构。为了保持向下兼容性,所有的虚拟文件,COM1, COM2, COM3, COM4, LPT1, LPT2, CON, AUX, PRN, 和 NUL,在所有磁盘的所有目录下,不管扩展名是什么,都存在并且实现相同的功能。

1985年,微软终于做出了他们自己的图形用户界面,Windows 1.0。Windows 1.0的所有文件API,都是在DOS中断的基础上实现的,因此那些虚拟文件,在Windows下仍然是你看不到,却永远是存在的,它们的文件名,也就成为了保留文件名。

1987年,微软和IBM合作,推出了一个旨在实现“比DOS更好的DOS,比Windows更好的Windows”的新操作系统OS/2。OS/2虽然已经不再基于DOS,甚至文件系统也换成了新的HPFS;但是,为了与MS-DOS程序相兼容,这些始于CP/M的虚拟文件,其实现被几乎原封不动地带到了OS/2中,它们的文件名,也成为了Windows的保留文件名。

1988年,微软挖来了前VMS工程师Dave Cutler。在他的带领下,一个将成为OS/2的继任者的多用户、抢占式多任务操作系统投入了开发。由于微软和IBM合作关系的破裂,这个系统并没有被作为OS/2的继任者发展起来,而是在1993年以Windows的超集与继任者身份发布——Windows NT。它引入了全新的、当时可谓强大的NTFS文件系统,使得文件名没有必要再被8.3字符限制;但是,因为需要通过NTVDM保持与DOS和Windows(16位)的兼容,以及和旧Windows程序的源码级兼容,DOS(也是Windows)的那些虚拟设备文件,COM1, COM2, COM3, COM4, LPT1, LPT2, CON, AUX, PRN, 和 NUL,又顺理成章地在Windows NT最重要的Win32子系统中实现(虽然由于系统对资源的保护,它们可能无法实现原有的功能),它们的主文件名继续成为保留文件名。

由于Windows NT在当时对系统要求过高(16MB内存在1993年仍然需要一笔较大的投入),而且其运行速度也不够快,微软仍然在继续并行发展旧的Windows架构。

1995年,第一个不需要MS-DOS就能工作的旧系列Windows——Windows 95在万众瞩目中诞生。它不仅拥有连Windows NT都羡慕的即插即用功能,并且正式将Win32的一个功能比较完整的子集引入了旧Windows,同时引入了前两年Windows NT在DOS传统的文件系统——FAT中加入的扩展VFAT,文件名不再受8.3字符限制。然而,一方面由于Windows 95仍然有来自DOS和以前的Windows的“根”,加上Win32子集同样保留了这条“根”,DOS的虚拟设备文件的文件名,继续作为保留文件名在Windows 95,以及后来的Windows 95 OSR2(加入了FAT的新实现FAT32)、Windows 98和Windows Me中存在。

2001年,微软正式发布了完全针对个人用户的Windows NT家族最新成员Windows XP,终结了旧系列Windows的15年历史。从那一时刻开始,Windows NT就是Windows。

2009年,微软发布了第一个不再具备兼容DOS和旧16位Windows程序的能力的Windows——Windows Server 2008 R2。虽然为了兼容DOS和Win16的子系统NTVDM已经消失,但是它又加入了一个能兼容32位的Windows程序的新NTVDM,就算是64位原生程序,其仍然最终实现在64位的Win32子系统(经常被称作Win64,但微软官方并不如此称呼)中。同样为了最大限度实现源码级向下兼容,CP/M、MS-DOS、Win16和32位Win32下的虚拟设备文件,虽然大部分已经失去原来的作用,但仍然如幽灵一般,在64位Win32子系统眼中的任何一个磁盘目录下隐藏着,虽然它们其实并不存在,但是你仍然无法直接建立和打开任何主文件名和它们中的任何一个相同的文件。

一个由虚拟设备文件而造成的限制,竟然能跨越三十多年,跨越CP/M、MS-DOS、Windows、OS/2和Windows NT五个架构而以相同的形式存在,如果从向下兼容角度看,这是个奇迹;但是从发展的角度来看,一个已经放弃与这个限制的来源——MS-DOS的兼容性的全 新64位系统,竟然还要被它所继续限制。反观类Unix系统,虽然存在着更多的虚拟设备文件,甚至存在着stdin/stdout/stderr这样和文 件系统无关的虚拟文件,但它们都是独立的,位置固定的文件,而不像现在我们谈到的的这些,不管在哪个目录,它们都像幽灵一样存在。

LPTx、COMx、PRN、AUX等等虚拟设备的功能,都是在当时为当年的PC而设定的。这些虚拟设备在现代Windows中的存在,在打印驱动程序设置的画面、拨号网络设置中都能清晰地看到。但是,Windows早已具备完善的、与底层无关的对串并口进行操作的API,开发者根本没有必要,甚至是不能通过读写这些虚拟文件来访问串口和并口。

CON、NUL,某种意义上可以说类似C语言的stdin、stdout和Unix的/dev/null,但是,在cmd环境下运行批处理文件,对console输入和输出都有比较完整的处理手段,而基本没有直接对CON进行处理的必要。当然,copy con 文件名 这样DOS下的东西,在CMD下仍然完全有效。

这些无处不在的虚拟文件的存在,也反映了DOS的“磁盘操作系统”的本性,文件系统就是磁盘的卷,里面的结构可以千变万化,而不像类Unix系统那样,整个文件系统是逻辑概念,不需要和磁盘等存储设备形成对应关系。Unix中的设备文件都放在/dev下,子文件系统可以被“mount”在根文件系统的任何目录下,然而DOS下由于文件系统没有统一的结构,每一个“盘符”下面就是一个独立王国,不可能拿出一个固定的地方来映射设备,也许微软当时也没有做长远考虑,就让这些幽灵般的设备文件在文件系统的任何地方都有效,然而他们显然没有想到,后来Windows NT的Native层已经有了一个和Unix有些类似的根文件系统,符号链接、挂载点等文件系统概念也在慢慢实现。但是,他们实现Win32有一个很重要的目的就是让为基于DOS的16位Windows系统开发者能够很快移植到NT为首的新平台上来,因此他们把DOS的这个显著特性也完全给移植了过来。后来,NT就算移植到非x86架构,移植到x86-64架构,仍然要对最初的Win32兼容,这样下来,DOS的这些特性一直保留到了DOS已经完全在系统中消失的今天。

苹果当年从90年代末已经成为“活化石”(协作式多任务,没有内存保护)的旧Mac OS系统迁移到基于Nextstep和BSD的Mac OS X系统,也设计了一个和当年的Win32类似的Carbon API,它把旧Mac OS中大多数正规的系统管理器(旧Mac OS的各种系统调用都称之为各种各样的“Manager”)移植到了Mac OS X,以方便开发者迅速转到Mac OS X上来。当初,苹果和微软不同,他们明确声明了Carbon将只是一个过渡的API,最终苹果将放弃对它的支持,开发者必须最终过渡到Mac OS X原生的接口Cocoa上来。然而,以Adobe为首的某些大公司忽略了这一说法,虽然很快就使用Carbon开发了一系列经典大型软件的Mac OS X版本,但他们并没有认真考虑Cocoa化的时间表。2007年苹果突然宣布,Carbon在Leopard系统之后将不再被更新,Mac OS X移植到x86-64架构时将不包括原生版本的Carbon库,iPhone OS也不支持Carbon。Adobe等这时才傻了眼,回过来慢慢Cocoa化自己的那些大怪物们已经显得非常仓促。这样,Flash插件在OSX下慢、Photoshop CS4 Mac版不支持64位等等问题成了乔布斯严厉抨击他们“懒惰”的重要理由。对Adobe来说,直到CS5,其Creative Suite系列仍未能彻底转向Cocoa,未能保持与其Windows版本同步的功能,至于Flash插件,则是仓促做了Cocoa版,却仍然和以前一样能让Macbook变成火炉。至于苹果,其异常高调的对Adobe的抨击,是建立在Leopard到Snow Leopard的大量进步基础上的:支持了OpenCL,支持了新的多线程API Grand Central Dispatch (GCD),完全Cocoa化的新QuickTime框架,而整个系统的大小反而比Leopard小了1G以上。虽然抛弃了Carbon的发展,但是Snow Leopard对旧程序的兼容性,和Leopard相比并没有降低。

微软通过各种正当的或者无耻的甚至非法的手段达成的强大垄断优势,一个方面也拖慢了微软的发展。虽然他们竭尽全力想保持向下兼容性,但是从Windows 98到Windows 2000、XP,Windows XP到Vista,总是有一批软件最终无法兼容。有人说如果一件东西没有坏就不要修它,但是当今IT的发展已经达到微软靠传统垄断模式越来越力不从心的程度了。前有苹果iOS/AppStore平台的强大威胁(至少在美国是如此),后有Google的云计算概念,微软总是被动迎战,但Zune打不过iPod,Windows Live永远找不着北,进入Bing时代后虽然耗费了比苹果还多的宣传费,却完全无法在全球和Google,中国和百度、腾讯对抗。掣肘微软创新的,也许就是微软的垄断平台中那些他们没有勇气砍掉的东西,那些CON、LPTx、COMx,那个C:,那个越来越难以实现的“向下兼容”……Windows 7中干脆搞了个在虚拟机上实现的“Windows XP 模式”,这证明他们已经开始意识到他们的那些“向下兼容”已经和他们的创新发生冲突了。也许有一天,当一个全新的、强大的、简洁的Windows系统出现的时候,所有的旧应用程序都能在一个几乎完美的虚拟旧系统的环境中运行,这时候,CON、LPTx、COMx终将从系统的保留文件名中彻底消失,而他们实现的新的“向下兼容性”将比以往任何时候都强大。

生物的进化达到人类这种水平,人类依然保持着灵长类的一切特征、哺乳类的一切特征和动物的一切特征,人类的身体成为人类发展的最后障碍;微软为了保持向下兼容性,折腾了20多年,.net这样的革新提出了10年,Windows仍然还没摆脱这样一个小小的限制。这最后也许真是微软的悲剧吧。

作者注:这篇文章在一位朋友发给我开头那张图之后顺手写成,几句气话而已。尽管把口水喷过来,无论你拿着美分、角票、日元,或者只是为了图一时之快。

Leave a comment

发现一个网站

www.baihui.com

先存档,以后仔细看看。

Leave a comment

R一些记录

包更新是什么来着?

Rserve如何接收图片?

Leave a comment

[转]R不务正业之RCurl

存档一下,仔细研究研究。

=========================================

首先感谢COS论坛同意我在这篇水文中用RCurl做一些简单的演示,但由这些功能的延展而给COS论坛造成的任何损失或破坏,请各位自己负责。

一、RCurl是什么
混迹于各大社区,经常会看到关于浏览器之争的口水战:某某浏览器的市场份额如何如何,某某浏览器的速度如何如何,某某浏览器支持的功能多么强大等等。各个网友也根据自己的喜好,将自身归档于某某浏览器阵营,以此找些心灵的归属。估计类似的口水之争将永远的进行下去(是啊,不然闲着干什么呢?)。如果换个角度看这些争论,也正反应出浏览器在大家日常生活中的地位:想想每天坐在电脑前,用的最多的软件是什么呢?但是提到浏览器阵营中的cURL——一款杀人放火、居家旅游必备的命令行浏览器,则普及率要不少。可它的功能绝不逊色于我们日常用的各大浏览器。R的RCurl包是对cURL库—libcurl的封装。感谢Duncan Temple Lang等牛人的无私工作,我们才可以在R中运用cURL,将R和cURL这两大开源利器的优势完美的结合到一起。

二、用RCurl浏览网页
想想我们平时绝大部分时间是怎么用浏览器的?第一步:打开自己钟爱的那款浏览器;第二部:输入某个网址,如http://cos.name/;第三部:回车;第四步:拖拖鼠标,看自己想看的东西;第五步:点进某个链接,接着看。在关注呈现的信息的时候,大多数人都不大会去关心上述的5步(或者更多步)中浏览器(客户端)和网站(服务器端)是如何工作的。其实客户端和服务器端一直在保持联系:告诉对方想干什么,是否同意等等内容?比如我们浏览http://cos.name/时,浏览器给服务器端提交了如下的一些内容:
GET /HTTP/1.1
Host:cos.name
User-Agent:Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.6)
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language:en-us
Accept-Encoding:gzip,deflate
Accept-Charset:GB2312,utf-8;q=0.7,*;q=0.7
Keep-Alive:300
Connection:keep-alive
通过上面的头信息,浏览器除了告诉COS服务器想浏览哪些内容,还告诉对方用了什么浏览器、想要什么样的数据格式、用什么协议/方法接收等非常细节的内容。COS服务器收到这些请求后,同样会提供一个物品清单:
HTTP/1.x200 OK
Date:Fri, 01 Jan 2010 13:11:20 GMT
Server:Apache/2.2.14 (Unix) X-Powered-By: PHP/5.2.11
X-Pingback:http://cos.name/xmlrpc.php
Vary:Accept-Encoding
Content-Encoding:gzip
Content-Length:13973
Keep-Alive:timeout=10, max=30
Connection:Keep-Alive
Content-Type:text/html; charset=UTF-8
通过这个清单,COS服务器告诉客户端:服务器是什么配置、你的协议我接受了、我给你的内容是什么格式等等信息。
当用RCurl这款客户端时,我们需要一一配置提交给服务器的内容,所以不妨先随心所欲、照葫芦画瓢的模仿一下上面的头信息:
myHttpheader<- c(
"User-Agent"="Mozilla/5.0(Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.6)",
"Accept"="text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language"="en-us",
"Connection"="keep-alive",
"Accept-Charset"="GB2312,utf-8;q=0.7,*;q=0.7"
)
然后可以运用getURL函数实现cURL的网页浏览:
temp“html文件”中所包含的内容。
如何看getURL的头信息呢?不妨再多设定几个RCurl的参数:

d =debugGatherer()
temp<- getURL("http://cos.name/",httpheader=myHttpheader,
debugfunction=d$update,verbose= TRUE)
此时d中包含了你所要的信息,其中:
cat(d$value()[3])
中为RCurl提交服务器的头信息,而
cat(d$value()[2])
中为服务器端返回的头信息。看看跟正常浏览器的交互内容是不是一样呢?怎么看一般浏览器的头信息呢?如果你用Firefox的话,用扩展Live http headers就可以了。

三、RCurl的Handles
在RCurl的目前版本中,有170多个(!!!!!!!!!)cURL系统参数可以设置,具体可以用
names(getCurlOptionsConstants())
查看一下,各个参数的详细说明则可以参照libcurl的官方说明文档。
如此众多参数,如果每次都设定,是不是会非常的繁琐?幸好在RCurl中有一个非常强大的功能可以有效的解决这个问题:那就是cRULhandles(当然,cRUL handles的优势不止这一个)。cRULhandles类似于行走江湖的一个百宝箱:根据自己的喜好设好后,每次背箱出发就行了。同时 cRULhandles还根据客户端、服务器端参数的设定在动态的变化,随时更新内容。如下便定义了一个最基本的cRULhandles:

cHandle<- getCurlHandle(httpheader = myHttpheader)
在getURL中可以如下应用:
d =debugGatherer()
temp <- getURL("http://cos.name/", .opts = list(debugfunction=d$update,verbose = TRUE), curl=cHandle)
此时,cHandle中的cRUL系统参数debugfunction、verbose均发生及时的更新。

四、用RCurl实现直接登录
上面提及的getURL函数仅仅实现了页面浏览的最简单功能。如果想用RCurl登录到某个网站(如http://cos.name/bbs/)怎么实现呢?还是继续看看你在正常登录过程中,客户端提交给服务器端的信息吧,然后照葫芦画一个。

http://cos.name/bbs/login.php?

POST/bbs/login.php? HTTP/1.1
Host:cos.name
User-Agent:Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.6)Gecko/20091201 Firefox/3.5.6
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language:en-us
Accept-Encoding:gzip,deflate
Accept-Charset:GB2312,utf-8;q=0.7,*;q=0.7
Keep-Alive:300
Connection:keep-alive
Referer:http://cos.name/bbs/login.php
Content-Type:application/x-www-form-urlencoded
Content-Length:110
forward=&jumpurl=http%3A%2F%2Fcos.name%2Fbbs%2F&step=2&lgt=0&pwuser=yourname&pwpwd=yourpw&hideid=0&cktime=31536000
这个头信息的核心就是客户端用POST方法给http://cos.name/bbs/login.php? 提交了一个字符串(即头信息最后的两行,其中包含了你的用户名和密码),请求服务器端给予身份认证。至于为什么提交那么稀奇古怪的一串字符,就要问谢老大了:)。
如果要让RCurl提交相同的字符串,需要将上面的那段关键字符串转变成如下的格式:
c(name1=”info1”,name2=”info2”,…)。字符串的处理工作交给R就行了:
myPost<- function(x){
post <-scan(x,what="character",quiet=TRUE,sep="n")
abcd=strsplit(post,"&")[[1]]
abc=gsub("(^.*)(=)(.*$)","3",abcd)
abcnames=gsub("(^.*)(=)(.*$)","1",abcd)
names(abc)=abcnames
return(abc)
}
postinfo<- myPost("clipboard")
然后用RCurl中的postForm函数,将postinfo提交给服务器:
temp<- postForm("http://cos.name/bbs/login.php?",.params=postinfo,
.opts=list(cookiefile=""),curl=cHandle,style="post")

cat(d$value()[2])
查看一下cos.name给你的客户端反馈了那些内容?作为登录认证的cookies是不是已经在里面了?到这一步,RCurl已经成功的登录到http://cos.name/bbs/了,需要的一切认证信息都已经记录到百宝箱 cHandle中了。用
getCurlInfo(cHandle)[["cookielist"]]
看看你想要的cookie是不是在那里了?接着用cHandle登录一下R子论坛吧,验证一下你是否真正的成功了?
temp<- getURL("http://cos.name/bbs/thread.php?fid=15",
curl=cHandle,.encoding="gbk")
五、用RCurl实现间接登录
由于“这事儿不能说太细”,我们有时候不能用上面的方法来完成RCurl登录认证。那能不能让RCurl来使用其他浏览器客户端与服务器端已经建立好的认证呢?答案是可以尝试一下的:)所谓的认证信息一般就是服务器端在你的浏览器里面写下的cookies,把他们导出来交给RCurl,RCurl同样可以做好你需要的cURLhandle。
先用你的常规浏览器(此处假定为Firefox)正常登录到http://cos.name/bbs/,然后再用Firefox的扩展Firecookie看看当前页面的cookie信息:你需要的就是它们了。将这些cookie信息导出成RCurl能够识别的格式,然后提交给RCurl就万事大吉了。

d2 =debugGatherer()
cHandle2<- getCurlHandle(httpheader=myHttpheader,followlocation=1,
debugfunction=d2$update,verbose=TRUE,
cookiefile="yourcookiefile.txt")
接着去cos.name的R论坛看看:

temp<- getURL("http://cos.name/bbs/thread.php?fid=15",
curl=cHandle2,.encoding="gbk")
验证一下temp里面是不是已经有你的大名了呢?
grep("yourname",temp)
如果有的话那么恭喜你:RCurl已经成功接管你的登录权限了。

六、登录后RCurl能继续干什么
实现了登录认证的RCurl handles,这仅仅是第一步。能用它和R+RCurl继续做些什么呢?这时候,只要闭上眼睛、海阔天空的想一下平时怎么样用浏览器就有答案了:
1、能不能让RCurl帮我数一下某VIP网络俱乐部中王小麻子灌了多少水?
2、能不能帮顶一下王二麻子发表的美女yy贴?
3、为了给我的外甥女选秀投票,点鼠标点的手都抬不起来了,能不能让RCurl来帮我做呢?
4、我天天去某网站下载文档,绝对的体力活!
5、半夜起来偷菜,太困了,交给RCurl做就好了。
6、用RCurl玩twitter、写博客就好了。
7、我就想用RCurl看门户网站的体育新闻。
8、我就想在各个网站的论坛上发个“顶”字,顺便留下我的牛皮膏药小广告。
9、……
天有多高,RCurl有多强……

七、结束语
没有想到会唠叨这么多的废话。但这篇水文仅涉及到libcurl、RCurl中的一点皮毛而已,更多的内容请参考DuncanTemple Lang写的RCurl帮助文档和libcurl官网。客观讲cURL属于浏览器中的一把剪刀,由于它强大的易编程属性,RCurl会带来一些意想不到的破坏性。但要记住:技术本身可能是无罪的,任何的破坏都可能是我们自己造成的。网络中的ID是现实中你的一个延伸,她同样有完整的人格和生命力,所以请尊重和爱护网络中的自己。
最后,希望这篇水文没有影响到你的好心情。

Leave a comment

存档怎么就直接排列了?

存档怎么就直接排列了?

算了,不写CSS了,直接注释掉。

Leave a comment

WP居然没有截行摘要的插件!

WP居然没有截行摘要的插件!

崩溃!崩溃!

Leave a comment

Ubuntu SubVersion服务安装设置

Subversion 是一款开放源代码的版本控制系统。使用Subversion,您可以重新加载源代码和文档的历史版本。Subversion管理了源代码在各个时期的版 本。一个文件树被集中放置在文件仓库中。这个文件仓库很像是一个传统的文件服务器,只不过它能够记住文件和目录的每一次变化。

2. 假设

首先我们假设您能够在 Ubuntu 中操作 Linux 的命令、编辑文件、启动和停止服务。当然,我们还认为您的 Ubuntu 正在运行中,您可以使用 sudo 操作并且您打算使用 Subversion。

我们假设您可能需要使用所有可能的 方法访问 SVN 文件仓库。同时我们也认为您应该已经配置好了您的 /etc/apt/sources.list 文件。

3. 本文涉及的范围

要通过 HTTP 协议访问 SVN 文件仓库,您需要安装并配置好 Web 服务器。Apache 2 被证实可以很好的与 SVN 一起工作。关于 Apache 2 的安装超出了本文的范围,尽管如此,本文还是会涉及如何配置 Apache 2 使用 SVN。

类似的,要通过 HTTPS 协议访问 SVN 文件仓库,您需要在您的 Apache 2 中安装并配置好数字证书,这也不在本文的讨论范围之中。

4. 安装

幸运的,Subversion 已经包含在 main 仓库中。所以,要安装 Subversion,您只需要简单的运行:

$ sudo apt-get install subversion

$ sudo apt-get install libapache2-svn

如果系统报 告了依赖关系的错误,请找出相应的软件包并安装它们。如果存在其它问题,也请自行解决。如果您是再不能解决这些问题,可以考虑通过 Ubuntu 的网站、Wiki、论坛或邮件列表寻求支持。

5. 服务器配置

您应该已经安装了上述的软件包。本节将阐述如何 创建 SVN 文件仓库以及如何设置项目的访问权限。

5.1. 创建 SVN 仓库

许多位置都可以放置 Subversion文件仓库,其中两个最常用的是:/usr/local/svn 以及 /home/svn。为了在下面的描述中简单明了,我们假设您的Subversion 文件仓库放在 /home/svn,并且你的项目名称是简单的“myproject”。

同样的,也有许多常用的方式设置文件仓库的访问权限。然 而,这也是安装过程中最经常出现错误的地方,因此我们会对此进行一个详细说明。典型的情况下,您应该创建一个名为“Subversion”的组来拥有文件 仓库所在的目录。下面是一个快速的操作说明,有关内容请参考相关文档的详细说明:

在 Ubuntu 菜单上选择“系统->系统管理->用户和组”;

切换到“组”标签;

点击“添加组”按钮;

组名为“subversion”;

将您自己和“www-data”(Apache 用户)加入组成员中;

点击“OK”以确认修改,关闭该程序。

您需要注销然后再登录以便您能够成为 subversion 组的一员,然后就可以执行签入文件(Check in,也称提交文件)的操作了。

现在执行下面的命令

$ sudo mkdir /home/svn

$ cd /home/svn

$ sudo mkdir myproject

$ sudo chown -R root:subversion myproject

$ sudo chmod -R g+rws myproject

最后的一条命令赋予组成员对所有新加入文件仓库的文件拥有相应的权限。

下面的命令用于创建 SVN 文件仓库:

$ sudo svnadmin create /home/svn/myproject

6. 访问方式

Subversion 文件仓库可以通过许多不同的方式进行访问(Check Out,签出)——通过本地硬盘,或者通过各种网络协议。无论如何,文件仓库的位置总是使用 URL 来表示。下表显示了不同的 URL 模式对应的访问方法:

模式

访问方法

file:///

直接访问本地硬盘上文件仓库

http://

通过 WebDAV 协议访问支持 Subversion 的 Apache 2 Web 服务器

https://

类似 http://,支持 SSL 加密

svn://

通过自带协议访问 svnserve 服务器

svn+ssh://

类似 svn://,支持通过 SSH 通道

本节中,我们将看到如何配置 SVN 以使之能够通过所有的方法得以访问。当然这里我们之讨论基本的方法。要了解更高级的用途,我们推荐您阅读《使用 Subversion 进行版本控制》在线电子书。

6.1. 直接访问文件仓库(file://)

这是所有访问方式中最简单的。它不 需要事先运行任何 SVN 服务。这种访问方式用于访问本地的 SVN 文件仓库。语法是:

$ svn co file:///home/svn/myproject

或者

$ svn co file://localhost/home/svn/myproject

注意:如果您并不确定主机的名称,您必须使用三个斜杠 (///),而如果您指定了主机的名称,则您必须使用两个斜杠(//).

对文件仓库的访问权限基于文件系统的权限。如果该用户具有 读/写权限,那么他/她就可以签出/提交修改。如果您像前面我们说描述的那样设置了相应的组,您可以简单的将一个用户添加到“subversion”组中 以使其具有签出和提交的权限。

6.2. 通过 WebDAV 协议访问(http://)

要通过 WebDAV 协议访问 SVN 文件仓库,您必须配置您的 Apache 2 Web 服务器。您必须加入下面的代码片段到您的 /etc/apach2/apache2.conf 中:

DAV svn

SVNPath /home/svn/myproject

AuthType Basic

AuthName “myproject subversion repository”

AuthUserFile /etc/subversion/passwd

Require valid-user

当您添加了上面的内容,您 必须重新起动 Apache 2 Web 服务器,请输入下面的命令:

sudo /etc/init.d/apache2 restart

接下来,您需要创建 /etc/subversion/passwd 文件,该文件包含了用户授权的详细信息。要添加用户,您可以执行下面的命令:

sudo htpasswd2 /etc/subversion/passwd user_name

它会提示您输入密码,当您输入了密码,该用户就建立了。您可以通 过下面的命令来访问文件仓库:

$ svn co http://hostname/svn/myproject myproject –username user_name

它会提示您输入密码。您必须输入您使用 htpasswd2 设置的密码。当通过验证,项目的文件就被签出了。

警告:密码是通过纯文本传输的。如果您担心密码泄漏的问题,我们建议您使用 SSL 加密,有关详情请看下一节。

6.3. 通过具有安全套接字(SSL)的 WebDAV 协议访问(https://)

通过具有 SSL 加密的 WebDAV 协议访问 SVN 文件仓库(https://)非 常类似上节所述的内容,除了您必须为您的 Apache 2 Web 服务器设置数字证书之外。

您可以安装由诸如 Verisign 发放的数字签名,或者您可以安装您自己的数字签名。

我们假设您已经为 Apache 2 Web 服务器安装和配置好了相应的数字证书。现在按照上一节所描述的方法访问 SVN 文件仓库,别忘了把 http:// 换成 https://。如何,几乎是一模一样的!

6.4. 通过自带协议访问(svn://)

当您创建了 SVN 文件仓库,您可以修改 /home/svn/myproject/conf/svnserve.conf 来配置其访问控制。

例 如,您可以取消下面的注释符号来设置授权机制:

# [general]

# password-db = passwd

现在,您可以在“passwd”文件中维护用户清单。编辑同一目录下“passwd”文件,添加新用户。语法如下:

username = password

要了解详情,请参考该文件。

现在,您可以在本地或者远程通过 svn:// 当文 SVN 了,您可以使用“svnserve”来运行 svnserver,语法如下:

$ svnserve -d –foreground -r /home/svn

# -d — daemon mode

# –foreground — run in foreground (useful for debugging)

# -r — root of directory to serve

要了解更多信息,请输入:

$ svnserve –help

当您执行了该命令,SVN 就开始监听默认的端口(3690)。您可以通过下面的命令来访问文件仓库:

$ svn co svn://hostname/myproject myproject –username user_name

基于服务器的配置,它会要求输入密码。一旦通过验证,就会签出文件仓库中的代码。

要同步文件仓库和本地的副本,您可以执行 update 子命令,语法如下:

$ cd project_dir

$ svn update

要了解更多的 SVN 子命令,您可以参考手册。例如要了解 co (checkout) 命令,请执行:

$ svn co help

6.5. 通过具有安全套接字(SSL)的自带协议访问(svn+ssh://)

配置和服务器进程于上 节所述相同。我们假设您已经运行了“svnserve”命令。

我们还假设您运行了 ssh 服务并允许接入。要验证这一点,请尝试使用 ssh 登录计算机。如果您可以登录,那么大功告成,如果不能,请在执行下面的步骤前解决它。

svn+ssh:// 协议使用 SSL 加密来访问 SVN 文件仓库。如您所知,数据传输是加密的。要访问这样的文件仓库,请输入:

$ svn co svn+ssh://hostname/home/svn/myproject myproject –username user_name

注意:在这种方式下,您必须使用完整的路径(/home/svn/myproject)来访问 SVN 文件仓库

基于服务器的配置,它会要求输入密码。您必须输入您用于登录 ssh 的密码,一旦通过验证,就会签出文件仓库中的代码。

您还应该参考 SVN book 以了解关于 svn+ssh:// 协议的详细信息。

7. 参考资料

Setting up Apache on Ubuntu

SVN Home page

SVN Book

Apache 2 Documentation

Mod-SSL

Apache-SSL

Leave a comment

vsftpd.conf 参考

vsftpd.conf设置部分
引用:
5、VSFTPD的设置选项

VSFTPD的配置文件/etc/vsftpd/vsftpd.conf是个文本文件。以“#”字符开始的行是注释行。每个选项设置为一行, 格式为“option=value”,注意“=”号两边不能留空白符。除了这个主配置文件外,还可以给特定用户设定个人配置文件,具体介绍见后。
VSFTPD包中所带的vsftpd.conf文件配置比较简单,而且非常偏执狂的(文档自称:-))。我们可以根据实际情况对其进行一些设 置,以使得VSFTPD更加可用。

5.1、连接选项

本部分主要是一些与建立FTP链接相关的选项。

5.1.1、监听地址与控制端口

listen_address=ip address
此参数在VSFTPD使用单独(standalone)模式下有效。此参数定义了在主机的哪个IP地址上监听FTP请求,即在哪个IP地址上 提供FTP服务。对于只有一个IP地址的主机,不需要使用此参数。对于多址主机,不设置此参数,则监听所有IP地址。默认值为无。

listen_port=port_value
指定FTP服务器监听的端口号(控制端口),默认值为21。此选项在standalone模式下生效。

5.1.2、FTP模式与数据端口

FTP 分为两类,PORT FTP和PASV FTP,PORT FTP是一般形式的FTP。这两种FTP在建立控制连接时操作是一样的, 都是由客户端首先和FTP服务器的控制端口(默认值为21)建立控制链接,并通过此链接进行传输操作指令。它们的区别在于使用数据传输端口(ftp- data)的方式。PORT FTP由FTP服务器指定数据传输所使用的端口,默认值为20。PASV FTP由FTP客户端决定数据传输的端口。 PASV FTP这种做法,主要是考虑到存在防火墙的环境下,由客户端与服务器进行沟通(客户端向服务器发出数据传输请求中包含了数据传输端口),决定两 者之间的数据传输端口更为方便一些。

port_enable=YES|NO
如果你要在数据连接时取消PORT模式时,设此选项为NO。默认值为YES。

connetc_from_port_20=YES|NO
控制以PORT模式进行数据传输时是否使用20端口(ftp-data)。YES使用,NO不使用。默认值为NO,但RHL自带的 vsftpd.conf文件中此参数设为YES。

ftp_data_port=port number
设定ftp数据传输端口(ftp-data)值。默认值为20。此参数用于PORT FTP模式。

port_promiscuous=YES|NO
默认值为NO。为YES时,取消PORT安全检查。该检查确保外出的数据只能连接到客户端上。小心打开此选项。

pasv_enable=YES|NO
YES,允许数据传输时使用PASV模式。NO,不允许使用PASV模式。默认值为YES。

pasv_min_port=port number
pasv_max_port=port number
设定在PASV模式下,建立数据传输所可以使用port范围的下界和上界,0 表示任意。默认值为0。把端口范围设在比较高的一段范围内,比 如50000-60000,将有助于安全性的提高。

pasv_promiscuous=YES|NO
此选项激活时,将关闭PASV模式的安全检查。该检查确保数据连接和控制连接是来自同一个IP地址。小心打开此选项。此选项唯一合理的用法是 存在于由安全隧道方案构成的组织中。默认值为NO。

pasv_address=
此选项为一个数字IP地址,作为PASV命令的响应。默认值为none,即地址是从呼入的连接套接字 (incoming connectd socket)中获取。

5.1.3 ASCII模式

默认情况下,VSFTPD是禁止使用ASCII传输模式。即使FTP客户端使用asc命令,指明要使用ASCII模式,但是,VSFTPD表 面上接受了asc命令,而在实际传输文件时,还是使用二进制方式。下面选项控制VSFTPD是否使用ASCII传输模式。

ascii_upload_enable=YES|NO
控制是否允许使用ascii模式上传文件,YES允许,NO不允许,默认为NO。

ascii_download_enable=YES|NO
控制是否允许使用ascii模式下载文件,YES允许,NO不允许,默认为NO。

5.2、性能与负载控制

5.2.1、超时选项

idle_session_timeout=
空闲(发呆)用户会话的超时时间,若是超出这时间没有数据的传送或是指令的输入,则会强迫断线。单位为秒,默认值为300。

data_connection_timeout=
空闲的数据连接的超时时间。默认值为300 秒。

accept_timeout=numerical value
接受建立联机的超时设定,单位为秒。默认值为60。

connect_timeout=numerical value
响应PORT方式的数据联机的超时设定,单位为秒。默认值为60。以上两个选项针对客户端的,将使客户端空闲1分钟后自动中断连接,并在中断 1分钟后自动激活连接。

5.2.2 负载控制

max_clients=numerical value
此参数在VSFTPD使用单独(standalone)模式下有效。此参数定义了FTP服务器最大的并发连接数,当超过此连接数时,服务器拒 绝客户端连接。默认值为0,表示不限最大连接数。

max_per_ip=numerical value
此参数在VSFTPD使用单独(standalone)模式下有效。此参数定义每个IP地址最大的并发连接数目。超过这个数目将会拒绝连接。 此选项的设置将影响到象网际快车这类的多进程下载软件。默认值为0,表示不限制。

anon_max_rate=value
设定匿名用户的最大数据传输速度value,以Bytes/s为单位。默认无。

local_max_rate=value
设定用户的最大数据传输速度value,以Bytes/s为单位。默认无。此选项对所有的用户都生效。此外,也可以在用户个人配置文件中使用 此选项,以指定特定用户可获得的最大数据传输速率。
步骤如下:
①在vsftpd.conf中指定用户个人配置文件所在的目录,如:
user_config_dir=/etc/vsftpd/userconf
②生成/etc/vsftpd/userconf目录。
③用户个人配置文件是在该目录下,与特定用户同名的文件,如:
/etc/vsftpd/userconf/xiaowang
④在用户的个人配置文件中设置local_max_rate参数,如:
local_max_rate=80000
以上步骤设定FTP用户xiaowang的最大数据传输速度为80KBytes/s。

VSFTPD 对于速度控制的变化范围大概在80%到120%之间。比如我们限制最高速度为100KBytes/s, 但实际的速度可能在 80KBytes/s 到120KBytes/s 之间。当然,若是线路带宽不足时,速率自然会低于此限制。

5.3 用户选项

VSFTPD的用户分为三类:匿名用户、本地用户(local user)以及虚拟用户(guest)。

5.3.1、匿名用户

anonymous_enable=YES|NO
控制是否允许匿名用户登录,YES允许,NO不允许,默认值为YES。

ftp_username=
匿名用户所使用的系统用户名。默认下,此参数在配置文件中不出现,值为ftp。

no_anon_password=YES|NO
控制匿名用户登入时是否需要密码,YES不需要,NO需要。默认值为NO。

deny_email_enable=YES|NO
此参数默认值为NO。当值为YES时,拒绝使用banned_email_file参数指定文件中所列出的e-mail地址进行登录的匿名用 户。即,当匿名用户使用banned_email_file文件中所列出的e-mail进行登录时,被拒绝。显然,这对于阻击某些Dos攻击有效。当此参 数生效时,需追加banned_email_file参数

banned_email_file=/etc/vsftpd.banned_emails
指定包含被拒绝的e-mail地址的文件,默认文件为/etc/vsftpd.banned_emails。

anon_root=
设定匿名用户的根目录,即匿名用户登入后,被定位到此目录下。主配置文件中默认无此项,默认值为/var/ftp/。

anon_world_readable_only=YES|NO
控制是否只允许匿名用户下载可阅读文档。YES,只允许匿名用户下载可阅读的文件。NO,允许匿名用户浏览整个服务器的文件系统。默认值为 YES。

anon_upload_enable=YES|NO
控制是否允许匿名用户上传文件,YES允许,NO不允许,默认是不设值,即为NO。除了这个参数外,匿名用户要能上传文件,还需要两个条件: 一,write_enable参数为YES;二,在文件系统上,FTP匿名用户对某个目录有写权限。

anon_mkdir_write_enable=YES|NO
控制是否允许匿名用户创建新目录,YES允许,NO不允许,默认是不设值,即为NO。当然在文件系统上,FTP匿名用户必需对新目录的上层目 录拥有写权限。

anon_other_write_enable=YES|NO
控制匿名用户是否拥有除了上传和新建目录之外的其他权限,如删除、更名等。YES拥有,NO不拥有,默认值为NO。

chown_uploads=YES|NO
是否修改匿名用户所上传文件的所有权。YES,匿名用户所上传的文件的所有权将改为另外一个不同的用户所有,用户由 chown_username参数指定。此选项默认值为NO。

chown_username=whoever
指定拥有匿名用户上传文件所有权的用户。此参数与chown_uploads联用。不推荐使用root用户。

5.3.2、本地用户

在使用FTP服务的用户中,除了匿名用户外,还有一类在FTP服务器所属主机上拥有账号的用户。VSFTPD中称此类用户为本地用户 (local users),等同于其他FTP服务器中的real用户。

local_enable=YES|NO
控制vsftpd所在的系统的用户是否可以登录vsftpd。默认值为YES。

local_root=
定义所有本地用户的根目录。当本地用户登入时,将被更换到此目录下。默认值为无。

user_config_dir=
定义用户个人配置文件所在的目录。用户的个人配置文件为该目录下的同名文件。个人配置文件的格式与vsftpd.conf格式相同。例如定义 user_config_dir=/etc/vsftpd/userconf,并且主机上有用户xiaowang,lisi,那我们可以在 user_config_dir的目录新增名为xiaowang、lisi的两个文件。当用户lisi 登入时,VSFTPD则会读取 user_config_dir下lisi这个文件中的设定值,应用于用户lisi。默认值为无。

5.3.3、虚拟用户

guest_enable=YES|NO
若是启动这项功能,所有的非匿名登入者都视为guest。默认值为关闭。

guest_username=
定义VSFTPD的guest用户在系统中的用户名。默认值为ftp。

5.4、安全措施

5.4.1、用户登录控制

pam_service_name=vsftpd
指出VSFTPD进行PAM认证时所使用的PAM配置文件名,默认值是vsftpd,默认PAM配置文件是/etc/pam.d /vsftpd。

/etc/vsftpd.ftpusers
VSFTPD禁止列在此文件中的用户登录FTP服务器。这个机制是在/etc/pam.d/vsftpd中默认设置的。

userlist_enable=YES|NO
此选项被激活后,VSFTPD将读取userlist_file参数所指定的文件中的用户列表。当列表中的用户登录FTP服务器时,该用户在 提示输入密码之前就被禁止了。即该用户名输入后,VSFTPD查到该用户名在列表,VSFTPD就直接禁止掉该用户,不会再进行询问密码等后续步聚。默认 值为NO。

userlist_file=/etc/vsftpd.user_list
指出userlist_enable选项生效后,被读取的包含用户列表的文件。默认值是/etc/vsftpd.user_list。

userlist_deny=YES|NO
决定禁止还是只允许由userlist_file指定文件中的用户登录FTP服务器。此选项在userlist_enable 选项启动后才 生效。YES,默认值,禁止文件中的用户登录,同时也不向这些用户发出输入口令的提示。NO,只允许在文件中的用户登录FTP服务器。

tcp_wrappers=YES|NO
在VSFTPD中使用TCP_Wrappers远程访问控制机制,默认值为YES。

5.4.2、目录访问控制

chroot_list_enable=YES|NO
锁定某些用户在自家目录中。即当这些用户登录后,不可以转到系统的其他目录,只能在自家目录(及其子目录)下。具体的用户在 chroot_list_file参数所指定的文件中列出。默认值为NO。

chroot_list_file=/etc/vsftpd/chroot_list
指出被锁定在自家目录中的用户的列表文件。文件格式为一行一用户。通常该文件是/etc/vsftpd/chroot_list。此选项默认 不设置。

chroot_local_users=YES|NO
将本地用户锁定在自家目录中。当此项被激活时,chroot_list_enable和chroot_local_users参数的作用将发 生变化,chroot_list_file所指定文件中的用户将不被锁定在自家目录。本参数被激活后,可能带来安全上的冲突,特别是当用户拥有上传、 shell访问等权限时。因此,只有在确实了解的情况下,才可以打开此参数。默认值为NO。

passwd_chroot_enable
当此选项激活时,与chroot_local_user选项配合,chroot()容器的位置可以在每个用户的基础上指定。每个用户的容器来 源于/etc/passwd中每个用户的自家目录字段。默认值为NO。

5.4.3、文件操作控制

hide_ids=YES|NO
是否隐藏文件的所有者和组信息。YES,当用户使用”ls -al”之类的指令时,在目录列表中所有文件的拥有者和组信息都显示为ftp。默 认值为NO。

ls_recurse_enable=YES|NO
YES,允许使用”ls -R” 指令。这个选项有一个小的安全风险,因为在一个大型FTP站点的根目录下使用”ls -R”会消耗大量系统 资源。默认值为NO。

write_enable=YES|NO
控制是否允许使用任何可以修改文件系统的FTP 的指令,比如STOR、DELE、RNFR、RNTO、MKD、RMD、APPE 以及 SITE。默认值为NO,不过自带的简单配置文件中打开了该选项。

secure_chroot_dir=
这选项指向一个空目录,并且ftp用户对此目录无写权限。当vsftpd不需要访问文件系统时,这个目录将被作为一个安全的容器,用户将被限 制在此目录中。默认目录为/usr/share/empty。

5.4.4、新增文件权限设定

anon_umask=
匿名用户新增文件的umask 数值。默认值为077。

file_open_mode=
上传档案的权限,与chmod 所使用的数值相同。如果希望上传的文件可以执行,设此值为0777。默认值为0666。

local_umask=
本地用户新增档案时的umask 数值。默认值为077。不过,其他大多数的FTP服务器都是使用022。如果您的用户希望的话,可以修改为 022。在自带的配置文件中此项就设为了022。

5.5、提示信息

ftpd_banner=login banner string
此参数定义了login banner string(登录欢迎语字符串)。用户可以自行修改。预设值为无。当ftpd_banner设置 后,将取代系统原来的欢迎词。

banner_file=/directory/vsftpd_banner_file
此项指定一个文本文件,当使用者登入时,会显示此该文件的内容,通常为欢迎话语或是说明。默认值为无。与ftpd_banner相 比,banner_file是文本文件的形式,而ftpd_banner是字串格式。banner_file选项将取代ftpd_banner选项。

dirmessage_enable=YES|MO
控制是否启用目录提示信息功能。YES启用,NO不启用,默认值为YES。此功能启用后,当用户进入某一个目录时,会检查该目录下是否有 message_file选项所指定的文档,若是有,则会出现此文档的内容,通常这个档案会放置欢迎话语,或是对该目录的说明。

message_file=
此选项,仅在dirmessage_enable选项激活方生效。默认值为.message。

5.6、日志设置

xferlog_enable=YES|NO
控制是否启用一个日志文件,用于详细记录上传和下载。该日志文件由xferlog_file选项指定。默认值为NO,但简单配置文件中激活此 选项。

xferlog_file=
这个选项设定记录传输日志的文件名。默认值为/var/log/vsftpd.log。

xferlog_std_format=YES|NO
控制日志文件是否使用xferlog的标准格式,如同wu-ftpd一样。使用xferlog格式,可以重新使用已经存在的传输统计生成器。 然而,默认的日志格式更为可读性。默认值为NO,但自带的配置文件中激活了此选项。

log_ftp_protocol=YES|NO
当此选项激活后,所有的FTP请求和响应都被记录到日志中。提供此选项时,xferlog_std_format不能被激活。这个选项有助于 调试。默认值为NO。

5.7、其他设置

setproctitle_enable=YES|NO
YES,VSFTPD将在系统进程列表中显示每个会话(session)的状态。也就是说,进程报告将显示每个vsftpd会话在做什么(挂 起、下载等),如用ps -ef|grep ftp。出于安全的目的,可以考虑将此选项关闭。NO,进程报告只显示一个vsftpd进程在运行。默认值为 NO。

text_userdb_names=YES|No
当使用者登入后使用ls -al 之类指令时,目录列表的用户和组信息域,默认是出现拥有者的UID,而不是该档案拥有者的名称。若是希望出 现拥有者的名称,则将此功能开启。默认值为NO。

user_localtime=YES|NO
默认为NO。YES,VSFTPD显示目录列表时使用你本地时区的时间。默认是显示GMT时间。同样,由ftp命令“MDTM”返回的时间值 也受此选项影响。

check_shell=YES|NO
此选项仅对不使用PAM方式的VSFTPD生效。当此选项关闭后,当本地用户登录时,VSFTPD不会检查/etc/shells文件以寻找 一个有效的用户shell。默认为YES。

nopriv_user=
指定一个用户,当VSFTPD不想要什么权限时,使用此用户身份。这用户最好是一个专用的用户,而不是用户nobody。在大多数的机器 上,nobody用户被用于大量重要的事情。默认值为nobody。

pam_service_name=
指明VSFTPD使用用PAM验证服务时的PAM配置文件名。默认值为ftp。

Leave a comment

关于Rserve的用法

赶快去看参考!!!

Leave a comment