Apache中Order Allow Deny详解

转自:http://www.cnblogs.com/top5/archive/2009/09/22/1571709.html

本文经原文已删掉部分内容。

Allow和Deny可以用于apache的conf文件或者.htaccess文件中(配合Directory, Location, Files等),用来控制目录和文件的访问授权。

所以,最常用的是:
Order Deny,Allow
Allow from All

注意“Deny,Allow”中间只有一个逗号,也只能有一个逗号,有空格都会出错;单词的大小写不限。上面设定的含义是先设定“先检查禁止设定,没有禁止的全部允许”,而第二句没有Deny,也就是没有禁止访问的设定,直接就是允许所有访问了。这个主要是用来确保或者覆盖上级目录的设置,开放所有内容的访问权。

按照上面的解释,下面的设定是无条件禁止访问:
Order Allow,Deny
Deny from All

如果要禁止部分内容的访问,其他的全部开放:
Order Deny,Allow
Deny from ip1 ip2
或者
Order Allow,Deny
Allow from all
Deny from ip1 ip2

apache会按照order决定最后使用哪一条规则,比如上面的第二种方式,虽然第二句allow允许了访问,但由于在order中allow不是最后规则,因此还需要看有没有deny规则,于是到了第三句,符合ip1和ip2的访问就被禁止了。注意,order决定的“最后”规则非常重要,下面是两个错误的例子和改正方式:

Order Deny,Allow
Allow from all
Deny from domain.org
错误:想禁止来自domain.org的访问,但是deny不是最后规则,apache在处理到第二句allow的时候就已经匹配成功,根本就不会去看第三句。
解决方法:Order Allow,Deny,后面两句不动,即可。

Order Allow,Deny
Allow from ip1
Deny from all
错误:想只允许来自ip1的访问,但是,虽然第二句中设定了allow规则,由于order中deny在后,所以会以第三句deny为准,而第三句的范围中又明显包含了ip1(all include ip1),所以所有的访问都被禁止了。
解决方法一:直接去掉第三句。
解决方法二:
Order Deny,Allow
Deny from all
Allow from ip1

 

下面是测试过的例子:
——————————–
Order deny,allow
allow from all
deny from 219.204.253.8
#全部都可以通行
——————————-
Order deny,allow
deny from 219.204.253.8
allow from all
#全部都可以通行
——————————-
Order allow,deny
deny from 219.204.253.8
allow from all
#只有219.204.253.8不能通行
——————————-
Order allow,deny
allow from all
deny from 219.204.253.8
#只有219.204.253.8不能通行
——————————-
——————————-
Order allow,deny
deny from all
allow from 219.204.253.8
#全部都不能通行
——————————-
Order allow,deny
allow from 219.204.253.8
deny from all
#全部都不能通行
——————————-
Order deny,allow
allow from 219.204.253.8
deny from all
#只允许219.204.253.8通行
——————————-
Order deny,allow
deny from all
allow from 219.204.253.8
#只允许219.204.253.8通行
——————————-
——————————–
Order deny,allow
#全部都可以通行(默认的)
——————————-
Order allow,deny
#全部都不能通行(默认的)
——————————-
Order allow,deny
deny from all
#全部都不能通行
——————————-
Order deny,allow
deny from all
#全部都不能通行
——————————-
对于上面两种情况,如果换成allow from all,则全部都可以通行!
——————————-
Order deny,allow
deny from 219.204.253.8
#只有219.204.253.8不能通行
——————————-
Order allow,deny
deny from 219.204.253.8
#全部都不能通行
——————————-
Order allow,deny
allow from 219.204.253.8
#只允许219.204.253.8通行
——————————-
Order deny,allow
allow from 219.204.253.8
#全部都可以通行
——————————-
——————————-
order deny,allow
allow from 218.20.253.2
deny from 218.20
#代表拒绝218.20开头的IP,但允许218.20.253.2通过;而其它非218.20开头的IP也都允许通过。
——————————-
order allow,deny
allow from 218.20.253.2
deny from 218.20
#和上面的差不多,只是掉换的order语句中的allow、deny先后顺序,但最终结果表示全部都拒绝!

影响最终判断结果的只有两点:

1. order语句中allow、deny的先后顺序;

2. allow、deny语句中各自包含的范围。

PS:

