当前位置:  编程技术>软件工程/软件设计
本页文章导读:
    ▪结合内核源码来看如何调整影响TIME_WAIT状态套接字数量的参数        这篇文件主要讨论tcp_max_tw_buckets、tcp_timestamps、tcp_tw_recycle、tcp_tw_reuse和tcp_fin_timeout参数。   测试的时候看到系统日志中不断地出现“TCP: time wait bucket table overflow”的信息。在代码中.........
    ▪生成器模式(Builder)      @@@模式定义: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 @@@练习示例:  继续工厂方法模式中的导出数据的应用框架。 @@@示例代码: \export\ExportHe.........
    ▪vmware环境下在linux中创建ftp服务器      ① 检查是否成功安装ftp相关的rpm软件   rpm -qa | grep vsftpd    ② 如果没有安装,那么用rpm命令安装,软件基本上在第二张安装盘上    命令: rpm -ivh 软件名 ③ 安装完.........

[1]结合内核源码来看如何调整影响TIME_WAIT状态套接字数量的参数
    来源: 互联网  发布时间: 2013-11-19
  这篇文件主要讨论tcp_max_tw_buckets、tcp_timestamps、tcp_tw_recycle、tcp_tw_reuse和tcp_fin_timeout参数。

  测试的时候看到系统日志中不断地出现“TCP: time wait bucket table overflow”的信息。在代码中搜索了一下,看到这条日志是在tcp_time_wait()函数中输出的,输出这条日志是在局部变量tw为NULL的情况下。局部变量tw的默认值为NULL, 在下面的代码中初始化:

    if (tcp_death_row.tw_count < tcp_death_row.sysctl_max_tw_buckets)
        tw = inet_twsk_alloc(sk, state);
其中tcp_death_row.tw_count是当前TIME_WAIT状态套接字的数量,tcp_death_row.sysctl_max_tw_buckets的值是系统参数tcp_max_tw_buckets的值,如果前者小于后者,则tw的值为NULL。假设分配内存失败,tw的值也为NULL。所以在TIME_WAIT套接字数量超过系统限制或者内存不足时,就会输出“TCP: time wait bucket table overflow”的日志信息,如下所示:
    if (tw != NULL) {
        ......

    } else {
        /* Sorry, if we're out of memory, just CLOSE this
         * socket up.  We've got bigger problems than
         * non-graceful socket closings.
         */
        LIMIT_NETDEBUG(KERN_INFO "TCP: time wait bucket table overflow\n");
    }
  我这里的问题是因为tcp_max_tw_buckets的值设置的太小了,调整大了之后就OK了。如果系统当前TIME_WAIT状态的套接字数量小于系统限制,出现这样的问题就是严重的内存泄露了。后来google了一下看怎么减小TIME_WAIT套接字的数量,设置的选项大致就是摘要中提到的那几个选项,不过大多数人都是几乎全都给设置,也根本没有考虑是否有用或者是否跟自己的业务相符合,看了内核代码之后发现这些选项并不是什么情况下都能减小time-wait套接字的数量,有些甚至会适得其反,下面来看内核是如何处理的。

一、tcp_max_tw_buckets参数
  tcp_max_tw_buckets参数是系统中TIME_WAIT套接字的最大数量。假如tcp_max_tw_buckets的值设的太小,否则会导致部分连接没法进入TIME_WAIT状态,TCP连接可能会不正常关闭,数据包会重传。假如tcp_max_tw_buckets的值设置的太大,TIME_WAIT状态套接字占用的内容可能很大。这个值通常设置的大一些比较好,利用空间来给内核足够的时间来清理之前的TIME_WAIT状态的套接字,然后再结合其他参数来减小TIME_WAIT套接字的影响。这个参数对服务器端和客户端都适用。

二、tcp_timestamps参数和tcp_tw_recycle参数
  tcp_timestamps参数用来设置是否启用时间戳选项,tcp_tw_recycle参数用来启用快速回收TIME_WAIT套接字。tcp_timestamps参数会影响到tcp_tw_recycle参数的效果。如果没有时间戳选项的话,tcp_tw_recycle参数无效,代码如下:

