• bittorrent 学习(二) LOG日志和peer管理连接


    代码中的log.h log.c比较简单

    void logcmd() 记录命令  int logfile();运行日志的记录

    int init_logfile() 开启log文件

    源码比较清晰也很简单。 可以直接看代码

    //=====================================================================================

     peer代码中 我们先来看看结构体

    1 typedef struct _Request_piece {
    2     int     index;                // 请求的piece的索引     也是bitmap中的index??
    3     int     begin;                // 请求的piece的偏移
    4     int     length;               // 请求的长度,一般为16KB
    5     struct _Request_piece *next;
    6 } Request_piece;
    View Code
     1 typedef struct  _Peer {
     2     int            socket;                // 通过该socket与peer进行通信
     3     char           ip[16];                // peer的ip地址
     4     unsigned short port;                  // peer的端口号
     5     char           id[21];                // peer的id
     6 
     7     int            state;                 // 当前所处的状态
     8 
     9     int            am_choking;            // 是否将peer阻塞
    10     int            am_interested;         // 是否对peer感兴趣
    11     int            peer_choking;          // 是否被peer阻塞
    12     int            peer_interested;       // 是否被peer感兴趣
    13 
    14     Bitmap         bitmap;                // 存放peer的位图
    15     
    16     char           *in_buff;              // 存放从peer处获取的消息
    17     int            buff_len;              // 缓存区in_buff的长度
    18     char           *out_msg;              // 存放将发送给peer的消息
    19     int            msg_len;               // 缓冲区out_msg的长度
    20     char           *out_msg_copy;         // out_msg的副本,发送时使用该缓冲区
    21     int            msg_copy_len;          // 缓冲区out_msg_copy的长度
    22     int            msg_copy_index;        // 下一次要发送的数据的偏移量
    23 
    24     Request_piece  *Request_piece_head;   // 向peer请求数据的队列
    25     Request_piece  *Requested_piece_head; // 被peer请求数据的队列
    26 
    27     unsigned int   down_total;            // 从该peer下载的数据的总和
    28     unsigned int   up_total;              // 向该peer上传的数据的总和
    29 
    30     time_t         start_timestamp;       // 最近一次接收到peer消息的时间
    31     time_t         recet_timestamp;       // 最近一次发送消息给peer的时间
    32 
    33     time_t         last_down_timestamp;   // 最近下载数据的开始时间
    34     time_t         last_up_timestamp;     // 最近上传数据的开始时间
    35     long long      down_count;            // 本计时周期从peer下载的数据的字节数
    36     long long      up_count;              // 本计时周期向peer上传的数据的字节数
    37     float          down_rate;             // 本计时周期从peer处下载数据的速度
    38     float          up_rate;               // 本计时周期向peer处上传数据的速度
    39 
    40     struct _Peer   *next;                 // 指向下一个Peer结构体
    41 } Peer;
    View Code

    注释标注的很清晰。 注意一点的是Peer和 Request_piece都是链表形式

    Peer结构体体中  int state; // 当前所处的状态

    状态定义为以下几种

    #define INITIAL -1 // 表明处于初始化状态
    #define HALFSHAKED 0 // 表明处于半握手状态
    #define HANDSHAKED 1 // 表明处于全握手状态
    #define SENDBITFIELD 2 // 表明处于已发送位图状态
    #define RECVBITFIELD 3 // 表明处于已接收位图状态
    #define DATA 4 // 表明处于与peer交换数据的状态
    #define CLOSING 5 // 表明处于即将与peer断开的状态

     但是状态的切换是不在Peer.c这个代码中, 真正的代码切换是在流程处理中,后面其他代码会慢慢讲到

    先来看看Peer的初始化

     1 int  initialize_peer(Peer *peer)
     2 {
     3     if(peer == NULL)   return -1;
     4 
     5     peer->socket = -1;
     6     memset(peer->ip,0,16);
     7     peer->port = 0;
     8     memset(peer->id,0,21);
     9     peer->state = INITIAL;
    10 
    11     peer->in_buff      = NULL;
    12     peer->out_msg      = NULL;
    13     peer->out_msg_copy = NULL;
    14 
    15     peer->in_buff = (char *)malloc(MSG_SIZE);
    16     if(peer->in_buff == NULL)  goto OUT;
    17     memset(peer->in_buff,0,MSG_SIZE);
    18     peer->buff_len = 0;
    19 
    20     peer->out_msg = (char *)malloc(MSG_SIZE);
    21     if(peer->out_msg == NULL)  goto OUT;
    22     memset(peer->out_msg,0,MSG_SIZE);
    23     peer->msg_len  = 0;
    24     
    25     peer->out_msg_copy = (char *)malloc(MSG_SIZE);
    26     if(peer->out_msg_copy == NULL)  goto OUT;
    27     memset(peer->out_msg_copy,0,MSG_SIZE);
    28     peer->msg_copy_len   = 0;
    29     peer->msg_copy_index = 0;
    30 
    31     peer->am_choking      = 1;
    32     peer->am_interested   = 0;
    33     peer->peer_choking    = 1;
    34     peer->peer_interested = 0;
    35     
    36     peer->bitmap.bitfield        = NULL;
    37     peer->bitmap.bitfield_length = 0;
    38     peer->bitmap.valid_length    = 0;
    39     
    40     peer->Request_piece_head     = NULL;
    41     peer->Requested_piece_head   = NULL;
    42     
    43     peer->down_total = 0;
    44     peer->up_total   = 0;
    45     
    46     peer->start_timestamp     = 0;
    47     peer->recet_timestamp     = 0;
    48     
    49     peer->last_down_timestamp = 0;
    50     peer->last_up_timestamp   = 0;
    51     peer->down_count          = 0;
    52     peer->up_count            = 0;
    53     peer->down_rate           = 0.0;
    54     peer->up_rate             = 0.0;
    55     
    56     peer->next = (Peer *)0;
    57     return 0;
    58 
    59 OUT:
    60     if(peer->in_buff != NULL)      free(peer->in_buff);
    61     if(peer->out_msg != NULL)      free(peer->out_msg);
    62     if(peer->out_msg_copy != NULL) free(peer->out_msg_copy);
    63     return -1;
    64 }
    View Code

    该创建的创建  该分配的分配  该置零的置零

    这里使用了不常见的GOTO。为了保证逻辑清晰,一般是不允许代码里四处GOTO跳转的。

    但是GOTO在跳出多重循环和 调至结尾释放资源是比较清晰简洁的写法。

    GOTO可以避免多处return忘记释放资源,而是跳转到结尾释放资源后return。return值在处理流程中会赋值1或者-1 表示成功与否

    这种写法在结构复杂,多出return还有资源要释放时可以尝试使用下.

    其他函数比较简单

    Peer* add_peer_node(); // 添加一个peer结点 插入链表
    int del_peer_node(Peer *peer); // 从链表中删除一个peer结点
    void free_peer_node(Peer *node); // 释放一个peer的内存

    int cancel_request_list(Peer *node); // 撤消当前请求队列
    int cancel_requested_list(Peer *node); // 撤消当前被请求队列

    void release_memory_in_peer(); // 释放peer.c中的动态分配的内存
    void print_peers_data(); // 打印peer链表中某些成员的值,用于调试

      1 Peer* add_peer_node()
      2 {
      3     int  ret;
      4     Peer *node, *p;
      5 
      6     // 分配内存空间
      7     node = (Peer *)malloc(sizeof(Peer));
      8     if(node == NULL)  { 
      9         printf("%s:%d error
    ",__FILE__,__LINE__); 
     10         return NULL;
     11     }
     12 
     13     // 进行初始化
     14     ret = initialize_peer(node);
     15     if(ret < 0) { 
     16         printf("%s:%d error
    ",__FILE__,__LINE__);
     17         free(node);
     18         return NULL;
     19     }
     20 
     21     // 将node加入到peer链表中
     22     if(peer_head == NULL)  { peer_head = node; }
     23     else {
     24         p = peer_head;
     25         while(p->next != NULL)  p = p->next;
     26         p->next = node;
     27     }
     28 
     29     return node;
     30 }
     31 
     32 int del_peer_node(Peer *peer)
     33 {
     34     Peer *p = peer_head, *q;
     35 
     36     if(peer == NULL)  return -1;
     37 
     38     while(p != NULL) {
     39         if( p == peer ) {
     40             if(p == peer_head)  peer_head = p->next;
     41             else  q->next = p->next;
     42             free_peer_node(p);  // 可能存在问题
     43             return 0;
     44         } else {
     45             q = p;
     46             p = p->next;
     47         }
     48     }
     49 
     50     return -1;
     51 }
     52 
     53 // 撤消当前请求队列
     54 int cancel_request_list(Peer *node)
     55 {
     56     Request_piece  *p;
     57 
     58     p = node->Request_piece_head;
     59     while(p != NULL) {
     60         node->Request_piece_head = node->Request_piece_head->next;
     61         free(p);
     62         p = node->Request_piece_head;
     63     }
     64 
     65     return 0;
     66 }
     67 
     68 // 撤消当前被请求队列
     69 int cancel_requested_list(Peer *node)
     70 {
     71     Request_piece  *p;
     72     
     73     p = node->Requested_piece_head;
     74     while(p != NULL) {
     75         node->Requested_piece_head = node->Requested_piece_head->next;
     76         free(p);
     77         p = node->Requested_piece_head;
     78     }
     79     
     80     return 0;
     81 }
     82 
     83 void  free_peer_node(Peer *node)
     84 {
     85     if(node == NULL)  return;
     86     if(node->bitmap.bitfield != NULL) {
     87         free(node->bitmap.bitfield);
     88         node->bitmap.bitfield = NULL;
     89     }
     90     if(node->in_buff != NULL) {
     91         free(node->in_buff); 
     92         node->in_buff = NULL;
     93     }
     94     if(node->out_msg != NULL) {
     95         free(node->out_msg);
     96         node->out_msg = NULL;
     97     }
     98     if(node->out_msg_copy != NULL) {
     99         free(node->out_msg_copy);
    100         node->out_msg_copy = NULL;
    101     }
    102 
    103     cancel_request_list(node);
    104     cancel_requested_list(node);
    105 
    106     // 释放完peer成员的内存后,再释放peer所占的内存
    107     free(node);
    108 }
    109 
    110 void  release_memory_in_peer()
    111 {
    112     Peer *p;
    113 
    114     if(peer_head == NULL)  return;
    115 
    116     p = peer_head;
    117     while(p != NULL) {
    118         peer_head = peer_head->next;
    119         free_peer_node(p);
    120         p = peer_head;
    121     }
    122 }
    123 
    124 void print_peers_data()
    125 {
    126     Peer *p    = peer_head;
    127     int  index = 0;
    128 
    129     while(p != NULL) {
    130         printf("peer: %d  down_rate: %.2f 
    ", index, p->down_rate);
    131 
    132         index++;
    133         p = p->next;
    134     }
    135 }
    View Code

    都是常规链表操作

     //=======================================================================

    参考

    《linux c编程实战》第十三章节btcorrent  及代码

    作 者: itdef
    欢迎转帖 请保持文本完整并注明出处
    技术博客 http://www.cnblogs.com/itdef/
    B站算法视频题解
    https://space.bilibili.com/18508846
    qq 151435887
    gitee https://gitee.com/def/
    欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
    如果觉得不错,欢迎点赞,你的鼓励就是我的动力
    阿里打赏 微信打赏
  • 相关阅读:
    打jar包的命令
    WebServiceWSDLWeb
    linux命令之检测端口是否启用
    mybatis generator 插件安装及使用
    Mybatis 中一对多,多对一的配置
    大数据时代日志分析平台ELK的搭建
    关于RestfulAPI与SpringMVC之间的传值
    linux快速清空文件内容
    Linux之第一个shell命令
    Linux之yum
  • 原文地址:https://www.cnblogs.com/itdef/p/9887702.html
Copyright © 2020-2023  润新知