1. 修改完配置后要保存并重启Apache服务才能生效;

2. 开头字母不分大小写;

3. allow、deny语句不分先后顺序,谁先谁后不影响最终判断结果;但都会被判断到;

4. order语句中,“allow,deny”之间“有且只有”一个逗号(英文格式的),而且先后顺序很重要;

5. Apache有一条缺省规则,“order allow,deny”本身就默认了拒绝所有的意思,因为deny在allow的后面;同理,“order deny,allow”本身默认的是允许所有;当然,最终判断结果还要综合下面的allow、deny语句中各自所包含的范围;(也就是说order语句后面可以没有allow、deny语句)

6. allow、deny语句中,第二个单词一定是“from”,否则Apache会因错而无法启动,

7. “order allow,deny”代表先判断allow语句再判断deny语句,反之亦然。

判断原则分4步:

1. 首先判断默认的;

2. 然后判断逗号前的;

3. 最后判断逗号后的;

4. 最终按顺序叠加而得出判断结果。

 

下面是测试过的例子:
——————————–
Order deny,allow
allow from all
deny from 219.204.253.8
#全部都可以通行
——————————-
Order deny,allow
deny from 219.204.253.8
allow from all
#全部都可以通行
——————————-
Order allow,deny
deny from 219.204.253.8
allow from all
#只有219.204.253.8不能通行
——————————-
Order allow,deny
allow from all
deny from 219.204.253.8
#只有219.204.253.8不能通行
——————————-
Order allow,deny
deny from all
allow from 219.204.253.8
#全部都不能通行
——————————-
Order allow,deny
allow from 219.204.253.8
deny from all
#全部都不能通行
——————————-
Order deny,allow
allow from 219.204.253.8
deny from all
#只允许219.204.253.8通行
——————————-
Order deny,allow
deny from all
allow from 219.204.253.8
#只允许219.204.253.8通行
——————————-
Order deny,allow
#全部都可以通行(默认的)
——————————-
Order allow,deny
#全部都不能通行(默认的)
——————————-
Order allow,deny
deny from all
#全部都不能通行
——————————-
Order deny,allow
deny from all
#全部都不能通行
——————————-
对于上面两种情况,如果换成allow from all,则全部都可以通行!
——————————-
Order deny,allow
deny from 219.204.253.8
#只有219.204.253.8不能通行
——————————-
Order allow,deny
deny from 219.204.253.8
#全部都不能通行
——————————-
Order allow,deny
allow from 219.204.253.8
#只允许219.204.253.8通行
——————————-
Order deny,allow
allow from 219.204.253.8
#全部都可以通行
——————————-
order deny,allow
allow from 218.20.253.2
deny from 218.20
#代表拒绝218.20开头的IP,但允许218.20.253.2通过;而其它非218.20开头的IP也都允许通过。
——————————-
order allow,deny
allow from 218.20.253.2
deny from 218.20
#和上面的差不多,只是掉换的order语句中的allow、deny先后顺序,但最终结果表示全部都拒绝!

 

 

 

分布式文件系统MFS、Ceph、GlusterFS、Lustre的比较