if (tcp_death_row.sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp)
        recycle_ok = icsk->icsk_af_ops->remember_stamp(sk);
如果没有时间戳选项,tp->rx_opt.ts_recent_stamp的值为0,这样局部变量recycle_ok的值为0,在后面就会使用默认的时间TCP_TIMEWAIT_LEN(60s)作为TIME_WAIT状态的时间长度,如下所示:

       if (recycle_ok) {
            tw->tw_timeout = rto;
        } else {
            tw->tw_timeout = TCP_TIMEWAIT_LEN;
            if (state == TCP_TIME_WAIT)
                timeo = TCP_TIMEWAIT_LEN;
        }
所以在设置tcp_tw_recycle参数后要检查一下tcp_timestamps参数是否设置。
  接下来对tcp_tw_recycle参数的讨论在tcp_timestamps设置的前提下进行。
  sock结构进入TIME_WAIT状态有两种情况:一种是在真正进入了TIME_WAIT状态,还有一种是真实的状态是FIN_WAIT_2的TIME_WAIT状态。之所以让FIN_WAIT_2状态在没有接收到FIN包的情况下也可以进入TIME_WAIT状态是因为tcp_sock结构占用的资源要比tcp_timewait_sock结构占用的资源多,而且在TIME_WAIT下也可以处理连接的关闭。内核在处理时通过inet_timewait_sock结构的tw_substate成员来区分这种两种情况。如果是第一种情况,在调用tcp_time_wait()时指定的超时时间timeo参数的值为0,如果没有设置tcp_tw_recycle参数,TIME_WAIT状态持续的时间是默认值TCP_TIMEWAIT_LEN(60s);如果设置tcp_tw_recycle参数,TIME_WAIT状态持续的时间为局部变量rto的值。如果是第二种情况,在调用tcp_time_wait()时指定的超时时间timeo不为0,决定的是在子状态下等待的时间,如果在FIN_WAIT_2状态下接收到FIN包,在真正的TIME_WAIT状态下等待的时间是由tw->tw_timeout成员决定的。同样,在设置tcp_tw_recycle参数的情况下,tw->tw_timeout的值为rto,否则为TCP_TIMEWAIT_LEN。所以tcp_tw_recycle参数如果要实现对回收TIME_WAIT状态套接字的加速,需要这个时间rto小于TCP_TIMEWAIT_LEN。rto的值由下面的式子计算:
const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1);
其中icsk->icsk_rto的值是超时重传的时间,这个值是根据网络情况动态计算的。rto的值为icsk->icsk_rto的3.5倍。在网络比较好的情况下,rto的值会小于TCP_TIMEWAIT_LEN,从而达到加速的目的;但是如果在网络情况比较差,也就是说客户端和服务器端往返的时间比较长的情况下,rto的值有可能会大于TCP_TIMEWAIT_LEN,这种情况下反而适得其反,这种情况通常是由客户端引起的。所以在设置tcp_tw_recycle的时候要考虑到客户端的情况。
  下面在来看看为什么rto的值要选择为icsk->icsk_rto的3.5倍,也就是RTO*3.5,而不是2倍、4倍呢?我们知道,在FIN_WAIT_2状态下接收到FIN包后,会给对端发送ACK包,完成TCP连接的关闭。但是最后的这个ACK包可能对端没有收到,在过了RTO(超时重传时间)时间后,对端会重新发送FIN包,这时需要再次给对端发送ACK包,所以TIME_WAIT状态的持续时间要保证对端可以重传两次FIN包。如果重传两次的话,TIME_WAIT的时间应该为RTO*(0.5+0.5+0.5)=RTO*1.5,但是这里却是RTO*3.5。这是因为在重传情况下,重传超时时间采用一种称为“指数退避”的方式计算。例如:当重传超时时间为1S的情况下发生了数据重传,我们就用重传超时时间为2S的定时器来重传数据,下一次用4S,一直增加到64S为止(参见tcp_retransmit_timer())。所以这里的RTO*3.5=RTO*0.5+RTO*1+RTO*2,其中RTO*0.5是第一次发送ACK的时间到对端的超时时间(系数就是乘以RTO的值),RTO*1是对端第一次重传FIN包到ACK包到达对端的超时时间,RTO*2是对端第二次重传FIN包到ACK包到达对端的超时时间。注意,重传超时时间的指数退避操作(就是乘以2)是在重传之后执行的,所以第一次重传的超时时间和第一次发送的超时时间相同。整个过程及时间分布如下图所示(注意:箭头虽然指向对端,只是用于描述过程,数据包并未被接收到):

