分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

继续接着第一篇写:使用C#实现DHT磁力搜索的BT种子后端管理程序+数据库设计(开源)[搜片神器]

开源地址:https://github.com/h31h31/H31DHTMgr

程序下载:H31DHT下载

看大家对昨天此类文章的兴趣没有第一篇高,今天就简单的对支持的朋友进行交流.园子里的朋友希望授大家以渔,所以这部分代码就先不放出来.希望大家更多的加入进来.

也希望谁有能力将C++的代码转换成C#的,添加到我们的搜片神器工具里面.

昨天通过向大家介绍DHT的工作原理,相信大家大概明白怎么回事,不明白的朋友可以继续分享接下来的文章.

本人借鉴的代码是C++版本的:transmission里面的DHT代码,大家可以访问网站下载:http://www.transmissionbt.com/

不过里面的代码环境是LINUX下的,需要自己转换到相应的WIN平台上来.

有兴趣使用C#来完成DHT功能的朋友可以借鉴mono-monotorrent,里面的框架代码比较多,不如C++的transmission里面就三个文件来得明白.

transmission里面只有三个文件就可以实现dht的功能: dht.c dht.h dht-example.c,并且接口很简单,复用性很好。

下面介绍进入DHT网络主要功能步骤

dht.c dht.h代码分成三部分:
1、路由表的插入操作。
1)如果节点已经在路由表中,则更新节点,返回。
2)如果桶没有满,则插入,返回。
3)如果发现失效节点,替换,返回。
4)发现可疑节点,则保存新节点到缓存中并且如果该可疑节点没有ping,发出ping_node操作,返回。
5)现在,桶已经充满了好的节点,如果自己的ID没有落在这个桶中,返回。
6)将桶空间分成两半。跳到步骤1)。

2、KAD远程处理调用。
这部分又分成3种,
1)ping/pong操作。
所有的包的tid都使用pg\0\0
2)find_node操作。
所有的包的tid都使用fn\0\0
3)get_peers/annouce_peer操作。
对同一个HASH的一次递归查询中,tid保持不变。
其中只有3)种实现bittorrent的DHT规范里面提到的递归查询操作,1)和2)仅仅用来维护路由表,并且不保存状态。

3、定时器处理:
为了检测路由表中节点的有效性(根据规范,路由表中应该只保存有效节点),在代码中,在执行krpc操作时如果发现时对路由表中的节点操作,那么则保存操作的开始时间 pinged_time,通过操作的开始时间来判断操作是否超时。

expire_stuff_time 超时时,会执行下面的操作:
1、检查路由表中失效的节点(根据pinged_time来判定),并将该节点删除。
2、检查用来保存annoounce_peer的节点是否超过30分钟(这个不打算深入讨论,故不做解析)。
3、检查递归查询操作超时。

rotate_secrets_time 定时器。
用来每隔大约15分左右就更换token(见DHT规范).

confirm_nodes_time 定时器。
查找长期没有活动的桶,然后通过执行一个find_node的krpc操作来刷新它。

search_time定时器。
有可能出现发出的所有的get_peers操作,都没有应答,那么search_time定时器遇到这种情形时负责重发所有请求。(注意: get_peers操作最大未决的krpc请求数是3)

用于维持路由表的ping/pong操作:
在试图插入节点时,发现桶已经满,而存在可疑节点时会触发ping_node操作。未响应的节点会有可疑最终变为失效节点,而被替换。

