[转载]Node.js Web开发(一)从零开始 - Henry Cui - 博客园

mikel阅读(948)

[转载]Node.js Web开发(一)从零开始 – Henry Cui – 博客园.

Node.js不必介绍,已经太火爆了。简单说是用JavaScript开发Web服务端,基于Google V8引擎,单线程。不多说从零开始Windows平台下的Node.js的开发之旅。

环境工具为先

首先到Node.js的官方网站下载安装包,一步步安装,现在最新版本为V0.8.12。安装完成后,验证下安装是否成功:打开命令行窗口输入:

node –version

获得如下提示,表示安装成功。

image

Windows 下我使用微软的WebMatrix作为开发工具,WebMatrix提供了Node.js开发时的几种模板,使用跟Visual Studio很接近,非常方便。另外提供了一些扩展的工具,比如Git的扩展工具等等。刚使用时,我还是使用node的命令进行一些操作,不直接使用 WebMatrix,WebMatrix只作为编写工具,这样更容易理解。

安装Express

我们通过使用 Node.js里面的‘http’模块进行http请求、响应的操作,来实现自己的Web框架,这里就不自己造轮子了(自己也没那个水平),使用 Node.js比较流行的Web框架“Express”。Node.js提供了很好的包的管理器“npm”,方便的进行包的安装、卸载、更新。

安装Express:

npm install –g express

会出现如下信息:

image

验证是否安装成功:

express –version

image

这里简单说下npm,上面的-g代表是全局的,默认npm是进行本地安装。本地安装时,npm会将包安装到当前目录的node_modules目录中,一般情况不可以直接在命令行中使用;全局安装时会将包安装到系统目录中,这样我们就可以在命令行中到处使用。

Express版的Hello World

我们通过Express命令创建项目S055:

Express –t ejs S055

image

这里Express提示我们要进入S005里面进行安装项目的依赖项,我们打开package.json:

{ "name": "application-name", "version": "0.0.1", "private": true, "scripts": { "start": "node app" }, "dependencies": { "express": "3.0.0rc5", "jade": "*" } }

奇怪的是,我发现依赖项里面有“jade”,而我希望使用的ejs来创建的,不知道为什么还是使用了jade(知道的朋友指点下我微笑).

jade是一种View引擎,我更喜欢使用ejs,方便,简单,这里修改成ejs.

执行npm install.

会提示我们:image,ejs跟express安装完成。

启动Node.js:

node app

启动成功后,我们再浏览器中输入http://localhost:3000/,意外发生了:

image

提示找不到jade模块,不管他了,把它修改成使用ejs.

使用ejs

使用WebMatrix打开网站image,选择刚才创建的目录(也可以直接使用WebMatrix创建Express站点),WebMatrix会自动帮我们检测到是Node.js站点。

1)打开app.js,修改下试图引擎:

app.configure(function(){ app.set('port', process.env.PORT || 3000); app.set('views', __dirname + '/views'); app.set('view engine', 'jade'); app.use(express.favicon()); app.use(express.logger('dev')); app.use(express.bodyParser()); app.use(express.methodOverride()); app.use(app.router); app.use(express.static(path.join(__dirname, 'public'))); });

将‘View engine’修改成‘ejs’。

2)删除layout.jade、index.jade,创建layout.ejs、index.ejs.

layout.ejs:

<!DOCTYPE html> <html> <head> <title><%=title%></title> <link rel="stylesheet" href="/stylesheets/style.css"> </head> <body> <%- body%> </body> </html>

index.ejs:

<h1><%=title%></h1> <p>Welcome to <%=title%></p>

这里只是把刚才的jade翻译成了ejs引擎的表现方式,其实大家可以猜下layout.ejs的作用,应该是想作为站点的模板。重新启动下Node.js,刷新下浏览器:

image

好像成功了,但是我们查看源,发现不对,没使用模板:

image

这里就不继续下去了,留到下一节的了解Express结构后,去解决它。

 

总结

本小节,初步使用了Node.js的Express框架成功创建了站点,但是视图模板还没使用成功,我们在下一节里面初步了解了Express结构之后,再去解决它。

[转载]几种SQL分页的总结 - 二炮哥 - 博客园

mikel阅读(1174)

[转载]几种SQL分页的总结 – 二炮哥 – 博客园.

在实际开发的过程中如果记录数非常的庞大,如果直接用SQL语句查询并填充到DataTable中,将是一件非常恐怖的事情。而且对网站性能,服务器性能消耗很大。

两个常犯的错误:

1)在现实数据时,查询时会将所有的满足条件的数据全部填充到DataTable中,然后在程序中根据条件显示其中的一部分数据。

2)在统计数据时,在获取符合条件的记录条数时也是通过将所有满足条件的数据全部填充到DataTable中,然后通过DataTable实例Rows.Count属性来获取记录条数。

这样做的结果就是效率极低,如果数据量太大,可能造成自己需要的数据长久的无法显示,所以显示数据是应该使用分页查询。分页查询就是每次只返回所需要的数据,而不用每次都从数据库中把数据全部提出来,这样可以降低程序与数据库之间的数据传送量,并且还可以提高程序的性能。

一般来说,在数据量大的情况下要分页显示,这样决定返回的查询结果集的参数有两个:当前显示的页数pageIndex和每页显示的记录条数size。

所使用的数据表如下图:表中的id是主键。

下面我们按照id正序排列查询所有人的信息,SQL语句如下:


select * from T_Person order by id ASC;

现在我们对数据进行分页,分页规则就是,页容量5条数据,那么我们完成第1页的数据查询可以使用SQL语句是:


select top 5 * from T_Person order by id asc;

这样我们就可以取出第1页所要显示的5条数据。但是我们应该怎么样编写SQL语句才可以显示第2,3,4……页的数据呢?

 

如果说我们第1页取出的数据时第1-5条记录,那么第2页的数据就应该是6-10的记录。我们应该怎么做到呢?有两种方法:第一种就是一次性的将所 有的数据都提取出填充到DataTable中,然后在for循环中通过i从5开始,并且i小于10这种方法显示数据,这种方法的缺点前面已经介绍。第二种 方法就是在数据库中对数据进行过滤,这个时候SQL语句中的 not in 就可以很好地排上用场。

那么怎么使用not in将第2页的数据显示出来呢,SQL语句如下:

1 select top 5 * from T_Person where id not in
2 (
3 select top 5 id from T_Person order by id asc
4 )order by id asc;

在这里使用了一个子查询先将第1页的数据编号显示出来,然后使用not in 将1-5的记录从数据中排出,显示的就是6-10 的数据记录。

因为数据id是从1开始,所以id为1-5的记录显示在第1页,id为6-10的记录在第2页显示,id为11-15的记录在第3页显示,依此类推第n页的数据的SQL语句是:n为定义显示数据的第几页,

select top 5 * from T_Person where id not in
(
select top (n-1)5 id from T_Person order by id asc
)order by id asc;

这样就可以根据参数n显示第几页的数据。

还有一个比较重要的知识点就是如何计算数据页分页的总数,如果现在有20条数据,如果每页5条数据,很明显就是分4页。但是如果记录数是21条,这个时候很明显应该分5页。有一个公式,假如总共有m条数据,每页显示n条数据(m,n都大于0),那么需要显示所有记录的页数page为:page=(m%n)==0?(m/n):(m/n+1);

第二种分页的方法:

这里需要使用SQL中的ROW_NUMBER函数,该函数的作用就是在返回的记录集合内为每一条记录标上顺序编号。

因为我们要对数据库进行删除操作的话,数据库表中的id的值可能是不连续的。因为在上面的方法中,我们主要是使用id来排序,不需要太多的操作,但是下面的方法,就需要有一个连续的id值来查询数据。

先看一个SQL语句:

select * from
(
select * from T_Person
)as a
where id&gt;5 and id(n-1)*5 and id&lt;=n*5

这个时候我们就可以根据参数n来选出相应页数的数据,但是我们可以很快的发现,这个分页对id的连续有很大的依赖性,所以,我们在对数 据进行删除操作的时候,数据库中的id很可能是不连续的,所以在数据库中进行分页的时候,就需要对数据进行编号,这个时候就要使用SQl中的 ROW_NUMBER函数,

使用ROW_NUMBER函数查询的SQl语句和显示结果如下:

很容易的我们发现在id的前面有了一个按照id正序排列的rl的列。

所以,完整的 SQL分页语句为:n为我们传入的分页的页码,默认的每页显示的数据位5条

 select * from
 (
 select * from T_Person
 )as a
 where id>(n-1)*5 and id<=n*5

这样,我们就可以建立相应的分页存储过程,在数据库中对数据进行分页,然后供程序进行调用。

最后分享一个,在网上看到的一个比较好的分页存储过程:

create PROCEDURE GetPageData
 (
 @TableName varchar(30),--表名称
 @IDName varchar(20),--表主键名称
 @PageIndex int,--当前页数 
 @PageSize int--每页大小 
 )
 AS
 IF @PageIndex > 0
 BEGIN
 set nocount on
    DECLARE @PageLowerBound int,@StartID int,@sql nvarchar(225)
    SET @PageLowerBound = @PageSize * (@PageIndex-1)
    IF @PageLowerBound<1
     SET @PageLowerBound=1
    SET ROWCOUNT @PageLowerBound
    SET @sql=N'SELECT @StartID = ['+@IDName+'] FROM '+@TableName+' ORDER BY '+@IDName
      exec sp_executesql @sql,N'@StartID int output',@StartID output
    SET ROWCOUNT 0
    SET @sql='select top '+str(@PageSize) +' * from '+@TableName+' where ['+@IDName+']>='+ str(@StartID) +' ORDER BY ['+@IDName+'] '
    EXEC(@sql)
 set nocount off
 END

[转载]推荐C#_开发桌面自动更新程序(服务端与客户端) - 牛肉幹 - 博客园

mikel阅读(894)

[转载]推荐C#_开发桌面自动更新程序(服务端与客户端) – 牛肉幹 – 博客园.

本文以小型应用的通用性自动更新程序,开发的程序可以直接拿过来使用,非常方便。

其工作原理如下:

Update.asmx仅提供一个功能,就是检测是否需要更新,在需要更新的时候就返回一个更新地址,通常情况下返回的地址就是 Download.ashx,而在某些特殊情况下,也可以修改服务端使之从其他Url提供更新下载。检测是否需要更新的的具体做法是:首先获取 Updata目录中的主程序版本号,再获取数据库中的最新版本号,两者对比。如果相同则直接与客户端提供的版本号相对比并返回结果;如果不同则将主程序版 本号写入数据库,然后生成新的更新文件包,直接向客户端返回更新地址。

Download.ashx的功能仅仅是将最新版本更新文件包输出。

而客户端部分包含主程序、Update.exe以及其他附属文件,更新时由主程序检测并下载更新,在主程序退出时,如有更新并已成功下载,则调用 Update.exe完成解包及更新覆盖工作。需注意的是:Update.exe永远不能被更新,因为它无法更新其自身,所以服务端更新时也不要将 Update.exe纳入更新包。

具体见附件

附件下载:推荐C_开发桌面自动更新程序(服务端与客户端).rar

[转载]工程师创业者 别急着做“平台” - 站长网 admin5.com

mikel阅读(1032)

[转载]工程师创业者 别急着做“平台” – 站长网 admin5.com.

 

Jamie, 我要做一个平台,让买家和卖家可以在上面自动媒合。

工程师创业者最常跟我提的就是这类型的创业构想。然后我会问他,那请问卖家如何知道要来你这个平台卖东西?或者买家如何知道要来你这个平台买东西? 他会回答:“我会铺天盖地用力的推广。”好,你接着问,好不容易拉来了一个卖家,却没有他的目标客户。回过头去拉了一些买家,却没有他们想买的商品,怎么 办?这时他的回答往往是:“运气应该不会这么差吧。”

事实上,运气就会这么差。从工程的角度来看,盖一个网络平台其实再简单不过了,就算你的程序功力不怎么样,网络发展近 20 年,市面上早就累积了无数个你可以拿来运用的套件、模块。问题是,这么多工程师在创业,这么多人都会做平台,为什么真正成功的却很少?你可以说大家的运气 都很差,也可以说其实都用错了方法。

 

