30 / 10 / 2013 admin

      公司竟然还在用qee这N年没人维护的框架,所以就索性淘汰掉,在DB连接方面没有选择任何ORM框架,而是只提供了一个简单的mysql类库,好像这个sql是从emlog博客演变而来,我个人还是很喜欢用,但DB有个小问题,如有两个DB使用了不同权限的帐号进行操作时

1
2
3
4
5
6
7
//db1和db2的配置只是库不同,帐号密码一样
 $db1 = Db_Mysql::get_instance('db1');
 $sql = 'select * from xx where id=%d';
 $db1->query($sql, array(2));
 $db2 = Db_Mysql::get_instance('db2');
 $sql = 'select * from oo where id=%d';
 $db2->query($sql, array(2));

这样的代码会报错:db1.oo表不存在,之前也出现过,但实在解不了,所以就索性google了一下“php mutiple mysql connect”,然后答案就有了:
http://stackoverflow.com/questions/274892/how-do-you-connect-to-multiple-mysql-databases-on-a-single-webpage
他这么写到

//You can make multiple calls to mysql_connect(), but if the parameters are the same you need to pass true for the '$new_link' (fourth) parameter, otherwise the same connection is reused.
$dbh1 = mysql_connect($hostname, $username, $password);
$dbh2 = mysql_connect($hostname, $username, $password, true);

09 / 10 / 2013 admin

     之前说过现在的开发环境很差,做开发太难,几经周折无果后只能退而求其次在本地搭建了一个apache环境,凑合着用。所有的静态页面已经资源都访问本机,至少不影响开发,且多用ajax,运营支撑系统更是extjs开发,数据全是来自ajax,再本地搭建完成后配置的域与正是环境不一样,是为了方便开发,不再正式本地之间来回切换,如,线上是 xxx.qq.com,本地为vartu.qq.com来访问,只要不跨主域名还是没有问题,但是遇到一个问题,很多用了ajax请求,那么就跨域了,所以在apache做了一个rewrite,以前没发现rewrite竟然可以跨域,下面来说实现

     1、打开apache安装目录下面的conf/httpd.conf,去除下面配置前的“;”
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule rewrite_module modules/mod_rewrite.so

     2、修改站点配置信息如下

<VirtualHost *:80>
ServerAdmin webmaster@dummy-host.x
DocumentRoot "F:\AppServ\www\softadmin\public"
ServerName game.oa.com
ErrorLog "logs/dummy-host.x-error.log"
CustomLog "logs/dummy-host.x-access.log" common
RewriteEngine on
RewriteRule ^/index\.php(.*)$ http://xxx.qq.com/index.php$1 [L,R=301,P,NC]
</VirtualHost>

     3、如果有登录态,即是需要带cookie的情况下,可以修改vartu.qq.com的cookie信息为一个登录过的cookie即可,rewrite也支持发送cookie,如“^/index\.php(.*)$ http://xxx.qq.com/index.php$1 [L,R=301,P,NC,CO=PHPSESSID:sadf2323423sdfd:.qq.com:/:1440]”

更多rewrite的规则可以访问 http://httpd.apache.org/docs/current/rewrite/flags.html

19 / 09 / 2013 admin

      话说很久没有写过文章了,自从离职后,进入tc也1个多月了,过的很忙,也很充实,现在发现比起后端我更爱前端,但潜意识还是觉得不够帅气,不够牛逼,所以还在努力挣扎着去接触cgi,原因也是因为这次的项目中有几个接口需要动态输出。现在回过头来看网站开发,把一个网站做牛逼,就应该把所有的静态化,动态内容全部异步或者定时生成再include,看业务需要。把所有的请求交给nginx来处理,至少不用再看着loading…………………………………………………

      今天中秋节,事情太多,加上环境不是很熟悉,实在处理不过来,今天就公司加班一天,上午把主要的事情处理了,下午来看看fastcgi相关信息,先来说cgi,再说fast-cgi。

一、cgi其实就是一个可执行的应用程序,apache在收到请求后交由你的这个应用来处理请求,如hello world来了

1
2
3
4
5
6
#include <stdio.h>
int main(){
    printf("Content-type:text/html\n\n");
    printf("Hello World\n");
    return 0;
}

编译一下:gcc hello.c -o hello;自己也可以测试一下 ./hello看看是否能正常打印
再把这个文件拷贝到 cgi-bin的目录,具体应该看apache配置 http.conf中站点的 ScriptAlias目录指定的地方

然后访问一下 http://站点域名/hello 看看是否正常输出了

