msgbartop
很傻很天真的程序员
msgbarbottom

02 七 10 MySQL Query Cache

MySql Query Cache
我们多知道mysql的查询是有缓存的,MySqlQueryCache不缓存执行计划而是整个结果集。我们要从Cache去中命中我们的查询结果,Query必须是完全一样的,导致的结果是Query改变就无法命中我们的查询,mysql会把改变后的Query作为一个新的Cache。因为mysql缓存的是整个结果集,所以Qcache_hits并不是很高。
1、Cache 机制对应用程序是透明的。

2、只缓存整个查询结果集,即对子查询,内联视图和部分UNION的查询是不缓存的。
注:我在执行部分UNION的时候,观察Qcache_queries_in_cache值也是增加的 不知道是不是和部分UNION的查询是不缓存有点矛盾?请大牛指正 我现在姑且当作union查询是缓存的

3、缓存机制工作在Packet 级别,第二项的只缓存整个查询结果集就是因为局限于这个机制的原因。由于没有额外的转换和处理,所以保证缓存结果集返回能够非常快。

4、缓存处理在解析查询前进行,保证缓存高性能的一个原因就是查询缓存在执行查询解析前先查找是否已经存在缓存,如果已经存在查询缓存,则直接返回结果集。

5、查询必须绝对完全同,由于在查找缓存是否存在前不进行查询解析( Query Parser )所以查询并没有经过规范化处理(Normalized),因此缓存查找的过程是按字节顺序进行的 ( Byte by byte )。更具体点说吧:在每次查询时包不同的注释、多余的空格以及大小写不同等等,都不会指向同一个缓存结果集。
注:sql语句必须完全一致 包括条件的值 如select * from user_id=1 和select * from user_id=2会作为两个不同的缓存

6、只有 SELECT 语句被缓存。 插入、删除、更新当然不需要进行缓存了,同时 SHOW 命令和 存储过程 stored procedure (包括存储过程中的SELECT)也不会进入缓存结果集,
查询缓存失效的粒度级别的是表,当表被修改时,所有与改表相关的缓存立即失效( invalidation )。
注:对同一张表的update、delete、insert操作会清空该表的QueryCache

7、空格和注释不要出现在查询语句的最前面,当查找缓存时第一个字幕如果不是”S” ,就会停止查询缓存结果集了。第5、6项已经解释过了。
注:我试过在SQL前面有空格是可以被缓存的,mysql缓存的时候会自动去掉前面的空格的;
在SQL前面有注释也会被缓存,等同于没有注释,我用的SQL语句如:/**/select

8、不支持预备查询 prepared statement 和 游标 cursors 。?

9、不支持事务处理。?

10、查询结果必须完全一致,才能进入缓存结果集。比如:查询语句中有 UUID , RAND , CONNECTION_ID 等会动态改变查询结果集的函数,都不会进入缓存结果集的。Ok

11、过长时间的查询缓存容易造成碎片 fragmentation  ,这一点和Windows的磁盘管理的碎片整理类似,长时间查询缓存产生的碎片对执行效率有一定影响。可以把查询缓存碎片看作是是查询缓存可用内存(Qcache_free_memory)的块(Qcache_free_blocks )。FLUSH QUERY CACHE  命令可以削除这种情况。

12、设定适当大小的查询缓存用的内存,由于前面提到的一些原因,一般情况下MySql 的查询缓存机制对内存的需求不可能无限增长,因此设定一个适当的查询缓存内存值是比较经济的做法。可以通过查看 Qcache_free_memory 和 Qcache_lowmem_prunes 的状态来进行适当设置。

13、查询缓存的运行模式,默认情况下开启缓存后MySql 的缓存机制对全局的有效,如果你只想对特定的查询语句使用缓存,可以通过把 query_cache_type  设定为 “DEMAND” 并且在查询语句中加入: SQL_CACHE  来进行,比如:SELECT SQL_CACHE DomoloSeoHelper from domolo where author=’tianchunfeng’ 。

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

