Ctorrent: copyshuffle function analyse
本文主要分析我们选中的 peer 中 piece 的请求队列,根据 piece 中 slice 的个数设置 shuffle 的次数。 另外还说明在 ctorrent 中是如何传输一个 struct 结构体的(如何传输,如何接受如何保持字符串和二进制的一致性?)
第一部分:
源码如下:
int RequestQueue::CopyShuffle(const RequestQueue *prq, size_t idx) { PSLICE n, u, ps, prev, end, psnext, temp; SLICE dummy; unsigned long rndbits; int len, shuffle, i=0, setsend=0; size_t firstoff; if( prq->IsEmpty() ) return 0; n = rq_head; u = (PSLICE)0; for( ; n ; u = n, n = u->next ); // move to end if( !rq_send ) setsend = 1; ps = prq->GetHead(); for( ; ps && ps->index != idx; ps = ps->next ); if( !ps ) return -1; firstoff = ps->offset; //只是局限在idx这个piece中 for( len=0; ps && ps->index == idx; ps = ps->next ){ if( Add(ps->index, ps->offset, ps->length) < 0 ){ //删除该slice for( n = u ? u->next : rq_head; n; n=temp ){ temp = n->next; delete n; } if( u ) u->next = (PSLICE)0; return -1; } len++; } if( !u ){ u = &dummy; u->next = rq_head; } //111 为0的几率为1/9 //shuffle 等于2的几率为1/9 为3的几率为8/9 shuffle = (random()&0x07)+2; // 如果len很小, shuffle 也可能比2小 if( shuffle > len/2 ) shuffle = len/2; for( ; shuffle; shuffle-- ){ prev = u; ps = u->next->next; u->next->next = (PSLICE)0; end = u->next; for( ; ps; ps = psnext ){ psnext = ps->next; if( !i-- ){ rndbits = random(); i = sizeof(rndbits) - 3; // insure an extra bit } if( (rndbits>>=1)&01 ){ // beginning or end of list if( (rndbits>>=1)&01 ){ prev = end; ps->next = (PSLICE)0; end->next = ps; end = ps; }else{ ps->next = u->next; u->next = ps; prev = u; } }else{ // before or after previous insertion if( (rndbits>>=1)&01 ){ // put after prev->next if( end == prev->next ) end = ps; temp = prev->next; ps->next = prev->next->next; prev->next->next = ps; prev = temp; }else{ // put after prev (before prev->next) ps->next = prev->next; prev->next = ps; } } } } // shuffle loop // If first slice is the same as in the original, move it to the end. if( u->next->offset == firstoff ){ end->next = u->next; u->next = u->next->next; end = end->next; end->next = (PSLICE)0; } if( u == &dummy ) rq_head = u->next; if( setsend ) rq_send = u->next; return 0; }
这个函数没有什么特殊的地方,我们选中了一个 piece 和一个 peer , 将该 peer 的请求队列拷入当前正在通信的 peer 的请求队列中 ? 在该函数中,首先是单纯的将它拷贝过来,其根据 len 的大小决定我们 shuffle (洗牌,这里的意思是乱序)的次数, 具体乱序的又是根据随机的原则来的 。
第二部分: ctorrent 中数据的传输
我们知道,网络编程中,我们要考虑大端,小端 ,异构网络等问题。最基本的一点就是,在发送端的数据怎么才能够保证在接收端收到的是一个完整的发送端的数据?
有很多第三方可以实现这个功能( xml 等, 不太了解)。
但是一般的网络编程中,我们都是通过一些顺序来转换的(在 ctorrent 中,我们只是用到了 int ,下面包括 float 的转换 , 其实 float 类型比较复杂的)
memcpy hton ntoh memcpy
float----------> int -------> 网络-------->int------------>float
在源码中有两个函数实现了这些转换
// 此函数是 set_nl() 的反操作,即把 sfrom 中的四个 1 字节数组合起来返回 1 个 4 字节的数。
size_t get_nl(char *from)
{
// assumes H_INT_LEN==H_LEN==4
uint32_t t = 0;
memcpy(&t, from, H_INT_LEN);
return
(size_t)ntohl((unsigned long)t);
}
void set_nl(char *to, size_t from)
{
// assumes H_INT_LEN==H_LEN==4
uint32_t from32 = (uint32_t)htonl((unsigned long)from);
memcpy(to, &from32, H_INT_LEN);
}
作为一个程序员,在自己看的代码中竟然有中文的注释,真的是一种耻辱
改之!!!!!!!!