三、tcp_tw_reuse参数
  tcp_tw_reuse参数用来设置是否可以在新的连接中重用TIME_WAIT状态的套接字。注意,重用的是TIME_WAIT套接字占用的端口号,而不是TIME_WAIT套接字的内存等。这个参数对客户端有意义,在主动发起连接的时候会在调用的inet_hash_connect()中会检查是否可以重用TIME_WAIT状态的套接字。如果你在服务器段设置这个参数的话,则没有什么作用,因为服务器端ESTABLISHED状态的套接字和监听套接字的本地IP、端口号是相同的,没有重用的概念。但并不是说服务器端就没有TIME_WAIT状态套接字。
四、tcp_fin_timeout参数
  有些人对这个参数会有误解,认为这个参数是用来设置TIME_WAIT状态持续的时间的。linux的内核文档说的很明白,这个参数是用来设置保持在FIN_WAIT_2状态的时间,原文如下():

tcp_fin_timeout - INTEGER Time to hold socket in state FIN-WAIT-2, if it was closed
    by our side. Peer can be broken and never close its side,
    or even died unexpectedly. Default value is 60sec.
    Usual value used in 2.2 was 180 seconds, you may restore
    it, but remember that if your machine is even underloaded WEB server, you risk to overflow memory with kilotons of dead sockets,
    FIN-WAIT-2 sockets are less dangerous than FIN-WAIT-1,
    because they eat maximum 1.5K of memory, but they tend
    to live longer.    Cf. tcp_max_orphans.
  如果是正常的处理流程就是在FIN_WAIT_2情况下接收到FIN进入到TIME_WAIT的情况,tcp_fin_timeout参数对处于TIME_WAIT状态的时间没有任何影响,但是如果这个参数设的比较小,会缩短从FIN_WAIT_1到TIME_WAIT的时间,从而使连接更早地进入TIME_WAIT状态。状态开始的早,等待相同的时间,结束的也早,客观上也加速了TIME_WAIT状态套接字的清理速度。
  如果在FIN_WAIT_2状态下没有接收到FIN而进入TIME_WAIT状态(FIN_WAIT_2状态超时或者超时时间大小、TCP_LINGER2等影响),在初始进入TIME_WAIT状态时使用的超时时间为tcp_fin_time()计算出来的,tc
    
[2]生成器模式(Builder)
    来源: 互联网  发布时间: 2013-11-19
@@@模式定义:
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。


@@@练习示例: 
继续工厂方法模式中的导出数据的应用框架。


@@@示例代码:
\export\ExportHeaderModel.java

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;

/**
 * 描述输出到文件头的内容的类
 */
public class ExportHeaderModel {
    /**
     * 分公司或门市点编号
     */
	private String depId;
	
	/**
	 * 导出数据的日期
	 */
	private String exportDate;

	public String getDepId() {
		return depId;
	}

	public void setDepId(String depId) {
		this.depId = depId;
	}

	public String getExportDate() {
		return exportDate;
	}

	public void setExportDate(String exportDate) {
		this.exportDate = exportDate;
	}
}

\export\ExportDataModel.java

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;

/**
 * 描述输出数据的类
 */
public class ExportDataModel {
    /**
     * 产品编号
     */
	private String productId;
	
	/**
	 * 销售价格
	 */
	private double price;
	
