不会飞的鸟

2010年12月10日 ... 不鸟他们!!! 我要用自己开发的分布式文件系统、分布式调度系统、分布式检索系统, 做自己的搜索引擎!!!大鱼有大志!!! ---杨书童

#

PowerDesigner(PD) Name/Code自动调整

大家都清楚在用PowerDesigner的时候,当你输入Name的时候Code是会自动帮你按照Name的内容填上的.
这个功能虽然好用,但是我需要在Name这一项加上一个中文的注释,这个时候怎么办呢?
下面两个例子,相信对你相当有用.
Examples

· Script 1:
.set_value(_First, true, new)
.foreach_part(%Name%, "'#'")
.if (%_First%)
.delete(%CurrentPart%)
.set_value(_First, false, update)
.else
%CurrentPart%
.endif
.next

这个例子是把Name内容的#号后边的内容当作Code.
如:在Name列输入    用户名#user_name  则在Code列自动会变成   user_name

· Script 2:
.set_value(_First, true, new)
.foreach_part(%Name%, "'#'")
.if (%_First%)
%CurrentPart%
.set_value(_First, false, update)
.endif
.next

这个例子是把Name内容的#号前边的内容当作Code.
如:在Name列输入    user_name#用户名  则在Code列自动会变成   user_name

具体操作方法是:
1、打开powerDesigner菜单的Tools->Model Options....->Naming Convention
2、选中Name,并勾选Enable name/code conversions.
3、选择Name To Code,把上面任意一个例子的代码(红色部分)贴到conversion script内容框中即可。

注:用这个script的时候,必须先设置,才会转换的。
如果你已经设计好了,再设置是不会对之前的东西改变的。

posted @ 2012-04-09 10:26 不会飞的鸟 阅读(723) | 评论 (0)编辑 收藏

如何进行数据库,比如ORACLE,SQL SERVER的逆向工程,将数据库导入到PowerDesigner中

Oracle的反向工程就是指将Oracle中的数据库,当然也可以是SQL Server中的数据库导入到PD中,这个需要建立一个数据库的链接,然后进行逆向工程的操作。

第一步:建立数据库的链接:

PowerDesigner建立与数据库的连接,以便生成数据库和从数据库生成到PD中。[Oracle 10G版]

PowerDesigner建立与数据库的连接,以便生成数据库和从数据库生成到PD中。[SQL SERVER 2005版]

第二步:建立完数据库的连接后,在【File】--【Reverse Engineer】--【Database】

第三步:点击确定,如图所示:

第四步:如图所示:注意点,如果数据库中的表很多时,比如一万张表,这个操作耗费的时间很长,甚至把PD崩溃掉

选择你要导入的表,视图,以及表的对象,就可以将数据库导入到PD中,至此数据库的逆向工程便结束了。

posted @ 2012-04-09 10:20 不会飞的鸟 阅读(676) | 评论 (0)编辑 收藏

[转]新浪微博 爬取实现之微博登录

最近做一个东西,需要抓取新浪微博的微话题,新浪微博api有所限制所以就没用新浪微博api了,想直接的从网页上获取内容,但微博的很多网页都需要登录后才能浏览的,所以做了个新浪微博的登录功能,基本需要的功能实现了,但并不健全。

对于新浪微博的页面是要用户登录之后才能进入的,如http://weibo.com/pub/topic,那么爬虫也必须登录上新浪微博才能爬取内容,在这里实现下新浪微博的登录功能,到现在还有一些问题没解决,但可以实现必须登录后才能进入的页面的文本捕获了。

先分析下微博登录提交的内容,新浪微博主页登录向服务器提交的是使用POST的,post附带的参数有


entry:weibo
gateway:1
from:
savestate:7
useticket:1
ssosimplelogin:1
vsnf:1
vsnval:
su:NDY0Mjg5NTg4JTQwcXEuY29t
service:miniblog
servertime:1321269451
nonce:HGE0XB 
pwencode:wsse
sp:a3135915db1b5d15a47a43e550d89e1499a26a9b
encoding:UTF-8
url:http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack
returntype:META

  在这些参数中su是用户的用户名使用base64编码的;servertime是该动作的开始时间,nonce是随机产生的6为随机数,pwencode:wsse应该指的是密码格式的编码了,sp是密码的通过编码后的形式。对于我现在的应用只需要这几个参数就好了。