MooseFS(MFS) Ceph GlusterFS Lustre
Metadata server 单个MDS。存在单点故障和瓶颈。 多个MDS,不存在单点故障和瓶颈。MDS可以扩展,不存在瓶颈。 无,不存在单点故障。靠运行在各个节点上的动态算法来代替MDS,不需同步元数据,无硬盘I/O瓶颈。 双MDS(互相备份)。MDS不可以扩展,存在瓶颈。
FUSE 支持 支持 支持 支持
访问接口 POSIX POSIX POSIX POSIX/MPI
文件分布/数据分布 文件被分片,数据块保存在不同的存储服务器上。 文件被分片,每个数据块是一个对象。对象保存在不同的存储服务器上。 Cluster Translators(GlusterFS集群存储的核心)包括AFR、DHT(和Stripe三种类型。AFR相当于RAID1,每个文件都被复制到多个存储节点上。Stripe相当于RAID0,文件被分片,数据被条带化到各个存储节点上。Translators可以组合,即AFR和stripe可以组成RAID10,实现高性能和高可用。 可以把大文件分片并以类似RAID0的方式分散存储在多个存储节点上。
冗余保护/副本 多副本 多副本 镜像
数据可靠性 由数据的多副本提供可靠性。 由数据的多副本提供可靠性。 由镜像提供可靠性。 由存储节点上的RAID1或RAID5/6提供可靠性。假如存储节点失效,则数据不可用。
备份 提供备份工具。支持远程备份。
故障恢复 手动恢复 当节点失效时,自动迁移数据、重新复制副本。 当节点、硬件、磁盘、网络发生故障时,系统会自动处理这些故障,管理员不需介入。
扩展性 增加存储服务器,可以提高容量和文件操作性能。但是由于不能增加MDS,因此元数据操作性能不能提高,是整个系统的瓶颈。 可以增加元数据服务器和存储节点。容量可扩展。文件操作性能可扩展。元数据操作性能可扩展。 容量可扩展。 可增加存储节点,提高容量可文件操作性能,但是由于不能增加MDS,因此元数据操作性能不能提高,是整个系统的瓶颈。
安装/部署 简单 简单 简单 复杂。而且Lustre严重依赖内核,需要重新编译内核。
开发语言 C C++ C C
适合场景 大量小文件读写 小文件 适合大文件。对于小文件,无元数据服务设计解决了元数据的问题。但GlusterFS并没有在I/O方面作优化,在存储服务器底层文件系统上仍然是大量小文件,本地文件系统元数据访问是瓶颈,数据分布和并行性也无法充分发挥作用。因此,GlusterFS的小文件性能还存在很大优化空间。 大文件读写
产品级别 小型 中型 中型 重型
应用 国内较多 较多用户使用 HPC领域。
优缺点 实施简单,但是存在单点故障。 不稳定,目前还在实验阶段,不适合于生产环境。 无元数据服务器,堆栈式架构(基本功能模块可以进行堆栈式组合,实现强大功能)。具有线性横向扩展能力。由于没有元数据服务器,因此增加了客户端的负载,占用相当的CPU和内存。但遍历文件目录时,则实现较为复杂和低效,需要搜索所有的存储节点。因此不建议使用较深的路径。 很成熟、很庞大。

php5.3之后版本配置php-fpm.conf

从php5.3版本开始,php默认已经嵌入了php-fpm的支持,并且php-fpm的配置文件php-fpm.conf 也使用了和php.ini的同样格式。
默认的配置文件中有很多内容,大多都被注释掉了,注意php-fpm.conf 使用 ‘;’ 注释。

  1. [global]
  2. pid = /usr/local/php/var/run/php-fpm.pid
  3. error_log = /usr/local/php/var/log/php-fpm.log
  4. [www]
  5. listen = /tmp/php-fcgi.sock
  6. user = php-fpm
  7. group = php-fpm
  8. pm = dynamic
  9. pm.max_children = 50
  10. pm.start_servers = 20
  11. pm.min_spare_servers = 5
  12. pm.max_spare_servers = 35
  13. pm.max_requests = 500
  14. rlimit_files = 1024

这些已经可以满足大多应用,但是有时候会有一些特殊需求。简单解释一下配置中的各个参数的含义:
首先,配置分为两个部分,第一部分 [global] 为全局配置项,用来定义日志、pid等相关内容。
第二部分[www], 这个为资源池配置项,其中[]内的字符串为自定义内容,我们也可以写成域名,比如 [www.example.com]
这部分内容用来定义,各个域名所使用的资源分配。
1. listen 用来定义该资源池所监听的socket,也可以是tcp形式;
2. user、group用来定义php-fpm以哪个账号和组的身份来运行;
3. pm = dynamic   如何控制子进程,选项有static和dynamic。
如果选择static,则由pm.max_children指定固定的子进程数。
如果选择dynamic,则由以下参数决定:
pm.max_children ,子进程最大数
pm.start_servers ,启动时的进程数

pm.start_servers默认值的公式:min_spare_servers + (max_spare_servers – min_spare_servers) / 2

pm.min_spare_servers ,保证空闲进程数最小值,如果空闲进程小于此值,则创建新的子进程
pm.max_spare_servers ,保证空闲进程数最大值,如果空闲进程大于此值,此进行清理
对于专用服务器,pm可以设置为static。

4. pm.max_children 这个选项来定义,最大开启的php-fpm子进程数量,根据机器的硬件配置来定义,如果内存高于4G,设置为200或者以上,如果低于4G,比如1G内存,设置50就可以了

5.  pm.max_requests   设置每个子进程重生之前服务的请求数. 对于可能存在内存泄漏的第三方模块来说是非常有用的. 如果设置为 ’0′ 则一直接受请求. 设置为500就可以了。

6. rlimit_files = 1024  设置文件打开描述符的rlimit限制.  一般情况下,设置为1024就足够了。

除了这些配置参数外,另外还有几个常用的,那就是sloglog和open_basedir

7. slowlog = log/www.discuz.net.slow  这里定义,slow log的路径,当php脚本执行时间超过 request_slowlog_timeout 值时,会记录slowlog 它用来帮助我们排查程序哪里有问题,提高程序的处理速度。

8. request_slowlog_timeout = 1 php脚本执行超时时间

9. php_admin_value[open_basedir]=/data/www/:/tmp/
这个选项是非常关键的安全选项,把php的执行账号只限定在指定的目录里,这样可以防止网站被入侵后,黑客获取其他站点的文件信息和服务器的某些关键信息。

php-fpm.conf 中可以定义多个 资源池,也就是说,我们还可以继续再写一个不同的:

  1. [www2]
  2. listen = /tmp/php-fcgi2.sock
  3. user = nobody
  4. group = nobody
  5. pm = dynamic
  6. pm.max_children = 50
  7. pm.start_servers = 20
  8. pm.min_spare_servers = 5
  9. pm.max_spare_servers = 35
  10. pm.max_requests = 500
  11. rlimit_files = 1024

其中,各个选项都可以和 [www]有所不同。

mysql连接类型与socket通信原理说明(转)

原文:http://blog.fity.cn/post/348/

MySQL连接类型中的localhost与127.0.0.1、IP区别:
localhost与127.0.0.1的区别是什么?相信有人会说是本地ip,曾有人说,用127.0.0.1比localhost好,可以减少一次解析。 看来这个入门问题还有人不清楚,其实这两者是有区别的。

NO.1 – 普通接说:
localhost也叫local ,正确的解释是:本地服务器
127.0.0.1在windows等系统的正确解释是:本机地址(本机服务器)

NO.2:
localhost(local)是不经网卡传输!这点很重要,它不受网络防火墙和网卡相关的的限制。
127.0.0.1是通过网卡传输,依赖网卡,并受到网络防火墙和网卡相关的限制。
一般设置程序时本地服务用localhost是最好的,localhost不会解析成ip,也不会占用网卡、网络资源。
有时候用localhost可以,但用127.0.0.1就不可以的情况就是在于此。猜想localhost访问时,系统带的本机当前用户的权限去访问,而用ip的时候,等于本机是通过网络再去访问本机,可能涉及到网络用户的权限。

NO.3 – MySQL被连接时主机类型:
1、 mysql -h 127.0.0.1 的时候,使用TCP/IP连接,
mysql server 认为该连接来自于127.0.0.1或者是”localhost.localdomain”
2、mysql -h localhost 的时候,是不使用TCP/IP连接的,而使用Unix socket;
此时,mysql server则认为该client是来自”localhost”

在mysql权限管理中的”localhost”有特定含义:
—— MySQL手册 5.6.4 ….. A Host value may be a hostname or an IP number, or ‘localhost’ to indicate the local host.

注意:虽然两者连接方式有区别,但当localhost 为默认的127.0.0.1时,两种连接方式使用的权限记录都是以下的记录(因为记录在前,先被匹配)
Host: localhost
User: root

MySQL连接类型证明:

# mysql -h 127.0.0.1  -u root -pfity.cn#123
ERROR 2003 (HY000): Can’t connect to MySQL server on ‘127.0.0.1’ (111)[需要指定端口,反之收到这个错误]

# mysql -h 127.0.0.1 -P 3307 -u root -pfity.cn#123

mysql> status;
————–
mysql  Ver 14.12 Distrib 5.0.95, for redhat-linux-gnu (i686) using readline 5.1

Connection id:          1599
Current database:
Current user:           root@127.0.0.1
SSL:                    Not in use
Current pager:          stdout
Using outfile:          ”
Using delimiter:        ;
Server version:         5.1.48-log Source distribution
Protocol version:       10
Connection:             127.0.0.1 via TCP/IP  //注意这里
Server characterset:    latin1
Db     characterset:    latin1
Client characterset:    latin1
Conn.  characterset:    latin1
TCP port:               3307
Uptime:                 5 hours 54 min 48 sec

Threads: 1  Questions: 5432  Slow queries: 1619  Opens: 72  Flush tables: 1  Open tables: 65  Queries per second avg: 0.255
————–

# mysql -h 192.168.1.246  -u root -pfity.cn#123

ERROR 2003 (HY000): Can’t connect to MySQL server on ‘192.168.1.246’ (111)[需要指定端口,反之收到这个错误]

# mysql -h 192.168.1.246 -P 3307 -u root -pfity.cn#123

mysql> status;
————–
mysql  Ver 14.12 Distrib 5.0.95, for redhat-linux-gnu (i686) using readline 5.1

Connection id:          1598
Current database:
Current user:           root@192.168.1.246
SSL:                    Not in use
Current pager:          stdout
Using outfile:          ”
Using delimiter:        ;
Server version:         5.1.48-log Source distribution
Protocol version:       10
Connection:             192.168.1.246 via TCP/IP    //注意这里
Server characterset:    latin1
Db     characterset:    latin1
Client characterset:    latin1
Conn.  characterset:    latin1
TCP port:               3307
Uptime:                 5 hours 53 min 54 sec

Threads: 1  Questions: 5428  Slow queries: 1619  Opens: 72  Flush tables: 1  Open tables: 65  Queries per second avg: 0.255
————–

# mysql -h localhost  -u root -pfity.cn#123[连接OK]

# mysql -h localhost -P 3307 -u root -pfity.cn#123

mysql> status;
————–
mysql  Ver 14.12 Distrib 5.0.95, for redhat-linux-gnu (i686) using readline 5.1

Connection id:          1600
Current database:
Current user:           root@localhost
SSL:                    Not in use
Current pager:          stdout
Using outfile:          ”
Using delimiter:        ;
Server version:         5.1.48-log Source distribution
Protocol version:       10
Connection:             Localhost via UNIX socket    //注意这里
Server characterset:    latin1
Db     characterset:    latin1
Client characterset:    latin1
Conn.  characterset:    latin1
UNIX socket:            /var/lib/mysql/mysql.sock
Uptime:                 5 hours 56 min 18 sec

Threads: 1  Questions: 5436  Slow queries: 1619  Opens: 72  Flush tables: 1  Open tables: 65  Queries per second avg: 0.254
————–

从这里看以看出,通过通过unix domain socket方式连接mysql时,你不需要特意指定端口,按照mysql官方所说通过unix domain socket方式连接mysql较快于TCP/IP方式。不过,如果通过socket方式连接mysql,当mysql.sock文件不再是默认的名称或存放路径时,你将会收到下面这个错误信息,当然,你可以需要在php代码config中声明一个变量指定unix domain socket路径或者在php.ini配置文件中定义也可。错误信息如下:
ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/lib/mysql/mysql.sock’ (2)

默认情况下我们PHP实例和mysql通信是走TCP/IP的,但如果你加载了socket模块,默认会走sock文件连接,但如果你的linux主机上没有指定默认的socket文件,这样如果你使用mysql_connect连接的话,经常我们使用mysql_connect()或socket方式连接mysql时会收到错误:
No such file or directory、Can’t connect to local MySQL server through socket… ,如图:

然而此时mysql客户端可以正常使用,当然此刻你通过mysqli或pdo方式连接一般情况下也是不会有错误的,所以可以确定不是服务器的问题。

简而言之:主要区别是localhost是通过unix domain socket方式来连接,而127.0.0.1则是走的TCP协议方式连接
这是linux套接字网络的特性,win平台不会有这个问题

php.ini文件中如何定义mysql socket路径:
mysql.default_socket = mysql.sock //绝对路径就可以了
或者你可以在my.cnf文件中把mysql.sock路径指向/tmp/mysql.sock也可以

请注意,如果你指定localhost作为一个主机名,mysqladmin默认使用Unix套接字文件连接,而不是TCP/IP。从 MySQL 4.1开始,通过–protocol= TCP | SOCKET | PIPE | MEMORY}选项,你可以显示地指定连接协议。

