分享
 
 
 

与基于udp协议的tracker服务器进行交互

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

通常BT客户端每几分钟就要向tracker发送一次请求.对于一些比较大的BT站点,其tracker的压力是可想而知的.降低tracker的压力首先考虑到的当然是采用更低网络开销的udp协议.于是Bittorrent udp-tracker protocol应运而生.

这个协议很简单.

下面是实现它的封装类:

// UDPTrackerClient.h: interface for the CUDPTrackerClient class.

//

//////////////////////////////////////////////////////////////////////

#if !defined(AFX_UDPTRACKERCLIENT_H__69B6ACC8_8193_4680_81D8_925B1550E92C__INCLUDED_)

#define AFX_UDPTRACKERCLIENT_H__69B6ACC8_8193_4680_81D8_925B1550E92C__INCLUDED_

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

#include <winsock2.h>

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

#ifndef _DISABLEWARNING4786_4355

#define _DISABLEWARNING4786_4355

#pragma warning( disable : 4786 )

#pragma warning( disable : 4355 )

#endif

#ifndef _ENABLEUSESTL

#define _ENABLEUSESTL

#include <list>

#include <map>

#include <set>

#include <vector>

#include <queue>

#include <string>

using namespace std;

#endif

class CPeerHostInfo

{

public:

DWORDIP;//节点IP

WORDPort;//节点端口

};

class CUDPTrackerClient

{

public:

CUDPTrackerClient();

virtual ~CUDPTrackerClient();

void CancelSocketOperate();

BOOL Connect(const char * szServer,WORD wPort = 0);

DWORD Announcing(BYTE* pInfoHash,BYTE * pPeerID,

__int64 idownloaded,__int64 ileft,__int64 iuploaded,

intievent,

DWORD dwIP,WORD wPort);

BOOL Disconnect();

public:

SOCKETm_socket;

DWORDm_dwIP;

WORDm_wPort;

__int64m_iConnection_id;

DWORDm_dwConnectTick;

stringm_strError;//如果请求失败,此变量保存错误信息

DWORD m_dwDonePeers;//种子数

DWORD m_dwNumPeers;//当前下载者个数

DWORD m_dwInterval;//查询间隔时间

list<CPeerHostInfo> m_listPeers;

};

#endif // !defined(AFX_UDPTRACKERCLIENT_H__69B6ACC8_8193_4680_81D8_925B1550E92C__INCLUDED_)

// UDPTrackerClient.cpp: implementation of the CUDPTrackerClient class.

//

//////////////////////////////////////////////////////////////////////

#include "stdafx.h"

#include "UDPTrackerClient.h"

#include "DataStream.h"

#ifdef _DEBUG

#undef THIS_FILE

static char THIS_FILE[]=__FILE__;

#define new DEBUG_NEW

#endif

//////////////////////////////////////////////////////////////////////

// Construction/Destruction

//////////////////////////////////////////////////////////////////////

#define RECVBUFSIZE 2048

CUDPTrackerClient::CUDPTrackerClient()

{

m_socket = INVALID_SOCKET;

m_iConnection_id = 0;

m_dwConnectTick = 0;

m_dwIP = 0;

m_wPort = 0;

m_dwDonePeers = 0;//种子数

m_dwNumPeers = 0;//当前下载者个数

m_dwInterval = 0;//查询间隔时间

}

CUDPTrackerClient::~CUDPTrackerClient()

{

Disconnect();

}

void CUDPTrackerClient::CancelSocketOperate()

{

if(m_socket != INVALID_SOCKET)

{

LINGER lingerStruct;

// If we're supposed to abort the connection, set the linger value

// on the socket to 0.

lingerStruct.l_onoff = 1;

lingerStruct.l_linger = 0;

setsockopt(m_socket, SOL_SOCKET, SO_LINGER,

(char *)&lingerStruct, sizeof(lingerStruct) );

}

}

BOOL CUDPTrackerClient::Disconnect()

{

m_iConnection_id = 0;

m_dwDonePeers = 0;//种子数

m_dwNumPeers = 0;//当前下载者个数

m_dwInterval = 0;//查询间隔时间

if ( m_socket != INVALID_SOCKET )

{

m_dwIP = 0;

m_wPort = 0;

// Now close the socket handle. This will do an abortive or

// graceful close, as requested.

shutdown(m_socket,SD_BOTH);

closesocket(m_socket);

m_socket = INVALID_SOCKET;

return TRUE;

}

return FALSE;

}