	/**
	 * 销售数量
	 */
	private double amount;

	public String getProductId() {
		return productId;
	}

	public void setProductId(String productId) {
		this.productId = productId;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	public double getAmount() {
		return amount;
	}

	public void setAmount(double amount) {
		this.amount = amount;
	}
}

\export\ExportFooterModel.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;

/**
 * 描述输出到文件尾的内容的类
 */
public class ExportFooterModel {
    /**
     * 输出人
     */
	private String exportUser;

	public String getExportUser() {
		return exportUser;
	}

	public void setExportUser(String exportUser) {
		this.exportUser = exportUser;
	}
}

\export\ExportToTxt.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;

import java.util.Collection;
import java.util.Map;

/**
 * 导出数据到文本文件的类
 */
public class ExportToTxt {
    /**
     * 导出数据到文本文件
     * @param ehm 文件头的内容
     * @param mapData 数据的内容
     * @param efm 文件尾的内容
     */
	public void export(ExportHeaderModel ehm,
			           Map<String, Collection<ExportDataModel>> mapData,
			           ExportFooterModel efm) {
		// 用来记录最终输出的文件内容
		StringBuffer buffer = new StringBuffer();
		// 1: 先来拼接文件头的内容
	    buffer.append(ehm.getDepId() + ", " + ehm.getExportDate() + "\n");
	    // 2: 接着来拼接文件体的内容
	    for (String tblName : mapData.keySet()) {
	    	// 先拼接表名称
	    	buffer.append(tblName + "\n");
	    	// 然后循环拼接具体数据
	    	for (ExportDataModel edm : mapData.get(tblName)) {
	    		buffer.append(edm.getProductId() + ", " + 
	    				edm.getPrice() + ", " + edm.getAmount() + "\n");
	    	}
	    }
	    // 3: 最后来拼接文件尾的内容
	    buffer.append(efm.getExportUser());
	    
	    // 为了演示的简洁性,省略写输出文件的代码
	    // 把要输出的内容输出到控制台看看
	    System.out.println("输出到文本文件的内容: \n" + buffer);
	}
}

\export\ExportToXml.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;

import java.util.Collection;
import java.util.Map;

/**
 * 导出数据到XML文件的类
 */
public class ExportToXml {
	/**
     * 导出数据到XML文件
     * @param ehm 文件头的内容
     * @param mapData 数据的内容
     * @param efm 文件尾的内容
     */
	public void export(ExportHeaderModel ehm,
			           Map<String, Collection<ExportDataModel>> mapData,
			           ExportFooterModel efm) {
		// 用来记录最终输出的文件内容
		StringBuffer buffer = new StringBuffer();
		// 1: 先来拼接文件头的内容
		buffer.append("<?xml version='1.0' encoding='gb2312'?>\n");
		buffer.append("<Report>\n");
		buffer.append("  <Header>\n");
		buffer.append("    <DepId>" + ehm.getDepId() + "</DepId>\n");
		buffer.append("    <ExportDate>" + ehm.getExportDate() + "</ExportDate>\n");
	    buffer.append("  </Header>\n");
	    // 2: 接着来拼接文件体的内容
	    buffer.append("  <Body>\n");
	    for (String tblName : mapData.keySet()) {
	    	// 先拼接表名称
	    	buffer.append("    <Datas TableName=\"" + tblName + "\">\n");
	    	// 然后循环拼接具体数据
	    	for (ExportDataModel edm : mapData.get(tblName)) {
	    		buffer.append("      <Data>\n");
	    		buffer.append("        <ProductId>" + 
	    				edm.getProductId() + "</ProductId>\n");
	    		buffer.append("        <Price>" + 
	    				edm.getPrice() + "</Price>\n");
	    		buffer.append("        <Amount>" +
	    				edm.getAmount() + "</Amount>\n");
	    		buffer.append("      </Data>\n");
	    	}
	    	buffer.append("    </Datas>\n");
	    }
	    buffer.append("  </Body>\n");
	    // 3: 最后来拼接文件尾的内容
	    buffer.append("  <Footer>\n");
	    buffer.append("    <ExportUser>" + efm.getExportUser() + "</ExportUser>\n");
	    buffer.append("  </Footer>\n");
	    buffer.append("</Report>\n");
	    
	    // 为了演示的简洁性,省略写输出文件的代码
	    // 把要输出的内容输出到控制台看看
	    System.out.println("输出到XML文件的内容: \n" + buffer);
	}
}

\user\Client.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package user;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import export.ExportDataModel;
import export.ExportFooterModel;
import export.ExportHeaderModel;
import export.ExportToTxt;
import export.ExportToXml;

public class Client {
    public static void main(String[] args) {
    	// 准备测试数据
    	ExportHeaderModel ehm = new ExportHeaderModel();
    	ehm.setDepId("一分公司");
    	ehm.setExportDate("2013-06-02");
    	
    	Map<String, Collection<ExportDataModel>> mapData = 
    		new HashMap<String, Collection<ExportDataModel>>();
    	Collection<ExportDataModel> col = new ArrayList<ExportDataModel>();
    	
        ExportDataModel edm1 = new ExportDataModel();
        edm1.setProductId("产品001号");
        edm1.setPrice(100);
        edm1.setAmount(80);
        
        ExportDataModel edm2 = new ExportDataModel();
        edm2.setProductId("产品002号");
        edm2.setPrice(108);
        edm2.setAmount(56);
        
        // 把数据组装起来
        col.add(edm1);
        col.add(edm2);
        mapData.put("销售记录表", col);
        
        ExportFooterModel efm = new ExportFooterModel();
        efm.setExportUser("李小二");
        
        // 测试输出到文本文件
        ExportToTxt toTxt = new ExportToTxt();
        toTxt.export(ehm, mapData, efm);
        
        // 测试输出到xml文件
        ExportToXml toXml = new ExportToXml();
        toXml.export(ehm, mapData, efm);
    }
}

-------------------------------------------------------------
不使用模式时存在的问题 : 
对于不同的输出格式,处理步骤是一样的,但是每步的具体实现是不一样的。
构建每种输出格式的文件内容时,都会重复这几个处理步骤,应该提炼出来,形成公共的处理过程。
今后可能会有很多不同输出格式的要求,这就需要在处理过程不变的情况下,能方便地切换不同的输出格式的处理。
构建每种格式的数据文件的处理过程,应该和具体的步骤实现分开,
这样就能够复用处理过程,而且能很容易地切换不同的输出格式。
-------------------------------------------------------------


\export\Builder.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;

import java.util.Collection;
import java.util.Map;

/**
 * 生成器接口,定义创建一个输出文件对象所需的各个部件的操作
 */
public interface Builder {
   /**
    * 构建输出文件的Header部分
    * @param ehm 文件头的内容
    */
	public void buildHeader(ExportHeaderModel ehm);
	
