如何提高NodeJS程序的稳定性
2011-05-16

   当我们写了个NodeJS程序的时候,一般用node yourjsfile.js命令启动该程序。但是如果程序中有东西出错,这个进程就会退出。我们写程序不可能保证万无一失,肯定有些没有处理的错误,这就让很多人觉得NodeJS不稳定,容易产生很多故障。 下面我就讲讲几种方法增加你的NodeJS程序的稳定性。

   1.使用 try{...} catch(error){...} 来执行容易出错的代码段。比如解析一个外来的json字符串等。
   2.使用 process.on('uncaughtException', function(err){...}); 来处理未被捕捉的错误。
   3.试用奶妈进程来启动你的程序,检测子进程的退出,然后自动重启该进程。比如 mother.js :


start();
function start()
{
    console.log('Mother process is running.');
    var ls = require('child_process').spawn('node', ['yourjsfile.js']);
    ls.stdout.on('data', function (data)
    {
        console.log(data.toString());
    });
    ls.stderr.on('data', function (data)
    {
        console.log(data.toString());
    });
    ls.on('exit', function (code)
    {
        console.log('child process exited with code ' + code);
        delete(ls);
        setTimeout(start,5000);
    });
}

    4.使用 nohup 让nodejs进程在后台运行。 比如运行"nohup node yourjsfile.js > /dev/null &"

完。

阅读:16939 评论: 16 💬
NodeJS实现HTTP/HTTPS代理
2011-05-06

    身在天朝,难免会用到代理的时候。 比如在学校内网用代理免费上外网,在墙内用代理上404网站等。

    现在使用的代理大部分为HTTP和Socket代理。 Socket代理更底层,需要本地解析域名,而HTTP代理则是基于HTTP协议之上的,不需要本地解析域名。下面我讲讲HTTP(S)代理的设计思路以及NodeJS代码实现。

HTTP协议

    HTTP协议简单说来就是浏览器把一串字符串发送到目标服务器,然后把目标服务器返回回来的一串字符串显示给用户。

    浏览器发送的这串字符主要分为两个部分,一部分是头,里面包含目标服务器域名,当前请求的文件路径等信息。另一部分是正文,一般的GET请求没有正文。

    服务器返回来的字符串也分为头和正文。

HTTP代理原理

    HTTP代理需要做的事情就是接收浏览器发来的请求字符串,再从请求字符串的头部分找出浏览器请求的目标主机,然后直接把这串请求字符串发给目标主机,再把目标主机返回的数据发给浏览器。 “什么?就这么简单?” “呃。。是啊,但这还没完。。”

    现代浏览器一般都是默认采用HTTP/1.1版本,并且默认会发送Connection: keep-alive请求。 这些信息是写在请求的头部的,意思是通知目标服务器采用keep-alive技术继续处理后续的请求。 但是我们做的代理程序要想支持keep-alive是比较麻烦的。所以干脆就把这个篡改成Connection: close。 这样就可以保证浏览器请求的每个文件都会单独发送一个HTTP请求。

下面是NodeJS代码实现

 

var net = require('net');
var local_port = 8893;