//szServer连接的主机,可以是下列形式的字符串:

//easeso.com:1000

//easeso.com

//如果wPort不为0,则szServer不应该包含端口信息

BOOL CUDPTrackerClient::Connect(const char * szServer,WORD wPort)

{

m_strError = "";

BOOL bRes = FALSE;

if ( m_socket == INVALID_SOCKET )

{

//用UDP初始化套接字

BOOL optval = TRUE;

m_socket =socket(AF_INET,SOCK_DGRAM,0);

if(m_socket == INVALID_SOCKET)

return FALSE;

//设置超时时间

int TimeOut=10000;

int err = setsockopt (m_socket, SOL_SOCKET,SO_RCVTIMEO,(CHAR *) &TimeOut,sizeof (TimeOut));

}

if(m_dwIP == 0)

{

CString strServer = szServer;

CString strHost;

if(wPort == 0)

{

int iNext = strServer.Find(':');

if(iNext>0)

{

strHost = strServer.Mid(0,iNext);

CString strPort = strServer.Mid(iNext+1);

m_wPort = (WORD)atoi(strPort);

}

else

strHost = strServer;

}

else

{

strHost = strServer;

m_wPort = wPort;

}

if(m_wPort == 0)

m_wPort = 80;

//Check if address is an IP or a Domain Name

int a = strHost[0];

if (a > 47 && a < 58)

m_dwIP = inet_addr(strHost);

else

{

struct hostent *pHost;

pHost = gethostbyname(strHost);

if(pHost != NULL)

m_dwIP = *((ULONG*)pHost->h_addr);

else

m_dwIP = 0;

}

}

if((GetTickCount()-m_dwConnectTick)>30000)

{

m_dwConnectTick = 0;

m_iConnection_id = 0;

}

if(m_socket != INVALID_SOCKET && m_dwIP && m_wPort && m_iConnection_id ==0)

{

DWORD dwTransaction_id = GetTickCount();

SOCKADDR_INfrom;

int fromlength=sizeof(SOCKADDR);

char buf[RECVBUFSIZE];

from.sin_family=AF_INET;

from.sin_addr.s_addr=m_dwIP;

from.sin_port=htons(m_wPort);

CDataStream sendstream(buf,2047);

sendstream.clear();

__int64 iCID = 0x41727101980;

sendstream.writeint64(CNetworkByteOrder::convert(iCID));

sendstream.writedword(CNetworkByteOrder::convert((int)0));

sendstream.writedword(dwTransaction_id);

int iRes = 0;

int iTimes = 6;

while(iTimes>0&&m_dwIP)

{

sendto(m_socket,sendstream.getbuffer(),sendstream.size(),0,(struct sockaddr FAR *)&from,sizeof(from));

iRes = recvfrom(m_socket,buf,RECVBUFSIZE-1,0,(struct sockaddr FAR *)&from,(int FAR *)&fromlength);

if(iRes >=0)

break;

iTimes--;

}

if(iRes>=16)

{

CDataStream recvstream(buf,RECVBUFSIZE-1);

DWORD dwAction = (DWORD)CNetworkByteOrder::convert((int)recvstream.readdword());

DWORD dwTIDResp= recvstream.readdword();

if(dwTIDResp == dwTransaction_id)

{

if(dwAction == 0)

{

m_iConnection_id = recvstream.readint64();

//BitComet将回复0x16字节数据,最后6字节是服务器查看到的本地IP和UDP端口

}

else if(dwAction == 3)//得到一个错误信息包

{

buf[iRes]=0;

m_strError = recvstream.readstring();

}

}

}

}

if(m_iConnection_id)

bRes = TRUE;

return bRes;

}

//提交请求

//pInfoHash 20字节的数据缓冲区指针

//pPeerID20字节的数据缓冲区指针

//ievent参数值:

//none = 0

//completed = 1

//started = 2

//stopped = 3

DWORD CUDPTrackerClient::Announcing(BYTE* pInfoHash,BYTE * pPeerID,

__int64 idownloaded,__int64 ileft,__int64 iuploaded,

intievent,

DWORD dwIP,WORD wPort)