接着分析下这些参数吧:

request.su=sinaSSOEncoder.base64.encode(urlencode(username));

  用户名通过了urlencode和base64编码后才提交的;

servertime在哪里忘记了,通过获取时间/1000就可以得到servertime了;

var makeNonce=function(len){var x="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";var str="";for(var i=0;i<len;i++){str+=x.charAt(Math.ceil(Math.random()*1000000)%x.length)}return str};

  nonce参数是上面函数得到的;

sp的得到就相对比较麻烦一些,是通过password,servertime,nonce 共同编码后得到的数据;使用的编码函数是

var sinaSSOEncoder=sinaSSOEncoder||{};(function(){var i=0;var g=8;this.hex_sha1=function(j){return h(b(f(j),j.length*g))};var b=function(A,r){A[r>>5]|=128<<(24-r%32);A[((r+64>>9)<<4)+15]=r;var B=Array(80);var z=1732584193;var y=-271733879;var v=-1732584194;var u=271733878;var s=-1009589776;for(var o=0;o<A.length;o+=16){var q=z;var p=y;var n=v;var m=u;var k=s;for(var l=0;l<80;l++){if(l<16){B[l]=A[o+l]}else{B[l]=d(B[l-3]^B[l-8]^B[l-14]^B[l-16],1)}var C=e(e(d(z,5),a(l,y,v,u)),e(e(s,B[l]),c(l)));s=u;u=v;v=d(y,30);y=z;z=C}z=e(z,q);y=e(y,p);v=e(v,n);u=e(u,m);s=e(s,k)}return Array(z,y,v,u,s)};var a=function(k,j,m,l){if(k<20){return(j&m)|((~j)&l)}if(k<40){return j^m^l}if(k<60){return(j&m)|(j&l)|(m&l)}return j^m^l};var c=function(j){return(j<20)?1518500249:(j<40)?1859775393:(j<60)?-1894007588:-899497514};var e=function(j,m){var l=(j&65535)+(m&65535);var k=(j>>16)+(m>>16)+(l>>16);return(k<<16)|(l&65535)};var d=function(j,k){return(j<<k)|(j>>>(32-k))};var f=function(m){var l=Array();var j=(1<<g)-1;for(var k=0;k<m.length*g;k+=g){l[k>>5]|=(m.charCodeAt(k/g)&j)<<(24-k%32)}return l};var h=function(l){var k=i?"0123456789ABCDEF":"0123456789abcdef";var m="";for(var j=0;j<l.length*4;j++){m+=k.charAt((l[j>>2]>>((3-j%4)*8+4))&15)+k.charAt((l[j>>2]>>((3-j%4)*8))&15)}return m};this.base64={encode:function(l){l=""+l;if(l==""){return""}var j="";var s,q,o="";var r,p,n,m="";var k=0;do{s=l.charCodeAt(k++);q=l.charCodeAt(k++);o=l.charCodeAt(k++);r=s>>2;p=((s&3)<<4)|(q>>4);n=((q&15)<<2)|(o>>6);m=o&63;if(isNaN(q)){n=m=64}else{if(isNaN(o)){m=64}}j=j+this._keys.charAt(r)+this._keys.charAt(p)+this._keys.charAt(n)+this._keys.charAt(m);s=q=o="";r=p=n=m=""}while(k<l.length);return j},_keys:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}}).call(sinaSSOEncoder);

  得到得到sp的函数为

password=sinaSSOEncoder.hex_sha1(""+sinaSSOEncoder.hex_sha1(sinaSSOEncoder.hex_sha1(password))+me.servertime+me.nonce)}request.sp=password;return request};

  必要的参数已经分析到了,只要封装http包先服务器发送即可。我使用的是java实现,把上面一些javascript函数改写成java函数

//用户名编码
private String encodeAccount(String account){
        return Base64.encodeBase64String(URLEncoder.encode(account).getBytes());
    }
//六位随机数nonce的产生
private String makeNonce(int len){
        String x="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        String str = "";
        for(int i=0;i<len;i++){
            str+=x.charAt((int) (Math.ceil(Math.random()*1000000)%x.length()));
        }
        return str;
    }
//servertime的产生
private String getServerTime(){
        long servertime = new Date().getTime()/1000;
        return String.valueOf( servertime);
    }
