当前位置:首页 > 代码 > 正文

关于dht办事器的代码实现的信息

admin 发布:2022-12-19 03:19 123


今天给各位分享dht办事器的代码实现的知识,其中也会对进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

本文目录一览:

如何用c++写一个dht爬虫

要想爬,先读取HTTP

读取后 进行字符串分割 

Http访问有两种方式,GET和POST,就编程来说GET方式相对简单点,它不用向服务器提交数据,程序中使用POST方式,

提交数据并从服务器获取返回值。

为实现Http访问,微软提供了二套API:WinINet, WinHTTP。WinHTTP比WinINet更加安全和健壮,可以这么认为WinHTTP是WinINet的升级版本。

程序中,通过一个宏的设置来决定是使用WinHttp还是WinINet。

#define USE_WINHTTP      //Comment this line to user wininet.

下面来说说实现Http访问的流程(两套API都一样的流程):

1, 首先我们打开一个Session获得一个HINTERNET session句柄;

2, 然后我们使用这个session句柄与服务器连接得到一个HINTERNET connect句柄;

3, 然后我们使用这个connect句柄来打开Http 请求得到一个HINTERNET request句柄;

4, 这时我们就可以使用这个request句柄来发送数据与读取从服务器返回的数据;

5, 最后依次关闭request,connect,session句柄。

 

/***********************定义HTTP发送所用方法***********************************/

HINTERNET OpenSession(LPCWSTR userAgent = 0)

{

#ifdef USE_WINHTTP

    return WinHttpOpen(userAgent, NULL, NULL, NULL, NULL);;

#else

    return InternetOpen(userAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);

#endif

}

HINTERNET Connect(HINTERNET hSession, LPCWSTR serverAddr, int portNo)

{

#ifdef USE_WINHTTP

    return WinHttpConnect(hSession, serverAddr, (INTERNET_PORT) portNo, 0);

#else

    return InternetConnect(hSession, serverAddr, portNo, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);

#endif

}

HINTERNET OpenRequest(HINTERNET hConnect, LPCWSTR verb, LPCWSTR objectName, int scheme)

{

    DWORD flags = 0;

#ifdef USE_WINHTTP

    if (scheme == INTERNET_SCHEME_HTTPS) {

        flags |= WINHTTP_FLAG_SECURE;

    }

    return WinHttpOpenRequest(hConnect, verb, objectName, NULL, NULL, NULL, flags);

#else

    if (scheme == INTERNET_SCHEME_HTTPS) {

        flags |= INTERNET_FLAG_SECURE;

    }

    return HttpOpenRequest(hConnect, verb, objectName, NULL, NULL, NULL, flags, 0);

#endif

}

BOOL AddRequestHeaders(HINTERNET hRequest, LPCWSTR header)

{

    SIZE_T len = lstrlenW(header);

#ifdef USE_WINHTTP

    return WinHttpAddRequestHeaders(hRequest, header, DWORD(len), WINHTTP_ADDREQ_FLAG_ADD);

#else

    return HttpAddRequestHeaders(hRequest, header, DWORD(len), HTTP_ADDREQ_FLAG_ADD);

#endif

}

BOOL SendRequest(HINTERNET hRequest, const void* body, DWORD size)

{

#ifdef USE_WINHTTP

    return WinHttpSendRequest(hRequest, 0, 0, const_castvoid*(body), size, size, 0);

#else

    return HttpSendRequest(hRequest, 0, 0, const_castvoid*(body), size);

#endif

}

BOOL EndRequest(HINTERNET hRequest)

{

#ifdef USE_WINHTTP

    return WinHttpReceiveResponse(hRequest, 0);

#else

    // if you use HttpSendRequestEx to send request then use HttpEndRequest in here!

    return TRUE;

#endif

}

BOOL QueryInfo(HINTERNET hRequest, int queryId, char* szBuf, DWORD* pdwSize)

{

#ifdef USE_WINHTTP

    return WinHttpQueryHeaders(hRequest, (DWORD) queryId, 0, szBuf, pdwSize, 0);

#else

    return HttpQueryInfo(hRequest, queryId, szBuf, pdwSize, 0);

#endif

}

BOOL ReadData(HINTERNET hRequest, void* buffer, DWORD length, DWORD* cbRead)