这就是cgi,很简单吧,cgi不限制语言开发,装B的都是用C/C++,好像装。


那么什么是fastcgi呢,我去,随便找个hello你就啊,用个while包了一下cgi就是fastcgi,本想多高级,结果while都需要自己写,注意,hello来了。

http://www.fastcgi.com/devkit/doc/fastcgi-prog-guide/ch2c.htm

1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <fcgi_stdio.h>
using namespace std;
int main(void){
    while(FCGI_Accept() >= 0){
        printf("Content-type: text/html\r\n");
		printf("hello world!");
    }
    return 0;
}

因为环境不好,没有测试,但我猜测是可以的,编译加入-lfcgi就可以了,至于cgi头文件..
下午看了一下内部的一个cgi的简单框架,写的很不错,也很简单,模板引擎用的是clearsliver (www.clearsilver.net/docs/c_api.hdf),其它过程就跟PHP扩展差不多过程,什么RINIT\MINTI之类的,业务只需要继承后写接口代码就行了。

顺便说一下再整个的学习过程中发现的两个点
1、在.h文件中加入 #pragma once 可以防止被多次加载,和编译环境有关系,普通的做法就是使用 #ifndef #define #endif;有点麻烦
2、#pragma pack() 例如:

1
2
3
4
5
6
#pragma pack(1) 
struct sample{
    char a;
    double b;
};
#pragma pack()

注:若不用#pragma pack(1)和#pragma pack()括起来,则sample按编译器默认方式对齐(成员中size最大的那个)。即按8字节(double)对齐,则sizeof(sample)==16.成员char a占了8个字节(其中7个是空字节);若用#pragma pack(1),则sample按1字节方式对齐sizeof(sample)==9.(无空字节),比较节省空间啦,有些场和还可使结构体更易于控制

14 / 07 / 2013 admin

      好快,就像是昨天,还在华科草坪一起讨论来深圳的事情。前两天一直被人力的妹子问:“你的签约已经到期了,是否要续签呢”。签?不甘心再来一个这样的三年;不签?我要去哪儿呢。

      今天这篇博客终于要写给自己了,写给过去三年。10年7月开始正式入职,接下来3个月的培训计划,我的老大是王松林(博客),从“http请求状态码”到“php本地cache”到“ICE中间件”,这三个月让我学到了很多基础知识,成长很快。接下来就是开始了500PAI网站的开发,主要负责的是支付和拍点两个模块,还有一个简单的Com_Page(不太记得名字了)的框架类。年底,由于我对后端技术的向往,海涛拉我进入了系统平台

      进入之前,完成了一个自动化邮件发送系统(PHP+ICE+PYTHON),从技术看这就是过渡,从PHP向后端脚本处理的过渡。我的第二个老大黎冠星(博客),他是我有今天这样一个非常重要的人。还记得10年春节前,只有两三天就要除夕了(那年我没有回家),给我分配了一个任务短信网关的开发(CMPP2.0协议),我python也就一个hello word水平,socket通信都不知为何物,更别说什么,前两个字节怎么读写。不过有时候不逼到那个地步了,就勤奋不起来。我把星哥写过的代码用公司打印机打印出来带回去学习,慢慢也看出来一些东西,CMPP完成了,然后就SMGP、SGIP,到此第一个正式的后台任务上线了。吃个饭,回来写。