//密码的编码
this.sp = new SinaSSOEncoder().encode(this.pwd, this.servertime, this.nonce);

  SinaSSOEncoder编码类的实现

package com.sinaweibo;
 
//新浪微博密码加密的算法
public class SinaSSOEncoder {
    private boolean i=false;
    private int g=8;
     
    public SinaSSOEncoder(){
         
    }
    public String encode(String psw,String servertime,String nonce){
        String password;
        password=hex_sha1(""+hex_sha1(hex_sha1(psw))+servertime+nonce);
        return password;
    }
     
    private String hex_sha1(String j) {
        return h(b(f(j,j.length()*g), j.length() * g));
    }
    private String h(int[] l){
        String k = i ? "0123456789ABCDEF" : "0123456789abcdef";
        String m = "";
        for (int j = 0; j < l.length * 4; j++) {
            m += k.charAt((l[j >> 2] >> ((3 - j % 4) * 8 + 4)) & 15) + "" + k.charAt((l[j >> 2] >> ((3 - j % 4) * 8)) & 15);
        }
        return m;
    }
     
    private int[] b(int[] A,int r){
        A[r>>5]|=128<<(24-r%32);
        A[((r+64>>9)<<4)+15]=r;
        int[] B = new int[80];
        int z = 1732584193;
        int y = -271733879;
        int v = -1732584194;
        int u = 271733878;
        int s = -1009589776;
        for (int o = 0; o < A.length; o += 16) {
            int q = z;
            int p = y;
            int n = v;
            int m = u;
            int k = s;
            for (int l = 0; l < 80; l++) {
                if (l < 16) {
                    B[l] = A[o + l];
                } else {
                    B[l] = d(B[l - 3] ^ B[l - 8] ^ B[l - 14] ^ B[l - 16], 1);
                }
                int C = e(e(d(z, 5), a(l, y, v, u)), e(e(s, B[l]), c(l)));
                s = u;
                u = v;
                v = d(y, 30);
                y = z;
                z = C;
            }
            z = e(z, q);
            y = e(y, p);
            v = e(v, n);
            u = e(u, m);
            s = e(s, k);
        }
        return new int[]{z,y,v,u,s};
    }
     
    private int a(int k,int j,int m,int l){
        if(k<20){return(j&m)|((~j)&l);};
        if(k<40){return j^m^l;};
        if(k<60){return(j&m)|(j&l)|(m&l);};
        return j^m^l;
    }
     private int c(int j){
        return(j<20)?1518500249:(j<40)?1859775393:(j<60)?-1894007588:-899497514;
    }
    private int e(int j, int m) {
        int l = (j & 65535) + (m & 65535);
        int k = (j >> 16) + (m >> 16) + (l >> 16);
        return (k << 16) | (l & 65535);
    }
    private int d(int j,int k){
        return(j<<k)|(j>>>(32-k));
    }
     
    private int[] f(String m,int r){
        int[] l;
        int j = (1<<this.g)-1;
        int len=((r+64>>9)<<4)+15;
        int k;
        for(k=0;k<m.length()*g;k+=g){
            len = k>>5>len?k>>5:len;
        }
        l = new int[len+1];
        for(k=0;k<l.length;k++){
            l[k]=0;
        }
        for(k=0;k<m.length()*g;k+=g){
            l[k>>5]|=(m.charAt(k/g)&j)<<(24-k%32);
        }
        return l;
    }
}

  得到这几个参数后连通其他的一些参数,其他的参数内容不需要改变,一起封装成HTTP包先服务器发送即可,到这一步,已经完成得差不多了,提交 到服务器后服务器返回了一些Cookie,有六个tgc,SUE,SUP,ALC,ALF,SUR。登录新浪微博提交的Cookie有很多,但在访问需要 用户登录的页面只需要这里面的2个参数即可, SUE,SUP;还有一个wvr的参数,其值为4,其他的参数还没去理解,为了方便我把所有服务器返回的Cookie全都封装在HTTP包里了。

要访问其他的之前需要登录的页面时,这需要在提交的http包的Header加上Cookie项,值为获得的这几个参数加上wvr=4就好了。这就会发现原来不能直接访问的页面,现在可以访问了。

分析数据是个挺花时间的过程,但最终能实现还是很爽的。。。

