电信ADSL宽带对路由器人为限速
2011-10-01

    最近住朋友家,他们家是电信4M ADSL,然后接的TP-Link的路由器。白天上网都没问题,一到高峰期的时候就慢的要死,开始还以为是路由器的问题。后来换了个路由器,还是慢。。。

    今天对这个情况进行了仔细的分析。网速慢的情况只是连接路由器后才发生,如果用电脑直接连modem拨号,就正常。于是我在不用路由器的情况下,记录了到61.139.2.69的ping值,只有2ms。然后连上路由器,再次ping 61.139.2.69,时间增加到400多ms。 但是这个情况有可能是路由器那里卡了,于是我又ping了到电信网关,发现时间只有2ms。说明从我电脑经由路由器到电信网关的通路是正常的,没有特别大的延迟。那么问题就只能出在电信机房那边了。估计是发现我用路由器,故意丢包或者故意降低带宽。

    问题找到后,先打了10000号投诉。客服MM接到电话后,我先问电信是不是有不准用路由器的政策,回答没有。于是直接表明身份,我是专业人员,发现电信违规操作。于是客服MM没有跟我瞎扯,直接反应问题到后台了。现在就等明天电信的技术人员回复了。  

    如果通过10000号投诉的途径解决不了,我就到工信部投诉。以前投诉过一次,效果非常好。工信部投诉网址如下:http://www.chinatcc.gov.cn/html/mains/shensushl.html

完。

7703 read 20 comment(s)
我才知道的几个Javascript小知识点
2011-09-02

    因为我学习Javascript的过程比较零散,没有仔细系统的看过。有些细节方面就被遗漏了。下面是我最近才搞清楚的几个函数。如果你此前就知道,那么恭喜你,你的JS比我好。如果也不清楚,那么也恭喜你,你看了此文就清楚了。

1. Array 的 slice方法

    slice(start,end)   此方法可从已有的数组中返回位于start和end之间的元素。并且不改变数组本身。start和end参数可以为负数,表示从后面开始数的第几个。

    例如: [1,2,3,4].slice(2,3) 返回[3] , [1,2,3,4].slice(2,-1) 也返回[3] 。

    另外,如果只写一个参数,那么第二个参数默认是数组的长度。也就是说 [1,2,3,4].slice(-2) 返回 [3,4]

2. Array 的 splice 方法

    splice(start,length) 此方法返回现有数组的从start开始的length个元素。并且会改变数组本身。start参数可以为负数。

    例如: var a = [1,2,3,4]; a.splice(2,2) 返回[3,4] ,并且a变成了[1,2] 

    另外,splice还支持第3,4,5...个参数,表示用后面的参数替换掉被删除的元素。

3. String 的 substr 方法

    substr(start,length) 此方法返回字符串从start开始的length个字符。不改变字符串本身。start参数可以为负数。

    例如: "abcd".substr(2,1) 返回 'c',"abcd".substr(-2) 返回 "cd"

4. String 的 substring 方法

    substring(start,end) 此方法返回字符串的start到end之间的字符。不改变字符串本身。start和end参数不能为负数!但是start可以比end小。

    例如:"abcd",substring(1,3) 和 "abcd".substring(3,1) 都返回 "bc"

表格对比

  参数 参数是否支持负数 是否改变对象本身
Array.slice (start,end) Yes No
Array.splice (start,length) Yes Yes
String.substr (start,length) Yes No
String.substring (start,end) No No

 

    此外,删除对象的某个属性用delete 操作符。

    例如: var o = {"a":1,"b":2}; delete o.a; 那么o就变成 {"b":2}

    但是如果要删除数组的某个元素,就要用上面提到的splice方法了。

    例如: var a = [1,2,3,4]; delete a[1]; 那么a就变成[1,undefined,3,4],并且a.length还是4。 必须要用a.splice(1,1)。

    还有Array.pop, Array.shift, Array.push, Array.unshift等常用方法就不说了。

完。

4216 read 9 comment(s)
Elance新手入门
2011-07-14

    Elance是全球最大的外包网站。给我的印象是门槛高,服务好,项目多,项目质量好。比起国内的猪八戒之类的网站好不知多少倍。如果你是程序员、翻译、设计师等,同时英文又好,那一定要到Elance上来接项目,这样才能充分体现你的优势嘛。因为Elance是个国际平台,上面的价格是国际价格,换算成人民币怎么都划算啊。

注册

    Elance的注册是需要验证电话号码的。注册完了之后,Elance的机器人会打电话过来,叫你把网页上的数字用英文念出来。通过验证之后就算注册成功了。可以开始接项目了。PS. 因为Elance涉及到钱,所以对帐号保护比较严,一定要记得你的密保答案啊,因为下次你换个地方登陆,它就会让你输入答案了。。。