{

#ifdef USE_WINHTTP

    return WinHttpReadData(hRequest, buffer, length, cbRead);

#else

    return InternetReadFile(hRequest, buffer, length, cbRead);

#endif

}

void CloseInternetHandle(HINTERNET hInternet)

{

    if (hInternet)

{

#ifdef USE_WINHTTP

        WinHttpCloseHandle(hInternet);

#else

        InternetCloseHandle(hInternet);

#endif

    }

}

/**********************************************************/

///通过Http方式发送短信

string SendSMS_HTTP(const long ececcid,const string  password ,const string  msisdn, const string smsContent)

{

 string rtnStr ="-1";

    HINTERNET hSession = 0;

    HINTERNET hConnect = 0;

    HINTERNET hRequest = 0;

    wstring strHeader(L"Content-type: application/x-www-form-urlencoded\r\n");

    // Test data

    CrackedUrl crackedUrl(L"");

 string StrPostData = "ececcid=600000password="+password+"msisdn="+msisdn+"smscontent="+smsContent+"msgtype=5longcode=";

 

 StrPostData = string_To_UTF8(StrPostData);

    // Open session.

    hSession = OpenSession(L"HttpPost by lyz_sea@163.com");

    if (hSession == NULL) {

        cout"Error:Open session!\n";

        return "-1";

    }

    // Connect.

    hConnect = Connect(hSession, crackedUrl.GetHostName(), crackedUrl.GetPort());

    if (hConnect == NULL) {

        cout"Error:Connect failed!\n";

        return "-1";

    }

    // Open request.

    hRequest = OpenRequest(hConnect, L"POST", crackedUrl.GetPath(), crackedUrl.GetScheme());

    if (hRequest == NULL) {

        cout"Error:OpenRequest failed!\n";

        return "-1";

   }

    // Add request header.

 if (!AddRequestHeaders(hRequest, strHeader.c_str())) {

        cout"Error:AddRequestHeaders failed!\n";

        return "-1";

    }

    // Send post data.

 if (!SendRequest(hRequest, StrPostData.c_str(), StrPostData.length())) {

        cout"Error:SendRequest failed!\n";

        return "-1";

    }

    // End request

    if (!EndRequest(hRequest)) {

        cout"Error:EndRequest failed!\n";

        return "-1";

    }

    char szBuf[BUF_SIZE];

    DWORD dwSize = 0;

    szBuf[0] = 0;

    // Query header info.

#ifdef USE_WINHTTP

    int contextLengthId = WINHTTP_QUERY_CONTENT_LENGTH;

    int statusCodeId = WINHTTP_QUERY_STATUS_CODE;

    int statusTextId = WINHTTP_QUERY_STATUS_TEXT;

#else

    int contextLengthId = HTTP_QUERY_CONTENT_LENGTH;

    int statusCodeId = HTTP_QUERY_STATUS_CODE;

    int statusTextId = HTTP_QUERY_STATUS_TEXT;

#endif

    dwSize = BUF_SIZE;

    if (QueryInfo(hRequest, contextLengthId, szBuf, dwSize)) {

        szBuf[dwSize] = 0;

        cout"Content length: "szBufendl;

    }

    dwSize = BUF_SIZE;

    if (QueryInfo(hRequest, statusCodeId, szBuf, dwSize)) {

        szBuf[dwSize] = 0;

        cout"Status code: " szBufendl;

    }

    dwSize = BUF_SIZE;

    if (QueryInfo(hRequest, statusTextId, szBuf, dwSize)) {

        szBuf[dwSize] = 0;

        cout"Status text:"szBufendl;

    }

    // read data.

    for (;;) {

        dwSize = BUF_SIZE;

        if (ReadData(hRequest, szBuf, dwSize, dwSize) == FALSE) {

           break;

        }

        if (dwSize = 0) {

            break;

        }

        szBuf[dwSize] = 0;

        

  rtnStr =::UTF8_To_string(string(szBuf));

  coutrtnStrendl;//Output 返回值

   

    }

    CloseInternetHandle(hRequest);

    CloseInternetHandle(hConnect);

    CloseInternetHandle(hSession);

 return  rtnStr;

}

 

 

以上方法中用到的CrackURL方法在以下CrackURL.h文件中:

