0%

用了国内的服务器,国内用户访问速度是快了,但是国外用户就会卡,如果用国外的服务器,国内的用户又会卡,从cnzz的统计来看,我的博客海外访客还是蛮多的,特别是台湾同胞,所以弄个cdn加速,就很有必要了。Google PageSpeed目前是免费服务,但是并不是所有的网站都能申请通过,至少我第一次被拒绝了,然后过了大半个月,就是今天,Google突然发邮件说申请通过了,好吧,那就试试吧。 配置PageSpeed需要先验证域名,可以使用Google Analysis,添加meta标记,上传html文件等方式。成功以后,需要在DNS上添加一个源站的解析(供google服务器抓数据,不是让访客访问的),再把www域名cname解析到pagespeed.googlehosted.com. 我的DNS用的是dnspod,免费用户,感觉dnspod快不行了,解析速度非常慢,甚至超时,不知道各位有没有推荐的。 DNSPOD支持智能解析,我把国内访客解析到自己服务器,国外访客解析到pagespeed.googlehosted.com.这样国内用户还是访问自己服务器。 解析完以后,用ping.chinaz.com,检测全球各地的ping值,基本没有红了,基本都在100ms以内,用webkaka测试访问速度,国外用户可以达到300多k/s,应该比国内用户访问自己服务器还快。 www.webpagetest.org测试的优化效果: googlepagespeed 可以看到,优化后,载入时间少了一半

ContentResolver之前在介绍联系人的时候已经用过了,用于查询另一个程序的数据库,相对的,而ContentProvider就是把自己的数据库提供给其他程序查询。 ChatDataProvider:

package com.pocketdigi.provider;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import com.pocketdigi.db.DatabaseHelper;


public class ChatDataProvider extends ContentProvider {

    
    @Override
    public boolean onCreate() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        // TODO Auto-generated method stub
        //查询未读总数
        UriMatcher  sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        Cursor cursor=null;
        //查询未读,匹配URI  content://com.pocketdigi.provider/unread
        sMatcher.addURI("com.pocketdigi.provider", "unread", 1);
        switch(sMatcher.match(uri))
        {
        case 1:
            DatabaseHelper dbHelper=new DatabaseHelper(	this.getContext());
            SQLiteDatabase db=dbHelper.getWritableDatabase();
            cursor= db.rawQuery("select count(*) as count from message where readed=0;",null);
            break;
        }
        
        return cursor;
    }

    @Override
    public String getType(Uri uri) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        // TODO Auto-generated method stub
        return 0;
    }

}

功能简单,只能查询未读的消息数量,所以query里很多参数都忽略了,各个参数可以参考db.query的参数列表。 AndroidManifest.xml里注册Provider:

        <provider
            android:name="com.pocketdigi.provider.ChatDataProvider"
            android:authorities="com.pocketdigi.provider" >
        </provider>

另一个程序中的使用方法:

ContentResolver resolver=getContentResolver();
        Uri uri=Uri.parse("content://com.pocketdigi.provider/unread");
        Cursor cursor=resolver.query(uri, null, null, null, null);
        if(cursor!=null)
        {
            cursor.moveToFirst();
            int count=cursor.getInt(0);
            updateUnReadCountUI(count);
        }

基于Openfire+asmack开发一个聊天软件,但发现客户端在一段时间没有操作以后,就会与服务器断开,而且客户端的XMPPConnection.connected字段还是true,就是客户端根本不知道自己是不是已经断了,openfire那边已经显示断开。而asmack在发送出消息以后,并不会检测对方是否已经收到。这个问题困扰了很久,必竟asmack用的人也挺多的,就没想过会是asmack的问题,实在找不到BUG在哪,就下了asmack研究,不看不知道,一看吓一跳,尼玛,asmack就是个半成品。打开org.jivesoftware.smack.PacketWriter,可以看到声明了一个keepAliveThread的线程,看这名字,很明显是用来发心跳包的。但是从源代码上看,这个keepAliveThread根本什么都没干,连初始化都没做,asmack根本就没有心跳机制。长时间连接不操作,openfire检测不到心跳,必然主动断线。 找到问题,解决就简单了,登录成功以后,开个Alarm,重复触发ping操作。关于发送ping包的代码,可以参考smack里的org.jivesoftware.smack.keepalive.KeepAliveManager,但是不建议直接用smack的心跳机制,smack是在收到服务器的packet以后,就发送ping,因为ping发送成功以后,服务器会返回个packet,这样就能无限循环了。但是服务器不仅会在收到ping后发送packet,用户上下线,新消息等都会发送packet,而客户端发送ping的线程是同步的,这样的话,后面排队的ping操作就会很多,而且也没必要高频率发送packet。

