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

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

int init_logfile() 开启log文件

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

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

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

 typedef struct _Request_piece {
int index; // 请求的piece的索引 也是bitmap中的index??
int begin; // 请求的piece的偏移
int length; // 请求的长度,一般为16KB
struct _Request_piece *next;
} Request_piece;
 typedef struct  _Peer {
int socket; // 通过该socket与peer进行通信
char ip[]; // peer的ip地址
unsigned short port; // peer的端口号
char id[]; // peer的id int state; // 当前所处的状态 int am_choking; // 是否将peer阻塞
int am_interested; // 是否对peer感兴趣
int peer_choking; // 是否被peer阻塞
int peer_interested; // 是否被peer感兴趣 Bitmap bitmap; // 存放peer的位图 char *in_buff; // 存放从peer处获取的消息
int buff_len; // 缓存区in_buff的长度
char *out_msg; // 存放将发送给peer的消息
int msg_len; // 缓冲区out_msg的长度
char *out_msg_copy; // out_msg的副本,发送时使用该缓冲区
int msg_copy_len; // 缓冲区out_msg_copy的长度
int msg_copy_index; // 下一次要发送的数据的偏移量 Request_piece *Request_piece_head; // 向peer请求数据的队列
Request_piece *Requested_piece_head; // 被peer请求数据的队列 unsigned int down_total; // 从该peer下载的数据的总和
unsigned int up_total; // 向该peer上传的数据的总和 time_t start_timestamp; // 最近一次接收到peer消息的时间
time_t recet_timestamp; // 最近一次发送消息给peer的时间 time_t last_down_timestamp; // 最近下载数据的开始时间
time_t last_up_timestamp; // 最近上传数据的开始时间
long long down_count; // 本计时周期从peer下载的数据的字节数
long long up_count; // 本计时周期向peer上传的数据的字节数
float down_rate; // 本计时周期从peer处下载数据的速度
float up_rate; // 本计时周期向peer处上传数据的速度 struct _Peer *next; // 指向下一个Peer结构体
} Peer;

注释标注的很清晰。 注意一点的是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的初始化

 int  initialize_peer(Peer *peer)
{
if(peer == NULL) return -; peer->socket = -;
memset(peer->ip,,);
peer->port = ;
memset(peer->id,,);
peer->state = INITIAL; peer->in_buff = NULL;
peer->out_msg = NULL;
peer->out_msg_copy = NULL; peer->in_buff = (char *)malloc(MSG_SIZE);
if(peer->in_buff == NULL) goto OUT;
memset(peer->in_buff,,MSG_SIZE);
peer->buff_len = ; peer->out_msg = (char *)malloc(MSG_SIZE);
if(peer->out_msg == NULL) goto OUT;
memset(peer->out_msg,,MSG_SIZE);
peer->msg_len = ; peer->out_msg_copy = (char *)malloc(MSG_SIZE);
if(peer->out_msg_copy == NULL) goto OUT;
memset(peer->out_msg_copy,,MSG_SIZE);
peer->msg_copy_len = ;
peer->msg_copy_index = ; peer->am_choking = ;
peer->am_interested = ;
peer->peer_choking = ;
peer->peer_interested = ; peer->bitmap.bitfield = NULL;
peer->bitmap.bitfield_length = ;
peer->bitmap.valid_length = ; peer->Request_piece_head = NULL;
peer->Requested_piece_head = NULL; peer->down_total = ;
peer->up_total = ; peer->start_timestamp = ;
peer->recet_timestamp = ; peer->last_down_timestamp = ;
peer->last_up_timestamp = ;
peer->down_count = ;
peer->up_count = ;
peer->down_rate = 0.0;
peer->up_rate = 0.0; peer->next = (Peer *);
return ; OUT:
if(peer->in_buff != NULL) free(peer->in_buff);
if(peer->out_msg != NULL) free(peer->out_msg);
if(peer->out_msg_copy != NULL) free(peer->out_msg_copy);
return -;
}

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

这里使用了不常见的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链表中某些成员的值,用于调试

 Peer* add_peer_node()
{
int ret;
Peer *node, *p; // 分配内存空间
node = (Peer *)malloc(sizeof(Peer));
if(node == NULL) {
printf("%s:%d error\n",__FILE__,__LINE__);
return NULL;
} // 进行初始化
ret = initialize_peer(node);
if(ret < ) {
printf("%s:%d error\n",__FILE__,__LINE__);
free(node);
return NULL;
} // 将node加入到peer链表中
if(peer_head == NULL) { peer_head = node; }
else {
p = peer_head;
while(p->next != NULL) p = p->next;
p->next = node;
} return node;
} int del_peer_node(Peer *peer)
{
Peer *p = peer_head, *q; if(peer == NULL) return -; while(p != NULL) {
if( p == peer ) {
if(p == peer_head) peer_head = p->next;
else q->next = p->next;
free_peer_node(p); // 可能存在问题
return ;
} else {
q = p;
p = p->next;
}
} return -;
} // 撤消当前请求队列
int cancel_request_list(Peer *node)
{
Request_piece *p; p = node->Request_piece_head;
while(p != NULL) {
node->Request_piece_head = node->Request_piece_head->next;
free(p);
p = node->Request_piece_head;
} return ;
} // 撤消当前被请求队列
int cancel_requested_list(Peer *node)
{
Request_piece *p; p = node->Requested_piece_head;
while(p != NULL) {
node->Requested_piece_head = node->Requested_piece_head->next;
free(p);
p = node->Requested_piece_head;
} return ;
} void free_peer_node(Peer *node)
{
if(node == NULL) return;
if(node->bitmap.bitfield != NULL) {
free(node->bitmap.bitfield);
node->bitmap.bitfield = NULL;
}
if(node->in_buff != NULL) {
free(node->in_buff);
node->in_buff = NULL;
}
if(node->out_msg != NULL) {
free(node->out_msg);
node->out_msg = NULL;
}
if(node->out_msg_copy != NULL) {
free(node->out_msg_copy);
node->out_msg_copy = NULL;
} cancel_request_list(node);
cancel_requested_list(node); // 释放完peer成员的内存后,再释放peer所占的内存
free(node);
} void release_memory_in_peer()
{
Peer *p; if(peer_head == NULL) return; p = peer_head;
while(p != NULL) {
peer_head = peer_head->next;
free_peer_node(p);
p = peer_head;
}
} void print_peers_data()
{
Peer *p = peer_head;
int index = ; while(p != NULL) {
printf("peer: %d down_rate: %.2f \n", index, p->down_rate); index++;
p = p->next;
}
}