下面介绍我们是如何进入DHT网络

  1. DHT必须把自己电脑当服务器,别人才能够知道自己是谁,所以需要通过UDP绑定端口,参考代码里面支持IPV6,个人觉得可以过滤掉.WIN平台代码如下:

     1     //初始化socket 2     m_soListen =(int)socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); 3     if (m_soListen == INVALID_SOCKET) { 4         m_iErrorNo=WSAGetLastError(); 5         _dout(_T("CH31CarMonitorDlg Start Error(%d).\n"),m_iErrorNo); 6         return -1; 7     } 8     //初始化服务器地址 9     SOCKADDR_IN addr;10     memset(&addr, 0, sizeof(addr));11     addr.sin_family = AF_INET;12     addr.sin_port = htons(port);13     addr.sin_addr.s_addr = htonl(INADDR_ANY);14     //绑定端口监听15     if (bind(m_soListen, (SOCKADDR*)&addr, sizeof(addr)) == SOCKET_ERROR) {16         m_iErrorNo=WSAGetLastError();17         _dout(_T("CH31CarMonitorDlg Start Error(%d).\n"),m_iErrorNo);18         return -2;19     }

    UDP端口绑定

  2. DHT需要生成一个自己的20位ID号,当然可以通过随机一个数值,然后通过SHA1来生成20位的ID号,WIN平台代码如下:   

    1 unsigned char p[20];2 CSHA1 sha1;3 sha1.Reset();4 sha1.Update((const unsigned char *)m_myID.GetBuffer(),   m_myID.GetLength());5 sha1.Final();6 sha1.GetHash(p);

    SHA1生成ID号

  3. 初始化他人服务器的IP信息,这样我们就可以从他们那里查询我们要的信息,借鉴代码如下:   

     1     rc = getaddrinfo("router.utorrent.com","6881", &hints1, &info); 2     //rc = getaddrinfo("router.bittorrent.com","6881", &hints1, &info); 3     //rc = getaddrinfo("dht.transmissionbt.com","6881", &hints1, &info); 4     if(rc != 0) { 5         fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rc)); 6         exit(1); 7     } 8     infop = info; 9     while(infop&&m_bDataThread) 10     {11         memcpy(&bootstrap_nodes[num_bootstrap_nodes],infop->ai_addr, infop->ai_addrlen);12         infop = infop->ai_next;13         num_bootstrap_nodes++;14     }15     freeaddrinfo(info);

    服务器信息

  4. 现在就可以初始化我们的DHT类了.由于此类使用C写的,大家可以自行封装成C++类使用.   

    1     rc = m_dht.dht_init(s, s6, m_myid,NULL);2     if(rc < 0) {3         perror("dht_init");4         exit(1);5     }

    初始化DHT类

  5. 对服务器进行PING操作,服务器就会回应PONG操作,这样就表明服务器活动正常.   

    1     for(int i = 0; i < num_bootstrap_nodes&&m_bDataThread; i++) 2     {3         m_dht.dht_ping_node((struct sockaddr*)&bootstrap_nodes[i],sizeof(bootstrap_nodes[i]));4         Sleep(m_dht.random() % 1000);5     }

    PING服务器

  6. 下面就可以使用搜索类进行操作,查询我们要的HASH值的BT种子文件代码.借鉴代码如下:   

    1  if(searching) {2             if(s >= 0)3                 dht_search(hash, 0, AF_INET, callback, NULL);4             if(s6 >= 0)5                 dht_search(hash, 0, AF_INET6, callback, NULL);6             searching = 0;7         }

    dht_search

  7. 大家可以借鉴dht-example.c里面接下来的Search函数的操作,不过我们不是这样来的,我们需要直接向服务器发送Findnode和Get_Peer操作.   

    1                 unsigned char tid[16];2                 m_dht.make_tid(tid, "fn", 0);3                 m_dht.send_find_node(&ipRecvPingList[ipListPOS].fromaddr,sizeof(sockaddr),tid,4,ipRecvPingList[ipListPOS].ID,0,0);4                 Sleep(100);5                 memset(tid,0,sizeof(tid));6                 m_dht.make_tid(tid, "gp", 0);7                 m_dht.send_get_peers(&ipRecvPingList[ipListPOS].fromaddr,sizeof(sockaddr),tid,4,hashList[0],0,0);

    发送FINDNODE和GET_PEER操作

  8. 接下来的事情就是等待别人返回的信息进行分析就可以了,当然DHT类代码已经全部为我们做好的.   

     1         FD_ZERO(&readfds); 2         if(m_soListen >= 0) 3             FD_SET(m_soListen, &readfds); 4         if(s6 >= 0) 5             FD_SET(s6, &readfds); 6         rc = select(m_soListen > s6 ? m_soListen + 1 : s6 + 1, &readfds, NULL, NULL, &tv); 7         if(rc <0&&m_bDataThread)  8         { 9             if(errno != EINTR) {10                 perror("select");11                 Sleep(1000);12             }13         }14         15         if(!m_bDataThread)16             break;17 18         if(rc > 0&&m_bDataThread) 19         {20             fromlen = sizeof(from1);21             memset(buf,0,sizeof(buf));22             if(m_soListen >= 0 && FD_ISSET(m_soListen, &readfds))23                 rc = recvfrom(m_soListen, buf, sizeof(buf) - 1, 0,&from1, &fromlen);24             else if(s6 >= 0 && FD_ISSET(s6, &readfds))25                 rc = recvfrom(s6, buf, sizeof(buf) - 1, 0,&from1, &fromlen);26             else27                 abort();28         }29 30         if(rc > 0&&m_bDataThread) 31         {32             buf[rc] = '\0';33             rc = m_dht.dht_periodic(buf, rc, &from1, fromlen,&tosleep, DHT_callback, this);34 35         } 36         else 37         {38             rc = m_dht.dht_periodic(NULL, 0, NULL, 0, &tosleep, DHT_callback, this);39         }

    等待返回DHT网络信息

  9. 如何解析信息DHT代码已经有了,如何别人的请求,代码也已经有了,大家可以分析DHT.c就知道是怎么回事.   

      1 int CDHT::dht_periodic(const void *buf, size_t buflen,const struct sockaddr *fromAddr, int fromlen,time_t *tosleep,dht_callback *callback, void *closure)  2 {  3     gettimeofday(&nowTime, NULL);  4   5     if(buflen > 0)   6     {  7         int message;  8         unsigned char tid[16], id[20], info_hash[20], target[20];  9         unsigned char nodes[256], nodes6[1024], token[128]; 10         int tid_len = 16, token_len = 128; 11         int nodes_len = 256, nodes6_len = 1024; 12         unsigned short port; 13         unsigned char values[2048], values6[2048]; 14         int values_len = 2048, values6_len = 2048; 15         int want; 16         unsigned short ttid; 17  18         struct sockaddr_in* tempip=(struct sockaddr_in *)fromAddr; 19  20         if(is_martian(fromAddr)) 21             goto dontread; 22  23         if(node_blacklisted(fromAddr, fromlen)) { 24             _dout("Received packet from blacklisted node.\n"); 25             goto dontread; 26         } 27  28         if(((char*)buf)[buflen] != '\0') { 29             _dout("Unterminated message.\n"); 30             errno = EINVAL; 31             return -1; 32         } 33  34         message = parse_message((unsigned char *)buf, buflen, tid, &tid_len, id, info_hash,target, &port, token, &token_len,nodes, &nodes_len, nodes6, &nodes6_len,values, &values_len, values6, &values6_len,&want); 35  36         if(token_len>0) 37         { 38             int a=0; 39         } 40         if(message < 0 || message == ERROR || id_cmp(id, zeroes) == 0)  41         { 42             _dout("Unparseable message: "); 43             debug_printable((const unsigned char *)buf, buflen); 44             _dout("\n"); 45             goto dontread; 46         } 47  48         if(id_cmp(id, myid) == 0) { 49             _dout("Received message from self.\n"); 50             goto dontread; 51         } 52  53         if(message > REPLY) { 54             /* Rate limit requests. */ 55             if(!token_bucket()) { 56                 _dout("Dropping request due to rate limiting.\n"); 57                 goto dontread; 58             } 59         } 60  61         switch(message)  62         { 63         case REPLY: 64             if(tid_len != 4)  65             { 66                 _dout("Broken node truncates transaction ids: "); 67                 debug_printable((const unsigned char *)buf, buflen); 68                 _dout("\n"); 69                 /* This is really annoying, as it means that we will 70                    time-out all our searches that go through this node. 71                    Kill it. */ 72                 blacklist_node(id, fromAddr, fromlen); 73                 goto dontread; 74             } 75             if(tid_match(tid, "pn", NULL))  76             { 77                 _dout("Pong!From IP:%s:[%d] id:[%s]\n",inet_ntoa(tempip->sin_addr),tempip->sin_port,id); 78                 new_node(id, fromAddr, fromlen, 2); 79                 (*callback)(closure, DHT_EVENT_PONG_VALUES,id,(void*)fromAddr, fromlen); 80                 //send_find_node(from,fromlen,tid,4,id,0,0); 81             }  82             else if(tid_match(tid, "fn", NULL) ||tid_match(tid, "gp", NULL))  83             { 84                 int gp = 0; 85                 struct search *sr = NULL; 86                 if(tid_match(tid, "gp", &ttid))  87                 { 88                     gp = 1; 89                     sr = find_search(ttid, fromAddr->sa_family); 90                 } 91                 _dout("Nodes found (%d+%d)%s!From IP:%s:[%d]\n", nodes_len/26, nodes6_len/38,gp ? " for get_peers" : "",inet_ntoa(tempip->sin_addr),tempip->sin_port); 92                 if(nodes_len % 26 != 0 || nodes6_len % 38 != 0)  93                 { 94                     _dout("Unexpected length for node info!\n"); 95                     blacklist_node(id, fromAddr, fromlen); 96                 }  97                 //else if(gp && sr == NULL)  98                 //{ 99     //                _dout("Unknown search!\n");100     //                new_node(id, fromAddr, fromlen, 1);101     //            } 102                 else 103                 {104                     int i;105                     new_node(id, fromAddr, fromlen, 2);106                     for(i = 0; i < nodes_len / 26; i++) 107                     {108                         unsigned char *ni = nodes + i * 26;109                         struct sockaddr_in sin;110                         if(id_cmp(ni, myid) == 0)111                             continue;112                         memset(&sin, 0, sizeof(sin));113                         sin.sin_family = AF_INET;114                         memcpy(&sin.sin_addr, ni + 20, 4);115                         memcpy(&sin.sin_port, ni + 24, 2);116                         new_node(ni, (struct sockaddr*)&sin, sizeof(sin), 0);117                         (*callback)(closure, DHT_EVENT_FINDNODE_VALUES, ni,(void*)&sin, sizeof(sin));118                         if(sr && sr->af == AF_INET) 119                         {120                             insert_search_node(ni,(struct sockaddr*)&sin,sizeof(sin),sr, 0, NULL, 0);121                         }122                         //send_get_peers((struct sockaddr*)&sin,sizeof(sockaddr),tid,4,ni,0,0);123                     }124                     for(i = 0; i < nodes6_len / 38; i++) 125                     {126                         unsigned char *ni = nodes6 + i * 38;127                         struct sockaddr_in6 sinip6;128                         if(id_cmp(ni, myid) == 0)129                             continue;130                         memset(&sinip6, 0, sizeof(sinip6));131                         sinip6.sin6_family = AF_INET6;132                         memcpy(&sinip6.sin6_addr, ni + 20, 16);133                         memcpy(&sinip6.sin6_port, ni + 36, 2);134                         new_node(ni, (struct sockaddr*)&sinip6, sizeof(sinip6), 0);135                         if(sr && sr->af == AF_INET6) 136                         {137                             insert_search_node(ni,(struct sockaddr*)&sinip6,sizeof(sinip6),sr, 0, NULL, 0);138                         }139                     }140                     if(sr)141                         /* Since we received a reply, the number of requests in flight has decreased.  Let's push another request. */142                         search_send_get_peers(sr, NULL);143                 }144                 //if(sr) 145                 {146                    // insert_search_node(id, fromAddr, fromlen, sr,1, token, token_len);147                     if(values_len > 0 || values6_len > 0) 148                     {149                         _dout("Got values (%d+%d)!\n", values_len / 6, values6_len / 18);150                         if(callback) {151                             if(values_len > 0)152                                 (*callback)(closure, DHT_EVENT_VALUES, sr->id,(void*)values, values_len);153 154                             if(values6_len > 0)155                                 (*callback)(closure, DHT_EVENT_VALUES6, sr->id,(void*)values6, values6_len);156                         }157                     }158                 }159             } 160             else if(tid_match(tid, "ap", &ttid)) 161             {162                 struct search *sr;163                 _dout("Got reply to announce_peer.\n");164                 sr = find_search(ttid, fromAddr->sa_family);165                 if(!sr) {166                     _dout("Unknown search!\n");167                     new_node(id, fromAddr, fromlen, 1);168                 } 169                 else 170                 {171                     int i;172                     new_node(id, fromAddr, fromlen, 2);173                     for(i = 0; i < sr->numnodes; i++)174                     {175                         if(id_cmp(sr->nodes[i].id, id) == 0) 176                         {177                             sr->nodes[i].request_time = 0;178                             sr->nodes[i].reply_time = nowTime.tv_sec;179                             sr->nodes[i].acked = 1;180                             sr->nodes[i].pinged = 0;181                             break;182                         }183                     }184                     /* See comment for gp above. */185                     search_send_get_peers(sr, NULL);186                 }187             } 188             else 189             {190                 _dout("Unexpected reply: ");191                 debug_printable((const unsigned char *)buf, buflen);192                 _dout("\n");193             }194             break;195         case PING:196             _dout("Ping (%d)!From IP:%s:%d\n", tid_len,inet_ntoa(tempip->sin_addr),tempip->sin_port);197             new_node(id, fromAddr, fromlen, 1);198             _dout("Sending pong.\n");199             send_pong(fromAddr, fromlen, tid, tid_len);200             break;201         case FIND_NODE:202             _dout("Find node!From IP:%s:%d\n",inet_ntoa(tempip->sin_addr),tempip->sin_port);203             new_node(id, fromAddr, fromlen, 1);204             _dout("Sending closest nodes (%d).\n", want);205             send_closest_nodes(fromAddr, fromlen,tid, tid_len, target, want,0, NULL, NULL, 0);206             break;207         case GET_PEERS:208             _dout("Get_peers!From IP:%s:%d\n",inet_ntoa(tempip->sin_addr),tempip->sin_port);209             new_node(id, fromAddr, fromlen, 1);210             if(id_cmp(info_hash, zeroes) == 0) 211             {212                 _dout("Eek!  Got get_peers with no info_hash.\n");213                 send_error(fromAddr, fromlen, tid, tid_len,203, "Get_peers with no info_hash");214                 break;215             } 216             else 217             {218                 struct storage *st = find_storage(info_hash);219                 unsigned char token[TOKEN_SIZE];220                 make_token(fromAddr, 0, token);221                 if(st && st->numpeers > 0) 222                 {223                      _dout("Sending found%s peers.\n",fromAddr->sa_family == AF_INET6 ? " IPv6" : "");224                      send_closest_nodes(fromAddr, fromlen,tid, tid_len,info_hash, want,fromAddr->sa_family, st,token, TOKEN_SIZE);225                 } 226                 else 227                 {228                     _dout("Sending nodes for get_peers.\n");229                     send_closest_nodes(fromAddr, fromlen,tid, tid_len, info_hash, want,0, NULL, token, TOKEN_SIZE);230                 }231                 if(callback) 232                 {233                     (*callback)(closure, DHT_EVENT_GET_PEER_VALUES, info_hash,(void *)fromAddr, fromlen);234                 }235             }236 237             break;238         case ANNOUNCE_PEER:239             _dout("Announce peer!From IP:%s:%d\n",inet_ntoa(tempip->sin_addr),tempip->sin_port);240             new_node(id, fromAddr, fromlen, 1);241 242             if(id_cmp(info_hash, zeroes) == 0) 243             {244                 _dout("Announce_peer with no info_hash.\n");245                 send_error(fromAddr, fromlen, tid, tid_len,203, "Announce_peer with no info_hash");246                 break;247             }248             if(!token_match(token, token_len, fromAddr)) {249                 _dout("Incorrect token for announce_peer.\n");250                 send_error(fromAddr, fromlen, tid, tid_len,203, "Announce_peer with wrong token");251                 break;252             }253             if(port == 0) {254                 _dout("Announce_peer with forbidden port %d.\n", port);255                 send_error(fromAddr, fromlen, tid, tid_len,203, "Announce_peer with forbidden port number");256                 break;257             }258             if(callback) 259             {260                 (*callback)(closure, DHT_EVENT_ANNOUNCE_PEER_VALUES, info_hash,(void *)fromAddr, fromlen);261             }262             storage_store(info_hash, fromAddr, port);263             /* Note that if storage_store failed, we lie to the requestor.264                This is to prevent them from backtracking, and hence polluting the DHT. */265             _dout("Sending peer announced.\n");266             send_peer_announced(fromAddr, fromlen, tid, tid_len);267         }268     }269 270  dontread:271     if(nowTime.tv_sec >= rotate_secrets_time)272         rotate_secrets();273 274     if(nowTime.tv_sec >= expire_stuff_time) {275         expire_buckets(buckets);276         expire_buckets(buckets6);277         expire_storage();278         expire_searches();279     }280 281     if(search_time > 0 && nowTime.tv_sec >= search_time) {282         struct search *sr;283         sr = searches;284         while(sr) {285             if(!sr->done && sr->step_time + 5 <= nowTime.tv_sec) 286             {287                 search_step(sr, callback, closure);288             }289             sr = sr->next;290         }291 292         search_time = 0;293 294         sr = searches;295         while(sr) {296             if(!sr->done) {297                 time_t tm = sr->step_time + 15 + random() % 10;298                 if(search_time == 0 || search_time > tm)299                     search_time = tm;300             }301             sr = sr->next;302         }303     }304 305     if(nowTime.tv_sec >= confirm_nodes_time) {306         int soon = 0;307 308         soon |= bucket_maintenance(AF_INET);309         soon |= bucket_maintenance(AF_INET6);310 311         if(!soon) 312         {313             if(mybucket_grow_time >= nowTime.tv_sec - 150)314                 soon |= neighbourhood_maintenance(AF_INET);315             if(mybucket6_grow_time >= nowTime.tv_sec - 150)316                 soon |= neighbourhood_maintenance(AF_INET6);317         }318 319         /* In order to maintain all buckets' age within 600 seconds, worst320            case is roughly 27 seconds, assuming the table is 22 bits deep.321            We want to keep a margin for neighborhood maintenance, so keep322            this within 25 seconds. */323         if(soon)324             confirm_nodes_time = nowTime.tv_sec + 5 + random() % 20;325         else326             confirm_nodes_time = nowTime.tv_sec + 60 + random() % 120;327     }328 329     if(confirm_nodes_time > nowTime.tv_sec)330         *tosleep = confirm_nodes_time - nowTime.tv_sec;331     else332         *tosleep = 0;333 334     if(search_time > 0) {335         if(search_time <= nowTime.tv_sec)336             *tosleep = 0;337         else if(*tosleep > search_time - nowTime.tv_sec)338             *tosleep = search_time - nowTime.tv_sec;339     }340 341     return 1;342 }

    dht_periodic

  10. 至于节点如何进行桶操作,调试过一次代码就会明白对应的原理,当然上面也介绍了如何进行桶分裂的原理.
  11. 接下来就是将上面的操作步骤进行循环.

通过上面的流程,了解DHT的工作方法后,如何增加更多的返回信息就需要下一篇的技术性问题的介绍,希望大家一起修改我们的开源程序.

大家有不明白的地方,可以一起讨论.

另外求服务器进行程序测试,需要有固定IP,10G的WIN服务器空间,h31h31@163.com,谢谢.

大家的推荐才是下一篇介绍的动力...

<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>

给我老师的人工智能教程打call!http://blog.csdn.net/jiangjunshow

搜片神器 之DHT网络爬虫的代码实现方法相关推荐

  1. [搜片神器]之DHT网络爬虫的代码实现方法

    继续接着第一篇写:使用C#实现DHT磁力搜索的BT种子后端管理程序+数据库设计(开源)[搜片神器] 谢谢园子朋友的支持,已经找到个VPS进行测试,国外的服务器: http://www.sosobta. ...

  2. [C#搜片神器] 之P2P中DHT网络爬虫原理

    继续接着上一篇写:使用C#实现DHT磁力搜索的BT种子后端管理程序+数据库设计(开源)[搜片神器] 昨天由于开源的时候没有注意运行环境,直接没有考虑下载BT种子文件时生成子文件夹,可能导致有的朋友运行 ...

  3. DHT网络爬虫的实现

    DHT协议原理以及一些重点分析: 要做DHT的爬虫,首先得透彻理解DHT,这样才能知道在什么地方究竟该应用什么算法去解决问题.关于DHT协议的细节以及重要的参考文章,请参考文末1 DHT协议作为BT协 ...

  4. dht java_一个java版本的dht网络爬虫,伪装dht节点获取hashinfo

    dht-spider 一个java版本的dht网络爬虫,伪装dht节点获取hashinfo 导入idea 在入口类DhtNetworkApplication 的main方法下 修改udp端口 直接运行 ...

  5. P2P中DHT网络爬虫

    DHT网络爬虫基于DHT网络构建了一个P2P资源搜索引擎.这个搜索引擎不但可以用于构建DHT网络中活跃的资源索引(活跃的资源意味着该网络中肯定有人至少持有该资源的部分数据),还可以分析出该网络中的热门 ...

  6. c语言dht网络爬虫,用Node.js实现一个DHT网络爬虫,一步一步完成一个BT搜索引擎(一)...

    传统的Bittorrent服务 传统的BT服务是由两部份组成的,tracker服务和p2p服务,通过前者用户可以知道谁拥有资源,后者是通过前者向拥有资源的用户发起下载. Trackerless 目前在 ...

  7. python DHT网络爬虫

    DHT是什么 DHT全称叫分布式哈希表(Distributed Hash Table),是一种分布式存储方法.在不需要服务器的情况下,每个客户端负责一个小范围的路由,并负责存储一小部分数据,从而实现整 ...

  8. BitTorrent协议DHT网络爬虫BitTorrentNetworkSpider

    代码连接:https://github.com/zhangbohun/BitTorrentNetworkSpider 代码简要介绍,主要分为几个部分 0 lib库,包括bencode(用于处理B编码) ...

  9. [搜片神器]迅雷云播视频地址获取代码分享[自己动手丰衣足食]

    DHT抓取程序开源地址:https://github.com/h31h31/H31DHTDEMO 数据处理程序开源地址:https://github.com/h31h31/H31DHTMgr . -- ...

最新文章

  1. canvars 画花
  2. 20131005第四章,第五章内容整理与归纳。
  3. 产品的三层境界:工具-平台-生态
  4. 云原生安全模型与实践
  5. Latex 插入目录 设置首页页码为空
  6. 小程序 || 语句_C ++条件语句| 查找输出程序| 套装2
  7. c 输出空格_C/C++知识分享:C++常用内置函数你会几个,使用过几次呢?
  8. Freescale MC9S08AW60汇编学习笔记(三)
  9. VMware 修复 Fusion 和 Horizon 中的两个提权漏洞
  10. python软件下载对电脑配置要求-python3批量统计用户电脑配置
  11. css hack 尽我所见
  12. EasyDrv 3.5 Beta 1.5驱动选择工具最新版
  13. Iframe背景透明
  14. Kvaser、C++、Qt编写监控界面(一)
  15. office2013卸载工具
  16. Git中HEAD和ORIG_HEAD指针指的是什么
  17. 企业微信机器人脚本python_Python实现企业微信机器人每天定时发消息实例
  18. Jmeter测试最大在线用户数
  19. date命令显示格式化的年月日时分秒
  20. idea不区分大小写提示

热门文章

  1. 斯柯达支持Android auto吗,斯柯达在SUV的布局输了吗?看柯米克和柯珞克的现状就知道...
  2. 法国为何是伟大数学家的摇篮?
  3. 透彻解析信号地与电源地的关系
  4. Java消息队列与JMS的诞生
  5. apk部分手机安装失败_安装apk解析包时出现错误怎么办?小编快速帮你解决
  6. FPGA学习之 直接数字频率合成器(DDS)
  7. java 编写方法和属性,Java类属性及方法的定义
  8. dllreg解除服务器注册,最简单的修复IE浏览器的方法:注册表重新注册DLL
  9. python语言流程控制语句的格式_慢步学python,编程基础知识,流程控制语句if
  10. 【C语言】算法学习·种类并查集