包装自己

    新手要顺利接到项目比较难,因为没有历史项目经历和别人给的评分。所以要靠自己profile上的自我简介,profilio和skill tests等来打动客户了。其中比较特别的是skill tests。Elance使用了第三方测试平台来衡量测试者的各种技能。在Elance网站上选择想要测试的技能,比如PHP5 Code Test,然后会进入一个第三方测试网站。一般选择类题目是40题,时间是40分钟。PHP5 Code Test属于代码实践题,需要测试者根据题目提供一段PHP程序,然后后台执行这段程序看看是否正确。

    测试的结果是按你在测试者中占的百分比来的,而且貌似只有top 1%,5%,10%,20%,30%(上次我做了个JS测试的top 2%,结果给我显示5%,冤屈啊。。。),其他的就用图形来显示你的测试成绩和平均测试成绩。免费会员可以选择5个测试成绩显示在自己的profile上。如果升级成付费会员则可以显示更多的成绩。如果某个测试你觉得不满意,没关系,14天之后可以再次做这个测试(题目大部分都一样的哦)。这些成绩是很有说服力的。比如你刚注册,但是在Javascript测试中获得了top 5%的成绩,那么你在投标的时候就可以说 “我刚来Elance,但是我在前端方面有 X年的经验,不信你去看我的profile,我在Javascript测试中排前5%哦。”。然后报价再稍微比别人低一点,获得项目的机会就会大很多。

项目流程

    Elance的项目主要分为固定价格的项目和按小时计费的项目。先说说fixed price project。

    首先在网站上搜索自己感兴趣又力所能及的项目。 然后就是投标了。

    投一个$500以下的项目需要1个Connect(Elance上的一种点数吧),$500-$1000的项目需要2个Connect ... $2000以上的貌似都是5个Connect。而且这个点数是不退的,也就是说对方发个项目,你去投,然后对方没选中你,甚至对方把项目关了,你都会一样损失这些点数。免费会员每月是10个点。我是每月$10的付费会员,每月有20点。这种点数的规则就限制了像猪八戒上那些胡乱杀价的人,所以Elance上看到的基本上都是正儿八经的人报的合理价格。

    然后投标内容一般用正式的英文书信格式,例如:

Hi Alex,

I am very interested in your project. I ....

Regards,
Chunlong

    而且内容一定要根据对方的项目需求来写。切记写一个模板到处去投标。比如对方想做个图片编辑器,你就应该说你以前做过类似的东西,然后把demo地址贴上去。这样对方会很感兴趣的。

    这段时间有可能对方会跟你来回通信几次,一旦他确定给你做,就会把项目award给你,然后你在elance后台就会看到这个项目,里面有各种设置和功能。一般项目award给你之后,对方就会把项目款打到Elance,如果没打,你可以等对方打了钱再开始做。这种第三方担保类似支付宝,需要双方同意钱才能转移。此时,你就可以跟对方交流任何内容,比如Skype帐号(上面的人大部分都用Skype,因为必要时候可以视频通话)。

    项目后台最常用的是message功能,可以收发消息,还可以带附件,每个消息还会forward到你的邮箱,甚至你可以用邮箱直接回复。另外还有一个是status reports,项目开始后记得用这个来向对方报告项目进度。Terms & Milestones是一个必须双方都同意的协议,里面涉及到项目的里程碑(可以在里程碑上协定支付部分项目款),项目截止日期,项目总价等。每个修改都需要双方同意之后才会生效。

    当项目结束后,如果对方确认了你的成果。那么就可以把status reports里面设置为completed。并且提醒对方放款。

    对于按小时付费的项目,大部分流程都是一样的。但是投标的时候的金额是每小时多少钱而不是项目总共多少钱。然后开始做之后,需要你下载一个Elance的Tracker软件(是一个Adobe AIR软件)。这个软件可以记录你的项目时间和屏幕截图。开始做项目的时候,进这个软件点击开始。然后就老老实实做这个项目,因为这个软件会不定期截屏上传的!万一被看到你在玩,那是有损声誉的事情啊。

    项目做完了就是提款,具体可以看我的《从Elance提现到国内银行的完美方法

完。

7723 read 10 comment(s)
如何提高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 &"

完。

6395 read 16 comment(s)
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程序在后台运行。

完。

6006 read 5 comment(s)
[1] 2 3 4 ...32 下一页
Copyright © Longbill 2008-2012 , Designed by EndTo , Powered by EndCMS