当 5945 呼叫师傅 两年多前加入第一届 appWorks 育成计划 时,他们想的就是一步做成平台。那时 RedBeacon 刚刚在美国获得 TechCrunch 比赛的冠军,提供的服务是一个“居家修缮师父”的搜寻引擎。5945的两位创办人心理打得如意算盘是,Google 在台湾的水电行资料搜寻做得非常差,他们只要把这块做好,就可以像 Google 一样靠卖搜寻广告赚大钱。所以两个人花了好几个月的时间,骑着摩托车跑遍台北市大街小巷,一家一家的把水电行的资料搜集了回来。(当我跟他们说 Google Maps 有“街景”服务时,两个人脸都绿了。)

好不容易把强大的“5945 师父搜寻”做了出了来,他们却发现使用者根本不买单,没有人要来这里搜寻师父。用力推广了一年,搜寻量还是一点起色也没有。更深入的研究后发现,光是找到 师傅的联络方式,根本没解决使用者的问题。电话打过去常常没人接,接起来了师傅没空,打了 10 通电话好不容易约了一个师傅,来了之后,喊价报价,消费者根本不知道到底合不合理。

就在这时候一封客服信给了他们灵感,email 里说:“我真的很忙,你可以直接帮我把师傅找来吗?”5945 发现消费者要的不是“强大的师傅搜寻引擎”,消费者要的是“谁来帮我把马桶修好”。想通了这点,他们把整个服务大 Pivot,从“搜寻”改成了“需求单”。从此之后,消费者只要填表把需求说出来,5945 会想办法帮他们解决所有后续的联络、追踪问题。

改成这样的服务方式后,5945 得到了 Product-MarketFit, 不仅网站开始经历疯狂的成长,每个月的需求单量也都上升超过 30%。虽然每一单他们必须要辛苦的处理、联络、追踪,偶尔还会出现棘手的客诉事件,但在这个过程中,他们累积了非常扎实的 Know-how,12 个月超过1,000 张订单下来,几乎什么居家修缮会出现的问题,他们都处理过了。

有了这些实际 Know-how,他们再回到设计桌上,把学到的东西化为功能,在日前又推出了 5945 呼叫师傅 2.0 平台,我想这一次,已经拥有既有的客户与师傅,再加上对修缮媒合的深入了解的他们,绝对会比第一次成功很多。

如果 5945 的故事能够教我们什么,那就是真正的“平台”,其实是从“案例”累积出来的。当你还没经手过足够的案例,制作出来的平台当然会过于理想化,也往往会离卖方 与买方想要的有很大的差距。所以一开始,比较好的方法是放弃直接做平台的想法,先想办法积累实际媒合的经验,等到这件事情做得够多了,你自然就会知道如何 变成一个平台。

先从 0 到 1,才能从 1 到 100。创业,往往是这样一个过程。

恭喜 5945 找到了他们的 1,也祝福他们接下来能顺利的从 1 慢慢前进到 2, 3… 10… 20… 50…, 98, 99, 100,加油了 Team 5945。

[转载]ASP.NET 如何固定表头(fixed header)

mikel阅读(1297)

[转载]ASP.NET 如何固定表头(fixed header) – JF Zhu – 博客园.

你在HTML中渲染一张表格(可能是GridView或者Repeater),如果表格的行数太多,你就得向下拖东滚动条,但你一旦向下拖动滚动条,表头的信息就不见了。具体见下图。

image

向下拖动滚动条后,表头信息消失:

image

在本文中,我向大家讲解如何固定住表头。网上可以搜索到很多种方法来实现这个功能,但这些方法基本的原理都是一样的。就是利用div,将表头的信息复制到表身之上的一个div中。

 

<div>     表头    </div>

<div>     表身    </div>

 

滚动条只在表身div中,这样拖动表身div就不会影响到表头的div了。

 

经过我的实验,有以下两个具体的方法比较好用,分别适用于ASP.NET的Repeater控件和GridView控件。

(一)用于Repeater控件:

WebForm1.aspx




<script type="text/javascript" language="javascript">// <![CDATA[
        function FixTableHeader() {
            var t = document.getElementById("table");
            var thead = t.getElementsByTagName("thead")[0];
            var t1 = t.cloneNode(false);
            t1.appendChild(thead);
            document.getElementById("tableHeader").appendChild(t1)
        }
        window.onload = FixTableHeader;

// ]]></script>
<form id="form1">
<div id="tableHeader"></div>
<div style="overflow: scroll; height: 100px; width: 500px;">
<table id="table" style="table-layout: fixed;" width="500">
<thead>
<tr id="thead" style="background-color: #bebebe;">
<th>Account Number</th>
<th>Account Name</th>
<th>City</th>
<th>Country</th>
</tr>
</thead>
<tbody>
<tr>
<td>&lt;%#DataBinder.Eval(Container.DataItem, "AccountNumber")%&gt;</td>
<td>&lt;%#DataBinder.Eval(Container.DataItem, "AccountName")%&gt;</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
</form>

注意,如果你想表头和表身的每一列都对齐的话,table的style=”table-layout: fixed”不能少。

C#文件

using System;
using System.Web.UI;
using System.Data;

namespace WebApplication1
{
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
DataTable dt = new DataTable();
dt.Columns.Add(new DataColumn("AccountNumber"));
dt.Columns.Add(new DataColumn("AccountName"));
dt.Columns.Add(new DataColumn("City"));
dt.Columns.Add(new DataColumn("Country"));
DataRow dr = dt.NewRow();
dr["AccountName"] = "Test1";
dr["AccountNumber"] = "001";
dr["Country"] = "China";
dr["City"] = "Beijing";
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["AccountName"] = "Test2";
dr["AccountNumber"] = "002";
dr["Country"] = "China";
dr["City"] = "Shanghai";
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["AccountName"] = "Test3";
dr["AccountNumber"] = "003";
dr["Country"] = "the Nederlands";
dr["City"] = "Amsterdam";
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["AccountName"] = "Test4";
dr["AccountNumber"] = "004";
dr["Country"] = "France";
dr["City"] = "Paris";
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["AccountName"] = "Test5";
dr["AccountNumber"] = "005";
dr["Country"] = "Spain";
dr["City"] = "Barcelona";
dt.Rows.Add(dr);
dr = dt.NewRow();
dr["AccountName"] = "Test6";
dr["AccountNumber"] = "006";
dr["Country"] = "China";
dr["City"] = "Shanghai";
dt.Rows.Add(dr);
Reapeter1.DataSource = dt;
Reapeter1.DataBind();
}
}
}
}

最后的效果为:

image

image

 

(二) 用于GridView控件:

WebForm2.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm2.aspx.cs" Inherits="WebApplication1.WebForm2" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title></title>
    <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
    <script src="Scripts/ScrollableGridPlugin.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            $('#<%=GridView1.ClientID %>').Scrollable({
                ScrollHeight: 100,
                Width: 500
            });
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:GridView runat="server" ID="GridView1" AutoGenerateColumns="false" Width="500px">
            <RowStyle BackColor="#EFF3FB" />
            <FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
            <PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" />
            <HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
            <AlternatingRowStyle BackColor="White" />
            <Columns>                
                <asp:BoundField DataField="AccountNumber" HeaderText="Account Number">                    
                </asp:BoundField>
                <asp:BoundField DataField="AccountName" HeaderText="Account Name">                                    
                </asp:BoundField>
                <asp:BoundField DataField="City" HeaderText="City" >                
                </asp:BoundField>
                <asp:BoundField DataField="Country" HeaderText="Country">                
                </asp:BoundField>
            </Columns>
        </asp:GridView>
    </div>
    </form>
</body>
</html>

这里主要用到了JQuery和ScrollableGridPlugin.js插件。ScrollableGridPlugin.js插件很好用,想要哪个GridView固定住表头,只需要在开始的Script中加入以下的代码。第一个参数用来设置表的高度,第二个设置表宽,单位都为px。这两个参数也可以省略,ScrollableGridPlugin.js中会设置默认值。

$(document).ready(function () { 
    $('#<%=GridView1.ClientID %>').Scrollable({ 
        ScrollHeight: 100, 
        Width: 500 
    }); 
});

ScrollableGridPlugin.js的代码为:

(function ($) {
    $.fn.Scrollable = function (options) {
        var defaults = {
            ScrollHeight: 300,
            Width: 0
        };
        var options = $.extend(defaults, options);
        return this.each(function () {
            var grid = $(this).get(0);
            var gridWidth = grid.offsetWidth;
            var gridHeight = grid.offsetHeight;
            var headerCellWidths = new Array();
            for (var i = 0; i < grid.getElementsByTagName("TH").length; i++) {
                headerCellWidths[i] = grid.getElementsByTagName("TH")[i].offsetWidth;
            }
            grid.parentNode.appendChild(document.createElement("div"));
            var parentDiv = grid.parentNode;

            var table = document.createElement("table");
            for (i = 0; i < grid.attributes.length; i++) {
                if (grid.attributes[i].specified && grid.attributes[i].name != "id") {
                    table.setAttribute(grid.attributes[i].name, grid.attributes[i].value);
                }
            }
            table.style.cssText = grid.style.cssText;
            table.style.width = gridWidth + "px";
            table.appendChild(document.createElement("tbody"));
            table.getElementsByTagName("tbody")[0].appendChild(grid.getElementsByTagName("TR")[0]);
            var cells = table.getElementsByTagName("TH");

            var gridRow = grid.getElementsByTagName("TR")[0];
            for (var i = 0; i < cells.length; i++) {
                var width;
                if (headerCellWidths[i] > gridRow.getElementsByTagName("TD")[i].offsetWidth) {
                    width = headerCellWidths[i];
                }
                else {
                    width = gridRow.getElementsByTagName("TD")[i].offsetWidth;
                }
                cells[i].style.width = parseInt(width - 3) + "px";
                gridRow.getElementsByTagName("TD")[i].style.width = parseInt(width - 3) + "px";
            }
            parentDiv.removeChild(grid);

            var dummyHeader = document.createElement("div");
            dummyHeader.appendChild(table);
            parentDiv.appendChild(dummyHeader);
            if (options.Width > 0) {
                gridWidth = options.Width;
            }
            var scrollableDiv = document.createElement("div");
            if (parseInt(gridHeight) > options.ScrollHeight) {
                gridWidth = parseInt(gridWidth) + 17;
            }
            scrollableDiv.style.cssText = "overflow:auto;height:" + options.ScrollHeight + "px;width:" + gridWidth + "px";
            scrollableDiv.appendChild(grid);
            parentDiv.appendChild(scrollableDiv);
        });
    };
})(jQuery);

C#的代码为:

using System;
using System.Web.UI;
using System.Data;

namespace WebApplication1
{
    public partial class WebForm2 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                DataTable dt = new DataTable();
                dt.Columns.Add(new DataColumn("AccountNumber"));
                dt.Columns.Add(new DataColumn("AccountName"));
                dt.Columns.Add(new DataColumn("City"));
                dt.Columns.Add(new DataColumn("Country"));
                DataRow dr = dt.NewRow();
                dr["AccountName"] = "Test1";
                dr["AccountNumber"] = "001";
                dr["Country"] = "China";
                dr["City"] = "Beijing";
                dt.Rows.Add(dr);
                dr = dt.NewRow();
                dr["AccountName"] = "Test2";
                dr["AccountNumber"] = "002";
                dr["Country"] = "China";
                dr["City"] = "Shanghai";
                dt.Rows.Add(dr);
                dr = dt.NewRow();
                dr["AccountName"] = "Test3";
                dr["AccountNumber"] = "003";
                dr["Country"] = "the Nederlands";
                dr["City"] = "Amsterdam";
                dt.Rows.Add(dr);
                dr = dt.NewRow();
                dr["AccountName"] = "Test4";
                dr["AccountNumber"] = "004";
                dr["Country"] = "France";
                dr["City"] = "Paris";
                dt.Rows.Add(dr);
                dr = dt.NewRow();
                dr["AccountName"] = "Test5";
                dr["AccountNumber"] = "005";
                dr["Country"] = "Spain";
                dr["City"] = "Barcelona";
                dt.Rows.Add(dr);
                dr = dt.NewRow();
                dr["AccountName"] = "Test6";
                dr["AccountNumber"] = "006";
                dr["Country"] = "China";
                dr["City"] = "Shanghai";
                dt.Rows.Add(dr);
                GridView1.DataSource = dt;
                GridView1.DataBind();
            }
        }
    }
}

 

