代码中的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  及代码

最新文章

  1. linux驱动开发之块设备学习笔记
  2. Git初步学习
  3. 使用nbrbutil工具來處理requested media id is in use, cannot process request
  4. git详细教程
  5. XEP-0079
  6. C#中如何将combox中的下拉项和一个枚举中的各项进行绑定
  7. Jtemplates 基本语法
  8. delphi TFontDialog
  9. 「Githug」Git 游戏通关流程
  10. php基础之三 数组
  11. 安卓使用spinner控件和pull解析实现全国省市县的三级联动
  12. 《Android底层接口与驱动开发技术详解》digest
  13. hdu 5586 Sum(dp+技巧)
  14. IIS7.5(IIS7)配置伪静态urlrewrite
  15. 给Activity设置Dialog属性,点击区域外消失;
  16. web 安全知识
  17. 调出js控制台可以在浏览器地址栏输入about:blank
  18. JavaScript 再谈闭包
  19. IntelliJ IDEA编译项目报错 &quot;xxx包不存在&quot; 或 &quot;找不到符号&quot;
  20. 【easy】263. Ugly Number 判断丑数

热门文章

  1. 【学习】数据规整化:清理、转换、合并、重塑(续)【pandas】
  2. matlab-单位圆内射线数次反射
  3. Zabbix11.3 Zabbix SNMP 常用OID列表
  4. MogoDB(6)--mongoDB高可用和4.0特性
  5. python读取excel,返回dic列表
  6. ajax的4个字母分别是什么意思
  7. Jeecg-Boot 1.0版本发布,企业级快速开发平台
  8. 同机器与不同机器redis集群
  9. MySQL 自带4个默认数据库
  10. gitlab 注册runner