都是常规链表操作

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

参考

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

bittorrent 学习(二) LOG日志和peer管理连接的更多相关文章

  1. 代码实现获取log日志和logcat使用方法

    代码实现获取log日志new Thread(new Runnable() {                        @Override                        publi ...

  2. Linux学习之CentOS(二十六)--Linux磁盘管理:LVM逻辑卷的创建及使用

    在上一篇随笔里面 Linux学习之CentOS(二十五)--Linux磁盘管理:LVM逻辑卷基本概念及LVM的工作原理,详细的讲解了Linux的动态磁盘管理LVM逻辑卷的基本概念以及LVM的工作原理, ...

  3. 安装程序配置服务器失败。参考服务器错误日志和C:\windows\sqlstp.log 了解更多信息

    重装sql经常遇到2个问题 1,以前的某个程序安装已在安装计算机上创建挂起的文件操作.运行安装程序之前必须重新启动计算机. 删除C:\Program Files\Microsoft SQL Serve ...

  4. ReactJS入门学习二

    ReactJS入门学习二 阅读目录 React的背景和基本原理 理解React.render() 什么是JSX? 为什么要使用JSX? JSX的语法 如何在JSX中如何使用事件 如何在JSX中如何使用 ...

  5. bittorrent 学习(一) 种子文件分析与bitmap位图

    终于抽出时间来进行 BITTORRENT的学习了 BT想必大家都很熟悉了,是一种文件分发协议.每个下载者在下载的同时也在向其他下载者分享文件. 相对于FTP HTTP协议,BT并不是从某一个或者几个指 ...

  6. Android JNI学习(二)——实战JNI之“hello world”

    本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Nati ...

  7. 第三篇-分析日志和sensor-data中的数据结构

    分析日志和sensor-data数据结构 该文章提供web端思路,ios和android端思路不提供,api也已经下线,本文也不提供任何可执行代码.有更多疑问欢迎查看github代码 协议 授权协议: ...

  8. Java开发学习(二十二)----Spring事务属性、事务传播行为

    一.事务配置 上面这些属性都可以在@Transactional注解的参数上进行设置. readOnly:true只读事务,false读写事务,增删改要设为false,查询设为true. timeout ...

  9. 我的MYSQL学习心得(十三) 权限管理

    我的MYSQL学习心得(十三) 权限管理 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) ...

随机推荐

  1. rsync:基本命令和用法

    以下是rsync系列篇: 1.rsync(一):基本命令和用法 2.rsync(二):inotify+rsync详细说明和sersync 3.rsync算法原理和工作流程分析 4.rsync技术报告( ...

  2. springboot之拦截器

    拦截器: package com.example.demo; import org.springframework.context.annotation.Bean; import org.spring ...

  3. 深度学习原理与框架- tf.nn.conv2d_transpose(反卷积操作) tf.nn.conv2d_transpose(进行反卷积操作) 对于stride的理解存在问题?

    反卷积操作: 首先对需要进行维度扩张的feature_map 进行补零操作,然后使用3*3的卷积核,进行卷积操作,使得其维度进行扩张,图中可以看出,2*2的feature经过卷积变成了4*4.    ...

  4. dataTable转换成Json格式

    #region dataTable转换成Json格式 /// <summary> /// /// </summary> /// <param name="dt& ...

  5. JAVA_04

    * a:局部代码块 * 在方法中出现:限定变量生命周期,及早释放,提高内存利用率 * b:构造代码块 (初始化块) * 在类中方法外出现:多个构造方法方法中相同的代码存放到一起,每次调用构造都执行,并 ...

  6. 项目集成swagger【转载】

    地址链接:https://blog.csdn.net/lx1309244704/article/details/81808788 swagger是一款高效易用的嵌入式文档插件,同时支持在线测试接口,快 ...

  7. Java开发中的23种设计模式(转)

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

  8. CSS 背景图像 填充部分元素示例

    填充部分元素示例 为某个元素设置CSS规则background-image 属性,则可以做到部分元素有背景颜色. 下面的示例演示如何如何给段落元素加背景. <!DOCTYPE html> ...

  9. 一千行ABAP代码实现Windows传统游戏扫雷

    *&---------------------------------------------------------------------* *& Report ZCHENH087 ...

  10. centos7安装 python3.6,且保留2.7版本

    CENTOS7安装PYTHON3.6 1. 安装python3.6可能使用的依赖# yum install openssl-devel bzip2-devel expat-devel gdbm-dev ...