Socket简要通信机制与原理说明
根据连接启动的方式以及本地套接字要连接的目标,套接字之间的连接过程可以分为三个步骤:服务器监听,客户端请求,连接确认。

服务器监听:是服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。

客户端请求:是指由客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。

连接确认:是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。

.net中Session的配置

一.摘要

所有Web程序都会使用Session保存数据. 使用独立的Session服务器可以解决负载均衡场景中的Session共享问题.本文介绍.NET平台下建立Session服务器的几种办法, 并介绍在使用Session时的各种经验和技巧.

二.关于Session,SessionID和Cookies

Session数据保存在服务器端, 但是每一个客户端都需要保存一个SessionID, SessionID保存在Cookies中, 关闭浏览器时过期.

在向服务器发送的HTTP请求中会包含SessionID, 服务器端根据SessionID获取获取此用户的Session信息.

很多初级开发人员不知道SessionID和Cookies的关系, 所以常常认为两者没有联系. 这是不正确的. 正是因为SessionID保存在Cookies中, 所以在我们保存Cookies的时候,一定要注意不要因为Cookies的大小和个数问题而导致SessionID对象. 在我们的程序中, 对SessionID的Cookies有特殊的处理:

/// <summary> /// 写入cookie. /// </summary> /// <param name=”day”></param> /// <returns></returns> public bool SetCookie(int day) { string CookieName = GetType().ToString(); HttpCookie SessionCookie = null; //对 SessionId 进行备份. if (HttpContext.Current.Request.Cookies[“ASP.NET_SessionId”] != null) { string SesssionId = HttpContext.Current.Request.Cookies[“ASP.NET_SessionId”].Value.ToString(); SessionCookie = new HttpCookie(“ASP.NET_SessionId”); SessionCookie.Value = SesssionId; }