$push:向文档数组中添加元素,如果没有该数组,则自动添加数组。 db.users.insert({"name":"zhang"}) db.users.update({"name":"zhang"},{"$push":{"emails":"zhang@pocketdigi.com"}}) db.users.update({"name":"zhang"},{"$push":{"emails":"zhang@fwvga.com"}}) 以上代码,先创建name为zhang的用户,再给该用户加入邮箱,放到emails数组中. $addToSet:功能与$push相同,区别在于,$addToSet把数组看作成一个Set,如果数组中存在相同的元素,不会插入。 db.users.update({"name":"zhang"},{"$addToSet":{"emails":"zhang@fwvga.com"}}) db.users.find() 可以看到,并没有两个zhang@fwvga.com的邮箱. $addToSet还可以与$each组合使用,一次添加多个值。 db.users.update({"name":"zhang"},{"$addToSet":{"emails":{"$each":["zhang@fwvga.com","zhang@163.com","zhang@qq.com"]}}}) $pop,与$push相对应,删除数组里的元素 db.users.update({"name":"zhang"},{"$pop":{"emails":{key:1}}}); key=1,从尾删除,key=-1,从头删除 $pull 删除指定元素,结合上面的例子,就是删除指定的邮箱 db.users.update({"name":"zhang"},{"$pull":{"emails":"zhang@163.com"}}); 修改指定位置的元素: 数组每个元素都有索引,从0开始。经过上面的一系列操作,zhang的文档应该是这样的: { "_id" : ObjectId("51a16b02d2ded250f4aab338"), "emails" : [ "zhang@pocketdigi.com", "zhang@fwvga.com" ], "name" : "zhang" } 假如要把第一个邮箱修改成zhang@163.com: db.users.update({"name":"zhang"},{"$set":{"emails.0":"zhang@163.com"}}); 假如要把zhang@fwvga.com替换成zhang@qq.com,在并不知道zhang@fwvga.com索引时: db.users.update({"name":"zhang","emails":"zhang@fwvga.com"},{"$set":{"emails.$":"zhang@qq.com"}});

官方下的MongoDB其实是绿色免安装的,http://www.mongodb.org/downloads 默认没有带配置文件,自己建一个: vi mongodb.conf: dbpath=/home/mongodata fork=true auth=true logpath=/home/server/mongodb-linux-i686-2.4.3/log.log logappend=true journal=true quiet=true 启动: /bin/mongod –config mongodb.conf 如果报 exception in initAndListen std::exception: locale::facet::_S_create_c_locale name not valid, terminating 先执行 export LC_ALL=C mongodb