一些其他的参数还没去理解他们的意义,爬取微话题的主页是没问题的,但使用一些新浪微博api时就出现了一些问题。

posted @ 2012-03-30 09:27 不会飞的鸟 阅读(954) | 评论 (1)编辑 收藏

Linux下动态加载动态库,更新动态库而不用更新程序

linux下动态加载动态库,主要用到dlopen(),dlsym(),dlclose(),dlerror()四个函数,他们所使用的头文件#include <dlfcn.h>
在这里主要介绍一下dlopen()函数

dlopen()  功能:打开一个动态链接库

  包含头文件:

  #include <dlfcn.h>

  函数定义

  void * dlopen( const char * pathname, int mode );

  函数描述:

  在dlopen的()函数以指定模式打开指定的动态连接库文件,并返回一个句柄给调用进程。使用dlclose()来卸载打开的库。

  mode:分为这两种

  RTLD_LAZY 暂缓决定,等有需要时再解出符号

  RTLD_NOW 立即决定,返回前解除所有未决定的符号。

  RTLD_LOCAL

  RTLD_GLOBAL 允许导出符号

  RTLD_GROUP

  RTLD_WORLD

  返回值:

  打开错误返回NULL

  成功,返回库引用

  编译时候要加入 -ldl (指定dl库)

  例如

  gcc test.c -o test -ldl


下面举个例子,同时考虑到几个细节。


/***********************main.c的内容**************************/
#include<stdio.h>
#include<dlfcn.h>
int main()
{
    int a,b;
    void *pHandle;
   
typedef int (*func)(int,int);   //注意函数的定义,这里要根据下面的max函数格式定义。
    scanf("%d%d",&a,&b);
    pHandle=dlopen("./dl2.so",RTLD_NOW);
    if (!pHandle)
    {
            cerr << "Cannot open library: " << dlerror() << ' ';
            return 1;
    }
   
    func=(func)dlsym(pHandle,"max");
    const char *dlsym_error = dlerror();
    if (dlsym_error) {
            cerr << "Cannot load symbol 'baidu': " << dlsym_error <<' ';
            dlclose(pHandle);
            return 1;
    }

    printf("%d与%d相比,%d为大数。\n",a,b,(*func)(a,b));
    dlclose(pHandle);
}
/***********************main.c的内容**************************/

/***********************testmax.c的内容**************************/
#include<stdio.h>
int max(int x,int y)
{
    return x>y?x:y;
}
/***********************testmax.c的内容**************************/

编译:
gcc testmax.c -shared -fPIC -o testmax.so
gcc -o main -ldl main.c

运行:
admin@admin-desktop:/abc/test$ ./main
2008 2012
2008与2012相比,2012为大数。


很浅层的东西,这样下次你直接修改你的testmax.c文件,编译成动态库拷贝到main目录,不用编译,直接可以加载你最新修改的testmax中的函数,前提是函数名、格式要相同

posted @ 2012-03-26 15:53 不会飞的鸟 阅读(2812) | 评论 (1)编辑 收藏

ora-00054:resource busy and acquire with nowait specified解决方法

当某个数据库用户在数据库中插入、更新、删除一个表的数据,或者增加一个表的主键时或者表的索引时,常常会出现ora-00054:resource busy and acquire with nowait specified这样的错误。

主要是因为有事务正在执行(或者事务已经被锁),所有导致执行不成功。

1、用dba权限的用户查看数据库都有哪些锁

select t2.username,t2.sid,t2.serial#,t2.logon_time
from v$locked_object t1,v$session t2
where t1.session_id=t2.sid order by t2.logon_time;

如:testuser 339 13545 2009-3-5 17:40:05
知道被锁的用户testuser,sid为339,serial#为13545

2、根据sid查看具体的sql语句,如果sql不重要,可以kill

select sql_text from v$session a,v$sqltext_with_newlines b
  where DECODE(a.sql_hash_value, 0, prev_hash_value, sql_hash_value)=b.hash_value
  and a.sid=&sid order by piece;

查出来的sql,如: begin :id := sys.dbms_transaction.local_transaction_id; end;

3、kill该事务
alter system kill session '339,13545';

4、这样就可以执行其他的事务sql语句了

如增加表的主键:
alter table test
  add constraint PK_test primary key (test_NO);