//省略掉中间的代码部分.只保留备份SessionID和找回SessionID的逻辑

//如果cookie总数超过20 个, 重写ASP.NET_SessionId, 以防Session 丢失. if (HttpContext.Current.Request.Cookies.Count > 20 && SessionCookie != null) { if (SessionCookie.Value != string.Empty) { HttpContext.Current.Response.Cookies.Remove(“ASP.NET_SessionId”); HttpContext.Current.Response.Cookies.Add(SessionCookie); } } return true; }

三.搭建Session服务器的几种方式

将Session保存在独立的服务器中可以实现在多台Web服务器之间共享Session.虽然我们也可以自己开发Session存储系统, 但是使用ASP.NET自带的存储机制将更加便捷.

.NET提供了5种保存Seission的方式:

方式名称 存储方式 性能
Off 设置为不使用Session功能
InProc 设置为将Session存储在进程内,就是ASP中的存储方式,这是默认值。 性能最高
StateServer 设置为将Session存储在独立的状态服务中。通常是aspnet_state.exe进程. 性能损失10-15%
SQLServer 设置将Session存储在SQL Server中。 性能损失10-20%
Customer 自定制的存储方案 由实现方式确定

我们可以在Web.Config中配置程序使用的Session存储方式.默认情况下是InProc, 即保存在IIS进程中. 关于Off, InProc和Customer本文不做讲解. 相关文章大家都可以在网上搜索到.