[转载]C#/winform 腾讯QQ注册

mikel阅读(1326)

[转载]C#/winform 腾讯QQ注册 – Aaron Ding – 博客园.

今日不知为何,总有点感慨人生。做了程序猿已经差不多快2年了,除了工作上的软件之外,貌似从来没为自己做过什么实用的软件,比如一些快捷的工具等 等。感觉着编程技术在工作上确实很难学到。特别是国内的公司,尽管更新的技术,更优秀的技术诞生了,可我们还是依然用着以前的技术,某些简单的技术,反反 复复。很难找到一些挑战性的元素。于是,就找点有意思的事情来做做吧。

腾讯QQ无疑已经是国内即时通讯软件的的巨头了. 相当于国外的MSN。围绕着腾讯QQ的软件也非常多非常多,例如自动回复软件.群发消息软件等等。今天,我们就以腾讯QQ的注册为案列实现一个只需要输入验证码就能注册的C#版软件。

首先我们看看腾讯QQ的注册页面

image

根据这个页面,我们可以了解到,注册一个QQ的基本元素。 昵称,密码,性别,生日,所在地,验证码(一般第一次打开这个页面时没有验证码),还有立即注册的提交按钮。

在这之前,我们需要这边一个抓包工具来抓取POST包 IE HttpAnalyzer V6

image

安装后在IE浏览器的工具里可以找到,如上图所示。具体用法请百度了。这里将不再讲述。

PS:刚刚抓包才发现,我的IE HttpAnalyzer已经过期了。将就用HttpWatch吧。其实用哪个都一样。。

抓包结果如图

image

 

我们主要关注POST提交这一段就可以了。如图

image

图片可能小了。看不清楚,附上文字

下面是提交POST的信息