#pragma once

//#includeiostream

//using namespace std;

#define USE_WINHTTP    //Comment this line to user wininet.

 #ifdef USE_WINHTTP

     #include winhttp.h

     #pragma comment(lib, "winhttp.lib")

 #else

     #include wininet.h

     #pragma comment(lib, "wininet.lib")

 #endif

 // CrackedUrl

 class CrackedUrl {

     int m_scheme;

     wstring m_host;

     int m_port;

     wstring m_path;

 public:

     CrackedUrl(LPCWSTR url)

     {

         URL_COMPONENTS uc = { 0};

         uc.dwStructSize = sizeof(uc);

 

         const DWORD BUF_LEN = 256;

 

         WCHAR host[BUF_LEN];

         uc.lpszHostName = host;

         uc.dwHostNameLength = BUF_LEN;

 

         WCHAR path[BUF_LEN];

         uc.lpszUrlPath = path;

         uc.dwUrlPathLength = BUF_LEN;

 

         WCHAR extra[BUF_LEN];

         uc.lpszExtraInfo = extra;

         uc.dwExtraInfoLength = BUF_LEN;

 

 #ifdef USE_WINHTTP

         if (!WinHttpCrackUrl(url, 0, ICU_ESCAPE, uc)) {

             cout"Error:WinHttpCrackUrl failed!\n";

         }

 

 #else

         if (!InternetCrackUrl(url, 0, ICU_ESCAPE, uc)) {

             printf("Error:InternetCrackUrl failed!\n");

         }

 #endif

         m_scheme = uc.nScheme;

         m_host = host;

         m_port = uc.nPort;

         m_path = path;

     }

 

     int GetScheme() const

     {

         return m_scheme;

     }

 

     LPCWSTR GetHostName() const

     {

   return m_host.c_str();

    }

    int GetPort() const

     {

         return m_port;

     }

 

     LPCWSTR GetPath() const

     {

   return m_path.c_str();

     }

 

     static string UrlEncode(const char* p)

     {

         if (p == 0) {

             return string();

         }

 

         string buf;

 

        for (;;) {

             int ch = (BYTE) (*(p++));

             if (ch == '\0') {

                 break;

             }

 

             if (isalnum(ch) || ch == '_' || ch == '-' || ch == '.') {

                 buf += (char)ch;

            }

            else if (ch == ' ') {

                buf += '+';

            }

            else {

                char c[16];

                wsprintfA(c, "%%%02X", ch);

                buf += c;

            }

        }

        return buf;

    }

};

基于stm32的多功能时钟2——DHT11测量温湿度

        亲爱的读者们,我又回来了~

         上一章中,我带着大家实现了时钟显示和按键调整的功能。在这一章中,我将利用DHT11温湿度传感器,来测量环境温度和湿度。

        DHT11温湿度传感器是数字式的,包括1个电阻式感湿元件和1个NTC测温元件,内部自带AD转换功能,采用单总线,具有响应快、抗干扰能力强、性价比高等特点。该模块总共4个引脚,其中两个是电源引脚VCC和GND,一个是数据引脚,还有一个为空引脚。

        目前流行的数据传输总线有II2C总线,SPI总线,单总线等,而DHT11则采用单总线传输数据。单总线,顾名思义,就是采用单根信号线,即可传输时钟,又能传输数据,而且数据传输是双向的,从而有主机和从机之别。在这里,stm32作为核心控制器,所以是主机,而DHT11为从机。           采用单总线进行数据传输,我们需要查看数据手册的时序图。                                                     

        总线空闲状态为高电平,主机把总线拉低等待 DHT11 响应,主机把总线拉低必须大于 18 毫秒,保证 DHT11 能检测到起始信号。DHT11 接收到主机的开始信号后, 等待主机开始信号结束,然后发送 80us 低电平响应信号.主机发送开始信号结束后,延时等待 20-40us 后, 读取 DHT11 的响应信号,主机发送开始信号后,可以切换到输入模式,或者输出高电平均可, 总线由上拉电阻拉高。

        根据时序图,单片机需要先将总线拉低至少18ms,然后拉高总线20~40us,此时主机的开始信号结束,检测DHT11的响应信号。如果检测到低电平,则DHT11响应,并且低电平时间维持80us,然后DHT11拉高总线80us。此时DHT11准备传输数据,传输的数据间隙为50us低电平,传输的数据通过高电平的时间长短来区分"0"和"1"。数据传输完毕,DHT11将总线拉低50us,最后主机再拉高总线。