posted @ 2011-10-29 13:19 不会飞的鸟 阅读(328) | 评论 (1)编辑 收藏

[转]纯真IP数据库格式详解

摘要 

网络上的IP数据库以纯真版的最为流行,LumaQQ也采用了纯真版IP数据库做为IP查询功能的基础。不过关于其格式的文档却非常之少,后来终于在网上 找到了一份文档,得以了解其内幕,不过那份文档寥寥数语,也是颇为耐心才读明白。在这里我重写一份,以此做为LumaQQ开发者文档的一部分,我想还是必 要的。本文详细介绍了纯真IP数据库的格式,并且给出了一些Demo以供参考。 
Luma, 清华大学
修改日期: 2005/01/14

Note: 在此感谢纯真IP数据库作者金狐和那唯一一份文档的作者。

修改历史:
2005-01-14 修改了原来一些表达不清和错误的地方 


--------------------------------------------------------------------------------

自从有了IP数据库这种东西,QQ外挂的显示IP功能也随之而生,本人见识颇窄,是否还有其他应用不得而知,不过,IP数据库确实是个不错的东西。如今网 络上最流行的IP数据库我想应该是纯真版的(说错了也不要扁我),迄今为止其IP记录条数已经接近30000,对于有些IP甚至能精确到楼层,不亦快哉。 2004年4、5月间,正逢LumaQQ破土动工,为了加上这个人人都喜欢,但是好像人人都不知道为什么喜欢的显IP功能,我也采用了纯真版IP数据库, 它的优点是记录多,查询速度快,它只用一个文件QQWry.dat就包含了所有记录,方便嵌入到其他程序中,也方便升级。

基本结构
QQWry.dat文件在结构上分为3块:文件头,记录区,索引区。一般我们要查找IP时,先在索引区查找记录偏移,然后再到记录区读出信息。由于记录区 的记录是不定长的,所以直接在记录区中搜索是不可能的。由于记录数比较多,如果我们遍历索引区也会是有点慢的,一般来说,我们可以用二分查找法搜索索引 区,其速度比遍历索引区快若干数量级。图1是QQWry.dat的文件结构图。


[img]http://lumaqq.linuxsir.org/article/images/1/qqwry_dat_overview.gif[img]
图1. QQWry.dat文件结构
要注意的是,QQWry.dat里面全部采用了little-endian字节序

一. 了解文件头
QQWry.dat的文件头只有8个字节,其结构非常简单,首四个字节是第一条索引的绝对偏移,后四个字节是最后一条索引的绝对偏移。

二. 了解记录区
每条IP记录都由国家和地区名组成,国家地区在这里并不是太确切,因为可能会查出来“清华大学计算机系”之类的,这里清华大学就成了国家名了,所以这个国 家地区名和IP数据库制作的时候有关系。所以记录的格式有点像QName,有一个全局部分和局部部分组成,我们这里还是沿用国家名和地区名的说法。

于是我们想象着一条记录的格式应该是: [IP地址][国家名][地区名],当然,这个没有什么问题,但是这只是最简单的情况。很显然,国家名和地区名可能会有很多的重复,如果每条记录都保存一 个完整的名称拷贝是非常不理想的,所以我们就需要重定向以节省空间。所以为了得到一个国家名或者地区名,我们就有了两个可能:第一就是直接的字符串表示的 国家名,第二就是一个4字节的结构,第一个字节表明了重定向的模式,后面3个字节是国家名或者地区名的实际偏移位置。对于国家名来说,情况还可能更复杂 些,因为这样的重定向最多可能有两次。

那么什么是重定向模式?根据上面所说,一条记录的格式是[IP地址][国家记录][地区记录],如果国家记录是重定向的话,那么地区记录是有可能没有的,于是就有了两种情况,我管他叫做模式1和模式2。我们对这些格式的情况举图说明:



图2. IP记录的最简单形式
图2表示了最简单的IP记录格式,我想没有什么可以解释的



图3. 重定向模式1
图3演示了重定向模式1的情况。我们看到在模式1的情况下,地区记录也跟着国家记录走了,在IP地址之后只剩下了国家记录的4字节,后面3个字节构成了一个指针,指向了实际的国家名,然后又跟着地址名。模式1的标识字节是0x01。



