局域网P2P技术实现

P2P技术实现方式有很多,现主要介绍利用socket tcp方式构建P2P环境的方法。

在开始的时候主要参考NBD协议部分的server端程序来实现BT服务端程序。

每个client端都有两个进程来实现P2P功能,一个是客户端的server程序,另一个是客户端的client程序。而BT服务器端只有一个进程,负责资源分配和负载平衡等工作。

下面是服务端程序的注意事项。调试是总发现有“Address already in use”信息出现,加入下面代码可以解决此问题。

/* lose the pesky "Address already in use" error message */
if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
        perror("setsockopt SO_REUSEADDR");
}
if (setsockopt(sockfd,SOL_SOCKET,SO_KEEPALIVE,&yes,sizeof(int)) == -1) {
        perror("setsockopt SO_KEEPALIVE");
}

每一个客户端发起请求时,首先询问服务器端,整个下载的镜像的种子分布状态,之后获得每一个片的种子分布状态。服务器端的server为每一个客户端的请求fork出一个进程。等待客户端下载完成后,报告个服务器端,此片我已经下载完成,并更新BT资源数据。同时可以设计客户端向BT服务器是否可以关机/开机做种等机制。

种子资源数据结构如下:

struct pieces_t{
        struct list_head head;
        struct pieceinfo_t pieceinfo;
        u32 len;                        //how many clients connect the piece
} __attribute__ ((packed));

struct clientinfo_t {
        struct list_head list;
        char ipaddr[IPADDRLEN];                 
        char mac[MACADDRLEN];                   //MAC address
};
struct pieceinfo_t
{
        u32 fid;                        
        u64 offset;                    

        u32 size;                       
        int  hash;                     

};

协议单元的程序例程如下:(客户端报告下载完成)

int download_finish(int sock,u32 fid)
{
        struct smc_request  request;
        struct smc_reply reply;
        int error = 0;

        request.magic = htonl(SMC_REQUEST_MAGIC);
        request.type = htonl(REQ_DOWNLOAD_FINISH);
        request.fid = htonl(fid);                       // 0 means all pieces is downloaded

        if(tcp_xmit(TCP_WRITE, sock, (char *)&request, sizeof(request)) <= 0) {
                fprintf(stderr,"request_update_finish:  failed 1/n");
                error=-1;
                goto err_out;
        }

        if(tcp_xmit(TCP_READ, sock, (char *)&reply, sizeof(reply)) <= 0) {
                fprintf(stderr,"request_update_finish:  failed 2/n");
                error=-2;
                goto err_out;
        }

        if(reply.error) {
                error=-3;
                fprintf(stderr,"request_update_finish:  failed 3/n");
                goto err_out;
        }
        DEBUG2("DOWNLOAD fid(%d) Finished/n",fid);
err_out:

        return error;
}

同时设计了支持黑名单的功能。即当很多客户机(已经下载完毕)关机的情况下,正在下载的客户机避免一些不必要的连接损耗,提供如果connect时返回无法连接,直接把该ip对应的客户机放入blacklist链表中,下次下载时,如果该机器在blacklist中,可以skip掉。同时定期更新黑名单里面的机器。如果里边的机器已经开机。那么可以从黑名单中解放出来,继续给其他的客户机做种。

 

 

你可能感兴趣的:(struct,socket,服务器,download,p2p,BT)