(1)编写延时函数

        由于DHT11的时序比较严格,需要毫秒级别和微妙级别的延时。这里我们采用Systick去做延时。在之前按键扫描函数里也用到延时的,在此我叙述一下。

        我们需要配置系统时钟,然后把Systick设置成72,这样就能产生1us时间基准,其次编写Systick中断处理函数,让变量自减,从而达到延时的效果,最后编写延时函数,也就是对自减的变量赋初始值。

__IO uint32_t TimingDelay;

/*配置SysTick函数*/

void systick_init(void)

{

    /*配置Systick重载值,系统时钟为72MHz*/

    /*设置72,中断时间:72*(1/72000000) = 1us*/

    if(SysTick_Config(72)==1)    //若SysTick_Config函数返回产生中断信号,返回值为0

    {

        while(1);                  //SysTick_Config函数返回值为1,则等待

    }

}

/*时间变量自减函数*/

void TimingDelay_Decrement(void)

{

    if(TimingDelay!=0x00)

    {

        TimingDelay--;

    }

}

/*SysTick中断处理函数*/

void SysTick_Handler(void)

{

    TimingDelay_Decrement();

}

/*延时函数,时间基准为1ms*/

void delay_ms(__IO uint32_t nTime)

{

    TimingDelay = nTime*1000;

    while(TimingDelay!=0);

}

/*延时函数,时间基准为1us*/

void delay_us(__IO uint32_t nTime)

{

    TimingDelay = nTime;

    while(TimingDelay!=0);

}

(2)配置相应的GPIO口作为单总线数据端

/*配置DHT11数据引脚,设置成浮空输入模式*/

void dht11_gpio_portIn(void)

{

    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOA, GPIO_InitStructure);

}

/*配置DHT11数据引脚,设置成推挽输出模式*/

void dht11_gpio_portOut(void)

{

    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOA, GPIO_InitStructure);

}

        由于DHT11采用单总线通信协议,所以数据传输是双向的,所以分别将数据端口设置成浮空输入模式和推挽输出模式。并且将数据口的输入和输出定义成宏定义的形式。

#define DHT11_OUT_H GPIO_SetBits(GPIOA, GPIO_Pin_4)

#define DHT11_OUT_L GPIO_ResetBits(GPIOA, GPIO_Pin_4)

#define DHT11_IN    GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4)

(3)根据DHT11时序图,编写时序函数

        现在,我们开始编写总线的驱动函数,根据时序图,主机发送命令启动转换,接着,等待DHT11转换响应并且输出数据,最后读取数据。

/*启动总线函数*/

void dht11_reset(void)

{

    dht11_gpio_portOut();        //设置成输出模式

    DHT11_OUT_L;                  //主机将总线拉低至少18ms

    delay_ms(18);

    DHT11_OUT_H;                  //主机拉高保持20~40us

    delay_us(30);

    dht11_gpio_portIn();          //设置成输入模式,等待DHT11响应

}

/*DHT11响应函数*/

u8 dht11_scan(void)

{

    return DHT11_IN;              //返回值为DHT11的响应信号

}

实时监控DHT11的数据线,直至其产生出低电平,表示DHT11响应主机请求,开始传输数据。

/*DHT11读取位函数*/

u8 dht11_read_bit(void)

{

    while(DHT11_IN==RESET);            //传输数据位前存在50us低电平   

    delay_us(40);                      //根据高电平的时间长短决定电平是1还是0

    if(DHT11_IN==SET)                  //"0"电平持续时间为26~28us,"1"电平持续时间为70us

    {

        while(DHT11_IN==SET);

        return 1;                      //若检测到高电平,返回值为1

    }

    else

    {

        return 0;                      //若检测到高电平,返回值为0

    }

}

/*DHT11读取字节函数*/

//注:数据最高位先传输

u8 dht11_read_byte(void)