几个命令:
mysql> show status like ‘Qcache%’; #查看mysql查询缓存的运行时状态
mysql> reset query cache ;#重置mysql查询缓存

来源:http://tianchunfeng.spaces.live.com/blog/cns!819E33AA1808A272!315.entry
具体解释参考:  http://dev.mysql.com/doc/refman/5.0/en/query-cache-status-and-maintenance.html

02 七 10 Perl中如何注释多行

最常用的方法是使用 POD(Plain Old Documentations) 来进行多行注释。方法如下:

=pod
codes to comment
=cut

注意:=pod =cut只能在行首

02 七 10 解决window.close()在IE7下弹出对话框的问题

window.opener=null;
window.open(”,’_self’,”);
window.close();

02 七 10 Spring-DM笔记之osgi:reference

现下osgi可谓是一个比较有人气的方向,它为应用系统带来了强大的动态解决方案。在某些程度上osgi同Maven、Antx十分相似,它们都提供了版本化条件化的引用系统,让我们在编译期、运行期拥有更加大的灵活性。同样的思想也可以运用在IOC的实现上,现在主流的IOC一般以名称、类型作为引用依赖定位的依据,并且带有强烈的一对一基数限制,spring-dm的出现将osgi强大的动态能力很自然地集成到IOC容器中,使之易于使用又具备很高的灵活性。

在整合spring和osgi的过程中,要做的很重要的一件事情就是如何将osgi的service引入到spring的管理体系中来。在spring一般依据属性(字段)的名字来确定这个属性的(字段)运行期注入物,但是在osgi的service体系下,光靠简单的名称或者类型来过滤符合条件的service,可能会得到好几个候选对象,这同spring的依赖解析是有矛盾的。再加上osgi的动态性,service的生命周期比较复杂,符合条件的service可能随时会被卸载,当然也可能有新的符合条件的service不知道什么时候就出现了。

在spring-dm中,OsgiNamespaceHandler负责解释所有同osgi相关的xml片段。用于解释导入osgi服务相关的主要有以下代码:
registerBeanDefinitionParser(”reference“, new ReferenceBeanDefinitionParser());
registerBeanDefinitionParser(”list“, new CollectionBeanDefinitionParser() {
protected CollectionType collectionType() {
return CollectionType.LIST;
}
});
registerBeanDefinitionParser(”set“, new CollectionBeanDefinitionParser() {
protected CollectionType collectionType() {
return CollectionType.SET;
}
});

这里主要看一下关于reference的内容,list、set基本的思路与reference基本一致,其实就是reference的复数(集合)形式。

首先可以看到负责解释reference的是ReferenceBeanDefinitionParser,这个类的精简之后的代码如下:
class ReferenceBeanDefinitionParser extends AbstractReferenceDefinitionParser {
protected Class getBeanClass(Element element) {
return OsgiServiceProxyFactoryBean.class;
}
}

从这里基本可以看出,一个reference元素被解析之后,将产生一个关于OsgiServiceProxyFactoryBean的BeanDefinition,xml元素携带的信息由这个FactoryBean接受并负责在运行创建合适的service对象代理。下面来看看这个FactoryBean中最主要的一个方法的代码:

Object createProxy() {

// 关于调用时线程上下文ClassLoader的拦截器。
// osgi规范没有定义在导出的service被调用时的线程上下文ClassLoader,spring-dm通过环绕拦截器的方式增加了这一控制点。在xml配置中可以指定unmanaged、service-provider。
final ServiceProviderTCCLInterceptor tcclAdvice = new ServiceProviderTCCLInterceptor();
// 监听器,实时获得当前被选中的service,从而实时更新当前的service-provider,设置正确的ClassLoader。说白了就是提供正确的ClassLoader给上面的拦截器。
final OsgiServiceLifecycleListener tcclListener = tcclAdvice.new ServiceProviderTCCLListener();
// 从变量的命名可以看出lookupAdvice,非常可能是在确定当前符合各项过滤限制的service对象,
实际上确实是这样,但是由于osgi的动态性,对于service的管理还是有一定复杂度的。
final ServiceDynamicInterceptor lookupAdvice = new ServiceDynamicInterceptor(getBundleContext(),
getUnifiedFilter(), getAopClassLoader());
// 设置service的依赖策略
lookupAdvice.setRequiredAtStartup(getCardinality().isMandatory());
// 这里可以看到在lookupAdvice被赋予了两部分的监听器。第一部分是getListeners()提供的,这一部分是由reference的子元素listener定义的。第二部分是tcclListener,这一个就是刚刚看到的那个ClassLoader的监听器了。
OsgiServiceLifecycleListener[] listeners = addListener(getListeners(), tcclListener);

lookupAdvice.setListeners(listeners);
synchronized (monitor) {
lookupAdvice.setRetryParams(retriesNumber, retryTimeout);
retryTemplate = lookupAdvice.getRetryTemplate();
}
lookupAdvice.setApplicationEventPublisher(applicationEventPublisher);

lookupAdvice.setStateListeners(stateListeners);
lookupAdvice.setServiceImporter(this);

// 定制一个ServiceProxyCreator,这里主要是定制createDispatcherInterceptor,createServiceProviderTCCLAdvice
ServiceProxyCreator creator = new AbstractServiceProxyCreator(getInterfaces(), getAopClassLoader(),
getBeanClassLoader(), getBundleContext(), getContextClassLoader()) {
ServiceInvoker createDispatcherInterceptor(ServiceReference reference) {
// 由lookupAdvice充当ServiceInvoker
return lookupAdvice;
}
Advice createServiceProviderTCCLAdvice(ServiceReference reference) {
return tcclAdvice;
}
};

// 通过ServiceProxyCreator创建一个service的代理对象,处理对于这个service的方法调用。
ProxyPlusCallback proxyPlusCallback = creator.createServiceProxy(lookupAdvice.getServiceReference());

synchronized (monitor) {
proxy = proxyPlusCallback.proxy;
destructionCallback = new DisposableBeanRunnableAdapter(proxyPlusCallback.destructionCallback);
}

lookupAdvice.setProxy(proxy);

lookupAdvice.afterPropertiesSet();

return proxy;
}

createServiceProxy方法大致的思路就是利用spring-aop的ProxyFactory结合一系列相关的advice创建出合适的proxy。到这儿,粗略的处理过程就是这样,但是好像几乎没有看到同osgi相关的什么东西,这里我们忽略了一个十分重要的对象ServiceDynamicInterceptor,正是这个拦截器它处理了service的定位。