图4. 重定向模式2
图4演示了重定向模式2的情况。我们看到了在模式2的情况下(其标识字节是0x02),地区记录没有跟着国家记录走,因此在国家记录之后4个字节之后还是 有地区记录。我想你已经明白了模式1和模式2的区别,即:模式1的国家记录后面不会再有地区记录,模式2的国家记录后会有地区记录。下面我们来看一下更复 杂的情况。



图5. 混和情况1
图5演示了当国家记录为模式1的时候可能出现的更复杂情况,在这种情况下,重定向指向的位置仍然是个重定向,不过第二次重定向为模式2。大家不用担心,没 有模式3了,这个重定向也最多只有两次,并且如果发生了第二次重定向,则其一定为模式2,而且这种情况只会发生在国家记录上,对于地区记录,模式1和模式 2是一样的,地区记录也不会发生2次重定向。不过,这个图还可以更复杂,如图7:



图6. 混和情况2
图6是模式1下最复杂的混和情况,不过我想应该也很好理解,只不过地区记录也来重定向而已,有一点我要提醒你,如果重定向的地址是0,则表示未知的地区名。

所以我们总结如下:一条IP记录由[IP地址][国家记录][地区记录]组成,对于国家记录,可以有三种表示方式:字符串形式,重定向模式1和重定向模式 2。对于地区记录,可以有两种表示方式:字符串形式和重定向,另外有一条规则:重定向模式1的国家记录后不能跟地区记录。按照这个总结,在这些方式中合理 组合,就构成了IP记录的所有可能情况。

设计的理由
在我们继续去了解索引区的结构之前,我们先来了解一下为何记录区的结构要如此设计。我想你可能想到了答案:字符串重用。没错,在这种结构下,对于一个国家 名和地区名,我只需要保存其一次就可以了。我们举例说明,为了表示方便,我们用小写字母代表IP记录,C表示国家名,A表示地区名: 

有两条记录a(C1, A1), b(C2, A2),如果C1 = C2, A1 = A2,那么我们就可以使用图3显示的结构来实现重用 
有三条记录a(C1, A1), b(C2, A2), c(C3, A3),如果C1 = C2, A2 = A3,现在我们想存储记录b,那么我们可以用图6的结构来实现重用 
有两条记录a(C1, A1), b(C2, A2),如果C1 = C2,现在我们想存储记录b,那么我们可以采用模式2表示C2,用字符串表示A2 

你可以举出更多的情况,你也会发现在这种结构下,不同的字符串只需要存储一次。

了解索引区
在"了解文件头"部分,我们说明了文件头实际上是两个指针,分别指向了第一条索引和最后一条索引的绝对偏移。如图8所示:



图8. 文件头指向索引区图示
实在是很简单,不是吗?从文件头你就可以定位到索引区,然后你就可以开始搜索IP了!每条索引长度为7个字节,前4个字节是起始IP地址,后三个字节就指 向了IP记录。这里有些概念需要说明一下,什么是起始IP,那么有没有结束IP? 假设有这么一条记录:166.111.0.0 - 166.111.255.255,那么166.111.0.0就是起始IP,166.111.255.255就是结束IP,结束IP就是IP记录中的那头 4个字节,这下你应该就清楚了吧。于是乎,每条索引配合一条记录,构成了一个IP范围,如果你要查找166.111.138.138所在的位置,你就会发 现166.111.138.138落在了166.111.0.0 - 166.111.255.255 这个范围内,那么你就可以顺着这条索引去读取国家和地区名了。那么我们给出一个最详细的图解吧:



图9. 文件详细结构
现在一切都清楚了是不是?也许还有一点你不清楚,QQWry.dat的版本信息存在哪里呢? 答案是:最后一条IP记录实际上就是版本信息,最后一条记录显示出来就是这样:255.255.255.0 255.255.255.255 纯真网络 2004年6月25日IP数据。OK,到现在你应该全部清楚了。

posted @ 2011-10-01 21:52 不会飞的鸟 阅读(313) | 评论 (0)编辑 收藏

C/C++读取纯真QQIP地址数据库

     摘要: 关于 纯真IP数据库格式,详细见下面帖子:http://blog.chinaunix.net/u1/41420/showart_322320.html程序说明:能够根据输入的IP,在 纯真IP数据库 中,搜索并且读取对应的 物理地址,还可以导出所有的IP段地址信息。Code highlighting produced by Actipro CodeHighlighter (freeware)htt...  阅读全文