	/**
	 * 构建输出文件的Body部分
	 * @param mapData 要输出的数据的内容
	 */
	public void buildBody(Map<String, Collection<ExportDataModel>> mapData);
	
	/**
	 * 构建输出文件的Footer部分
	 * @param efm 文件尾的内容
	 */
	public void buildFooter(ExportFooterModel efm);
}

\export\TxtBuilder.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

package export;

import java.util.Collection;
import java.util.Map;

/**
 * 实现导出数据到文本文件的具体生成器类
 */
public class TxtBuilder implements Builder {
	/**
	 * 用来记录构建的文件的内容,相当于产品
	 */
	private StringBuffer buffer = new StringBuffer();
	
	@Override
	public void buildHeader(ExportHeaderModel ehm) {
		 buffer.append(ehm.getDepId() + ", " + ehm.getExportDate() + &      
    
[3]vmware环境下在linux中创建ftp服务器
    来源: 互联网  发布时间: 2013-11-19

① 检查是否成功安装ftp相关的rpm软件   rpm -qa | grep vsftpd

 

 ② 如果没有安装,那么用rpm命令安装,软件基本上在第二张安装盘上    命令: rpm -ivh 软件名

③ 安装完毕后配置ftp的主配置文件vsftpd.conf,该文件在/etc/vsftpd/文件夹下,打开如下

 

④ 各条配置(以下内容拷贝自Jack.Tech_StoreRoom的博客)

1.登录和对匿名用户的设置 
write_enable=YES               //是否对登录用户开启写权限。属全局性设置。默认NO
local_enable=YES               //是否允许本地用户登录FTP服务器。默认为NO
anonymous_enable=YES          //设置是否允许匿名用户登录FTP服务器。默认为YES
ftp_username=ftp                //定义匿名用户的账户名称,默认值为ftp。
no_anon_password=YES             //匿名用户登录时是否询问口令。设置为YES,则不询问。默
认NO
anon_world_readable_only=YES   //匿名用户是否允许下载可阅读的文档,默认为YES。
   anon_upload_enable=YES      //是否允许匿名用户上传文件。只有在write_enable设置为
YES时,该配置项才有效。而且匿名用户对相应的目录必须有写权限。默认为NO。
anon_mkdir_write_enable=YES //是否允许匿名用户创建目录。只有在write_enable设置为    YES时有效。且匿名用户对上层目录有写入的权限。默认为NO。
anon_other_write_enable=NO    //若设置为YES,则匿名用户会被允许拥有多于
上传和建立目录的权限,还会拥有删除和更名权限。默认值为NO。

2.设置欢迎信息

用户登录FTP服务器成功后,服务器可向登录用户输出预设置的欢迎信息。
ftpd_banner=Welcome to my FTP server.
//该配置项用于设置比较简短的欢迎信息。若欢迎信息较多,则可使用banner_file配置项。
banner_file=/etc/vsftpd/banner    
//设置用户登录时,将要显示输出的文件。该设置项将覆盖ftpd_banner的设置。
dirmessage_enable=YES        
//设置是否显示目录消息。若设置为YES,则当用户进入特定目录(比如/var/ftp/linux)时,将显示该目录中的由message_file配置项指定的文件(.message)中的内容。
message_file=.message          //设置目录消息文件。可将显示信息存入该文件。该文件需要放在 相应的目录(比如/var/ftp/linux)下

 3.设置用户登录后所在的目录
local_root=/var/ftp            
// 设置本地用户登录后所在的目录。默认配置文件中没有设置该项,此时用户登录FTP服务器后,所在的目录为该用户的主目录,对于root用户,则为/root目录。
anon_root=/var/ftp           
//设置匿名用户登录后所在的目录。若未指定,则默认为/var/ftp目录。

 4.控制用户是否允许切换到上级目录
        在默认配置下,用户可以使用“cd..”命名切换到上级目录。比如,若用户登录后所在的目录为/var/ftp,则在“ftp&gt;”命令行 下,执行“cd..”命令后,用户将切换到其上级目录/var,若继续执行该命令,则可进入Linux系统的根目录,从而可以对整个Linux的文件系统 进行操作。

若设置了write_enable=YES,则用户还可对根目录下的文件进行改写操作,会给系统带来极大的安全隐患,因此,必须防止用户切换到Linux的根目录,相关的配置项如下:
chroot_list_enable=YES                   
// 设置是否启用chroot_list_file配置项指定的用户列表文件。设置为YES则除了列在j/etc/vsftpd/chroot_list文件中的的帐号外,所有登录的用户都可以进入ftp根目录之外的目录。默认NO
chroot_list_file=/etc/vsftpd/chroot_list        
// 用于指定用户列表文件,该文件用于控制哪些用户可以切换到FTP站点根目录的上级目录。
chroot_local_user=YES                   
// 用于指定用户列表文件中的用户,是否允许切换到上级目录。默认NO
注意:要对本地用户查看效果,需先设置local_root=/var/ftp

具体情况有以下几种:
1)当chroot_list_enable=YES,chroot_local_user=YES时,在/etc/vsftpd/chroot_list文件中列出的用户,可以切换到上级目录;未在文件中列出的用户,不能切换到站点根目录的上级目录。
2)当chroot_list_enable=YES,chroot_local_user=NO时,在/etc/vsftpd/chroot_list文件中列出的用户,不能切换到站点根目录的上级目录;未在文件中列出的用户,可以切换到上级目录。
3)当chroot_list_enable=NO,chroot_local_user=YES时,所有用户均不能切换到上级目录。
4)当chroot_list_enable=NO,chroot_local_user=NO时,所有用户均可以切换到上级目录。
5)当用户不允许切换到上级目录时,登录后FTP站点的根目录“/”是该FTP账户的主目录,即文件的系统的/var/ftp目录。

 5.设置访问控制