//edit at 2013-08-07
      话说某人说这个饭吃的有点长。也是因为当时没有什么情愫来把这篇博客写完整,就一直停留在这里。接着,第一个项目做完后来也陆陆续续做了很多别的项目。总体说来,这三年大概可以分这么几个阶段:1、最开始半年(10.06-10.12月)一直在学习php基础,已经了解一些后端的知识;2、后1年(11.01-11.12)做了很多小项目也得到了老大的认可;3、再一年(12.01-12.12)是一个被老大们看来悲剧的一年,因为这一年本应该参加开发的项目我都拒绝了;4、最后半年(13.01-13.07)不温不火的半年却对我很重要。

      前两个阶段就不提了,意义不大,第三个阶段我之所以拒绝无非是做的事情太没有挑战性,如果是个技术人就应该拒绝,如果是个好员工就不应该。这一年的结果落得一个人人都喜欢对我说:“你有个坏习惯不好,喜欢挑项目,要改”,我想说现在的我不是去年的我,应该没人信,这不是很重要。不过回想来,如果再来一次我还是会拒绝,真的很没有什么追求,从rocket项目的订单化说起,我觉得订单这样的东西不应该是我们讨论出来的结果,而应该是行业共识,那么多开源的购物系统被大众检测,我们从没有研究分析过,最终就被几个人决定了,没有意义。再说德州扑克,又是python,还是python,毫无争议的python,设计过度已经远远超过预期,一样没有意义。所幸在这段时间学习了android开发,虽然没有牛人指点,但开发普通应用基本没有难度,再年尾,沉下心来写了一个php框架,虽然有些点我个人还是有争议性,但毕竟大部分都是在我的意料内实现的。

      再说最后这个阶段,都说事情很容易好头烂尾,还好我幸运的收了个尾。今年分组,ht想让我继续待原组,考虑到我这性格也不会怎么样,如果这样又是毫无意义。所以还是申请进了架构组,进组前和shil谈话我就说很想写c++,最后这半年基本上都在c++上面,用ace开发配置中心,虽然过程有点挣扎,但结果无非是好的,不会的时候各种折腾的结果就是很熟练。以前对c++总是近而远之,现在已经不再害怕,即便今天老大让写c++也毫不示弱。这跟当你对一个事物产生了崇敬感以至于以后都不敢靠近,当有一天逼不得已得亲密接触后才发现原来他也没有那么神秘,这跟女神一样,泡到手一样也会成为凡物。

      走之前我和很多朋友聊过天,都或多少涉及到公司技术的现状,且不评,我只记得,当你离开一家公司的时候原因应该是以下两者其一:
1、你已经学会了所以应该了解的东西,靠自己才能成长
2、你的能力超出了公司可以支付你的能力,其实这跟第一条是对应的,因为现在的环境已经没有办法发挥自己的能力了。

最后,虽然我不太明确目前离职的原因,但潜意识理由再这二者中。做事,态度决定结果,无愧于心,无愧于行

无标签信息 0 条

glog初始化的一些方法,其中如果要实时flush日志,可以设置FLAGS_logbufsecs=0;

1
2
3
    FLAGS_logbufsecs = 1;
    google::InitGoogleLogging("");
    google::SetLogDestination(google::GLOG_INFO, "./xxx.log.");

glog 不支持按天轮转日志,所以需要对glog源码做一些修改,修改如下

修改 src/logging.cc文件,第913行(LogFileObject::Write开始之前)加上如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/***************CHANGE LOG BY DAY*************/
int _now_day = 0;
bool DayHasChanged(){
    time_t tt;
    time(&tt);
    struct tm *p;
    p=localtime(&tt);
    if(_now_day != p->tm_mday){
        _now_day = p->tm_mday;
        return true;
    }
    return false;
}
/********************************************/
 
