代码中的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. IDL实现矢量文件裁剪栅格数据

    利用ENVI_SUBSET_VIA_ROI_DOIT函数实现矢量文件裁剪栅格数据. 测试数据:栅格文件是Mercator投影,矢量文件是Geographic坐标系 infile='F:\Temp_Da ...

  2. 分布式 基本理论 CAP 2

    关于P P, 即 Partition字面意思是网络分区,其实 包括了 各种网络问题, 我们要把它理解 一个 广义的 分区问题. P 涉及到了 时间, 这么说吧, 出现了分区, 那就是节点之间 “长久的 ...

  3. log4j2 Filter用法详解

    主要说下组合过滤器 CompositeFilter ,比较常用 <Filters> 是组合过滤器额标签,它包含的子标签是具体的过滤器,这三个具体过滤器分别是日志等级过滤器,正则表达式过滤器 ...

  4. azkaban使用--依赖dependencies作业

    1.创建作业 [root@localhost azkaban_job]# ls one.job two.job [root@localhost azkaban_job]# cat one.job ty ...

  5. [C#]打包项目[转]

    原文:https://www.cnblogs.com/danyu/p/7243706.html 加入自定义操作:https://blog.csdn.net/ristal/article/details ...

  6. 'Settings' object has no attribute 'FYFQ_URL_test'

    读取django settings内容时报错: 'Settings' object has no attribute 'FYFQ_URL_test' 原因:settings中的变量,必须都是大写

  7. <mvc:resources mapping="/xxx/**" location="/xxx/"/>无效,可能和Controller的URL模式有关

    某项目webapp下有子目录res,其中有img.css.js等存放静态资源的文件夹. 在定义了dispacher-servlet的<url-pattern>/</url-patte ...

  8. 【转】如何用Eclispe调试java -jar xxx.jar 方式执行的jar包

    原文地址:https://www.cnblogs.com/zzpbuaa/p/5443269.html 有时候,我们经常会需要调试 java -jar xxx.jar方式运行的代码,而不是必须在Ecl ...

  9. 使用IDEA的项目上传到GitHub

    使用IDEA的项目上传到GitHub 前提条件: 1.配置好Git(https://jingyan.baidu.com/article/8275fc867b652046a03cf613.html) 2 ...

  10. PeopleSoft通过status汇总进程运行情况

    下面SQL可以按照run_status汇总进程的运行状态 SELECT RQST.RUNSTATUS, RQST.PRCSTYPE, (SELECT XLAT.XLATLONGNAME FROM PS ...