下面主要讲解 StateServer 和 SQLServer 的应用.

四.使用 StateServer 模式搭建Session服务器

(1)服务器端配置

1.启动 Asp.net State service服务.(这个服务默认的状态为手动.修改为自动并启动.)

2.修改注册表: [HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\aspnet_state\Parameters]

设置 AllowRemoteConnection = 1 , 设置 Port = 42424 (十进制,默认即为42424)

Port是服务的端口号

AllowRemoteConnection 表示是否允许其他机器连接,0为仅能本机使用,1为可以供其他机器使用.

(2)客户端设置

在Web应用程序的Web.Config中, 我们需要修改 <configuration> / <system.web> 的<sessionState>节点.如果没有

没有则添加(默认使用的是InProc方式)

<sessionState mode=”StateServer” stateConnectionString=”tcpip=服务器ip:42424″ cookieless=”false” timeout=”60″/>

上面的参数我们可以根据需要修改.

五.使用SqlServer模式搭建Session服务器

(1)服务器端配置

使用SqlServer模式搭建Session服务器端有两种方式. ASP.NET 1.0和1.1版本请使用方式a, 2.0即以上版本请使用方式b.

a.使用SQL文件创建Session数据库

在ASP.NET 1.0和1.1 版本中, 只能使用这种方式.对于2.0及其以上版本,请使用aspnet_regsql.exe工具.(当然此方法也通用2.0版本)