//再修改LogFileObject::Write方法中判断语句加入
if (static_cast<int>(file_length_ >> 20) >= MaxLogSize() ||
      PidHasChanged() || DayHasChanged()) {

      接上一篇触屏插件 touchwipe,这篇是触屏广告切换插件,是基于touchwipe开发的,下面看看效果吧,独立地址:http://www.mjix.com/wp-code/plugin/tab.html

下载地址:http://www.mjix.com/wp-code/plugin/zepto.tabwipe.js

下面说一下使用方法:

View Code JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
~function(){
    /******轮换广告测试*****/
    var tabins = $('.wipe-list-ulo').tabwipe({
        done_process : 0.4, //移动超过40%则跳转
        ani_time : 300, //动画切换时间
        max_speed:800, //滑屏速度超过800dip跳转
        is_circle : true, //循环滚动
        callback : function(index){ //切换回调
            $('.gcdt-list-curo div').removeClass('cur').eq(index).addClass('cur');
        }
    }).interval(2000);
 
    //支持点击切换图片
    $('.gcdt-list-cur div').click(function(){
        tabins.move($(this).index());
    });
}();

1、上面的参数配置写的很明确了,我就不多说了,如果不想要循环滑动效果,只需要修改is_circle为false就好了
2、为了灵活使用这个插件,所以切换条没有固定,需要自己实现其风格,有的可能是原点,有的是横条,随自己喜欢
3、去掉 .interval(2000);则可以去除自动切换效果,其中2000为2秒中自动切换一次。
4、赶紧下载使用一下吧!

无标签信息 0 条

      最近本来一直忙于写c++的配置中心,写博客的时间越来越少了,前段时间无线同事有几个touch事件的需求我就接了顺便学习练手。我把touch事件抽离出来做了一个封装,理论上这个plugin应该是兼容jquery的,代码不多,下面先上使用方法:

演示地址test.mjix.com下载地址:http://www.mjix.com/wp-code/plugin/zepto.touchwipe.js

View Code JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
$('#test').touchwipe({
    listen : 'x', //监听x轴方向的滑动
    start  :  function(result){
        alert('开始触屏了');
    },
    move   : function(result){
        alert('正在滑动:'+result.dx+"____"+result.dy);
    },
    stop   : function(result){
        alert('结束了');
    }
});

      目前事件就三个start doing stop,下面对touchwipe的入参配置做一下说明:
1、listen:①、x监听x轴方面的滑动,不影响y轴方面的滚动;②、y监听y轴方面的滑动,不影响x轴方向浏览器自带的切换效果(uc);③、a监听x、y两个方向的触屏,这样浏览器的x和y方向默认事件都将被屏蔽,除非业务需要应该明确指定x和y

2、min_distance:最小触发距离,默认为6像素。

3、start:触屏开始回调事件。参数有{x:起点x值, y:起点y值},适合做一些初始化事情

4、move:触屏移动回调事件。参数有{x:x值, y:y值, dx:x方向移动差值, dy:y方向移动差值, du:(‘x’, ‘y’)其中一值,表明当前趋势为“水平方面滑动”或“垂直方向滑动”},适合做一些效果

5、stop:触屏结束回调事件。参数有{dx:x方向移动差值, dy:y方向移动差值, speed:du方向的速度,可以再移动速度大于多少时做一些触发事件}

备注:方向一致原则:一旦方向确定以后都不会变化,如触屏上去第一次move感知到时为水平反向移动,那么在移动过程中从水平移动变成垂直移动也不会影响du的值。这跟四川麻将的缺一门很像,第一轮打出的那一张就是你注定要缺的那一门,中途是不可以更换的

今天在对python的扩展做压力测试时发现内存一直在猛涨,结果发现原来是在返回PyDict_New的时候出现了问题,原来的代码如下:

1
2
3
4
5
    PyObject *d = PyDict_New();
    map<string,string>::iterator it=result.begin();   
    for(; it!=result.end(); ++it){
        PyDict_SetItem(d, Py_BuildValue("s", it->first.c_str()), Py_BuildValue("s", it->second.c_str()));
    }

后来google发现一篇文章写的很不错:http://blog.csdn.net/littlegrizzly/article/details/7701096,就不多说了,直接上修正后的代码:

1
2
3
4
5
6
7
8
    for(; it!=result.end(); ++it){
        PyObject *key = Py_BuildValue("s", it->first.c_str());
        PyObject *val = Py_BuildValue("s", it->second.c_str());
        PyDict_SetItem(d, key, val);
 
        Py_XDECREF(key);
        Py_XDECREF(val);
    }
无标签信息 0 条

      这两天一直在忙着配置中心的开发,现在终于到了python的扩展开发部分,其它都好说,主要是在当c++线程检测到配置更新时回调通知python的问题上,下面来看示例
在python端是这样:

View Code PYTHON
1
2
3
4
5
6
7
import ConfigApp
 
def callback(name):
    print 'update_____________', name
 
config = ConfigApp.Config()
config.register_modify(callback)

上面的register_modify在c++扩展开发中怎么实现呢,且看代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//回调句柄
static PyObject *update_callback = NULL;
 
//配置更新通知,参考:http://docs.python.org/2/extending/extending.html 官方demo
static PyObject* Config_method_register_modify(Config *self, PyObject *pArgs, PyObject *kwds){
    PyObject *temp;
    int ret = -1;
    if (PyArg_ParseTuple(pArgs, "O:set_callback", &temp)) {
        if (!PyCallable_Check(temp)) {
            PyErr_SetString(PyExc_TypeError, "parameter must be callable");
            return NULL;
        }
 
        Py_XINCREF(temp);             /* Add a reference to new callback */
        Py_XDECREF(update_callback);  /* Dispose of previous callback */
        update_callback = temp;       /* Remember new callback */
 
        ret = AppApi::register_modify(_modify_callback);
    }
 
    return Py_BuildValue("i", ret);
}

接下来就看我们注册的c++函数_modify_callback的实现过程:

1
2
3
4
5
6
7
8
9
10
static void _modify_callback(const char *module){
    if (!PyCallable_Check(update_callback)) {
        PyErr_SetString(PyExc_TypeError, "callable have some problem!");
        return ;
    }
 
    PyObject *arglist = Py_BuildValue("(s)", module);
    PyObject_CallObject(update_callback, arglist);
    Py_DECREF(arglist);
}

看完啊,千万不要把上面代码copy走了!在异步回调的时候出现 :python2.6: line 4: 16251 Segmentation fault

      真要命,这如何是好,主要是我咋搜索呢,百般尝试发现搜索“python extension callback thread”是很靠谱的,最终确认了这样的一篇文章“C++调用PythonAPI线程状态和全局解释器锁 ” ,Py_BEGIN_ALLOW_THREADS这个尝试失败,我就不扯蛋了,直接说官方文档“Initialization, Finalization, and Threads”,按官方现在的代码应该是下面这样的:

1
2
3
4
5
6
7
8
9
//....上面一样,省略
    PyGILState_STATE gstate = PyGILState_Ensure();
 
    PyObject *arglist = Py_BuildValue("(s)", module);
    PyObject_CallObject(update_callback, arglist);
    Py_DECREF(arglist);
 
    PyGILState_Release(gstate);
//....上面一样,省略

      啊,回调终于成功了!如果你这个时候走了,那你又悲剧了,因为回调完成后就“Segmentation fault”,然后就继续google,得到结论:http://stackoverflow.com/questions/5140998/why-does-pygilstate-release-segfault-in-this-case,改代码如下:

1
2
3
4
5
6
7
8
9
10
    //下面这句话很重要
    PyEval_InitThreads();
    //########################
    PyGILState_STATE gstate = PyGILState_Ensure();
 
    PyObject *arglist = Py_BuildValue("(s)", module);
    PyObject_CallObject(update_callback, arglist);
    Py_DECREF(arglist);
 
    PyGILState_Release(gstate);

      恭喜恭喜

无标签信息 1 条

      今天一同事突然有个想法找到我来实现,我就先不介绍这个想法了,大意是需要自动生成android应用,中午就随便看了看,确定可行性,因为实在是太忙,只能挪到晚上来研究,终于搞定个大概了,下面做些记录

      首先需要安装ant,这个是必须的,如果已经有了就略过,
wget http://apache.dataguru.cn//ant/binaries/apache-ant-1.9.1-bin.tar.gz
export PATH=$PATH:$HOME/apache-ant/bin

      下面就直接到sdk了,我在http://developer.android.com/sdk/index.html上找了好久,结果藏的也太深了:“DOWNLOAD FOR OTHER PLATFORMS”下载sdk就行了

1
2
3
4
5
6
7
8
9
10
wget http://dl.google.com/android/android-sdk_r22.0.1-linux.tgz
tar -xzf android-sdk_r22.0.1-linux.tgz
export PATH=$PATH:$HOME/android/android-sdk/tools
 
#到此环境配置完了,接下来更新sdk,此动作很慢
android update sdk --no-ui #我更新到2.2就停止了
android list targets #找出自己要编译的版本,比如,我的2.2对应的target是1,那么
android create project -n hello -t 1 -p project/ -k com.mjix -a DefaultActivity #参数的解释就直接 --help吧, -t指定target
cd project
ant release #开始编译

      结果出现了一个超级坑爹的事情就是: libz.so.1: cannot open shared object file: No such file or directory,我再三检查,确信自己安装了,可以通过 1、yum -qa|grep zlib或者2、locate libz.so.1来查看,最后终于找到一位知音博客。下面就直接引用了:
因为现在的系统捏是尼玛64位滴,而该死的Android都是基于32开发的,它依赖的是32位的libz
那位同学的解决办法是export CFLAGS=-m32 后再编译zlib安装,我就偷个懒,直接yum install了一个32位的zlib。

      终于,成功的生成了:BUILD SUCCESSFUL。

接下来可以看到bin下面有一个 hello-release-unsigned.apk,未签名的apk,当然不能发布啦,好了,下面我们就来签名吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//生成一个自己的签名,其它自己填就好了
keytool -genkey -v -keystore hello.key -alias hello -keyalg RSA -keysize 2048 -validity 10000
//第一种签名方式
vi ant.properties //添加
key.store=hello.key
key.store.password=123456
key.alias=hello
key.alias.password=123456
//执行 ant release就可以看到 hello-release-unsigned.apk
 
//第二种签名方法:或者使用如下语句生成:
jarsigner -verbose -keystore hello.key -signedjar bin/hello_signed.apk ./bin/hello-release-unsigned.apk hello -keypass 123456
//最终生成的文件是bin/hello_signed.apk
 
//使用android sdk的zipalign工具优化已签名的apk文件
zipalign -v 4 bin/hello-release-unaligned.apk bin/hello-release-aligned.apk

下面给一些参考链接:

http://my.oschina.net/u/559701/blog/75333

http://developer.android.com/tools/devices/managing-avds-cmdline.html

http://www.android123.com.cn/androidkaifa/173.html

http://developer.android.com/tools/publishing/app-signing.html

无标签信息 2 条