POST /cgi-bin/chs/numreg/get_acc?r=0.6192339314225849 HTTP/1.1
Accept: */*
Accept-Language: zh-cn
Referer: http://zc.qq.com/chs/index.html
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Host: zc.qq.com
Content-Length: 487
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: pt2gguin=o2863947406; pgv_pvid=7187609245; RK=4/CD46/CsN; ptui_loginuin=617975284; uin=o2863947406; skey=@qeJO2b28Y; ptisp=ctc; pgv_info=ssid=s4156213344; o_cookie=2863947406; verifysession=h00168891a5a6d40916b6ff218c92710d21caffe26443b349cba00a65b3849c8105588840fd02f67123; machineCookie=655f408c42841e99c57598d3968eebf866fa30383ff98073; zc_uid=1350381363_1822484793; sessionCookie=a20b4ac684c8f95844944206dec3534fa154a2929499851a; uoc=0-0-9-0-10-0-0-19; _new_uin=2863947406; wdl=57fe92992131b79c8df28eea424ac528a95c183264a47555; clientkey=b3c7928a115950440deb11c9e59c7f7c1fd8459b8592f2c2; index_ec=0; nick=sdfsdf

&verifycode=ovur&qzone_flag=1&country=1&province=44&city=3&isnongli=0&year=1995&month=3&day=3&isrunyue=0&password=b0b81bd39cc122dc2389abd9a6753c474ffc5cd44b29c6fae65a82d0dc9926d0ae52cfad3e70d2801f81d9fbbdaed68880d1af187d246af698ecb25c7d38795579be20cf9d553c3a9e9c70b205a8152aebd22449e0d253296d94eecad82e9583380d76dce6d91bf3760acc44e4f71ba55026e32cd9ae3601f017b757ca4bb63d&phone_num=&nick=sdfsdf&email=false&other_email=false&elevel=1&sex=1&qzdate=&jumpfrom=58030&csloginstatus=0&r5d8=w5g8

下面是提交完成后返回的数据

HTTP/1.1 200 OK
Server: QZHTTP-2.12
Date: Thu, 18 Oct 2012 02:43:42 GMT
UUID: 0
Content-Length: 61
Set-Cookie:_new_uin=1791969847; Domain=zc.qq.com; Path=/
Set-Cookie:sessionCookie=; Domain=zc.qq.com; Path=/
Set-Cookie:wdl=0341a2fea2414c9b26097c75206bb7339a25631b7f6860c5; Domain=zc.qq.com; Expires=Thu, 18 Oct 2012 03:43:42 GMT; Path=/; HTTPOnly
Set-Cookie:clientkey=bf972ece0ce54040c485d69242c3d588d7fa22a82773ffc6; Domain=zc.qq.com; Path=/
Content-Type: text/html
Connection: keep-alive

{“ec”:0,”safeverifyResult”:”1″,”type”:”0″,”uin”:”1791969847″}

———————————————————————————————————————————————————————————-

分析提交的数据

&verifycode=ovur&qzone_flag=1&country=1&province=44&city=3&isnongli=0&year=1995&month=3&day=3&isrunyue=0&password=b0b81bd39cc122dc2389abd9a6753c474ffc5cd44b29c6fae65a82d0dc9926d0ae52cfad3e70d2801f81d9fbbdaed68880d1af187d246af698ecb25c7d38795579be20cf9d553c3a9e9c70b205a8152aebd22449e0d253296d94eecad82e9583380d76dce6d91bf3760acc44e4f71ba55026e32cd9ae3601f017b757ca4bb63d&phone_num=&nick=sdfsdf&email=false&other_email=false&elevel=1&sex=1&qzdate=&jumpfrom=58030&csloginstatus=0&r5d8=w5g8

verifycode:验证码

qzone_flag:是否开通空间,1代表开通0不开通

&country=1&province=44&city=3&isnongli=0&year=1995&month=3&day=3:这些你们懂的。。

isrunyue=0:不知道什么,估计是一个固定值

password::密码你懂得后面是加密过密码的字符串

&phone_num=&nick=sdfsdf&email=false& other_email=false&elevel=1&sex=1&qzdate=&jumpfrom=58030& amp;csloginstatus=0&r5d8=w5g8:这些就不说了。估计你不知道的参数保持原样,我们只替换知道的参数就行

分析返回的结果

{“ec”:0,”safeverifyResult”:”1″,”type”:”0″,”uin”:”1791969847″}

ec:返回的标志代码,初步预测如下:

case 0: 注册成功;

case 1: EMAIL注册成功;

case 2: 验证码错误;

case 4:case 5:case 6: 生日或省份错误;

case 8:case 9: EMAIL错误;

case 13:case 15:昵称错误;

case 20: 需要手机短信验证;
原因:可能是COOKIE错误

case 21: 恶意注册,暂时禁止;
原因:注册的账号过多,或RSA算法错误

case 26: 需要手机激活;
原因:相同IP注册过多或提交的COOKIE已经过期,或SESSION超时

case 30: 浏览器不兼容;

 

safeverifyResult:验证码通过

type:真心不知

uin:很明显,QQ号码

———————————————————————————————————————————————————————————-

接下来我们就是要模拟数据了,在这之前,我们需要获得一些元素

第一:URL分析

地址:【+ 0.161        !    0.019    944    304    GET    200    html    http://zc.qq.com/cgi-bin/chs/numreg/init?r=0.5402871509444349&cookieCode=undefined

分析:返回结果 -》{“city”:”娣卞湷”,”cityid”:”3″,”country”:”涓 浗”,”countryid”:”1″,”ec”:0,”elevel”:”1″,”localdate”:”2012-10-18″,”province”:” 骞夸笢”,”provinceid”:”44″}

utf-8编码之后,就是正常的了。看字面上的意思,我相信你们理解的。

参数r:随机数,准确的来说是  0.(+16个随机数)[不写貌似也可能获得]

cookiecode:cookie代码,直接忽略吧。不管它

验证码:  【 0.244        !    0.039    630    2812    GET    200    jpeg    http://captcha.qq.com/getimage?aid=1007901&r=0.7166559025129264
分析:aid是当前的版本,r是随机数

Post地址:【+ 0.000        !    0.166    1459    564    POST    200    html    http://zc.qq.com/cgi-bin/chs/numreg/get_acc?r=0.6192339314225849

分析:没什么好说的。

第二:密码分析

根 据:password=b0b81bd39cc122dc2389abd9a6753c474ffc5cd44b29c6fae65a82d0dc9926d0ae52cfad3e70d2801f81d9fbbdaed68880d1af187d246af698ecb25c7d38795579be20cf9d553c3a9e9c70b205a8152aebd22449e0d253296d94eecad82e9583380d76dce6d91bf3760acc44e4f71ba55026e32cd9ae3601f017b757ca4bb63d

很明显,经过加密的,到底使用什么加密呢?????正在思考

通常,如果是我们写注册模块的话。会把加密文件写在哪里呢???正在思考

没错,不用怀疑,就是JS。。。JS。

根据我们的预测,我们来look,look我们抓包的页面的js下载的URL(带上你们的火眼look,look)

image

相信不用一分钟的实现,你们就发现了 simple.js,rsa.js,index.js 我了个去。够明显吧。 rsa.js…..

预测90%是rsa加密了。

index.js  做网站的人大部分都知道…这个文件的含义是什么…。很明显,也是90%通过这个文件提交表单数据,然后再这个文件里面条用rsa.js进行加密。

(PS:剩下10%大家去研究吧..仔细看看文件里面的内容)

本人也在研究中…………………….

大约看了10分钟的样子,肯定加一定:rsa.js加密

细心的你们肯定还会发现…他是这样调用的。。。

rsaEncrypt:function(a)

{

var b=new RSAKey;b.setPublic(“C4D23C2DB0ECC904FE0CD0CBBCDC988C039D79E1BDA8ED4BFD4D43754EC9693460D15271AB43A59AD6D0F0EEE95424F70920F2C4A08DFDF03661300047CA3A6212E48204C1BE71A846E08DD2D9F1CBDDFF40CA00C10C62B1DD42486C70A09C454293BCA9ED4E7D6657E3F62076A14304943252A88EFA416770E0FBA270A141E7″,”10001”);

return b.encrypt(a)

}

ok,ok,到这里。我们及知道了rsa.js加密js文件,也知道了调用的方法…那就是说。。密码这一关,过了!!!!

 

———————————————————————————————————————————————————————————-

万事俱备,只欠东风啊!!!!

分析就此完成,现在开始编码…………….

新建winform程序。。拖点控件啥的就不说了…直接切入主题

 

第一:准备js

拷贝rsa.js的内容,在后面加个方法,如下:

function parseBigInt(a, b) { return new BigInteger(a, b) } function linebrk(a, b) { for (var c = "", d = 0; d + b &lt; a.length; ) c += a.substring(d, d + b) + "\n", d += b; return c + a.substring(d, a.length) } function byte2Hex(a) { return a &lt; 16 ? "0" + a.toString(16) : a.toString(16) }function pkcs1pad2(a, b) { if (b &lt; a.length + 11) return uv_alert("Message too long for RSA"), null; for (var c = [], d = a.length - 1; d &gt;= 0 &amp;&amp; b &gt; 0; ) { var e = a.charCodeAt(d--); e &lt; 128 ? c[--b] = e : e &gt; 127 &amp;&amp; e &lt; 2048 ? (c[--b] = e &amp; 63 | 128, c[--b] = e &gt;&gt; 6 | 192) : (c[--b] = e &amp; 63 | 128, c[--b] = e &gt;&gt; 6 &amp; 63 | 128, c[--b] = e &gt;&gt; 12 | 224) } c[--b] = 0; d = new SecureRandom; for (e = []; b &gt; 2; ) { for (e[0] = 0; e[0] == 0; ) d.nextBytes(e); c[--b] = e[0] } c[--b] = 2; c[--b] = 0; return new BigInteger(c) } function RSAKey() { this.n = null; this.e = 0; this.coeff = this.dmq1 = this.dmp1 = this.q = this.p = this.d = null }function RSASetPublic(a, b) { a != null &amp;&amp; b != null &amp;&amp; a.length &gt; 0 &amp;&amp; b.length &gt; 0 ? (this.n = parseBigInt(a, 16), this.e = parseInt(b, 16)) : uv_alert("Invalid RSA public key") } function RSADoPublic(a) { return a.modPowInt(this.e, this.n) } function RSAEncrypt(a) { a = pkcs1pad2(a, this.n.bitLength() + 7 &gt;&gt; 3); if (a == null) return null; a = this.doPublic(a); if (a == null) return null; a = a.toString(16); return (a.length &amp; 1) == 0 ? a : "0" + a }RSAKey.prototype.doPublic = RSADoPublic;RSAKey.prototype.setPublic = RSASetPublic;RSAKey.prototype.encrypt = RSAEncrypt;var dbits, canary = 244837814094590, j_lm = (canary &amp; 16777215) == 15715070; function BigInteger(a, b, c) { a != null &amp;&amp; ("number" == typeof a ? this.fromNumber(a, b, c) : b == null &amp;&amp; "string" != typeof a ? this.fromString(a, 256) : this.fromString(a, b)) } function nbi() { return new BigInteger(null) } function am1(a, b, c, d, e, f) { for (; --f &gt;= 0; ) { var g = b * this[a++] + c[d] + e, e = Math.floor(g / 67108864); c[d++] = g &amp; 67108863 } return e }function am2(a, b, c, d, e, f) { var g = b &amp; 32767; for (b &gt;&gt;= 15; --f &gt;= 0; ) { var h = this[a] &amp; 32767, i = this[a++] &gt;&gt; 15, k = b * h + i * g, h = g * h + ((k &amp; 32767) &lt;&lt; 15) + c[d] + (e &amp; 1073741823), e = (h &gt;&gt;&gt; 30) + (k &gt;&gt;&gt; 15) + b * i + (e &gt;&gt;&gt; 30); c[d++] = h &amp; 1073741823 } return e } function am3(a, b, c, d, e, f) { var g = b &amp; 16383; for (b &gt;&gt;= 14; --f &gt;= 0; ) { var h = this[a] &amp; 16383, i = this[a++] &gt;&gt; 14, k = b * h + i * g, h = g * h + ((k &amp; 16383) &lt;&lt; 14) + c[d] + e, e = (h &gt;&gt; 28) + (k &gt;&gt; 14) + b * i; c[d++] = h &amp; 268435455 } return e }j_lm = true; BigInteger.prototype.am = am2; dbits = 30; BigInteger.prototype.DB = dbits; BigInteger.prototype.DM = (1 &lt;&lt; dbits) - 1; BigInteger.prototype.DV = 1 &lt;&lt; dbits; var BI_FP = 52; BigInteger.prototype.FV = Math.pow(2, BI_FP); BigInteger.prototype.F1 = BI_FP - dbits; BigInteger.prototype.F2 = 2 * dbits - BI_FP; var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz", BI_RC = [], rr, vv;rr = "0".charCodeAt(0); for (vv = 0; vv = 0; --b) a[b] = this[b]; a.t = this.t; a.s = this.s } function bnpFromInt(a) { this.t = 1; this.s = a &lt; 0 ? -1 : 0; a &gt; 0 ? this[0] = a : a &lt; -1 ? this[0] = a + DV : this.t = 0 }function nbv(a) { var b = nbi(); b.fromInt(a); return b }function bnpFromString(a, b) { var c; if (b == 16) c = 4; else if (b == 8) c = 3; else if (b == 256) c = 8; else if (b == 2) c = 1; else if (b == 32) c = 5; else if (b == 4) c = 2; else { this.fromRadix(a, b); return } this.s = this.t = 0; for (var d = a.length, e = false, f = 0; --d &gt;= 0; ) { var g = c == 8 ? a[d] &amp; 255 : intAt(a, d); g &lt; 0 ? a.charAt(d) == "-" &amp;&amp; (e = true) : (e = false, f == 0 ? this[this.t++] = g : f + c &gt; this.DB ? (this[this.t - 1] |= (g &amp; (1 &lt;&lt; this.DB - f) - 1) &lt;&lt; f, this[this.t++] = g &gt;&gt; this.DB - f) : this[this.t - 1] |= g &lt;&lt; f, f += c, f &gt;= this.DB &amp;&amp; (f -= this.DB)) } if (c == 8 &amp;&amp; (a[0] &amp; 128) != 0) this.s = -1, f &gt; 0 &amp;&amp; (this[this.t -1] |= (1 &lt;&lt; this.DB - f) - 1 &lt;&lt; f); this.clamp(); e &amp;&amp; BigInteger.ZERO.subTo(this, this)} function bnpClamp() { for (var a = this.s &amp; this.DM; this.t &gt; 0 &amp;&amp; this[this.t - 1] == a; ) --this.t }function bnToString(a) { if (this.s &lt; 0) return "-" + this.negate().toString(a); if (a == 16) a = 4; else if (a == 8) a = 3; else if (a == 2) a = 1; else if (a == 32) a = 5; else if (a == 4) a = 2; else return this.toRadix(a); var b = (1 &lt;&lt; a) - 1, c, d = false, e = "", f = this.t, g = this.DB - f * this.DB % a; if (f-- &gt; 0) { if (g &lt; this.DB &amp;&amp; (c = this[f] &gt;&gt; g) &gt; 0) d = true, e = int2char(c); for (; f &gt;= 0; ) g &lt; a ? (c = (this[f] &amp; (1 &lt;&lt; g) - 1) &lt;&lt; a - g, c |= this[--f] &gt;&gt; (g += this.DB - a)) : (c = this[f] &gt;&gt; (g -= a) &amp; b, g 0 &amp;&amp; (d = true), d &amp;&amp; (e += int2char(c)) } return d ? e : "0" }function bnNegate() { var a = nbi(); BigInteger.ZERO.subTo(this, a); return a } function bnAbs() { return this.s &lt; 0 ? this.negate() : this } function bnCompareTo(a) { var b = this.s - a.s; if (b != 0) return b; var c = this.t, b = c - a.t; if (b != 0) return b; for (; --c &gt;= 0; ) if ((b = this - a) != 0) return b; return 0 } function nbits(a) { var b = 1, c; if ((c = a &gt;&gt;&gt; 16) != 0) a = c, b += 16; if ((c = a &gt;&gt; 8) != 0) a = c, b += 8; if ((c = a &gt;&gt; 4) != 0) a = c, b += 4; if ((c = a &gt;&gt; 2) != 0) a = c, b += 2; a &gt;&gt; 1 != 0 &amp;&amp; (b += 1); return b }function bnBitLength() { return this.t = 0; --c) b = this; for (c = a - 1; c &gt;= 0; --c) b = 0; b.t = this.t + a; b.s = this.s } function bnpDRShiftTo(a, b) { for (var c = a; c &lt; this.t; ++c) b = this; b.t = Math.max(this.t - a, 0); b.s = this.s }function bnpLShiftTo(a, b) { var c = a % this.DB, d = this.DB - c, e = (1 &lt;&lt; d) - 1, f = Math.floor(a / this.DB), g = this.s &lt;&lt; c &amp; this.DM, h; for (h = this.t - 1; h &gt;= 0; --h) b[h + f + 1] = this[h] &gt;&gt; d | g, g = (this[h] &amp; e) &lt;&lt; c; for (h = f - 1; h &gt;= 0; --h) b[h] = 0; b[f] = g; b.t = this.t + f + 1; b.s = this.s; b.clamp() }function bnpRShiftTo(a, b) { b.s = this.s; var c = Math.floor(a / this.DB); if (c &gt;= this.t) b.t = 0; else { var d = a % this.DB, e = this.DB - d, f = (1 &lt;&lt; d) - 1; b[0] = this &gt;&gt; d; for (var g = c + 1; g &lt; this.t; ++g) b[g - c - 1] |= (this[g] &amp; f) &lt;&lt; e, b[g - c] = this[g] &gt;&gt; d; d &gt; 0 &amp;&amp; (b[this.t - c - 1] |= (this.s &amp; f) &lt;&lt; e); b.t = this.t - c; b.clamp() } }function bnpSubTo(a, b) { for (var c = 0, d = 0, e = Math.min(a.t, this.t); c &lt; e; ) d += this - a, b = d &amp; this.DM, d &gt;&gt;= this.DB; if (a.t &lt; this.t) { for (d -= a.s; c &lt; this.t; ) d += this, b = d &amp; this.DM, d &gt;&gt;= this.DB; d += this.s } else { for (d += this.s; c &lt; a.t; ) d -= a, b = d &amp; this.DM, d &gt;&gt;= this.DB; d -= a.s } b.s = d &lt; 0 ? -1 : 0; d &lt; -1 ? b = this.DV + d : d &gt; 0 &amp;&amp; (b = d); b.t = c; b.clamp() }function bnpMultiplyTo(a, b) { var c = this.abs(), d = a.abs(), e = c.t; for (b.t = e + d.t; --e &gt;= 0; ) b[e] = 0; for (e = 0; e &lt; d.t; ++e) b[e + c.t] = c.am(0, d[e], b, e, 0, c.t); b.s = 0; b.clamp(); this.s != a.s &amp;&amp; BigInteger.ZERO.subTo(b, b) } function bnpSquareTo(a) { for (var b = this.abs(), c = a.t = 2 * b.t; --c &gt;= 0; ) a = 0; for (c = 0; c &lt; b.t - 1; ++c) { var d = b.am(c, b, a, 2 * c, 0, 1); if ((a += b.am(c + 1, 2 * b, a, 2 * c + 1, d, b.t - c - 1)) &gt;= b.DV) a -= b.DV, a = 1 } a.t &gt; 0 &amp;&amp; (a[a.t - 1] += b.am(c, b, a, 2 * c, 0, 1)); a.s = 0; a.clamp() }function bnpDivRemTo(a, b, c) { var d = a.abs(); if (!(d.t 0 ? (d.lShiftTo(h, f), e.lShiftTo(h, c)) : (d.copyTo(f), e.copyTo(c)); d = f.t; e = f[d - 1]; if (e != 0) { var i = e * (1 &lt;&lt; this.F1) + (d &gt; 1 ? f[d - 2] &gt;&gt; this.F2 : 0), k = this.FV / i, i = (1 &lt;&lt; this.F1) / i, o = 1 &lt;&lt; this.F2, l = c.t, m = l - d, j = b == null ? nbi() : b; f.dlShiftTo(m, j); c.compareTo(j) &gt;= 0 &amp;&amp; (c = 1, c.subTo(j, c)); BigInteger.ONE.dlShiftTo(d,j); for (j.subTo(f, f); f.t &lt; d; ) f[f.t++] = 0; for (; --m &gt;= 0; ) { var n = c[--l] == e ? this.DM : Math.floor(c[l] * k + (c[l - 1] + o) * i); if ((c[l] += f.am(0, n, c, m, 0, d)) &lt; n) { f.dlShiftTo(m, j); for (c.subTo(j, c); c[l] &lt; --n; ) c.subTo(j, c) } } b != null &amp;&amp; (c.drShiftTo(d, b), g != a &amp;&amp; BigInteger.ZERO.subTo(b, b)); c.t = d; c.clamp(); h &gt; 0 &amp;&amp; c.rShiftTo(h, c); g &lt; 0 &amp;&amp; BigInteger.ZERO.subTo(c, c) } } } } function bnMod(a) { var b = nbi(); this.abs().divRemTo(a, null, b); this.s &lt; 0 &amp;&amp; b.compareTo(BigInteger.ZERO) &gt; 0 &amp;&amp; a.subTo(b, b); return b } function Classic(a) { this.m = a }function cConvert(a) { return a.s &lt; 0 || a.compareTo(this.m) &gt;= 0 ? a.mod(this.m) : a } function cRevert(a) { return a } function cReduce(a) { a.divRemTo(this.m, null, a) } function cMulTo(a, b, c) { a.multiplyTo(b, c); this.reduce(c) } function cSqrTo(a, b) { a.squareTo(b); this.reduce(b) } Classic.prototype.convert = cConvert; Classic.prototype.revert = cRevert; Classic.prototype.reduce = cReduce; Classic.prototype.mulTo = cMulTo; Classic.prototype.sqrTo = cSqrTo;function bnpInvDigit() { if (this.t &lt; 1) return 0; var a = this[0]; if ((a &amp; 1) == 0) return 0; var b = a &amp; 3, b = b * (2 - (a &amp; 15) * b) &amp; 15, b = b * (2 - (a &amp; 255) * b) &amp; 255, b = b * (2 - ((a &amp; 65535) * b &amp; 65535)) &amp; 65535, b = b * (2 - a * b % this.DV) % this.DV; return b &gt; 0 ? this.DV - b : -b } function Montgomery(a) { this.m = a; this.mp = a.invDigit(); this.mpl = this.mp &amp; 32767; this.mph = this.mp &gt;&gt; 15; this.um = (1 &lt;&lt; a.DB - 15) - 1; this.mt2 = 2 * a.t }function montConvert(a) { var b = nbi(); a.abs().dlShiftTo(this.m.t, b); b.divRemTo(this.m, null, b); a.s &lt; 0 &amp;&amp; b.compareTo(BigInteger.ZERO) &gt; 0 &amp;&amp; this.m.subTo(b, b); return b } function montRevert(a) { var b = nbi(); a.copyTo(b); this.reduce(b); return b }function montReduce(a) { for (; a.t &gt; 15) * this.mpl &amp; this.um) &lt;&lt; 15) &amp; a.DM, c = b + this.m.t; for (a += this.m.am(0, d, a, b, 0, this.m.t); a &gt;= a.DV; ) a -= a.DV, a[++c]++ } a.clamp(); a.drShiftTo(this.m.t, a); a.compareTo(this.m) &gt;= 0 &amp;&amp; a.subTo(this.m, a) } function montSqrTo(a, b) { a.squareTo(b); this.reduce(b) } function montMulTo(a, b, c) { a.multiplyTo(b, c); this.reduce(c) } Montgomery.prototype.convert = montConvert;Montgomery.prototype.revert = montRevert; Montgomery.prototype.reduce = montReduce; Montgomery.prototype.mulTo = montMulTo; Montgomery.prototype.sqrTo = montSqrTo; function bnpIsEven() { return (this.t &gt; 0 ? this[0] &amp; 1 : this.s) == 0 } function bnpExp(a, b) { if (a &gt; 4294967295 || a &lt; 1) return BigInteger.ONE; var c = nbi(), d = nbi(), e = b.convert(this), f = nbits(a) - 1; for (e.copyTo(c); --f &gt;= 0; ) if (b.sqrTo(c, d), (a &amp; 1 &lt;&lt; f) &gt; 0) b.mulTo(d, e, c); else var g = c, c = d, d = g; return b.revert(c) }function bnModPowInt(a, b) { var c; c = a &lt; 256 || b.isEven() ? new Classic(b) : new Montgomery(b); return this.exp(a, c) } BigInteger.prototype.copyTo = bnpCopyTo; BigInteger.prototype.fromInt = bnpFromInt; BigInteger.prototype.fromString = bnpFromString; BigInteger.prototype.clamp = bnpClamp; BigInteger.prototype.dlShiftTo = bnpDLShiftTo; BigInteger.prototype.drShiftTo = bnpDRShiftTo; BigInteger.prototype.lShiftTo = bnpLShiftTo; BigInteger.prototype.rShiftTo = bnpRShiftTo; BigInteger.prototype.subTo = bnpSubTo;BigInteger.prototype.multiplyTo = bnpMultiplyTo; BigInteger.prototype.squareTo = bnpSquareTo; BigInteger.prototype.divRemTo = bnpDivRemTo; BigInteger.prototype.invDigit = bnpInvDigit; BigInteger.prototype.isEven = bnpIsEven; BigInteger.prototype.exp = bnpExp; BigInteger.prototype.toString = bnToString; BigInteger.prototype.negate = bnNegate; BigInteger.prototype.abs = bnAbs; BigInteger.prototype.compareTo = bnCompareTo; BigInteger.prototype.bitLength = bnBitLength; BigInteger.prototype.mod = bnMod; BigInteger.prototype.modPowInt = bnModPowInt;BigInteger.ZERO = nbv(0); BigInteger.ONE = nbv(1); var rng_state, rng_pool, rng_pptr; function rng_seed_int(a) { rng_pool[rng_pptr++] ^= a &amp; 255; rng_pool[rng_pptr++] ^= a &gt;&gt; 8 &amp; 255; rng_pool[rng_pptr++] ^= a &gt;&gt; 16 &amp; 255; rng_pool[rng_pptr++] ^= a &gt;&gt; 24 &amp; 255; rng_pptr &gt;= rng_psize &amp;&amp; (rng_pptr -= rng_psize) } function rng_seed_time() { rng_seed_int((new Date).getTime()) } if (rng_pool == null) { rng_pool = []; rng_pptr = 0; var t; for (; rng_pptr &lt; rng_psize; ) t = Math.floor(65536 * Math.random()), rng_pool[rng_pptr++] = t &gt;&gt;&gt; 8, rng_pool[rng_pptr++] = t &amp; 255; rng_pptr = 0; rng_seed_time() }function rng_get_byte() { if (rng_state == null) { rng_seed_time(); rng_state = prng_newstate(); rng_state.init(rng_pool); for (rng_pptr = 0; rng_pptr &lt; rng_pool.length; ++rng_pptr) rng_pool[rng_pptr] = 0; rng_pptr = 0 } return rng_state.next() } function rng_get_bytes(a) { var b; for (b = 0; b &lt; a.length; ++b) a[b] = rng_get_byte() } function SecureRandom() { } SecureRandom.prototype.nextBytes = rng_get_bytes; function Arcfour() { this.j = this.i = 0; this.S = [] }function ARC4init(a) { var b, c, d; for (b = 0; b &lt; 256; ++b) this.S[b] = b; for (b = c = 0; b &lt; 256; ++b) c = c + this.S[b] + a[b % a.length] &amp; 255, d = this.S[b], this.S[b] = this.S, this.S = d; this.j = this.i = 0 } function ARC4next() { var a; this.i = this.i + 1 &amp; 255; this.j = this.j + this.S[this.i] &amp; 255; a = this.S[this.i]; this.S[this.i] = this.S[this.j]; this.S[this.j] = a; return this.S[a + this.S[this.i] &amp; 255] } Arcfour.prototype.init = ARC4init; Arcfour.prototype.next = ARC4next; function prng_newstate() { return new Arcfour } var rng_psize = 256; function rs(a) { var b = new RSAKey; b.setPublic("C4D23C2DB0ECC904FE0CD0CBBCDC988C039D79E1BDA8ED4BFD4D43754EC9693460D15271AB43A59AD6D0F0EEE95424F70920F2C4A08DFDF03661300047CA3A6212E48204C1BE71A846E08DD2D9F1CBDDFF40CA00C10C62B1DD42486C70A09C454293BCA9ED4E7D6657E3F62076A14304943252A88EFA416770E0FBA270A141E7", "10001"); return b.encrypt(a) }

要想在winform中调用js….需要安装控件

【Microsoft Script Control 】/Winform 调用js

没有的,猛击这里

不懂怎么操作的,猛击这里

提示一下:imageimage

引用的文件要把嵌入互操作类型设为false

第二:准备HttpHelper类

没有的,猛击这里

核心代码页贴出来吧,如下。。。(别人写的)

using System;

using System.Collections.Generic;

using System.Text;

using System.Net;

using System.IO;

using System.Drawing;

using System.Text.RegularExpressions;

namespace WindowsFormsRs

{

public class HttpHelper

{

private CookieContainer cc;

public CookieContainer CC

{

get

{

return cc;

}

set

{

this.cc = value;

}

}

public HttpHelper()

{

this.cc = new CookieContainer();

}

public HttpHelper(CookieContainer cc)

{

this.cc = cc;

}

///

&nbsp;

<summary>/// 使用post方式访问目标网页,返回stream二进制流///

</summary>

&nbsp;

&nbsp;

public Stream PostAndGetStream(string targetURL, string formData, string contentType, string referer, bool allowAutoRedirect)

{

//数据编码

ASCIIEncoding encoding = new ASCIIEncoding();

//UTF8Encoding encoding = new UTF8Encoding();

byte[] data = encoding.GetBytes(formData);

//请求目标网页

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(targetURL);

request.CookieContainer = cc;

request.Method = "POST"; //使用post方式发送数据

request.ContentType = "application/x-www-form-urlencoded";

request.Referer = referer;

request.AllowAutoRedirect = allowAutoRedirect;

request.ContentLength = data.Length;

request.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1; .NET CLR 2.0.1124)";

//request.UnsafeAuthenticatedConnectionSharing = false;

//模拟一个UserAgent

Stream newStream = request.GetRequestStream();

newStream.Write(data, 0, data.Length);

newStream.Close();

//获取网页响应结果

HttpWebResponse response = (HttpWebResponse)request.GetResponse();

cc.Add(response.Cookies);

Stream stream = response.GetResponseStream();

return stream;

}

///

&nbsp;

<summary>/// 使用post方式访问目标网页,返回字节数组///

</summary>

&nbsp;

&nbsp;

public byte[] PostAndGetByte(string targetURL, string formData, string contentType, string referer, bool allowAutoRedirect)

{

Stream stream = PostAndGetStream(targetURL, formData, contentType, referer, allowAutoRedirect);

byte[] bytes = new byte[stream.Length];

stream.Read(bytes, 0, bytes.Length);

stream.Seek(0, SeekOrigin.Begin);

return bytes;

}

///

&nbsp;

<summary>/// 使用post方式访问目标网页,返回图片///

</summary>

&nbsp;

&nbsp;

public Image PostAndGetBitmap(string targetURL, string formData, string contentType, string referer, bool allowAutoRedirect)

{

Stream stream = PostAndGetStream(targetURL, formData, contentType, referer, allowAutoRedirect);

Image image = Image.FromStream(stream);

return image;

}

///

&nbsp;

<summary>/// 使用post方式访问目标网页,返回文件///

</summary>

&nbsp;

&nbsp;

public void PostAndGetBitmap(string targetURL, string formData, string contentType, string referer, bool allowAutoRedirect,string fileName)

{

byte[] bytes = PostAndGetByte(targetURL, formData, contentType, referer, allowAutoRedirect);

FileStream fs = new FileStream(fileName, FileMode.Create);

BinaryWriter bw = new BinaryWriter(fs);

bw.Write(bytes);

bw.Close();

fs.Close();

}

///

&nbsp;

<summary>/// 使用post方式访问目标网页,返回html页面///

</summary>

&nbsp;

&nbsp;

public string PostAndGetHtml(string targetURL, string formData, string contentType, string referer, bool allowAutoRedirect, Encoding encoding)

{

Stream stream = PostAndGetStream(targetURL, formData, contentType, referer, allowAutoRedirect);

string html = new StreamReader(stream, encoding).ReadToEnd();

return html;

}

///

&nbsp;

<summary>/// 使用get方式访问目标网页,返回stream二进制流///

</summary>

&nbsp;

&nbsp;

public Stream GetAndGetStream(string targetURL, string contentType, string referer, bool allowAutoRedirect)

{

//请求目标网页

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(targetURL);

request.CookieContainer = cc;

CC = cc;

request.Method = "GET"; //使用get方式发送数据

request.ContentType = contentType;

request.Referer = referer;

request.AllowAutoRedirect = allowAutoRedirect;

request.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1; .NET CLR 2.0.1124)";

//获取网页响应结果

HttpWebResponse response = (HttpWebResponse)request.GetResponse();

cc.Add(response.Cookies);

Stream stream = response.GetResponseStream();

return stream;

}

///

&nbsp;

<summary>/// 使用get方式访问目标网页,返回字节数组///

</summary>

&nbsp;

&nbsp;

public byte[] GetAndGetByte(string targetURL, string contentType, string referer, bool allowAutoRedirect)

{

Stream stream = GetAndGetStream(targetURL, contentType, referer, allowAutoRedirect);

byte[] bytes = new byte[stream.Length];

stream.Read(bytes, 0, bytes.Length);

stream.Seek(0, SeekOrigin.Begin);

return bytes;

}

///

&nbsp;

<summary>/// 使用get方式访问目标网页,返回图片///

</summary>

&nbsp;

&nbsp;

public Image GetAndGetBitmap(string targetURL, string contentType, string referer, bool allowAutoRedirect)

{

Stream stream = GetAndGetStream(targetURL, contentType, referer, true);

Image image = Image.FromStream(stream);

return image;

}

///

&nbsp;

<summary>/// 使用get方式访问目标网页,返回文件///

</summary>

&nbsp;

&nbsp;

public void GetAndGetFile(string targetURL, string contentType, string referer, bool allowAutoRedirect, string fileName)

{

byte[] bytes = GetAndGetByte(targetURL, contentType, referer, allowAutoRedirect);

FileStream fs = new FileStream(fileName, FileMode.Create);

BinaryWriter bw = new BinaryWriter(fs);

bw.Write(bytes);

bw.Close();

fs.Close();

}

///

&nbsp;

<summary>/// 使用get方式访问目标网页,返回html页面///

</summary>

&nbsp;

&nbsp;

public string GetAndGetHtml(string targetURL, string contentType, string referer, bool allowAutoRedirect, Encoding encoding)

{

Stream stream = GetAndGetStream(targetURL, contentType, referer, allowAutoRedirect);

string html = new StreamReader(stream, encoding).ReadToEnd();

return html;

}

}

}

第三:编写代码开始

private static HttpHelper httpHelper = new HttpHelper();

///

<summary>/// 得到第一次加密后的密码

///

</summary>

&nbsp;

///js文件

///加密的方法名

///加密方法需要传进的参数(一个是密码,另一个是页面上可获取的一个标志码)

///加密过后的密码

public static object GetRSAPassword(string jsFilePath, string funcName, params object[] paramers)

{

StreamReader reader = new StreamReader(jsFilePath);

string sScript = reader.ReadToEnd();

ScriptEngine se = new ScriptEngine(ScriptLanguage.JavaScript);

object obj = se.Run(funcName, paramers, sScript);

return obj;

}

//"nick=" + name+ "&amp;isnongli=0&amp;isrunyue=0&amp;appid=9&amp;year=" + year + "&amp;month=" + month + "&amp;day=" + day + "&amp;sex=" + sex+"&amp;elevel=1&amp;password=" + GetRSAPassword(password) + "&amp;verifycode=" + code;

public static string RegisterQQNum(string name, string rsapassword, string sex, string year, string month, string day, string code)

{

UTF8Encoding utf8 = new UTF8Encoding();

Byte[] encodedBytes = utf8.GetBytes(name);//编码

name = System.Text.Encoding.UTF8.GetString(encodedBytes, 0, (int)encodedBytes.Length);

string registerURL = "http://zc.qq.com/cgi-bin/iframe/numreg/get_acc_9";

string postData = string.Format("nick={0}&amp;isnongli=0&amp;isrunyue=0&amp;appid=9&amp;year={1}&amp;month={2}&amp;day={3}&amp;sex={4}&amp;elevel=1&amp;password={5}&amp;verifycode={6}", "aaaaabbbb", year, month, day, sex, rsapassword, code);

Debug.WriteLine(postData);

// httpHelper.CC = new System.Net.CookieContainer();

string html = httpHelper.PostAndGetHtml(registerURL, postData, null, null, false, Encoding.UTF8);

//string html= htlp.GetHtml(registerURL, postData, Encoding.UTF8);

return html;

}

public static string GetRandrom()

{

Random rand = new Random();

string strNum = "";

int i = 0;

while (i&lt;16)

{

i++;

int randomNum = rand.Next(0,10);

strNum += randomNum.ToString();

}

strNum = "0." + strNum;

return strNum;

}

public static Image GetCode()

{

string path = "http://captcha.qq.com/getimage?aid=1007901&amp;"+GetRandrom();

Image image= httpHelper.GetAndGetBitmap(path, null, null, false);

return image;

}

public static string GetAddress()

{

string path = "http://zc.qq.com/cgi-bin/iframe/numreg/init_9?id="+ GetRandrom();

string html= httpHelper.GetAndGetHtml(path, null, null, true, Encoding.UTF8);

return html;

}

以上是我编写的代码 .  调用而已…没啥啥技术含量滴。。

注册的参数删掉了很多,可以吧不必要的删掉。但是需要谨慎操作啊…!!!大笑

 

Winform界面代码:(上图,总有动手写几行代码哦,亲…)

image

界面效果如下:

image

 

image

 

 

——————————————–运行中,下图返回—————————————

 

AMO1~1HGL54(S$E`~NRNY3R

ok,注册成功

大功告成 !!!

 

HttpHelper要小小修改一下,腾讯QQ在POST提交的时候要把获取验证码的cookie一并提交上去

但是这个HttpHelper没有把获取图片的Cookie赋值到POST Cookie.

所以要把CC=cc的代码写入.

image

 

—————————————————————————————————–

申明,本文只做教学指导只用,切勿干坏事!!!

如有疑问请回复本文章

源码:猛击下载

[转载]性能测试知多少---测试工具介绍

mikel阅读(1111)

[转载]性能测试知多少—测试工具介绍 – 虫师 – 博客园.

 

  继续这个系列的学习,这一节重点介绍目前流行的性能测试工具以及如何选择适合项目的工具。在此之前,我已经对性能测试工具的原理与架构做了分析。

http://www.cnblogs.com/fnng/archive/2012/07/31/2617546.html

性能测试工具的选择与评估                                              

  在性能工具原理与架构一章中,我们了解到性能测试工具的原理通常是:通过录制、回放脚本,模拟多用户同时访问被测试系统,模拟产生负载压力,监控并记录各种性能指标,生成性能分析结果和报告,从而完性能测试的基本任务。

  对需要进行性能测试的组织来说,决定使用哪种性能测试工具也不是一个简单的问题。我们有需要对性能需求进行分析,购买成本,人员学习使用成本进行综合考虑,从而确定最适合的本次性能测试的工具。

:这里所提到的性 能测试工具为狭义上的性能测试工具,特指包含脚本生成、负载生成与测试数据搜集的性能测试工具,从广义上来讲,在性能测试过程中所用到一切工具,都可以称 为性能测试工具,其中包括,软件协议分析工具,测试数据生成工具,测试监控工具等都属于性能测试工具范畴。

  我简单的软件性能测试工具分为三类,商业收费工具、开源免费工具、自主开发工具。下面是这三类工具的比较:

通过上面的比较分析,很难判别对某类工具的取舍,各自有其明显的优势,当然也有明显的缺点,如何更好选择工具,这里就要结合实际性能的需求了。

需要考虑以下几个方面:

性能需求

  首先要考虑的是否满足性能需求,例如系统的协议不支持,无法创建脚本,系统的模拟用户数达不到,或都某此特殊功能无法测试,如流媒体性能测试等。一些有性能工具是无法满足这些需求的,那当然要首先排除。

购买成本

  对于商业工具的购买成本也是我们需要考虑的问题,其实,这个问题也是老板需要考虑的问题,对性能测试成本的整体预算等。 当然了,在满足性能需求的前提下,当然一切从简。如果只需要某商业软件的部分功能,也可以只购买部分功能。有的是根据支持协议的多少、并发用户上限来区 分,如loadrunner 

  这里要多扯一点,loadrunner应该是性能测试领域的巨无霸,它的年服务费多百万,这不是一般的小公司能承受的,可能许多网友用破解习惯了不以为然。而且loadrunner是可以定制的,一般商业软件都是可以定制的,也就是说,你有特定的需求,只要你愿意花钱,提供商都可以帮你定制开发。这样算下来成本会很高。

  那么开源软件呢? 开源的性能测试工具其实非常的多,因为它们都分别适合在不同的需求场景下,所以,它们的体积相比商业 软件会小很大,当然功能也相对简陋。但是他们在某些情况下可以完全满足某些性能需求,或者可以通过几款开源工具配合满足,或者通过对开源工具进行扩展进行 满足。对开源工具进行扩展,对测试人员的要求较高。需要测试人员对工具的原理及源代码有相当有研究。这里对测试人员自动能力的提升非常有帮助。

  或者你的性能测试项目特殊,找遍市面上的所有性能工具无一款满意,商业定制成本过高。或者你想构建自己有工具体系。处于 公司需求的特殊性与长期性考虑,可以自主开发一个性能测试工具来用。一次开发,永久收益(当然也需要维护与升级、扩展等),而且更贴近自已的需求。目前很 多知明的大公司都有自己的性能测试工具,用于内部使用。

人员学习成本

  最后要提到的就是人员对工具的学习成本,其实,测试人员在选择性能测试工具时最先考虑的就是从自己会使用的工具入手,这 样可以最低的控制学习成生,如果整一个工具,测试人员单学测试脚本就学了半年,老板早让你走人了。这也是对性能测试人员要求较高的地方。所以,对于性能测 试人员,你最好熟悉一款流程的商业性能工具,一款开源免费性能具,还需要熟悉常见的性能脚本开发语言等,这是基本要求。

性能测试工具介绍                                                                      

  QA Load:Compuware公司的QALoad是客户/服务器系统、企业资 源配置(ERP)和电子商务应用的自动化负载测试工具。QALoad是QACenter性能版的一部分,它通过可重复的、真实的测试能够彻底地度量应用的 可扩展性和性能。QACenter汇集完整的跨企业的自动测试产品,专为提高软件质量而设计。QACenter可以在整个开发生命周期、跨越多种平台、自 动执行测试任务。

    SilkPerformer:一种在工业领域最高级的企业级负载测试工具。它可 以模仿成千上万的用户在多协议和多计算的环境下工作。不管企业电子商务应用的规模大小及其复杂性,通过SilkPerformer,均可以在部署前预测它 的性能。可视的用户化界面、实时的性能监控和强大的管理报告可以帮助我们迅速的解决问题,例如加快产品投入市场的时间,通过最小的测试周期保证系统的可靠 性,优化性能和确保应用的可扩充性。

     LoadRunner:一种较高规模适应性的,自动负载测试工具,它能预测系 统行为,优化性能。LoadRunner强调的是整个企业的系统,它通过模拟实际用户的操作行为和实行实时性能监测,来帮助您更快的确认和查找问题。此 外,LoadRunner 能支持最宽范的协议和技术,为您的特殊环境,量身定做地提供解决方案。

 

  WebRunner:是RadView公司推出的一个性能测试和分析工具,它让 web应用程序开发者自动执行压力测试;webload通过模拟真实用户的操作,生成压力负载来测试web的性能,用户创建的是基于JavaScript 的测试脚本,称为议程agenda,用它来模拟客户的行为,通过执行该脚本来衡量web应用程序在真实环境下的性能。

 

  IBM Rational Performance Tester(简称 RPT) 也是一款性能测试工具,适用于基于 Web 的应用程序的性能和可靠性测试。Rational Performance Tester 将易用性与深入分 析功能相结合,从而简化了测试创建、负载生成和数据收集,以帮助确保应用程序具有支持数以千计并发用户并稳定运行的性能。

  Apache JMeter是Apache组织开发的基于Java的压力测试工具。 用于对软件做压力测试,它最初被设计用于Web应用测试但后来扩展到其他测试领域。 它可以用于测试静态和动态资源例如静态文件、Java 小服务程序、 CGI 脚本、Java 对象、数据库, FTP 服务器, 等等。JMeter 可以用于对服务器、网络或对象模拟巨大的负载,来在不同压力类别下测试 它们的强度和分析整体性能。

  AutoBench 是一款基于httperf的Perl脚本。它会在一次测试中调 用多次httperf来对web服务器进行测试,每次会按照给定的参数增加并发连接数,将 httperf的测试结果保存为CSV格式的文件,该文件可以 被Excel直接读取,方便生成测试报告。借助于autobench自带的 bench2graph工具可以生成漂亮的测试结果对比图。

 

  ApacheBench 工具程式(ab)是 Apache 网站伺服器软体的一个 附带的工具软体,专门用来执行网站伺服器的运行效能,特别是针对 Apache 网站伺服器 的效能分析。这支程式原本是用来检测 Apache 网站伺 服器(Web Server) 所能够提供的效能,特别是可以看出 Apache 网站伺服器能提供每秒能送出多少网页,当然的,也可以用在任何其他的网 站伺服器 Apache ab的全称是ApacheBench,是 Apache 附带的一个小工具,专门用于 HTTP Server 的 benchmark testing,可以同时模拟多个并发请求。

 

  curl-loader(也被称为“omes-NIK”和“davilka”)是一 个开源的C语言编写的工具,模拟应用负载和成千上万的几十万人的HTTP / HTTPS和FTP/ FTPS的客户端应用程序的行为,每个有其自己的源 IP地址。相反,其他curl-loader使用真正的C编写的客户端协议栈,即libcurl和TLS/ openssl的SSL的HTTP和FTP协 议栈,支持登录和验证口味和模拟用户行为的工具。

 

  Iago 是一个网站负载测试工具,Iago 针对一个给定的网站进行访问录制并合成流量数据。它不同于其他的负载生成工具,它试图保持恒定的请求率。例如如果你想按每分钟100K来请求您的服务,Iago 会试图保持这个速度进行测试。

 

  Pylot 是一款开源的用以测试 Web Service性能和扩展性的工具,它 运行HTTP负载测试,这对于制定容量计划、确定基准点、分析系统瓶颈以及系统调优都非常有用。在使用过程 中,Pylot会发起并发请求 (HTTP Requests),检验服务器响应,以及带有相关指标的报表。它通过GUI或者Shell/Console来执行和监视对被测试网站的测试 过程。

———————————————–

 关于性能测试工具非常的多,如果你是个开源的粉丝可以去开源中国转转,那里有许多非常优秀的开源软件。

[转载]HTTP头域列表与解释 之 response篇

mikel阅读(867)

[转载]HTTP头域列表与解释 之 response篇 – 柯柏文 – 博客园.

Access-Control-Allow-Origin:表面该站点可以被哪些网站进行跨域资源共享 (cross-origin resource sharing,CORS)(请参考“同源策略”和“跨域之源共享”),例如:Access-Control-Allow-Origin: http://example.com:8080 http://foo.example.com,或者Access-Control-Allow-Origin:*

Accept-Ranges:表明服务器支不支持资源范围请求(“资源范围请求”是指按byte为单位,请求资 源的某一段数据,例如请求一个文件的200byte—400byte的数据)。Accept-Ranges:bytes 表示该资源支持byte形式资源范围请求,Accept-Ranges:none则表示不支持。

Age:一个资源存在于代理中缓存的时间。单位是秒。

Allow:一个资源允许哪些HTTP方法进行请求,例如:Allow: GET, HEAD

Cache-Control:(Cache-Control是内容比较多的一个头域,我会在下一篇博客做介绍)

Connection:连接方式。值有keep-alive和close

Content-Encoding:服务器对响应数据的编码方式,但这里的编码方式不同于编码字符集(GB2312,UTF-8等),而是(通常)指压缩方式,例如Content-Encoding:gzip

Content-Language:响应数据的自然语言,例如:Content-Language:ZH-CN

Content-Length:响应数据的数据长度,单位是byte,例如Content-Length:1024

Content-Location:(这个没搞清什么意思)

Content-MD5:基于base64编码的回应数据的MD5校验和,例如:Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ==

Content-Disposition:当客户端请求的资源是一个可下载的资源(这里的“可下载”是指浏览器 会弹出下载框或者下载界面)时,对这个可下载资源的描述(例如下载框中的文件名称)就是来源于该头域。例如:Content-Disposition: attachment; filename=”some_app.exe”

Content-Range:表示如果当前这个响应数据是整个资源的一部分时,是具体的哪一部分(从第几 byte到第几byte)。在请求中,客户端可以通过设定”Range”头域来通知服务器其只想请求整个资源中某一段数据,而对应的,当服务器响应这种请 求,并发送某一段数据到客户端的时候,必须通过Content-Range头来告诉客户端当前的响应数据是整个资源的第几byte到第几byte。这个在 资源的分段下载和续点下载应用中很有用。例如:Content-Range:500-900

Content-Type:响应数据的MIME类型,例如:Content-Type: text/html; charset=utf-8

Date:响应消息发送的GMT格式日期,例如:Date: Tue, 15 Nov 1994 08:12:31 GMT

ETag:(Entity-Tag的缩写)资源的一个标识,类似于key-value pair(键值对)中的key。ETag通常用于校验一个资源实体有没有被修改过。在数据缓存和PUT方法更新资源时候有用处。例如:ETag: “737060cd8c284d8af7ad3082f209582d”

Expires:告诉客户端该响应数据会在指定的时间过期,通常用于给客户端缓存作为参考。例如:Expires: Thu, 01 Dec 1994 16:00:00 GMT

Last-Modified:客户端所请求的资源的最后修改时间。

Link:描述当前被请求的资源和另外一个资源的关系。这种关系被定义在RFC5988。例如:Link: </feed>; rel=”alternate”

Location:用户通知客户端转跳(重定向)到另一个URL(就是ASP.NET中Response.Redirect()方法的效果)。例如:Location: http://www.w3.org/pub/WWW/People.html

P3P:Platform for Privacy Preferences Project的缩写,表示本站点遵守P3P协议(标称本站点不会违法使用用户信息)并希望收集用户信息。不过P3P目前使用并不广泛,特别国内并不重视 P3P。P3P的值的格式为: P3P:CP=”your_compact_policy”。

Pragma:在请求/响应链上附近的一些参数。该头域内容较多,我会在下一篇博客中做介绍。

Proxy-Authenticate:访问代理时需要使用的验证方式。例如:Proxy-Authenticate: Basic

Refresh:用于令客户端在指定N秒后转跳到另外一个URL。例如:Refresh:6,http://www.google.com.hk 6秒后转跳到google

Retry-After:用于因为某些原因(例如该资源暂时无效)通知客户端在指定时间后重新尝试请求,时间单位为秒。例如:Retry-After:60 一分钟后重新尝试请求该资源。

Server:服务器的名称。例如 Server: Apache/2.4.1 (Unix)

Set-Cookie:对客户端设置cookie。例如:Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1

Strict-Transport-Security:用于指示客户端如何对HTTPS进行缓存(缓存多长时间)以及是否对子域生效。例如:Strict-Transport-Security: max-age=16070400; includeSubDomains

Trailer:当响应资源已chunked编码(具体请google一下chunked编码)传输时,每个Chunked-Body尾部的额外数据。

Transfer-Encoding:响应内容的传输编码方式,通常有 chunked, deflate, gzip等。

Vary:用来指示缓存代理(例如squid)根据什么条件去缓存一个请求。Vary的可能值有: Vary: Accept-Encoding Vary: Accept-Encoding,User-Agent Vary: X-Some-Custom-Header,Host Vary: *

Via:告诉客户端,该回应经历了那些代理。例如 Via: 1.0 example1.com, 1.1 example2.com (Apache/1.1)

WWW-Authenticate:表示当前是用什么验证方式访问一个资源。例如:WWW-Authenticate:base
通用的非标准HTTP头域:

X-XSS-Protection:IE8+中开启或关闭跨站脚本攻击。例如:X-XSS- Protection: 1; mode=block 有关请看:http://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling- the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx

X-Content-Type-Options:IE和chrome中的一个非标准头域,只有一个值:nosniff。通常地,针对一个请求的响应的头域中有content-type头域来描述内容的MIME类型,但有些内容并没有提供其MIME类型,这时候浏览器可以自己探测
该内容是什么类型,而X-Content-Type-Options:nosniff正是用于关闭自动嗅探功能。

X-Powered-By:表面当前站点(或资源)是用什么技术开发,例如 X-Powered-By:ASP.NET。相关的还有X-Runtime, X-Version, X-AspNet-Version

[转载]提高页面响应的20款杰出的jquery插件推荐

mikel阅读(1176)

转载提高页面响应的20款杰出的jquery插件推荐 – 58分享 – 博客园.

JQuery的是一个快速,简洁的JavaScript库,它简化了HTML文档遍历,事件处理,动画和Ajax交互网络的快速发展,  JQuery的目的是改变你写JavaScript的方式。

JQuery改变了开发人员的设计方式,每天jQuery 插件都被不断被创造,最新的 jQuery 插件和脚本的 对于web 设计人员和开发人员总是很需要的。
今天就给大家分享20个精美的 jQuery 插件、包括 滑块、 图像画廊、 幻灯片显示插件、 jQuery 导航菜单、 交互式地图、 手机界面、 手风琴菜单、 工具提示插件和收集许多其他有用的 jQuery 脚本。你可以尽情下载用在你的项目当中

jQuery的的轻型工具提示插件:Tooltipster

jQuery的的轻型工具提示插件:Tooltipster

Tooltipster是一个轻量级的jQuery插件,使您可以轻松地创建漂亮的HTML5验证工具提示。该插件是小尺寸(4.8kb),工作速度快,可以轻松定制。

可以改变它的外观与主题支持(CSS)和箭头的位置,跟随鼠标移动,延迟/周期的外观都可以被定义。

网址: http://calebjacob.com/tooltipster/

RoyalSlider – 专业图片廊和响应的内容jQuery滑块插件

RoyalSlider  - 专业图片廊和响应的内容jQuery滑块插件

RoyalSlider的界面可以显示任何HTML内容(图像,视频,文字。)是一个专业的触摸功能的jQuery插件

RoyalSlider专注于在每一个桌面和移动设备上提供出色的用户体验

RoyalSlider是可以定制外观的

兼容性: All Modern Browsers
网站: http://dimsemenov.com/plugins/royal-slider/
演示: http://dimsemenov.com/plugins/royal-slider/templates

跨浏览器的JavaScript拖放文件上传:FileDrop

跨浏览器的JavaScript拖放文件上传:FileDrop

FileDrop是一个JavaScript的跨浏览器类,用于快速创建拖放和AJAX(多个)文件上传界面。

它不依赖任何 JavaScript 框架,并且可以在多个浏览器中运行,包括 IE6。

兼容性:兼容所有浏览器

网站: http://proger.i-forge.net/FileDrop_%E2%80%93_cross-browser_JavaScript_Drag_-amp_Drop_file_upload/7CC

Really Simple Slideshow:一个灵活的更大的滑块jQuery插件

真正简单的幻灯片:一个灵活的更大的滑块jQuery插件

Really Simple Slideshow是一个灵活的jQuery插件可以创建任何类型的图像滑块。动态加载图像的每一个要求,允许加载较大的幻灯片,而不必预先加载大量的图片。

该插件可将任何图像转换到幻灯片列表,它可以显示字幕与每个幻灯片,包括链接,并有多种过渡效果。

兼容性:兼容所有浏览器
Website: http://reallysimpleworks.com/slideshow/
Download:https://github.com/reallysimple/Really-Simple-Slideshow

响应jQuery滑块:IVIEWSLIder

响应jQuery滑块:IVIEW滑块

IVIEW slider是一个jQuery Slider 插件可用于展示任意类型的内容(图片,HTML,视频)。

这个插件支持响应式布局并能够很好的兼容触摸界面。

它已经内置35种转换效果,可以为每一个slide可以定义不同的效果。

该插件支持向下移动的响应布局

滑块具有内置的过渡效果,这是完全兼容所有主流浏览器(包括IE6到IE9,火狐,Chrome,Safari浏览器,歌剧)等移动平台的iOS / Android3.5

要求: jQuery

网站:http://iprodev.com/2012/07/iview/ 

演示:http://iprodev.com/iview/

移动Web应用程序的轻量级框架:Sidetap

移动Web应用程序的轻量级框架:Sidetap

Sidetap的移动Web应用程序(2KBgzip压缩)是一个轻量级的框架

是一个简洁轻量级的移动 Web 应用开发框架,它专注于提供类似于 Path 或者 Sparrow 这样的侧导航形式的 UI 体验。

  • 轻量级:缩减压缩后只有2KB。
  • 支持不同设备
  • 方便配置,让你立刻开始开发应用。
  • 使用简单
  • 依赖jQuery(1.7.2)或者zepto.js

 

要求: jQuery or Zepto.js
兼容性: All Modern Browsers
网址: http://sidetap.it/
演示:http://sidetap.it/demo/stonehenge/index.html
下载:https://github.com/harvesthq/Sidetap



Javascript的幻灯片Flickr的图片:Flickrshow

Javascript的幻灯片Flickr的图片:Flickrshow

Flickrshow是一个简单的JavaScript Flickr图片幻灯片

网址: http://www.flickrshow.co.uk/ 
下载: https://github.com/beseku/javascript.flickrshow

HTML生成jQuery Mobile框架:jqmPhp

HTML生成jQuery Mobile框架:jqmPhp

jqmPhp jQuery Mobile框架旨在简化项目使用jQuery Mobile与PHP是一个开源的HTML代码生成器

jqmPhp是一个包的PHP类,方便地创建HTML文件,然后使用jQuery Mobile框架。所有的类可以在jqmPhp包转换为字符串

网站: http://www.jqmphp.com/
下载: http://code.google.com/p/jqmphp/downloads/list

 

UI通知框架:Backbone.Notifier

UI通知框架:Backbone.Notifier

Backbone.Notifier是一个强大的UI通知框架,用于显示和控制的UI通知。

它是建立在jQuery的顶部,Backbone.js + Underscore.js,有许多很酷的功能,如一个的3D模块或动画支持。

通知可以显示在顶部或在中间,存在模式的通知,这是可以通过设置自定义样式CSS + JS API。

要求: jQuery的,Backbone.js和Underscore.js 

兼容性:所有主要的浏览器
网站: http://e-w.co.il/backbone.notifier/
下载: https://github.com/ewebdev/backbone.notifier/

最简单的谷歌地图GMaps.js整合

最简单的谷歌地图随着GMaps.js整合

GMaps.js除了添加指定经纬度的标准地图之外,GMaps.js 还能定义地图放大的级别,添加标注,获取当前用户的地理位置(HTML5 geolocation),定义路线,绘制折线,并且实现这些功能只需要简单的几行代码。

另外 GMaps.js 每个动作都有 callback 函数让你去集成自定义事件。目前 GMaps.js 没有详细的文档,但是每个功能都有具体的例子,参考下基本就可以使用了。

Requirements: jQuery
Website: http://hpneo.github.com/gmaps/
Demo:http://hpneo.github.com/gmaps/examples.html
Download:https://github.com/HPNeo/gmaps

Chronoline.js:JavaScript库,用于显示图像事件时间表

Chronoline.js:JavaScript库,用于显示图像事件时间表

Chronoline.js是一个JavaScript库,创建一个按时间顺序的图形时间轴的事件

整个时间线水平方向显示,我们可以方便的显示任何时间长度的事件,并且提供一个tooltip来展示事件详细内容。

的要求: Raphael.js,jQuery的,jQueryqTip2

插件兼容性:所有的现代浏览

网站:http://stoicloofah.github.com/chronoline.js/

JavaScript的所见即所得的编辑器拖动:Redactor

Redactor 是一个 jQuery 的插件,实现在线所见即所得的 HTML 编辑器。界面简洁,加载速度快。不过不支持 IE6 浏览器,如果你不需要考虑 IE6 不妨试试。

它自动转换到编辑器中的textarea的领域和编辑器是所有主要的行动(文字造型,添加文件/图像/视频/表/列表)。

兼容性:IE6好像不支持

网站:http://redactorjs.com/ 

演示:http://redactorjs.com/examples/

滚动效果的jQuery插件:SuperScrollorama

令人敬畏的滚动效果的jQuery插件:SuperScrollorama

SuperScrollorama 是一个用来实现超酷的滚动动画效果的 jQuery 插件。

实现的效果有:文字褪色,飞,旋转,缩放,斯马什,针脚,滑动,隐退,反弹,颜色,扔,移动,视差。

 

要求: All Modern Browsers
网站: http://johnpolacek.github.com/superscrollorama/
下载:https://github.com/johnpolacek/superscrollorama

下拉菜单中的图像jQuery插件:ddSlick

下拉菜单中的图像的jQuery插件:ddSlick

ddSlick,一个免费的轻量级的jQuery插件,为创造一个更好的外观和更多信息的图像和说明,列表菜单的下拉菜单(列表菜单)

它可以作为一个下拉菜单,在这里我们可以使用一个简单的文本的图像和说明

兼容性:所有主流浏览器

网站:http://designwithpc.com/Plugins/ddSlick

真棒jQuery的日历:jQuery Verbose Calendar

真棒jQuery的日历:jQuery的详细日程

jQuery Verbose Calendar 是一个可以把整年的日历显示在一个页面上的 jQuery 插件,加载之后,

它会自动滚到今天的日期处,当你鼠标移动到日期上,可以显示今天星期几。并且这个日历插件支持 Callback 函数,

当你点击某个日期的时候,你可以执行一些自定义行为,或者插入任意的 HTML 元素。

 

要求jQuery + Tipsy & jQuery.ScrollTo plugins
兼容性All Major Browsers
网站: http://iamjpg.github.com/jQuery-Verbose-Calendar/
下载; https://github.com/iamjpg/jQuery-Verbose-Calendar

使用jQuery,现代浏览器的矢量图形地图矢量地图:JQVMAP

使用jQuery,现代浏览器的矢量图形地图矢量地图:JQVMAP

JQVMap 是一个用于输出向量地图的 jQuery 插件,使用可改变大小的 SVG 处理,支持的浏览器包括:Firefox, Safari, Chrome, Opera and Internet Explorer 9.  对 IE 6-8 的版本通过 VML 支持。。

兼容性:大多数浏览器

网站:http://jqvmap.com/ 

下载:https://github.com/manifestinteractive/jqvmap

JCS媒体库(jCSML)Cross-Browser Animation

JCS媒体库(jCSML)创建跨浏览器动画

它是专门设计用于创建跨浏览器的动画,而无需调整任何个别浏览器或平台。

能够让创建动画媒体而不需要改变任何代码,支持桌面和移动浏览器。它没有使用Flash, SilverLight, SVG, HTML5, 或 奇特的CSS3动画。

JCSML可以运行在IE7浏览器,Android或iPad / iPhone上。

要求: jQuery & jQuery easing library
兼容性: All Major Browsers
网站: http://jcsml.com/
演示: http://jcsml.com/pageshell.html?root=Tutorials&target=Starship#
下载: http://www.jcsml.com/pageshell.html?root=PurchasePages&target=PurchasePage&TOCEnabled=FALSE

minjs:轻量级JavaScript组件

minjs:轻量级JavaScript组件

minjs是一个独立的JavaScript组件的集合,是建立在jQuery的,轻量级的代码,以完成特定的工作。

minjs 是一组轻量级的 jQuery 组件,提供多种 Web 常用组件,包括表单、表格、日历等,其中迷你表单帮助你使用 HTML5 表单增强,尽管浏览器不一定支持也可以使用。

目前,有3个组成部分:minform,longtable和dtcal。

minform带来了跨浏览器兼容HTML5表单增强功能(属性:占位符所需自动对焦)。

兼容性:所有主要浏览器

网址:http://www.minjs.com/

实时阴影:jQuery-Sensitive & Realistic Shadows

实时阴影:jQuery插件鼠标敏感和逼真的阴影

Sensitive & Realistic Shadows是一个简单而有效的jQuery插件,鼠标敏感的任何HTML元素都可以创建逼真的阴影效果

用一个简单的功能,它的工作原理是按照鼠标的位置针对任意数量的元素和操作的box-shadow CSS属性的值的元素

因此,确定阴影的位置和大小由鼠标元素操控

兼容性: All Modern Browsers
网站: 
http://indamix.github.com/real-shadow/
下载: https://github.com/Indamix/real-shadow/

MiniJs:写在CoffeeScript的一套jQuery插件

MiniJs:写在CoffeeScript的一套jQuery插件

MiniJS 是一组使用 CoffeeScript 编写的 jQuery 插件

 

兼容性:所有主要的浏览器

网站:http://minijs.com/ 

下载:https://github.com/minijs

jPages:真棒的JavaScript分页插件

jPages是一个客户端JavaScript分页插件(jQuery插件),有很多的功能,如键盘+滚动导航,自动翻页,延迟显示屏和一个可定制的导航面板也集成与Animate.css延迟加载。。

兼容性: All Major Browsers
网站: http://luis-almeida.github.com/jPages/
演示: http://luis-almeida.github.com/jPages/defaults.html
下载: https://github.com/luis-almeida/jPages

 

 

本文链接:提高页面响应的20款杰出的jquery插件推荐

[转载]有关T-SQL的10个好习惯

mikel阅读(1084)

[转载]有关T-SQL的10个好习惯 – CareySon – 博客园.

1.在生产环境中不要出现Select *

这一点我想大家已经是比较熟知了,这样的错误相信会犯的人不会太多。但我这里还是要说一下。

不使用Select *的原因主要不是坊间所流传的将*解析成具体的列需要产生消耗,这点消耗在我看来完全可以忽略不计。更主要的原因来自以下两点:

  •      扩展方面的问题
  •      造成额外的书签查找或是由查找变为扫描

扩展方面的问题是当表中添加一个列时,Select *会把这一列也囊括进去,从而造成上面的第二种问题。

而额外的IO这点显而易见,当查找不需要的列时自然会产生不必要的IO,下面我们通过一个非常简单的例子来比较这两种差别,如图1所示。

1

图1.*带来的不必要的IO

 

2.声明变量时指定长度

这一点有时候会被人疏忽,因为对于T-SQL来说,如果对于变量不指定长度,则默认的长度会是1.考虑下面这个例子,如图2所示。

2

图2.不指定变量长度有可能导致丢失数据

 

3.使用合适的数据类型

合适的数据类型首先是从性能角度考虑,关于这一点,我写过一篇文章详细的介绍过,有兴趣可以阅读:对于表列数据类型选择的一点思考,这里我就不再细说了

不要使用字符串类型存储日期数据,这一点也需要强调一些,有时候你可能需要定义自己的日期格式,但这样做非常不好,不仅是性能上不好,并且内置的日期时间函数也不能用了。

 

4.使用Schema前缀来选择表

解析对象的时候需要更多的步骤,而指定Schema.Table这种方式就避免了这种无谓的解析。

不仅如此,如果不指定Schema容易造成混淆,有时会报错。

还有一点是,Schema使用的混乱有可能导致更多的执行计划缓存,换句话说,就是同样一份执行计划被多次缓存,让我们来看图3的例子。

3

图3.不同的schema选择不同导致同样的查询被多次缓存

 

5.命名规范很重要

推荐使用实体对象+操作这种方式,比如Customer_Update这种方式。在一个大型一点的数据库会存在很多存储过程,不同的命名方式使得找到需要 的存储过程变得很不方便。因此有可能造成另一种问题,就是重复创建存储过程,比如上面这个例子,有可能命名规范不统一的情况下又创建了一个叫 UpdateCustomer的存储过程。

 

6.插入大量数据时,尽量不要使用循环,可以使用CTE,如果要使用循环,也放到一个事务中

这点其实显而易见。SQL Server是隐式事务提交的,所以对于每一个循环中的INSERT,都会作为一个事务提交。这种效率可想而知,但如果将1000条语句放到一个事务中提交,效率无疑会提升不少。

打个比方,去银行存款,是一次存1000效率高,还是存10次100?

 

7.where条件之后尽量减少使用函数或数据类型转换

 

换句话说,WHERE条件之后尽量可以使用可以嗅探参数的方式,比如说尽量少用变量,尽量少用函数,下面我们通过一个简单的例子来看这之间的差别。如图4所示。

4

图4.在Where中使用不可嗅探的参数导致的索引查找

 

对于另外一些情况来说,尽量不要让参数进行类型转换,再看一个简单的例子,我们可以看出在Where中使用隐式转换代价巨大。如图5所示。

5

图5.隐式转换带来的性能问题

 

8.不要使用旧的连接方式,比如(from x,y,z)

可能导致效率底下的笛卡尔积,当你看到下面这个图标时,说明查询分析器无法根据统计信息估计表中的数据结构,所以无法使用Loop join,merge Join和Hash Join中的一种,而是使用效率地下的笛卡尔积。

image

 

所以,尽量使用Inner join的方式替代from x,y,z这种方式。

 

9.使用游标时,加上只读只进选项

 

首先,我的观点是:游标是邪恶的,尽量少用。但是如果一定要用的话,请记住,默认设置游标是可进可退的,如果你仅仅设置了

declare c cursor

    for

 

这样的形式,那么这种游标要慢于下面这种方式。

 declare c cursor

    local static read_only forward_only

    for

 

 

所以,在游标只读只进的情况下,加上上面代码所示的选项。

 

10.有关Order一些要注意的事情

首先,要注意,不要使用Order by+数字的形式,比如图6这种。

6

图6.Order By序号

 

当表结构或者Select之后的列变化时,这种方式会引起麻烦,所以老老实实写上列名。

 

还有一种情况是,对于带有子查询和CTE的查询,子查询有序并不代表整个查询有序,除非显式指定了Order By,让我们来看图7。

7

图7.虽然在CTE中中有序,但显式指定Order By,则不能保证结果的顺序