.net提供了数据库安装脚本,可以在机器的windows文件夹中找到:

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ InstallSqlState.sql

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ InstallSqlStateTemplate.sql

根据ASP.NET的版本不同, 需要使用不同的SQL脚本. ASP.NET主要有1.1和2.0两个版本,可以在不同的版本文件夹找到这两个SQL.

InstallSqlState.sql 是创建默认名称的数据库”[ASPState]”.此SQL可以直接运行.

InstallSqlStateTemplate.sql 可以使用自己指定的数据库保存数据.此SQL需要自己修改后运行, 打开SQL文件将其中 [DatabaseNamePlaceHolder] 替换为自己指定的数据库名称.

执行installsqlstate.sql时不需要指定数据库,可以在任意数据库上执行.此SQL会自己创建新的数据库

b. 使用aspnet_regsql.exe工具

ASP.NET 2.0版本后微软提供了aspnet_regsql.exe工具可以方便的配置Session数据库.该工具位于 Web 服务器上的”系统根目录\Microsoft.NET\Framework\版本号”文件夹中.

使用举例:

aspnet_regsql.exe -S . -U sa -P 123456 -ssadd -sstype p

-S参数:

表示数据库实例名称. 可以用”.”表示本机.

-U和-P参数:

表示用户名和密码.

-E参数:

可以再-U –P 与 -E中选择一组. –E表示以当前系统用户通过windows身份验证登录数据库, -U -P则是使用SqlServer用户登录数据库.

-ssadd / –ssremove 参数:

-ssadd表示是添加Session数据库, -ssremove表示移除Session数据库.

sstype 参数:

选项 说明
t 将会话数据存储到 SQL Server tempdb 数据库中。这是默认设置。如果将会话数据存储到 tempdb 数据库中,则在重新启动 SQL Server 时将丢失会话数据。
p 将会话数据存储到 ASPState 数据库中,而不是存储到 tempdb 数据库中。
c 将会话数据存储到自定义数据库中。如果指定 c 选项,则还必须使用 -d 选项包括自定义数据库的名称。

(2)Session客户端设置

此房是同样需要Web应用程序修改Web.Config中的<sessionState>节点.如果使用默认的数据库(ASPState库), 则配置如下:

<sessionState mode=”SQLServer” sqlConnectionString=”server=192.168.9.151; uid=sa; pwd=123456;” />

如果使用了自定义的数据库名称,则还需要制定allowCustomSqlDatabase属性并在数据库连接串中指定数据库:

<sessionState mode=”SQLServer” allowCustomSqlDatabase=”true” sqlConnectionString=”server=192.168.9.151; DataBase=MyAspState;uid=sa; pwd=123456;” />

六.使用经验与技巧总结

下面是SessionID, Session_End时间, StatServer模式 和 SqlServer模式的各种经验和技巧总结.

(1)StateServer模式:

1.在web farm中,请确认在所有的web服务器上有相同的<machineKey>

2. 要保存在Session中的对象是可序列化的。

3.为了在web farm中的不同web服务器上维护session state,IIS Metabase中的网站应用程序路径(如\LM\W3SVC\2)应该在所有的服务器上保持一致(大小写敏感).

4. ASP.NET处理Session是在Machine.Config中配置的HttpModuel模块, 在.NET的安装目录下的Config文件夹中, 查看Web.Config(1.1版本是在Machine.Config):

<httpModules> …

<add name=”Session” type=”System.Web.SessionState.SessionStateModule”/>

</httpModules>

确认此模块是否存在.

5.StateServer不支持负载均衡, 所以如果大并发推荐使用SqlServer模式, 可以享受到SqlServer的高性能和安全性.虽然存储效率会有下降.

6.需要让所有机器的MachineKey相同.在Machine.Config中配置:

<machineKey validationKey=”1234567890123456789012345678901234567890AAAAAAAAAA” decryptionKey=”123456789012345678901234567890123456789012345678″ validation=”SHA1″ decryption=”Auto” />

(2)SqlServer模式:

1. 要保存在Session中的对象是可序列化的。