(1)设置允许或不允许访问的主机(见TBP14)
tcp_wrappers=YES用来设置vsftpd服务器是否与tcp  wrapper相结合,进行主机的访问控制。默认设置为YES,vsftpd服务器会检查/etc/hosts.allow和/etc /hosts.deny中的设置,以决定请求连接的主机是否允许访问该FTP服务器。这两个文件可以起到简易的防火墙功能。
比如,若要仅允许192.168.168.1~192.168.168.254的用户,可以访问连接vsftpd服务器,则可在/etc/hosts.allow文件中添加以下内容:
vsftpd:192.168.168.0/255.255.255.0 :allow
all:all:deny

(2)设置允许或不允许访问的用户
对用户的访问控制由/etc/vsftpd/user_list和/etc/vsftpd/ftpusers文件来控制实现。相关配置命令如下:
userlist_enable=YES      
// 决定/etc/vsftpd/user_list文件是否启用生效。YES则生效,NO不生效。
userlist_deny=YES        
//  决定/etc/vsftpd/user_list文件中的用户是允许访问还是不允许访问。若设置为YES,则/etc/vsftpd/user_list 文件中的用户将不允许访问FTP服务器;若设置为NO,则只有vsftpd.user_list文件中的用户,才能访问FTP服务器。

 6.设置访问速度