posted @ 2011-10-01 21:51 不会飞的鸟 阅读(636) | 评论 (0)编辑 收藏

[转]验证码识别技术

     摘要: 模拟精灵是首个公开最有效的验证码识别技术的软件,使用模拟精灵制作了大量的免费、商用群发软件,对很多复杂BT的验证码都能成功的识别。但是验证码仍然需要精湛的技术与足够的耐心。请牢记这一点。验证码识别不适合浮躁的人去做。验证码识别是一项特殊的技术,任何一个公开的验证码识别代码都会很快的失效。因为代码的公开后相关网站都会很快的更改验证码。所以下面我只会介绍其原理。在这里讨论验证码识别技术纯粹基于技术研究...  阅读全文

posted @ 2011-09-14 13:38 不会飞的鸟 阅读(2279) | 评论 (0)编辑 收藏

socket学习中网络序与主机序

主机字节序转换到网络字节序列的原理:
网络字节序列采用低字节在高位的排列方式,
而X86主机字节序列采用低字节在低位的方式
其实只要交换一下就可以实现网络字节序列和主机字节序列的转换,
所以对于上面的函数,htonl和ntohl是一样的。
  h   host   主机  
  n   net     网络  
  l   long   长整形  
  s   short   短整形  
  XtoX就是进行数据存储顺序的主机和网络顺序的转换
htonl和htons分别把无符号长整型和无符号短整型数字转换成TCP/IP协议规定的统一的网络字节序的数字,即大头序。不同体系的计算机存储数字时有些把最低位放在前面,另一些相反,即所谓大头和小头。数字进入Internet时应先用htonl或htons转换成统一的大头序。
 
htonl(将32位主机字符顺序转换成网络字符顺序) 
定义函数  unsigned long int htonl(unsigned long int hostlong);
 
函数说明  htonl()用来将参数指定的32位hostlong 转换成网络字符顺序。
 
返回值  返回对应的网络字符顺序。
 
htons(将16位主机字符顺序转换成网络字符顺序)   
定义函数  unsigned short int htons(unsigned short int hostshort);
 
函数说明  htons()用来将参数指定的16位hostshort转换成网络字符顺序。
 
返回值  返回对应的网络字符顺序。
ntohl(将32位网络字符顺序转换成主机字符顺序) 
定义函数  unsigned long int ntohl(unsigned long int netlong);
 
函数说明  ntohl()用来将参数指定的32位netlong转换成主机字符顺序。
 
返回值  返回对应的主机字符顺序。
 
 
ntohs(将 16位网络字符顺序转换成主机字符顺序)  
 
定义函数  unsigned short int ntohs(unsigned short int netshort);
 
函数说明  ntohs()用来将参数指定的16位netshort转换成主机字符顺序。
 
返回值  返回对应的主机顺序。
比如网络字节 为 00 01
u_short    a;   // a=0100; 因为主机是从高字节到低字节的,所以应该转化后
a=ntohs(0001); //这样 a=0001;
 
假设你已经有了一个sockaddr_in结构体ina,你有一个IP地址"132.241.5.10" 要储存在其中,你就要用到函数inet_addr(),将IP地址从 点数格式转换成无符号长整型。使用方法如下:
ina.sin_addr.s_addr = inet_addr(“132.241.5.10″);
注意,inet_addr()返回的地址已经是网络字节格式,所以你无需再调用函数htonl()。
 
 
inet_addr(将网络地址转成二进制的数字)  
定义函数  unsigned long int inet_addr(const char *cp);
 
函数说明  inet_addr()用来将参数cp所指的网络地址字符串转换成网络所使用的二进制数字。网络地址字符串是以数字和点组成的字符串,例如:“163.13.132.68”。
 
返回值  成功则返回对应的网络二进制的数字,失败返回-1。
 
//ntoa:network to ascii
//aton:ascii to network 
 
inet_aton(将网络地址转成网络二进制的数字) 
定义函数  int inet_aton(const char * cp,struct in_addr *inp);
 
函数说明  inet_aton()用来将参数cp所指的网络地址字符串转换成网络使用的二进制的数字,然后存于参数inp所指的in_addr结构中。
结构 in_addr定义如下
struct in_addr
{
unsigned long int s_addr;
};
 