{

    u8 i,dat = 0x00;

    for(i=0; i8; i++)

    {

        dat = dat1;

        dat = dat|dht11_read_bit();//将串行数据读取出来

    }

    return dat;

}

        当DHT11响应后,就开始通过单总线传输数据,在读取位函数里,通过高电平的时间长短来判断输出的是'1'还是'0',在读取字节函数里,调用读取位函数,将传输的每8位整合出字节,并读取出来。

        我们查阅DHT11数据手册,得知数据传输的结构(依次顺序):湿度整数部分(1字节)、湿度小数部分(1字节)、温度整数部分(1字节)、温度小数部分(1字节)、校验和(1字节)。这里,其实就是一个简单的通信协议。校验和就是源数据所有字节之和的低8位,确保传输数据的正确与稳定。

/*DHT11读取数据函数*/

u8 dht11_read_data(void)

{

    u8 i;

    dht11_reset();

    if(dht11_scan()==RESET)            //DHT11发出响应信号

    {

        while(DHT11_IN==RESET);        //DHT11拉低总线80us

        while(DHT11_IN!=RESET);        //DHT11拉高总线80us

        for(i=0; i5; i++)

        {

            buffer[i] = dht11_read_byte();

        }

        while(DHT11_IN==RESET);        //发送完最后1bit数据后,等待50us低电平结束

        dht11_gpio_portOut();

        DHT11_OUT_H;                    //主机拉高总线

        if(buffer[0]+buffer[1]+buffer[2]+buffer[3]==buffer[4])

        {

            return 1;                  //校验成功

        }

        else

        {

            return 0;                  //校验失败

        }

    }

    else

    {

        return 0;                      //DHT11未发出响应信号

    }

}

        在读取字节里,先等待DHT11响应,然后开始接收数据,并且连续读取5次,存放在事先定义好的数组里,主机发出结束信号,最后对读取的数据进行校验。

(4)测量显示温湿度

主函数调用DHT11读数据函数,并调用lcd显示函数,将温度和湿度显示出来即可。

        if(dht11_read_data()==1)//读取数据,前提是DHT11响应,并且数据校验成功

        {

            humidity = buffer[0];//buffer[0]存放的是湿度整数部分

            temperature = buffer[2];//buffer[2]存放的是温度整数部分

        }

        lcd_display_string(2,0,"温度");

        lcd_display_num_m(2,32,temperature/10);

        lcd_display_num_m(2,40,temperature%10);

        lcd_display_string(4,0,“湿度”);

        lcd_display_num_m(4,32,humidity/10);

        lcd_display_num_m(4,40,humidity%10);

         至此,通过本章的讲解,我相信,大家应该对于DHT11模块有了大致的了解,当然,如果你只是看看文章的话,可能效果不怎么理想。这些东西,都需要亲自动手的,正所谓"实践出真知"。所以,你可以在网上买开发板,再买一些模块,不一定要和我的一样。当然,想要挑战自己的话,可以买块最小系统板,这样,外围的硬件电路可以由自己搭建(功能自定义),灵活性强的同时,也锻炼了自己的动手能力。如果你是会设计PCB的大佬,那更好,估计你的水平,就浏览一下我的文章即可。

DHT11数字传感器与单片机怎么实现连接。

四条引角中有两条是电源引脚,有两条是输出数据的引脚,只需要给他供上额定电压,然后再他的输出引脚采集信号就可以了,输出信号如果是模拟量的话,通过A/D芯片,将模拟量转换为数字信号,然后传送给单片机。

DHT11是数字传感器,所以不需要进行模数的转换,具体接口如下

引脚1: VDD 供电3-5.5VDC

引脚2: DATA 串行数据,单总线

引脚3:NC 空脚,请悬空

引脚4:GND 接地,电源负极

注意:引脚2在接单片机时,同时要在数据线接一上拉电阻,接到电源上。

数字传感器是指将传统的模拟式传感器经过加装或改造A/D转换模块,使之输出信号为数字量(或数字编码)的传感器,主要包括:放大器、A/D转换器、微处理器(CPU)、存储器、通讯接口、温度测试电路等。

数字传感器特点:

1、先进的A/D转换技术和智能滤波算法,在满量程的情况下仍可保证输出码的稳定。

2、可行的数据存储技术,保证模块参数不会丢失。

3、良好的电磁兼容性能。