{

m_listPeers.clear();

m_dwNumPeers = 0;

m_dwDonePeers = 0;

m_strError = "";

DWORD dwReturnCode = 0;

if(m_iConnection_id && m_socket != INVALID_SOCKET && m_dwIP & m_wPort)

{

DWORD dwTransaction_id = GetTickCount();

//srand(dwTransaction_id);

//DWORD dwKey = rand();

DWORD dwKey = 0x3753;

SOCKADDR_INfrom;

int fromlength=sizeof(SOCKADDR);

char buf[RECVBUFSIZE];

from.sin_family=AF_INET;

from.sin_addr.s_addr=m_dwIP;

from.sin_port=htons(m_wPort);

CDataStream sendstream(buf,RECVBUFSIZE-1);

sendstream.clear();

sendstream.writeint64(m_iConnection_id);

sendstream.writedword(CNetworkByteOrder::convert((int)1));

sendstream.writedword(dwTransaction_id);

sendstream.writedata(pInfoHash,20);

sendstream.writedata(pPeerID,20);

sendstream.writeint64(CNetworkByteOrder::convert(idownloaded));

sendstream.writeint64(CNetworkByteOrder::convert(ileft));

sendstream.writeint64(CNetworkByteOrder::convert(iuploaded));

sendstream.writedword(CNetworkByteOrder::convert(ievent));

sendstream.writedword(dwIP);

sendstream.writedword(CNetworkByteOrder::convert((int)dwKey));

sendstream.writedword(CNetworkByteOrder::convert((int)200));

sendstream.writedword(CNetworkByteOrder::convert(wPort));

int iRes = 0;

int iTimes = 2;

while(iTimes>0&&m_dwIP)

{

sendto(m_socket,sendstream.getbuffer(),sendstream.size(),0,(struct sockaddr FAR *)&from,sizeof(from));

iRes = recvfrom(m_socket,buf,RECVBUFSIZE-1,0,(struct sockaddr FAR *)&from,(int FAR *)&fromlength);

if(iRes >=0)

break;

iTimes--;

}

if(iRes>=20)

{

CDataStream recvstream(buf,RECVBUFSIZE-1);

DWORD dwAction = (DWORD)CNetworkByteOrder::convert((int)recvstream.readdword());

DWORD dwTIDResp= recvstream.readdword();

if(dwTIDResp == dwTransaction_id)

{

if(dwAction == 1)

{

m_dwInterval = (DWORD)CNetworkByteOrder::convert((int)recvstream.readdword());

m_dwNumPeers = (DWORD)CNetworkByteOrder::convert((int)recvstream.readdword());

m_dwDonePeers = (DWORD)CNetworkByteOrder::convert((int)recvstream.readdword());

CPeerHostInfo hi;

for(int iCurPos = 20;iCurPos+6<=iRes;iCurPos+=6)

{

hi.IP= recvstream.readdword();

hi.Port = (WORD)CNetworkByteOrder::convert((unsigned short)recvstream.readword());

m_listPeers.push_back(hi);

}

if(m_dwNumPeers>m_listPeers.size())

{

iRes = 0;

iTimes = 6;

while(iTimes>0&&m_dwIP)

{

iRes = recvfrom(m_socket,buf,RECVBUFSIZE-1,0,(struct sockaddr FAR *)&from,(int FAR *)&fromlength);

if(iRes >=0)

break;

iTimes--;

}

if(iRes>=6)

{

for(iCurPos = 0;iCurPos+6<=iRes;iCurPos+=6)

{

hi.IP= recvstream.readdword();

hi.Port = (DWORD)CNetworkByteOrder::convert((int)recvstream.readword());

m_listPeers.push_back(hi);

}

}

}

m_dwNumPeers = m_listPeers.size();

dwReturnCode = 200;

}

else if(dwAction == 3)//得到一个错误信息包

{

buf[iRes]=0;

m_strError = recvstream.readstring();

dwReturnCode = 400;

}

}

}

}

//每次都要求重新连接

m_iConnection_id = 0;

return dwReturnCode;

}

// DataStream.h: interface for the CDataStream class.

//

//////////////////////////////////////////////////////////////////////

#if !defined(AFX_DATASTREAM_H__D90A2534_EA73_4BEA_8B7E_87E59A3D1D26__INCLUDED_)