anon_max_rate=0        
//设置匿名用户所能使用的最大传输速度,单位为b/s。若设置为0,则不受速度限制,此为默认值。
local_max_rate=0        
// 设置本地用户所能使用的最大传输速度。默认为0,不受限制。

 7.定义用户配置文件
在vsftpd服务器中,不同用户还可使用不同的配置,这要通过用户配置文件来实现。
user_config_dir=/etc/vsftpd/userconf  //用于设置用户配置文件所在的目录。
  设置了该配置项后,当用户登录FTP服务器时,系统就会到/etc/vsftpd/userconf目录下读取与当前用户名相同的文件,并根据文件中的配 置命令,对当前用户进行更进一步的配置。比如,利用用户配置文件,可实现对不同用户进行访问的速度进行控制,在各用户配置文件中,定义 local_max_rate配置,以决定该用户允许的访问速度。

 8.与连接相关的设置
listen=YES         
//设置vsftpd服务器是否以standalone模式运行。以standalone模式运行是一种较好的方式,此时listen必须设置为YES, 此为默认值,建议不要更改。很多与服务器运行相关的配置命令,需要此运行模式才有效。若设置为NO,则vsftpd不是以独立的服务运行,要受 xinetd服务的管理控制,功能上会受限制。

max_clients=0
//设置vsftpd允许的最大连接数,默认为0,表示不受限制。若设置为150时,则同时允许有150个连接,超出的将拒绝建立连接。只有在以standalon

    
最新技术文章:
▪主-主数据库系统架构    ▪java.lang.UnsupportedClassVersionError: Bad version number i...    ▪eclipse项目出现红色叉叉解决方案
▪Play!framework 项目部署到Tomcat    ▪dedecms如何做中英文网站?    ▪Spring Batch Framework– introduction chapter(上)
▪第三章 AOP 基于@AspectJ的AOP    ▪基于插件的服务集成方式    ▪Online Coding开发模式 (通过在线配置实现一个表...
▪观察者模式(Observer)    ▪工厂模式 - 程序实现(java)    ▪几种web并行化编程实现
▪机器学习理论与实战(二)决策树    ▪Hibernate(四)——全面解析一对多关联映射    ▪我所理解的设计模式(C++实现)——解释器模...
▪利用规则引擎打造轻量级的面向服务编程模式...    ▪google blink的设计计划: Out-of-Progress iframes    ▪FS SIP呼叫的消息线程和状态机线程
▪XML FREESWITCH APPLICATION 实现    ▪Drupal 实战    ▪Blink: Chromium的新渲染引擎
▪(十四)桥接模式详解(都市异能版)    ▪你不知道的Eclipse用法:使用Allocation tracker跟...    ▪Linux内核-进程
▪你不知道的Eclipse用法:使用Metrics 测量复杂度    ▪IT行业为什么没有进度    ▪Exchange Server 2010/2013三种不同的故障转移
▪第二章 IoC Spring自动扫描和管理Bean    ▪CMMI简介    ▪目标检测(Object Detection)原理与实现(六)
▪值班总结(1)——探讨sql语句的执行机制    ▪第二章 IoC Annotation注入    ▪CentOS 6.4下安装Vagrant
▪Java NIO框架Netty1简单发送接受    ▪漫画研发之八:会吃的孩子有奶吃    ▪比较ASP和ASP.NET
▪SPRING中的CONTEXTLOADERLISTENER    ▪在Nginx下对网站进行密码保护    ▪Hibernate从入门到精通(五)一对一单向关联映...
▪.NET领域驱动设计—初尝(三:穿过迷雾走向光...    ▪linux下的块设备驱动(一)    ▪Modem项目工作总结
▪工作流--JBPM简介及开发环境搭建    ▪工作流--JBPM核心服务及表结构    ▪Eclipse:使用JDepend 进行依赖项检查
javascript开源软件 iis7站长之家
▪设计模式11---设计模式之中介者模式(Mediator...    ▪带你走进EJB--JMS编程模型    ▪从抽象谈起(二):观察者模式与回调
▪设计模式09---设计模式之生成器模式(Builder)也...    ▪svn_resin_持续优化中    ▪Bitmap recycle方法与制作Bitmap的内存缓存
▪Hibernate从入门到精通(四)基本映射    ▪设计模式10---设计模式之原型模式(Prototype)    ▪Dreamer 3.0 支持json、xml、文件上传
▪Eclipse:使用PMD预先检测错误    ▪Jspx.net Framework 5.1 发布    ▪从抽象谈起(一):工厂模式与策略模式
▪Eclipse:使用CheckStyle实施编码标准    ▪【论文阅读】《Chain Replication for Supporting High T...    ▪Struts2 Path_路径问题
▪spring 配置文件详解    ▪Struts2第一个工程helloStruts极其基本配置    ▪Python学习入门基础教程(learning Python)--2 Python简...
▪maven springmvc环境配置    ▪基于SCRUM的金融软件开发项目    ▪software quality assurance 常见问题收录
▪Redis集群明细文档    ▪Dreamer 框架 比Struts2 更加灵活    ▪Maven POM入门
▪git 分支篇-----不断更新中    ▪Oracle非主键自增长    ▪php设计模式——UML类图
▪Matlab,Visio等生成的图片的字体嵌入问题解决...    ▪用Darwin和live555实现的直播框架    ▪学习ORM框架—hibernate(二):由hibernate接口谈...
▪(十)装饰器模式详解(与IO不解的情缘)    ▪无锁编程:最简单例子    ▪【虚拟化实战】网络设计之四Teaming
▪OSGi:生命周期层    ▪Javascript/Jquery——简单定时器    ▪java代码 发送GET、POST请求
▪Entity Framework底层操作封装(3)    ▪HttpClient 发送GET、POST请求    ▪使用spring框架,应用启动时,加载数据
▪Linux下Apache网站目录读写权限的设置    ▪单键模式的C++描述    ▪学习ORM框架—hibernate(一):初识hibernate
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3