2. 如果使用了默认是数据库, 则在客户端配置文件中的数据库链接字符串的用户,需要拥有ASPState和tempdb两个库的dbowner权限.

3. 在SQLServer模式下,session过期是由SQL Agent使用一个注册任务完成的,要确认SQL Agent已经运行。否则无法清理过期的Session数据, 会导致数据库数据一直增加.

4. 如果使用SqlServer模式时, 对于Web场中的各服务器的 ASP.NET 应用程序路径必须是相同的。请在 IIS 配置数据库中对 Web 场中的所有 Web 服务器进行 Web 站点的应用程序路径同步。大小写一定要相同,因为 Web 站点的应用程序路径是区分大小写的。

5.需要让所有机器的MachineKey相同.在Machine.Config中配置:

<machineKey validationKey=”1234567890123456789012345678901234567890AAAAAAAAAA” decryptionKey=”123456789012345678901234567890123456789012345678″ validation=”SHA1″ decryption=”Auto” />

(3)Session:

1. 不能直接通过Session服务器在ASP.NET和ASP之间共享Session. 请使用微软提供的解决方案:
http://msdn.microsoft.com/zh-cn/library/aa479313.aspx

2. 在不同的应用程序或一个网站的不同虚拟目录之间无法共享Session

3. Session的过期时间是滑动时间.

4. Session存储.NET自带的值类型性能最优. 存储对象会降低性能.

(4)SessionID:

1.SessionID 还可以保存在URL上, 设置Web.Config文件中的System.Web/sessionState节点的Cookiesless属性即可:

<sessionState cookieless=”UseUri” />

2. 一般在Session超时或删除之后,SessionID保持不变. 因为Session过期后会在服务器端清除数据, 但是SessionID保存在用户浏览器上, 所以只要浏览器不关闭则HTTP头中的SessionID保持不变.

3.关闭浏览器后再访问, SessionID会不同.

4.每打开一个IE6窗口, SessionID都不同, 在IE6中两个窗口的Session不能共享.

5.FireFox的标签页和新的FireFox窗口, SessionID都相同, 在FF的窗口和标签页上Session能共享.

6.对于包含FrameSet的页面,比如:

<frameset cols=”25%,50%,25%”> <frame src=”SessionID.aspx”> <frame src=”SessionID.aspx”> <frame src=”SessionID.aspx”> </frameset>

如果后缀名是.htm并且.htm文件没有交给ASP.NET的ISAPI处理, 那么根据服务器速度在每个Frame页面生成不同的SessionID, 再刷新后相同都等于最后一个SessionID.

解决办法是将.htm后缀改成.aspx, 或者将.htm文件交给ASP.NET的ISAPI处理.

(5)Session_End事件:

1. Session_End仅在InProc模式中可用

2. 关闭浏览器,Session_End是不会触发的。HTTP是一种无状态协议,服务器没有办法知道你的浏览器是否已经关闭。

3. 当Session因为时间过期或调用Session.Abandon时,Session_End才会触发.Session.Clear()仅仅是清除数据,但没有删除session。

4. Session_End由一个后台线程触发,使用工作者进程账号运行. 所以程序不会通知发生的错误.

5. 在Session_End访问数据库要考虑权限问题. Session_End是用运行工作者进程(aspnet_wp.exe)的帐号运行的,这个账号可以在machine.config中指定。因此,在Session_End中,如果使用integrity security连接SQL,它将使用工作者进程账号身份连接,这可能会引起登录失败.

6.因为Session_End是有独立线程出发的, 所以在Session_End中无法使用HttpContext对象(Request,Response,Server等对象都在HttpContext中),  即无法使用 Response.Redirect 和Server.Transfer等方法.

七.总结

我已经使用SqlServer模式对公司的多台服务器实现了Session共享, 服务器重启也不会导致用户预定过程重新开始(预定过程需要的Session不会丢失).  希望本文对具体的Session服务器搭建人员有所帮助.

参考文献:

使用一个 SQL 数据库 SQL Server 会话状态的所有应用程序可能导致瓶颈

http://support.microsoft.com/kb/836680/zh-cn

ASP.NET 中 Session 实现原理浅析 [1] /[2]

http://www.cnblogs.com/flier/archive/2004/08/04/30226.html

http://www.cnblogs.com/flier/archive/2004/08/07/30902.html