每次开机都要手工一个一个启动,nginx,php,mongodb,太麻烦了,写了个脚本,但是MongoDB启动会输出日志,所以不是很完美,会显示日志。 /root/webserver #!/bin/bash PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH export LC_ALL=C # Check if user is root if [ $(id -u) != "0" ]; then printf "Error: You must be root to run this script!\n" exit 1 fi NGINXDAEMON=/home/server/nginx-1.4.1/sbin/nginx NGINXPIDFILE=/home/server/nginx-1.4.1/logs/nginx.pid PHPFPMDAEMON=/home/server/php-5.4.15/sbin/php-fpm PHPFPMPID=/home/server/php-5.4.15/var/run/php-fpm.pid MONGODBDAEMON=/home/server/mongodb-linux-i686-2.4.3/bin/mongod MONGODBCONF=/home/server/mongodb-linux-i686-2.4.3/mongodb.conf function_start() { printf "Starting Nginx+PHP+Mongodb...\n" if [ -f $NGINXPIDFILE ]; then printf "Nginx is runing!\n" else $NGINXDAEMON fi if [ -f $PHPFPMPID ]; then printf "PHP-FPM is runing!\n" else $PHPFPMDAEMON fi lsof -i:27017 && printf "MongoDB is runing!\n" || $MONGODBDAEMON --config $MONGODBCONF } function_stop() { printf "Stoping Nginx+PHP...\n" if [ -f $NGINXPIDFILE ]; then kill -QUIT `cat $NGINXPIDFILE` else printf "Nginx program is not runing!\n" fi if [ -f $PHPFPMPID ]; then kill -INT `cat $PHPFPMPID` else printf "PHP-FPM program is not runing!\n" fi lsof -i:27017 && killall mongod || printf "MongoDB is not runing!\n" } function_status() { if [ -f $NGINXPIDFILE ]; then printf "Nginx is runing!\n" else printf "Nginx is stop!\n" fi if [ -f $PHPFPMPID ]; then printf "PHP-FPM is runing!\n" else printf "PHP-FPM is stop!\n" fi lsof -i:27017 && printf "MongoDB is runing!\n" || printf "MongoDB is stop!\n" } if [ "$1" = "start" ]; then function_start elif [ "$1" = "stop" ]; then function_stop elif [ "$1" = "restart" ]; then function_stop function_start elif [ "$1" = "status" ]; then function_status else printf "Usage: /root/webserver {start|stop|restart|status}\n" fi chmod +x /root/webserver 添加开机启动: vi /etc/rc.local 添加 /root/webserver start 重启生效

对比了一下mysql和mongodb,以后自己开发基本选定mongodb了。 MongoDB驱动下载地址: https://github.com/mongodb/mongo-php-driver 安装(下载里有安装说明,不过有些小不同): unzip mongo-php-driver-master.zip cd mongo-php-driver-master export PHP_PREFIX="/home/server/php-5.4.15/" $PHP_PREFIX/bin/phpize ./configure -with-php-config=$PHP_PREFIX/bin/php-config make install 装完提示so保存在/home/server/php-5.4.15/lib/php/extensions/no-debug-non-zts-20100525/ 修改php.ini,加上一句: extension="/home/server/php-5.4.15/lib/php/extensions/no-debug-non-zts-20100525/mongo.so" 重启ngix+php

unzip eAccelarator.zip cd eaccelerator-master export PHP_PREFIX="/home/server/php-5.4.15/" $PHP_PREFIX/bin/phpize /configure --enable-eaccelerator=shared --with-php-config=$PHP_PREFIX/bin/php-config make make install phpize的时候可能会提示Cannot find autoconf. apt-get install autoconf 如果提示perl: warning: Falling back to the standard locale (“C”). 先执行export LC_ALL=C 装完后,提示so库在/home/server/php-5.4.15/lib/php/extensions/no-debug-non-zts-20100525/eaccelerator.so 修改php.ini: 最底部添加 [eaccelerator] extension="/home/server/php-5.4.15/lib/php/extensions/no-debug-non-zts-20100525/eaccelerator.so" eaccelerator.shm_size="32" eaccelerator.cache_dir="/data/cache/eaccelerator" eaccelerator.enable="1" eaccelerator.optimizer="1" eaccelerator.check_mtime="1" eaccelerator.debug="0" eaccelerator.filter="" eaccelerator.shm_max="0" eaccelerator.shm_ttl="0" 创建缓存目录,并设置权限: mkdir -p /data/cache/eaccelerator chmod 0777 /data/cache/eaccelerator 重启nginx+php

启动nginx 停止:kill -QUIT `cat /home/server/nginx-1.4.1/logs/nginx.pid`

编辑php-fpm.conf,把pid文件注释去掉,这里加了注释并不是默认值,而是不生成pid文件。 启动,php-fpm 关闭:kill -INT `cat /home/server/php-5.4.15/var/run/php-fpm.pid` 重启:kill -USR2 `cat /home/server/php-5.4.15/var/run/php-fpm.pid`