4、传感器的性能采用数字化误差补偿技术和高度集成化电子元件,用软件实现传感器的线性、零点、温漂、蠕变等性能参数的综合补偿,消除了人为因素对补偿的影响,大大提高了传感器综合精度和可靠性。

5、传感器的输出一致性误差可以达到0.02%以内甚至更高,传感器的特性参数可完全相同,因而具有良好的互换性。

6、采用A/D转换电路、数字化信号传输和数字滤波技术,传感器的抗干扰能力增加,信号传输距离远,提高了传感器的稳定性。

7、数字传感器能自动采集数据并可预处理、存储和记忆,具有唯一标记,便于故障诊断。

8、传感器采用标准的数字通讯接口,可直接连入计算机,也可与标准工业控制总线连接,方便灵活。

9, 数字传感器是将AD,EPROM,DIE(传感器芯片),封装在一块用PCB,金属块或陶瓷板上的集成。通过各种温度,压力点的校准,计算出DIE的线性,再利用AD去补偿的方法加工而成的。

dht是什么?

DHT类似Tracker的根据种子特征码返回种子信息的网络。DHT全称叫分布式哈希表(Distributed Hash Table),是一种分布式存储方法。

在不需要服务器的情况下,每个客户端负责一个小范围的路由,并负责存储一小部分数据,从而实现整个DHT网络的寻址和存储。

新版BitComet允许同时连接DHT网络和Tracker,也就是说在完全不连上Tracker服务器的情况下,也可以很好的下载,因为它可以在DHT网络中寻找下载同一文件的其他用户。

相关信息:

一般用户是完全不需要理会这个具体过程的。这里可以简单的介绍一下:连入DHT网络的用户叫做节点(node),节点之间互相有路由记录,因此只要和任何一个已经在DHT网络中的节点连接上,客户端就可以寻找到更多的节点,从而连入网络。

简单地说:DHT技术就是可以使得网络中的任何一个机器都实现服务器的部分功能,使得用户的下载不再依靠于服务器。用户不需要干涉这个功能。对于普通用户来说,不明白也没有关系。

请问一下,BT下载里面的DHT技术到底是什么意思?

DHT网路的介绍

DHT网路的介绍

评论:新版Bitcomet发布,DHT加深反盗难度

本文已发表于《电脑商情报•家用电脑》

2005年6月8日,著名的BT下载软体Bitcomet升级到版本0.59。这次的升级与以往不同,它包含著里程碑式的改变——其开始“支援连入公用DHT网路,实现无Tracker下载”。联想到此前另一著名BT用户端Azureus从2.3.0.0,以及BT官方的BitTorrent从Beta 4.1.0开始使用的"trackerless" torrents,BT下载已经进入崭新的DHT时代。

那麼,DHT究竟为BT带来了什麼?我们采访了Bitcomet的作者灿烂微笑,并将在此文中加以剖析。

一、实战新版Bitcomet

目前国内用户使用最多的BT用户端就是Bitcomet,因此我们在这裏也以它为例讲解DHT网路的使用。

默认情况下,无须做任何设置BitComet即可自动连接并使用DHT网路。启动软体,它会使用和TCP埠号相同的UDP埠进行DHT网路连接。此时,用户可以在Bitcomet的状态条上得到DHT网路连接的状态。

当然,如果要顺利使用DHT功能,除了连接DHT网路之外,还需要档的发布者在制作种子的时候就打开DHT选项。单击功能表“档”-“制作Torrent档”,在弹出的视窗中,就可以调节是否让种子使用DHT网路,共有三种选择。

“使用公用DHT网路(推荐)”表示种子同时使用Tracker伺服器和公用DHT网路来寻找用户,列表框中可以填写传统Tracker伺服器位址或者DHT网路节点位址,也可以只填其中一种,也可以什麼都不填。什麼都不填代表仅仅使用DHT网路,自动连接节点;只填写DHT网路节点代表仅仅使用DHT网路,而且默认连接这几个填写的节点;只填写Tracker代表同时使用Tracker和DHT网路,自动连接Tracker伺服器和节点;同时填写Tracker和DHT网路节点代表同时使用Tracker和DHT网路,而且默认连接这几个Tracker伺服器和节点。总之,此种方式下的BT种子将采取尽可能多的方式进行连接,因此建议种子制作者保持这个默认选项,列表框中像往常一样填写一两个普通的Tracker伺服器地址。