ServiceDynamicInterceptor继承了ServiceInvoker,先看看ServiceInvoker的代码:
protected Object doInvoke(Object service, MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
try {
return method.invoke(service, invocation.getArguments());
}
catch (IllegalAccessException ex) {
throw (RuntimeException) new IllegalAccessException(….)
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
public final Object invoke(MethodInvocation invocation) throws Throwable {
return doInvoke(getTarget(), invocation);
}

不难得到getTarget这个方法的实现应该是这个体系中关键的一环,再继续查看在ServiceDynamicInterceptor中getTarget的实现,可以看到它是依赖于private ServiceWrapper wrapper这样一个字段的。在代码中查找对wrapper的操作,很多重要的操作都是由一个名为Listener的ServiceDynamicInterceptor的内部类发起的,而这个内部类唯一的实例在afterPropertiesSet方法中被引用了,OsgiListenerUtils.addSingleServiceListener(bundleContext, listener, filter)。至此终于看到同osgi关联比较紧密的地方了,这是一个监听osgi中关于service状态变更的重要入口。Listener中的serviceChanged方法主要是针对service的注册、修改、卸载做了相应的回调处理,并依据当前已经存在的ServiceReference做必要的更新。当然在卸载的时候会重新启动原始的基于osgi的service查找,newReference = OsgiServiceReferenceUtils.getServiceReference(bundleContext, (filter == null ? null : filter.toString())),其中spring-dm会依据ranking(越大越好)、serviceId(越小越好)的原则过滤出至多一个ServiceReference,然后模拟service修改的方式再次调用serviceChanged方法来处理剩下的问题。最后在适当的地方播发service的bind、unbind事件(tcclListener 等)。如果在调用getTarget方法时不能确定service引用,则表示当前没有任何时候的对象被发布到osgi的运行环境中,这个时候会触发ServiceUnavailableException的抛出。

总的来看,spring-dm对osgi中service的引入是基于aop技术的,通过一个代理对象向外提供一个稳定的统一的引用(占位符),同时通过不同的advice实现它不同的附加功能,最重要的lookupAdvice使用osgi框架的ServiceListener监听相关service的动态更动,从而实时更新目标service(其实是对wrapper对象的实时维护)。从动态性上面来看lookupAdvice有点类似于spring-aop中的TargetSource。
PS:以上代码阅读基于spring-osgi-1.1.2

02 七 10 使用apache的activemq集合JMS处理异步消息

1:先去apache下载

http://activemq.apache.org/ ,大约有25M,要有点耐心

直接打开就可以使用;当然它也提供了安装为windows service的方法

2:配置activemq

在conf文件夹中配置

activemq.xml

主要是配置内存和端口

<policyEntry queue=”>” memoryLimit=”100mb”/>
<policyEntry topic=”>” memoryLimit=”100mb”>
<memoryUsage limit=”50 mb”/>

3:使用web方式访问管理

http://localhost:8161/admin/

很是方便

4:编程方式使用,系统安装后,有一个DEMO,你可以先测试一下,以后就照这个DEMO写就行了

5:在应用中的web.xml配置

<context-param>
<param-name>brokerURI</param-name>
<param-value>/WEB-INF/activemq.xml</param-value>
</context-param>
<listener>
<listener-class>org.activemq.web.SpringBrokerContextListener</listener-class>
</listener>

6:工具类

/**
*
*/
package MQ;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;

/**
* @author Administrator
* 消息的生产者(发送者)
*/
public class JmsSender {

public static void main(String []args) throws JMSException{
//ConnectionFactory:连接工厂,JMS用它创建连接
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD,
“tcp://127.0.0.1:61616″);
//JMS客户端到JMS Provider的连接
Connection connection = connectionFactory.createConnection();
connection.start();
//Session:一个发送或接收消息的线程
Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
//Destination:消息的目的地;消息发送给谁
//获取session注意参数值my-queue是Query的名字
Destination destination = session.createQueue(“my-queue”);
//MessageProducer:消息生产者
MessageProducer producer = session.createProducer(destination);
//设置不持久化
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
//发送一条信息
sendMsg(session,producer);
session.commit();
connection.close();
}

/**
* 在指定的会话上,通过指定的消息生产者发出一条消息
* @param session 消息会话
* @param producer消息生产者
* @throws JMSException
*/
private static void sendMsg(Session session, MessageProducer producer) throws JMSException {
//创建一条文本消息
TextMessage textMessage = session.createTextMessage(“Hello ActiveMQ!”);
//通过消息生产者发出消息
producer.send(textMessage);
System.out.println(“”);
}
}

/**
*
*/
package MQ;

/**
* @author Administrator
* 消息的消费者(接受者)
*/
public class JmsReceiver {

/**
* @param args
* @throws JMSException
*/
public static void main(String[] args) throws JMSException {
//ConnectionFactory:连接工厂,JMS用它创建连接
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD,
“tcp://127.0.0.1:61616″);
//JMS客户端到JMS Provider的连接
Connection connection = connectionFactory.createConnection();
connection.start();
//session:一个发送或接收消息的线程
Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
//Destination:消息的目的地,消息发送给谁
//获取session注意参数值xingbo.xu-queue是一个服务器的queue是一个服务器的queue,须在在ActiveMq的console的配置
Destination destination = session.createQueue(“my-queue”);
//消息者,消息接收者
MessageConsumer consumer = session.createConsumer(destination);
while(true){
TextMessage message = (TextMessage)consumer.receive(1000);
if(null!=message){
System.out.println(“收到消息:”+message.getText());
}else{
break;
}
}
consumer.close();
session.close();
connection.close();
}

}

02 七 10 JMS的安全性

对于JMS服务的安全控制,ActiveMQ提供两种方式:简单授权方式和JAAS授权方式。我们在这里采用简单的授权方式。如果要实现复杂的权限和角色机制,可以使用JAAS方式,这里不予讲述。

JMS安全的配置,在文件${activemq.base}/conf/activemq-security.xml中有范例。打开该文件,可以看到,有两个plugins:simpleAuthenticationPlugin和authorizationPlugin,后者是JAAS授权方式需要用到的,在这里,我们只需要用到前者。

编辑${activemq.base}/conf/activemq.xml文件,加入如下一段代码:

<plugins>
<simpleAuthenticationPlugin>
<users>
<authenticationUser username=”${activemq.username}” password=”${activemq.password}” groups=”users,admins”/>
</users>
</simpleAuthenticationPlugin>
</plugins>

${activemq.username}和${activemq.password}是在credentials.properties文件中设置的用户名和密码。该文件位于${activemq.base}/conf/目录下,打开该文件,设置你的用户名和密码即可。

配置完毕。这样,你的ActiveMQ就需要用户名和密码才能发送和接收JMS消息了。连接ActiveMQ的Java代码相应的改为如下:
ConnectionFactory cf = new ActiveMQConnectionFactory(“myusername”, “mypassword”, “tcp://192.168.1.109:61616″)
在Spring中,则如下:
<bean id=”connectionFactory”>
<property name=”brokerURL” value=”tcp://192.168.1.109:61616″ />
<property name=”userName” value=”myusername” />
<property name=”password” value=”password” />
</bean>

02 七 10 Windows下PHP5和Apache的安装与配置

在这里以PHP5为例介绍一下Windows下Apache和PHP5的安装与配置方法。

一 下载安装程序

Apache可以从http://www.apache.org/dyn/closer.cgi/httpd/binaries/win32/下载

PHP可以从http://www.php.net下载.

二 安装程序

1、Apache的程序安装相对来说要较为的简单一些,我们从网站下来的是一个Windows下的安装程序,我们可以直接双击运行,这样我们就便利Apache在我们的电脑上安下家来了。

2、我们在这里要注意的就是在下载PHP时一定要下载那个zip包的,而不要下载Installer的.将我们下载下来的PHP包解压到C盘下的根目录下,并将解压出来的文件夹改名为php。

三 配置

1、最好是无论使用何种接口(CGI 或者 SAPI)都确保 php5ts.dll 可用,因此必须将此文件放到 Windows 路径中。最好的位置是 Windows 的 system 目录:
c:\windows\system for Windows 9x/ME
c:\winnt\system32 for Windows NT/2000 或者 c:\winnt40\system32 for Windows NT/2000 服务器版
c:\windows\system32 for Windows XP

2、下一步是设定有效的 PHP 配置文件,php.ini。压缩包中包括两个 ini 文件,php.ini-dist 和 php.ini-recommended。建议使用 php.ini-recommended,因为此文件对默认设置作了性能和安全上的优化。

将选择的 ini 文件拷贝到 PHP 能够找到的目录下并改名为 php.ini。PHP 默认在 Windows 目录下搜索 php.ini:

3 在 Windows 9x/ME/XP 下将选择的 ini 文件拷贝到 %WINDIR%,通常为 c:\windows。

在 Windows NT/2000 下将选择的 ini 文件拷贝到 %WINDIR% 或 %SYSTEMROOT% 下,通常为 c:\winnt 或 c:\winnt40 对应于服务器版本。

4 Apache中PHP的设置

有两种方法使得 PHP 工作在 Windows 下的 Apache。一是使用 CGI 二进制文件,另一是使用 Apache 模块 DLL。无论那种方法,您首先必须停止 Apache 服务器,然后编辑 httpd.conf,以配置 Apache 和 PHP 协同工作。

如果我们要使用CGI二进制文件,那么我们要将如下指令插入到 Apache 的 httpd.conf 配置文件中,以设置 CGI 二进制文件:

PHP 以 CGI 方式安装到 Apache 2.0:
ScriptAlias /php/ “c:/php/”
AddType application/x-httpd-php .php
Action application/x-httpd-php “/php/php.exe”

如果我们想把 PHP 作为 Apache 2.0 的模块,那么就一定要移动 php4ts.dll 到 winnt/system32(Windows NT/2000)或 windows/system32(Windows XP),覆盖原有文件(如果有的话),对于 PHP 5,这个文件是 php5ts.dll。然后我们要插入如下两行到 httpd.conf 中,以使我们的 PHP 作为 Apache 的 PHP-Module 安装:

PHP 以模块方式安装到 Apache 2.0:

; For PHP 4 do something like this:
LoadModule php4_module “c:/php/php4apache2.dll”
AddType application/x-httpd-php .php

; For PHP 5 do something like this:
LoadModule php5_module “c:/php/php5apache2.dll”
AddType application/x-httpd-php .php

经过这样的配置以后,我们就安装好了我们的PHP和Apache服务器了。我们可以简单的测试一下:

1、测试Apache:

我们打开浏览器,在地址栏中输入localhost,如果可以出现Apache页面,则说明我们的Apache可以正常工作了。

2、测试PHP设置:

我们可以简单的编写一个PHP页面,我们可以用文本编辑器,输入下面的代码:
<html>
<head><title>hello </title></head>
<body>
<?php echo “hello,php”; ?>
</body>
</html>

然后将这个文件存为hello.php,将其放在Apache的htdocs目录中(我们也可以在http.conf文件中来更改这个目录的),然后在我们的浏览器中输入http://localhost/hello.php,如果能够正确的显示hello,php就说明我们的PHP配置是可以正常工作的。

02 七 10 cassandra api概览

Cassandra的thrift api在0.3后发生大幅改变,在往后的小版本,0.4,0.5和0.6的改变都是向后兼容的。这份文档主要解释与说明在0.5到0.6版本的变化。
Cassandra的客户端api都是基于thrift构建的。值得指出的,这些文档提到的默认值,并是被所有基于thrift api的各种语言所支持的。所有基于thrift的cassandra例子和模板都可以在ThriftExamples上找到。更多关于cassandra客户端可以看ClientOptions
注意:在文档中会类比SQL/关系型数据库讲解cassandra客户端api。关系型数据库和cassandra的数据存储很少有相似之处。更多信息请看cassandra的数据模型
名词解析
Keyspace:包含多重列集合,相当于关系型数据库中的database。
CF:CF是某个特定Key的数据集合,相当于关系数据库中的table,在storage-conf.xml中定义(需要重启服务器才生效),每个CF存放一个单独的文件。
SCF:一种特殊的column的数据集合。
Key:一个唯一的字符串,标识一行CF。行需要一个唯一的字符串来标识,列是通过名称来标识的。thrift的java客户端总是使用utf-8编码的,但是如果你使用的是非java的客户端,那么你可能需要首先手动转码成utf-8。(这主要说明了thrift不支持不同平台间的互操作性)。
Column:一个元组,它包含一个名称,值及时间戳,名字在行中是唯一的。

异常信息
NotFoundException:被请求的特定列不存在。
InvalidRequestExeption:无效的请求可能意味着Keyspace或CF不存在,导致无效请求的原因可能是必要参数丢失或者参数格式不对。
UnavailableException:不是所有的备份都需要被创建和读取的。
TimeOutException:数据节点的读取或者写入过程中没有在配置文件中规定的时间间隔内响应请求(默认是10s)。当节点的请求过大时,导致负载过高或者系统当机时但是失败检测器无法检测到(一般是时间超过30s)。
TApplicationException:内部服务器有错或者无效的thrift方法(可能是因为使用旧版本thrift客户端去访问新版本的cassandra服务器)。
AuthenticationException:无效的身份验证的请求(用户不存在或者凭据无效)
AuthorizationException:无效授权请求(用户没有权限访问keyspace)

02 七 10 apache转发实现iis和apache共享80端口

因为只有一台服务器(win2003 server) 既需要在上面跑asp程序 又需要在上面跑php应用 又不想用iis跑php应用 还有就是不想把asp程序跑在apache上 就需要一个apache与iis共存的方案。

iis是windows2003 server自带的iis6.0

apache是apache2.2.8

首先当然是下载并安装apache

接着开始先把自动启动的iis服务器停下来,修改iis的端口为非80(比如8081)

再接着打开apache的httpd.conf文件开始配置

要让apache支持转发也就是做iis的代理那么就要先启用apache的代理模块:

#LoadModule proxy_module modules/mod_proxy.so
–>LoadModule proxy_module modules/mod_proxy.so

#LoadModule proxy_connect_module modules/mod_proxy_connect.so

–>LoadModule proxy_connect_module modules/mod_proxy_connect.so
#LoadModule proxy_ftp_module modules/mod_proxy_ftp.so

–>LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
#LoadModule proxy_http_module modules/mod_proxy_http.so

–>LoadModule proxy_http_module modules/mod_proxy_http.so

完成了代理模块的启用 那么我们开始配置虚拟主机

先包含httpd-vhosts.conf文件

#Include conf/extra/httpd-vhosts.conf

–>Include conf/extra/httpd-vhosts.conf

保存httpd.conf,打开httpd-vhosts.conf文件

开始配置虚拟机

NameVirtualHost *:80

<VIRTUALHOST *:80>

ServerAdmin b@b.com
ServerName    www.b.com
DocumentRoot  “C:/Program Files/Apache Software Foundation/Apache2.2/htdocs”
</VIRTUALHOST >
<VIRTUALHOST *:80>
ProxyPreserveHost On
ServerAdmin a@a.com
ServerName www.a.com
DefaultLanguage zh-CN
AddDefaultCharset GB2312
ProxyPass / http://www.a.com:8081/
ProxyPassReverse / http://www.a.com:8081/
</VIRTUALHOST>

配置完成并保存httpd-vhosts.conf

开始重启apache服务器和iis服务器

我们通过www.a.com访问过去就会看到iis的默认页面

通过www.b.com访问过去就可以看到it’s work。

这样我们就实现了iis和apache共享80端口

02 七 10 apache出现You don’t have permission to access

apache出现You don’t have permission to access / on this server. 提示

今天在新的linux上跑原来的代码,使用的虚拟主机的模式进行操作。几个相关的网站放在一个文件里,想法是通过网站列出的目录进行相应的网站进行操作。一切设置完成后,在浏览器中运行出现在You don’t have permission to access / on this server.  提示。查了一下apache手册找到问题所在处。这里定义了默认对网站根的访问权限。

# Each directory to which Apache has access can be configured with respect
# to which services and features are allowed and/or disabled in that
# directory (and its subdirectories).
#
# First, we configure the ”default” to be a very restrictive set of
# features.
#
<Directory />
Options FollowSymLinks
AllowOverride None
Order deny,allow
Deny from all
</Directory>

这里改成

<Directory />
Options Indexes FollowSymLinks
AllowOverride None
</Directory>

问题解决

Analytics Plugin created by Web Hosting

普人特福的博客cnzz&51la for wordpress,cnzz for wordpress,51la for wordpress