//在本地创建一个server监听本地local_port端口
net.createServer(function (client)
{
    
    //首先监听浏览器的数据发送事件,直到收到的数据包含完整的http请求头
    var buffer = new Buffer(0);
    client.on('data',function(data)
    {
        buffer = buffer_add(buffer,data);
        if (buffer_find_body(buffer== -1return;
        var req = parse_request(buffer);
        if (req === falsereturn;
        client.removeAllListeners('data');
        relay_connection(req);
    });

    //从http请求头部取得请求信息后,继续监听浏览器发送数据,同时连接目标服务器,并把目标服务器的数据传给浏览器
    function relay_connection(req)
    {
        console.log(req.method+' '+req.host+':'+req.port);
        
        //如果请求不是CONNECT方法(GET, POST),那么替换掉头部的一些东西
        if (req.method != 'CONNECT')
        {
            //先从buffer中取出头部
            var _body_pos = buffer_find_body(buffer);
            if (_body_pos < 0_body_pos = buffer.length;
            var header = buffer.slice(0,_body_pos).toString('utf8');
            //替换connection头
            header = header.replace(/(proxy\-)?connection\:.+\r\n/ig,'')
                    .replace(/Keep\-Alive\:.+\r\n/i,'')
                    .replace("\r\n",'\r\nConnection: close\r\n');
            //替换网址格式(去掉域名部分)
            if (req.httpVersion == '1.1')
            {
                var url = req.path.replace(/http\:\/\/[^\/]+/,'');
                if (url.path != urlheader = header.replace(req.path,url);
            }
            buffer = buffer_add(new Buffer(header,'utf8'),buffer.slice(_body_pos));
        }
        
        //建立到目标服务器的连接
        var server = net.createConnection(req.port,req.host);
        //交换服务器与浏览器的数据
        client.on("data", function(data){ server.write(data); });
        server.on("data", function(data){ client.write(data); });

        if (req.method == 'CONNECT')
            client.write(new Buffer("HTTP/1.1 200 Connection established\r\nConnection: close\r\n\r\n"));
        else
            server.write(buffer);
    }
}).listen(local_port);

console.log('Proxy server running at localhost:'+local_port);


//处理各种错误
process.on('uncaughtException', function(err)
{
    console.log("\nError!!!!");
    console.log(err);
});



/**
* 从请求头部取得请求详细信息
* 如果是 CONNECT 方法,那么会返回 { method,host,port,httpVersion}
* 如果是 GET/POST 方法,那么返回 { metod,host,port,path,httpVersion}
*/
function parse_request(buffer)
{
    var s = buffer.toString('utf8');
    var method = s.split('\n')[0].match(/^([A-Z]+)\s/)[1];
    if (method == 'CONNECT')
    {
        var arr = s.match(/^([A-Z]+)\s([^\:\s]+)\:(\d+)\sHTTP\/(\d\.\d)/);
        if (arr && arr[1] && arr[2] && arr[3] && arr[4])
            return { method: arr[1], host:arr[2], port:arr[3],httpVersion:arr[4] };
    }
    else
    {
        var arr = s.match(/^([A-Z]+)\s([^\s]+)\sHTTP\/(\d\.\d)/);
        if (arr && arr[1] && arr[2] && arr[3])
        {
            var host = s.match(/Host\:\s+([^\n\s\r]+)/)[1];
            if (host)
            {
                var _p = host.split(':',2);
                return { method: arr[1], host:_p[0], port:_p[1]?_p[1]:80, path: arr[2],httpVersion:arr[3] };
            }
        }
    }
    return false;
}




/**
* 两个buffer对象加起来
*/
function buffer_add(buf1,buf2)
{
    var re = new Buffer(buf1.length + buf2.length);
    buf1.copy(re);
    buf2.copy(re,buf1.length);
    return re;
}

/**
* 从缓存中找到头部结束标记("\r\n\r\n")的位置
*/
function buffer_find_body(b)
{
    for(var i=0,len=b.length-3;i<len;i++)
    {
        if (b[i] == 0x0d && b[i+1] == 0x0a && b[i+2] == 0x0d && b[i+3] == 0x0a)
        {
            return i+4;
        }
    }
    return -1;
}

 

另外,可以用 "nohup node some.js > /dev/null &" 命令让nodejs程序在后台运行。

完。

阅读:41551 评论: 32 💬
从Elance提现到国内银行的完美方法
2011-05-04

    我开始做自由职业已经有一个月左右了。主要是在elance.com上接项目。

    第一个项目做的是用jQuery做一个图片裁剪的功能,包括图片上传进度显示,两个比例的图片裁剪框。这个项目是100刀,elance扣了8.75刀的中介费,到手91.25刀。这个比例还是可以接受的。

     第二个项目是用nodejs做一个gtalk聊天机器人、一个facebook chat聊天机器人、一个msn聊天机器人。每个机器人200刀。在5天内搞完另外给400刀的bonus。结果我顺利在规定时间搞完,拿了1000刀。哈哈哈。

     钱到了Elance帐户上,怎么变成能够提现的人民币是个麻烦事情。我搜了网上很多文章,都说只有用moneybookers的服务最便宜。 于是我又搞了个moneybookers帐户。 那天突然发现如果成为elance的付费会员(最便宜的付费会员$10/月),就可以享受每月一次的免费电汇(wire transfer),超出一次以后貌似每笔要给25刀5刀手续费。于是就搞了个付费会员玩玩,不仅可以享受免费电汇,还有更多的点数和其他东西可以享受。付费会员只是多了一些Connect。免费会员一样每月又一次免费电汇的机会。那天试探提了200刀到我的中国银行活期一本通上,用的swiftcode是BKCHCNBJ570。过了大概4天,发现卡上真的有200美元,一分中间行费用都没扣。太TM爽了,这绝对是最便宜的提现途径,虽然每月只有一次机会。

     下一步就是去银行结汇,把美元转成人民币,这个步骤不知道要不要收手续费。

2012年10月更新:

      大家最好还是用中国银行。因为中国银行现在收到美元之后是自动上账(不知道其他地方,反正成都貌似都是),而其他一些银行(尤其是工商银行)收到美元后,要人工审核再上到你的账户上。人工审核这个时间就说不清楚了,快的话当天,慢的话无底限。。。关键是工行还要求我本人带身份证到我卡的开户行去办理!别人给我汇款还要我亲自去开户行办理接收手续!!

      还是中国银行好。在Elance上点击withdraw之后,2-3天Elance就会提醒说汇款手续已经办理。一般这个时候钱已经在中国银行账号上了,直接在网银就可以办理结汇,当然汇率要低一些。

      另外,Elance前段时间不知道搞什么飞机,直接提美元到美国以外的国家,每笔收25刀手续费。但是提其他币种就还是继续原来的价格(每月一次免费,超出5刀一次)。 Elance解释说是提倡在Elance完成币种转换,然后直接汇当地货币给你。我觉得可能elance想通过汇率差价赚钱?  操蛋的是提供选择的币种没有RMB! 不过我随便选了个欧元,就可以了。

BTW,欢迎加入Elance QQ群:162095216

完。

阅读:32452 评论: 38 💬
Mac OS 上的各种ipv6配置命令
2011-04-11

IPv6 在Mac OS上是默认开启的。也可以用下面的命令手动开启或者关闭ipv6支持:

在所有网卡上开启ipv6:

ip6 -a

 

关闭ipv6:

ip6 -x

 

要打开router advertisements (RAs)可以用下面的命令:

sysctl -w net.inet6.ip6.accept_rtadv=1

 

关闭RAs的话,将上面的命令最后的数字改成0即可。

 

私有地址默认没有开启,可以用下面的命令开启:

sysctl net.inet6.ip6.use_tempaddr=1

 

在Mac OS上开启ISATAP隧道支持:

 

1、下载ISATAP client for Mac OS X

地址:http://www.momose.org/macosx/isatap.html

2、解压ISATAP client

 

cd /usr/local
sudo tar xfz ~/Downloads/macosx-isatap-*.tar.gz

 

3、更改权限

 

sudo chown -R root:wheel /usr/local/isatap
sudo chmod -R 644 /usr/local/isatap/isatap.kext

 

4、配置ISATAP

4.1 配置ist0和得到IPv4地址(你需要制定现在使用的网卡,比如en0)

 

sudo ./config-ist.sh en0

 

4.2 指定ISATAP router (111.111.111.111更换为你当地的ISATAP服务器地址)

 

sudo ./ifconfig ist0 isataprtr 111.111.111.111
sudo ./rtsold.sh &

 

4.3 设置路由表

 

sudo route delete -inet6 default

 

注:在执行上面命令之前可以用netstat -r查看ipv6路由表上是否有default这一项,没有则不用执行上面命令

 

sudo route add -inet6 default -interface ist0

 

4.4 启动IPv6

 

sudo ifconfig ist0 up

 

5、关闭IPv6

 

sudo ifconfig ist0 down

 

这样ISATAP就配置好了。

 

我的例子:

我在电子科技大学清水河校区,我们学校采用802.1X拨号上网。 我在拨号可以上网的前提下配置了RAs支持,即可正常上ipv6网站。 另外,我也可以通过配置ISATAP,使用隧道连接上ipv6。

完。

阅读:42408 评论: 5 💬
还可以注册的3个字母的.ca域名
2011-03-11

    最近想注册个短一点的域名,搜了一下,发现.ca的域名还有很多3个字母的没有被注册。于是搞了个脚本统计了一下所有的3个字母的.ca域名。更新时间是2011年3月9号。以下是列表,总共3353个。有需要的同学可以找自己喜欢的注册。 推荐在godaddy注册,好处不用多说。

agz.ca
ajz.ca
akz.ca
awx.ca
axb.ca
axc.ca
axd.ca
axm.ca
axq.ca
axv.ca
ayq.ca
ayv.ca
ayw.ca

查看全文...  

阅读:44092 评论: 11 💬
Kindle 3的系统和网络情况以及通过其连电脑上网
2011-01-23

    搜索“kindle 3用作modem共享3G上网”,有很多文章,但绝大部分都是翻译国外一个哥们的文章,写的很大概,一般人很难操作成功。 昨天根据这篇文章研究了下kindle 3的系统,得到一些成功。

    Kindle 的系统是amazon基于linux开发的嵌入式系统。通过在kindle上安装usbNetwork(网上自己搜索,有很多东西都要用到usbNetwork),可以把kindle与电脑连成一个局域网内。然后通过ssh或者telnet可以进入kindle内部。(用户名是root,密码是空,一般usbNetwork装好后,电脑的ip就是192.168.2.1,kindle的ip是192.168.2.2)

    Kindle 3 打开wireless 并成功连上3g网络后,用ifconfig命令可以看到有一个ppp0连接,这就是3G网卡。 按理说就算是漫游,设备在连接上3G网络后,都应该有完全的网络访问能力。但是kindle系统限制了只能连接某几个ip(几个*.amazon.com的站点)。ping www.amazon.com 可以,但是ping 8.8.8.8就不行。 kindle系统里面的浏览器是通过fints-
g7g.amazon.com ( 72.21.206.113 ) 这个http代理服务器实现上网的(https代理服务器是另外一个)。

    可恶的是,amazon的代理服务器需要验证身份,在发送给代理服务器的http请求header里面需要加上x-fsn和x-fn-appid头才能通过验证。不同的kindle设备这两个值不同,所以需要先截取kindle内部浏览器发送的请求,得到这两个header值。方法是下载一个tcpdump-arm软件,传到kindle内(可以使用scp命令,或者先在U盘模式下存到kindle的sd卡里,然后可以在/mnt/us/下面找到)。然后进入kindle内部,运行此软件(如果提示没有权限,可以试试chmod 555 tcpdump-arm设置下权限)。运行方式是找到tcpdump-arm文件的文件夹,然后./tcpdump-arm -nAi ppp0 -s0。 然后在kindle上打开浏览器,随便上一个http网站,电脑上的命令行界面就可以看到截取的各种消息,很容易就从中找出需要的两个header值。

    得到两个header值之后,我们就可以在电脑上伪造kindle内部浏览器的请求了。 很遗憾,目前只能用firefox实现,并需要一枚firefox扩展:modify-headers。安装好这个扩展,先添加上面说的两个header,然后设置forefix的http代理服务器为 localhost 端口号是1234(随你)。 然后在kindle上做一个逆向端口转发,把本地的1234端口的数据转发到72.21.206.113的80端口上。 具体步骤是 先telnet或者ssh进你的kindle,然后输入ssh -R 1234:72.21.206.113:80 username@192.168.2.1。其中username@192.168.2.1是你电脑的ssh用户名和ip。能这样做的前提是你的电脑可以通过ssh登录,这个在mac os 和linux下非常容易,windows用户只能说靠你自己了。。。。

    此时你应该可以用你的firefox正常上网了。 你可以跳过添加验证header的步骤,也可以上网,但是仅限于*.amazon.com站点。 不过遗憾的是,就算能够正常上网,也无法访问https链接,因为modify-headers这个扩展貌似不支持https请求。

    另外,ssh可能会经常断,kindle的3g连接在一段时间不使用后,也会自动断开。为了防止此种情况发生,在创建好反向连接后,输入ping 192.168.2.2 从你的电脑不停的ping kindle,这样可以保持这个反向连接不断开。然后再开一个命令行窗口,再次进入kindle,输入ping www.amazon.com ,这样可以保持kindle的3G网络不断开。

    如果某个高人能够破解kindle系统对网络访问的限制,使其能访问任意站点,那就不用这么麻烦了,而且数据也不用走美国跑一趟。这应该是可以通过软方法实现的,因为既然kindle能直接访问*.amazon.com,那就证明kindle有网络访问权限,问题肯定在操作系统上。

    如果实在无法破解其限制,我在考虑做一个proxy程序,在kindle上运行,自动添加验证header到每个请求头部。这样,就可以简化到 1在kindle上运行usbNetwork和proxy并连接到电脑,2在电脑上任意浏览器输入http代理 192.168.2.2 80端口,就可以了。 而且也能更好的支持https。 我在考虑用开源的tinyproxy修改,交叉编译然后放到kindle里面运行。

    交叉编译我们学校教过,但是被我完全忘了。。。。一切得从头学一下。

    对于某些同学认为如果大家都滥用kindle的免费3G,amazon肯定会禁用全部kindle的3g访问。 我觉得不会,因为目前,所有流量都是走amazon的代理,他们知道所有流量信息,并且能区分不同的kindle设备发送的数据,觉得某个kindle有问题,把那个kindle设备禁用掉就行,不会殃及到其他人的。 要是那个高人破解了kindle系统的网络访问限制,那估计AT&T会真的找到amazon禁用全球漫游的数据。。。

    kindle的所有网络请求都走代理,虽然响应速度慢了点,但是下载速度还可以,我试过下载最高可以达到100-200K/s,但是如果持续的大流量下载,代理服务器会禁用你的连接一会儿。 比如我无法完整的看完一个视频。   另外,就是这个代理服务器可以顺便实现翻墙,不过悲剧的事情有来了,twitter和facebook等绝大部分墙外的东西登录都用的是https。。。解决办法是先用电脑正常翻墙登录并保存登录信息,然后再用kindle上。

完。

阅读:44824 评论: 23 💬
无需smtp服务器直接发送邮件
2011-01-20

 

    以前发邮件都是连接smtp服务器然后再发送的。比如先用自己的gmail账号连接到smtp.gmail.com,认证之后再发送邮件。但是这种方式常常会有限制,发送速度慢不说,每日发送数量还有限制。

    后来一直在想邮件服务器之间是怎么发送的呢,如果可以直接连接对方mail服务器就好了。 经过很多尝试都不行,现在知道是因为各个邮件服务器都有反垃圾邮件机制,所以要做很多预备工作才可以。

    下面我以 longbill@php.js.cn 为发送者发送邮件为例,讲讲这种直接连对方服务器发送邮件的方式。

    首先需要设置 php.js.cn 域名的 txt 记录为:v=spf1 ip4:173.230.145.228 ~all 。意思是增加一个spf记录,允许173.230.145.228ip发送邮件。邮件服务器收到邮件的时候会检查这个。

    然后设置 php.js.cn 的 MX记录为 173.230.145.228 。这点按理说是不需要的,但是我觉得还是加上比较好。 意思是别人发送邮件到 xxx@php.js.cn 的时候,会被连接到这个IP。     

    然后就可以用php直接发送邮件了。 php要做的事情如下:

  • 拿到对方email后,首先检查域名的mx记录。例如 longbill.cn@gmail.com ,要用getmxrr函数得到gmail.com的mx记录,一般取第一条就可以了。
  • 用fsockopen连接刚刚得到的服务器域名
  • 按照SMTP协议写命令,取得返回结果。

    看起来像这样: 绿色的是服务器返回的信息,红色的是php发送的信息。每个换行都是\r\n

 

220 126.com Anti-spam GT for Coremail System (126com[20101010])

HELO php.js.cn

250 OK

MAIL FROM:<longbill@php.js.cn>

250 Mail OK

RCPT TO:<lclgg@126.com>

250 Mail OK

DATA

354 End data with <CR><LF>.<CR><LF>

MIME-Version: 1.0

Delivered-To: lclgg@126.com

Subject: =?UTF-8?B?6L+Z6YeM5piv5rWL6K+V6YKu5Lu25qCH6aKY?=

From: Longbill <longbill@php.js.cn>

To:  lclgg@126.com

Content-Type: text/plain; charset=UTF-8

Content-Transfer-Encoding: base64


6L+Z6YeM5piv5rWL6K+V6YKu5Lu25YaF5a6544CC

.

250 Mail OK queued as mx9,J8mowLDb7+xoCDdNCIe9AA--.240S2 1295452266

QUIT

221 Bye


就是这样。  源代码在这里。 http://php.js.cn/down/sample/mail.php.txt

完。

阅读:21761 评论: 17 💬
入手kindle3一月后有感
2011-01-04

    我的kindle3是美国的朋友帮我代购的,在amazon买了之后邮寄到美国朋友那,然后他再转寄给我。邮费用了$36。我的kindle3是带3G版本的,amazon原价$189。全球免费3G,感觉挺爽的。

    我为什么买kindle?

    有人可能觉得有电脑可以看电子书,实在不行手机上也可以看。但是我发现我在电脑前面的时候会被无数的东西吸引,根本无法集中精力看书。手机上也一样。 但是纸质书又太麻烦了,所以还是kindle最好。   但是我犯了一个错误,我不应该买带3G的,因为很少用它上网,一般下电子书wifi就可以了。

    Kindle有哪些优点?

  • E-ink电子墨水屏幕,省电,和纸质书看起来差不多,不翻页的时候保持显示内容且不用电。
  • 屏幕黑白色,不能彩色的图片和视频。
  • 屏幕翻页需要1秒左右,因此上网很不爽。
  • 对中文支持良好。
  • 下载书的时候发送书籍到一个Email,然后打开kindle的wifi就可以自动下载了。很方便。
  • 白色的,很漂亮。
  • 左右手拿着都可以很容易的翻书。
  • 未来可能可以拿来当3G猫用。
  • 可以播放音乐,有耳机插口。
  • 不开无线电池可以用非常久。。。

    总结下,核心优点就是它除了拿来看书,其他什么都不能。这点很重要,正是这点保证了我可以专心的看书,而不会跑去微博或者人人逛下。

    一些问题

  • Q:kindle有背光吗? A:No
  • Q:kindle可以上网吗? A:可以,但是很难用,如果你想拿来上网,去买个ipad吧
  • Q:kindle支持什么格式的电子书? A:pdf, txt, doc都没问题,其他格式貌似都需要转。我到目前为止,只看过pdf和txt

完。

阅读:14006 评论: 8 💬
我做的同步显示iTunes当前歌曲歌词的widget
2010-12-07

    有新版本了。看这里

 

    以前在Leopard下有著名的小芊,但是升级到Snow Leopard后,小芊就不好用了。于是自己手动写了个用于Dashboard的Widget。 放歌的时候如果想看歌词,触发Dashboard就可以了。 

    原理大概是这样的:

  • 获得当前歌曲播放时间:取自自带iTunes widget的插件。这个插件获得当前播放时间很快。
  • 获得当前歌曲标题等:用Applescript写的。
  • 自动搜索歌词:php去取百度的搜索结果,然后分析网页源代码,匹配歌词信息(歌词文件显示在网页里面也可以识别)
  • 保存歌词:保存到mp3文件的同样位置,后缀名为lrc。
  • 各种技术之间的整合:Javascript
  • 歌词动态显示效果:CSS3

    用法:添加此widget,开启iTunes听歌就可以了。如果发现歌词不对,按右下角的刷新按钮,自动找另外一个歌词文件。

    下载在这里

完。

阅读:12394 评论: 12 💬
我做的Google Tasks Widget for Mac OS
2010-11-29

    一直在找可以同步的Task或者Todo List,后来想到Google本来就有嘛,于是自己写了个Widget放在Dashboard里面,很方便。而起可以在公司电脑和自己电脑上登录同一个帐号而实现同步。

    其实实现挺简单的,一张网页,嵌一个iframe就可以了。自动同步是iframe里面的Google的网页做的事情了。 

    点击这里下载Google Tasks Widget For Mac OS

完。

阅读:10727 评论: 11 💬
Copyright © Longbill 2008-2026