返回值  成功则返回非0值,失败则返回0。
 
 
 
inet_ntoa(将网络二进制的数字转换成网络地址) 
定义函数  char * inet_ntoa(struct in_addr in);
 
函数说明  inet_ntoa()用来将参数in所指的网络二进制的数字转换成网络地址,然后将指向此网络地址字符串的指针返回。( 将网络地址转换成“.”点隔的字符串格式)
 
返回值  成功则返回字符串指针,失败则返回NULL。

posted @ 2011-07-07 10:24 不会飞的鸟 阅读(541) | 评论 (0)编辑 收藏

socket编程-预备知识

1. 预备知识

1.1. 网络字节序

我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分,磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分。网络数据流同样有大端小端之分,那么如何定义网络数据流的地址呢?发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出,接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存,因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址。

TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。例如上一节的UDP段格式,地址0-1是16位的源端口号,如果这个端口号是1000(0x3e8),则地址0是0x03,地址1是0xe8,也就是先发0x03,再发0xe8,这16位在发送主机的缓冲区中也应该是低地址存0x03,高地址存0xe8。但是,如果发送主机是小端字节序的,这16位被解释成0xe803,而不是1000。因此,发送主机把1000填到发送缓冲区之前需要做字节序的转换。同样地,接收主机如果是小端字节序的,接到16位的源端口号也要做字节序的转换。如果主机是大端字节序的,发送和接收都不需要做转换。同理,32位的IP地址也要考虑网络字节序和主机字节序的问题。

为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。

#include <arpa/inet.h>

uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

这些函数名很好记,h表示host,n表示network,l表示32位长整数,s表示16位短整数。例如htonl表示将32位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回,如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。

1.2. socket地址的数据类型及相关函数 请点评

socket API是一层抽象的网络编程接口,适用于各种底层网络协议,如IPv4、IPv6,以及后面要讲的UNIX Domain Socket。然而,各种网络协议的地址格式并不相同,如下图所示:

图 37.1. sockaddr数据结构

sockaddr数据结构

IPv4和IPv6的地址格式定义在netinet/in.h中,IPv4地址用sockaddr_in结构体表示,包括16位端口号和32位IP地址,IPv6地址用sockaddr_in6结构体表示,包括16位端口号、128位IP地址和一些控制字段。UNIX Domain Socket的地址格式定义在sys/un.h中,用sockaddr_un结构体表示。各种socket地址结构体的开头都是相同的,前16位表示整个结构体的长度(并不是所有UNIX的实现都有长度字段,如Linux就没有),后16位表示地址类型。IPv4、IPv6和UNIX Domain Socket的地址类型分别定义为常数AF_INET、AF_INET6、AF_UNIX。这样,只要取得某种sockaddr结构体的首地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容。因此,socket API可以接受各种类型的sockaddr结构体指针做参数,例如bind、accept、connect等函数,这些函数的参数应该设计成void *类型以便接受各种类型的指针,但是sock API的实现早于ANSI C标准化,那时还没有void *类型,因此这些函数的参数都用struct sockaddr *类型表示,在传递参数之前要强制类型转换一下,例如:

struct sockaddr_in servaddr;
/* initialize servaddr */
bind(listen_fd, (struct sockaddr *)&servaddr, sizeof(servaddr));

本节只介绍基于IPv4的socket网络编程,sockaddr_in中的成员struct in_addr sin_addr表示32位的IP地址。但是我们通常用点分十进制的字符串表示IP地址,以下函数可以在字符串表示和in_addr表示之间转换。

字符串转in_addr的函数:

#include <arpa/inet.h>

int inet_aton(const char *strptr, struct in_addr *addrptr);
in_addr_t inet_addr(const char *strptr);
int inet_pton(int family, const char *strptr, void *addrptr);

in_addr转字符串的函数:

char *inet_ntoa(struct in_addr inaddr);
const char *inet_ntop(int family, const void *addrptr, char *strptr, size_t len);

其中inet_pton和inet_ntop不仅可以转换IPv4的in_addr,还可以转换IPv6的in6_addr,因此函数接口是void *addrptr。

posted @ 2011-07-03 14:00 不会飞的鸟 阅读(377) | 评论 (0)编辑 收藏

仅列出标题
共9页: 1 2 3 4 5 6 7 8 9