#define AFX_DATASTREAM_H__D90A2534_EA73_4BEA_8B7E_87E59A3D1D26__INCLUDED_

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

#include <stdio.h>

//数据流操作函数

class CDataStream

{

public :

CDataStream(char * szBuf,int isize)

{

m_isize = isize;

buffer = szBuf;

current = buffer;

}

~CDataStream()

{

}

void clear()

{

current = buffer;

current[0]=0;

}

//此函数不动态增加内存,一次打印的数据长度不应该超过缓冲区的三分之一,否则可能导致失败

bool printf(const char * format,...)

{

if(current)

{

if(current - buffer > (m_isize*2)/3)

return false;

va_list argPtr ;

va_start( argPtr, format ) ;

int count = vsprintf( current, format, argPtr ) ;

va_end( argPtr );

current += count ;

return true;

}

return false;

}

//此函数拷贝字符串

bool strcpy(const char * szStr)

{

if(current&&szStr)

{

int ilen = lstrlen(szStr);

if((m_isize-(current - buffer)) < (ilen +2))

return false;

memcpy(current,szStr,ilen+1);

current += ilen;

return true;

}

return false;

}

char * getcurrentpos()

{

return current;

}

void move(int ilen)//当前指针向后移动ilen

{

current += ilen;

}

void reset()

{

current = buffer;

}

BYTE readbyte()

{

current ++;

return *(current-1);

}

void writebyte(BYTE btValue)

{

*current = btValue;

current ++;

}

WORD readword()

{

current +=2;

return *((WORD*)(current-2));

}

void writeword(WORD wValue)

{

*((WORD*)current) = wValue;

current +=2;

}

DWORD readdword()

{

current +=4;

return *((DWORD*)(current-4));

}

void writedword(DWORD dwValue)

{

*((DWORD*)current) = dwValue;

current +=4;

}

__int64 readint64()

{

current +=8;

return *((__int64*)(current-8));

}

void writeint64(__int64 iValue)

{

*((__int64*)current) = iValue;

current +=8;

}

BYTE * readdata(DWORD dwLen)

{

current +=dwLen;

return (BYTE*)(current-dwLen);

}

void writedata(BYTE * pData,DWORD dwLen)

{

memcpy(current,pData,dwLen);

current +=dwLen;

}

char * readstring()

{

char * szRes = current;

int ilen = lstrlen(current);

current +=(ilen+1);

return szRes;

}

int size()

{

return (int)(current-buffer);

}

const char * getbuffer(){return buffer;}

private :

char* buffer;

char* current;

int m_isize;

};

class CNetworkByteOrder

{

public:

static unsigned short int convert(unsigned short int iValue)

{

unsigned short int iData;

((BYTE*)&iData)[0] = ((BYTE*)&iValue)[1];

((BYTE*)&iData)[1] = ((BYTE*)&iValue)[0];

return iData;

}

static int convert(int iValue)

{

int iData;

((BYTE*)&iData)[0] = ((BYTE*)&iValue)[3];

((BYTE*)&iData)[1] = ((BYTE*)&iValue)[2];

((BYTE*)&iData)[2] = ((BYTE*)&iValue)[1];

((BYTE*)&iData)[3] = ((BYTE*)&iValue)[0];

return iData;

}

static __int64 convert(__int64 iValue)

{

__int64 iData;

((BYTE*)&iData)[0] = ((BYTE*)&iValue)[7];

((BYTE*)&iData)[1] = ((BYTE*)&iValue)[6];

((BYTE*)&iData)[2] = ((BYTE*)&iValue)[5];

((BYTE*)&iData)[3] = ((BYTE*)&iValue)[4];

((BYTE*)&iData)[4] = ((BYTE*)&iValue)[3];

((BYTE*)&iData)[5] = ((BYTE*)&iValue)[2];

((BYTE*)&iData)[6] = ((BYTE*)&iValue)[1];

((BYTE*)&iData)[7] = ((BYTE*)&iValue)[0];

return iData;

}

};

#endif // !defined(AFX_DATASTREAM_H__D90A2534_EA73_4BEA_8B7E_87E59A3D1D26__INCLUDED_)

[url=http://www.easeso.com]逸搜(EaseSo)论坛可以下载到支持udp tracker的测试程序BTTrackerTest.

到此,第一阶段工作完成,下面要做的就是peer之间的交互了.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有