另外两个选择:“不使用公用DHT网路(优先使用Tracker伺服器)”表示在不能链结上Tracker伺服器的情况下使用DHT网路功能,如果能链结上Tracker伺服器,就不使用DHT网路功能;“仅从Tracker伺服器获取用户资讯(禁用DHT及用户来源交换)”则代表禁止使用公用DHT网路以及用户来源交换来寻找用户,完全禁用DHT网路功能,相当於Azureus软体的“安全Torrent”。

如果你不想用Bitcomet的DHT网路功能,则可以在“选项”-“高级设置”中去掉“自动添加DHT网路作为备用Tracker”,并在其下的“网路连接”中去掉“允许加入到公用DHT网路”前面的勾。

在Azureus和BitTorrent Beta中制作支援DHT功能的种子,以及使用DHT网路同样简单,只不过它们的DHT网路功能都没有Bitcomet这麼强大。因此Bitcomet可以同时支援DHT网路和Tracker伺服器,而其他两种软体同时只能支援这两者之一。

有关BT之DHT网路的使用,还请参看我的另外一篇文章--实战BT之DHT网路。

二、DHT技术让反盗版更加困难?

在多数人眼中,任何P2P技术的改进都与版权的博奕脱不了干系,DHT网路能够引起如此注目亦是如此。

确实,BT采用DHT网路后,反盗版将变得更加困难。因为在此之前,用户进行BT下载时,必需首先连接上Tracker伺服器,根据所获得的正在进行下载和上传的用户列表,才能够进行正常的档交换。这样的话,只需封禁掉提供Tracker服务的网站,便可以截断盗版传播的途径。DHT网路则不同,由於此时互联网中任何一个运行BT用户端的用户都可以作为DHT网路中的节点,因此即使封禁掉那些提供Tracker服务的网站,用户还是能够通过全球范围的逻辑DHT网路分享档,反盗版就无从谈起。除非让世界上的人都不上网,或宣布使用BT软体为重罪。

不过,在我们对Bitcomet作者的采访中,他否认了DHT网路是为了更好的传播盗版。他指出,DHT网路的“主要优势是稳定性,本来Tracker伺服器人多了很容易宕机,但是DHT网路没有这个问题,再多的人也没事”。

这一切还是印证著那句话——“技术从来都是一把双刃剑”。在批判BT助长盗版气焰的同时,我们也应该看到,BT也正在日渐成为合法作品传播的途径。由於无法承受大流量的访问,一些免费和共用软体(如Foobar2000等)开始采用BT方式分发,大型的合法软体——Linux系统,更是将BT作为主要的分发管道。这种良性的应用可能会为BitTorrent带来一定的法律保护,使BT下载商业化甚至合法化。

而随著DHT技术的采用,这种应用还将向纵深发展。虽然它加重了反盗版的难度,但也将使合法分发各种文件更加容易。事物就是如此辩证,但笔者相信P2P软体一定能够寻求到一个更加合理的应用。

三、主要优势在於稳定--采访Bitcomet作者“灿烂微笑”

Bitcomet 0.59发布笠日,我们有幸通过MSN Messenger采访了Bitcomet的作者“灿烂微笑”(网名),请他来谈一下使用DHT网路后的BT:

问:BT的各个用户端软体是从什麼时候开始用DHT的?它与eMule中的Kad有何不同?

答:BitTorrent是5月份开始测试DHT的,Azureus比较早,但糟糕的是它们两个不互通。eMule中的Kad也是DHT的一种,不过它的实现协议与BT中的并不相同,所以不能互通。 Bitcomet中的DHT与BitTorrent是相容的。

问:为何会出现不互通的现像呢?

答:开发者不同,而且在这个DHT问题上互相之间没有协调好,所以就成了现在这样。更糟糕的是Azureus的DHT代码很长,我却找不到协议文档。

问:对一个用户来说,它获得一个使用DHT网路的种子后,启动Bitcomet进行下载,这时软体是如何连接的?

答:用户打开软体以后就连入网路了,启动使用DHT网路的种子的任务后,Bitcomet就会在DHT网路中搜索。种子上如果有默认节点,那麼可以帮助没有连入网路的用户通过那些节点连入网路,如果下载者已经联入DHT网路了,种子裏填写的节点就不需要了。Bitcomet内置了2个节点,分别是node://router.bittorrent.com:6881和node://router.bitcomet.net:554。其实任何一个长期线上的用户都可以做个好节点。

问:如果这两个长期线上的内置节点出现问题时,是不是就连接不上DHT网路了?

答:不会,这个只是最初的连接用的,如果它们都失效了,那麼1.曾经连上过DHT的用户保存了其他节点,所以只要不要很长时间不用,应该还可以连上;2.新的用户可以通过打开带有DHT节点的种子连入。

问:那麼,DHT网路相比Tracker伺服器来说,有什麼主要的优势?是不是以前下载时,种子只是同时连接同一台Tracker伺服器的下载者,而现在却可以搜索整个DHT网路中,得到更多的源?

答:主要优势是稳定性,本来Tracker伺服器人多了很容易宕机,但是DHT网路没有这个问题,再多的人也没事。如果是单个档的种子,确实也有你说的好处。

问:刚才你说Emule也用DHT,那麼相比之下,BT协议在技术上的优势是什麼呢?

答:应该说BT的DHT才刚开始,eMule应该测试了有1年左右了,BT的优势可能还是原来的吧,就是对新的东西分享比较快。

问:你是如何看待BT下载和软体版权问题的?

答:这个……有难度啊!BT本来只是一种不错的P2P网路技术,我觉得它的流行也代表了一种市场需要吧,说明通过互联网分发作品的可能的价值。虽然目前BT有些被滥用了,不过我想这种P2P技术应该能够寻求到一个更加合理的应用,就像Skype的创始人原来做的是Kazza一样。

问:再问一个读者关心的问题,你认为BT伤硬碟麼?

答:软体刚出来的时候,没有任何缓冲,完全大范围随机地按16K来读写硬碟,所以确实对硬碟不好(不过要速度快的时候才有影响)。当然后来就在软体裏面做缓存了,这个问题就基本不存在了。

问:最后一个问题,你自己经常使用BT下载吗?

答:我很久没用了(很出乎意料吧),不过感觉DHT很好玩,现在的乐趣更多是在编写软体上了。

DHT网路

DHT的全称是Distributed Hash Table,即分散式哈希表技术,是一种分散式存储方法。这种网路不需要中心节点伺服器,而是每个用户端负责一个小范围的路由,并负责存储一小部分资料,从而实现整个DHT网路的定址和存储。和中心节点伺服器不同,DHT网路中的各节点并不需要维护整个网路的资讯,而是只在节点中存储其临近的后继节点资讯,大幅减少了带宽的占用和资源的消耗。DHT网路还在与关键字最接近的节点上复制备份冗余资讯,避免了单一节点失效问题。

形象地,我们可以把整个DHT网路想像成一个大城市,那麼每个用户端,就好比城市裏各个角落的地图,上面绘制了附近区域的地形情况,把这些地图一汇总,城市的全貌就出来了。

而DHT所采用的演算法中最出名的是Kademlia,eMule早在一年多前就开始采用,Bitcomet、Azureus和BitTorrent只是步其后尘,同样使用Kademlia演算法的DHT。不过它们各自的实现协议不尽相同,因此不能相互相容(BitComet与BitTorrent相容,Azureus更像eMule,但与其他都不相容)。

Tracker

Tracker是指运行於伺服器上的一个服务程式,也称Tracker伺服器。这个程式能够追踪到底有多少人同时在下载或上传同一个档。用户端连上Tracker伺服器,就会获得一个正在下载和上传的用户的资讯列表(通常包括IP位址、埠、用户端ID等资讯),根据这些资讯,BT用户端会自动连上别的用户进行下载和上传。

dht办事器的代码实现的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于、dht办事器的代码实现的信息别忘了在本站进行查找喔。

版权说明:如非注明,本站文章均为 AH站长 原创,转载请注明出处和附带本文链接;

本文地址:http://ahzz.com.cn/post/1576.html


取消回复欢迎 发表评论:

分享到

温馨提示

下载成功了么?或者链接失效了?

联系我们反馈

立即下载