bittorrent 学习(二) LOG日志和peer管理连接
代码中的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管理连接的更多相关文章
- 代码实现获取log日志和logcat使用方法
代码实现获取log日志new Thread(new Runnable() { @Override publi ...
- Linux学习之CentOS(二十六)--Linux磁盘管理:LVM逻辑卷的创建及使用
在上一篇随笔里面 Linux学习之CentOS(二十五)--Linux磁盘管理:LVM逻辑卷基本概念及LVM的工作原理,详细的讲解了Linux的动态磁盘管理LVM逻辑卷的基本概念以及LVM的工作原理, ...
- 安装程序配置服务器失败。参考服务器错误日志和C:\windows\sqlstp.log 了解更多信息
重装sql经常遇到2个问题 1,以前的某个程序安装已在安装计算机上创建挂起的文件操作.运行安装程序之前必须重新启动计算机. 删除C:\Program Files\Microsoft SQL Serve ...
- ReactJS入门学习二
ReactJS入门学习二 阅读目录 React的背景和基本原理 理解React.render() 什么是JSX? 为什么要使用JSX? JSX的语法 如何在JSX中如何使用事件 如何在JSX中如何使用 ...
- bittorrent 学习(一) 种子文件分析与bitmap位图
终于抽出时间来进行 BITTORRENT的学习了 BT想必大家都很熟悉了,是一种文件分发协议.每个下载者在下载的同时也在向其他下载者分享文件. 相对于FTP HTTP协议,BT并不是从某一个或者几个指 ...
- Android JNI学习(二)——实战JNI之“hello world”
本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Nati ...
- 第三篇-分析日志和sensor-data中的数据结构
分析日志和sensor-data数据结构 该文章提供web端思路,ios和android端思路不提供,api也已经下线,本文也不提供任何可执行代码.有更多疑问欢迎查看github代码 协议 授权协议: ...
- Java开发学习(二十二)----Spring事务属性、事务传播行为
一.事务配置 上面这些属性都可以在@Transactional注解的参数上进行设置. readOnly:true只读事务,false读写事务,增删改要设为false,查询设为true. timeout ...
- 我的MYSQL学习心得(十三) 权限管理
我的MYSQL学习心得(十三) 权限管理 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) ...
随机推荐
- Vue stage2
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 关于Vue(旅游APP)的一些总结点
1.保持宽高比例 .wrapper{ width:100%; height:0; padding-bottom:31.25% } 2. box-sizing属性可以为三个值之一:content-box ...
- js 序列化
Python 序列化 字符串 = json.dumps(对象) 对象转字符串 对象 = json.loads(字符串) 字符串转对象 Javascript 字符串 = JSON.stringif ...
- WPF 主窗口关闭时结束所有相关线程
程序主窗口的 Closed 事件中添加代码: Process.GetCurrentProcess().Kill();
- python之路:变量与变量基本操作(老王版)
python开发之路:变量与变量基本操作 你是一个师范大学的优秀毕业生,现在在某某小学工作. 你想:判作业真的很累,隔壁老王现在天天玩<蓝月传奇>,银行里存满了钱.唉,每节课1个小时,每个 ...
- K8s简单yaml文件运行例子deployment
kubectl run 创建并运行一个或多个容器镜像. 创建一个deployment 或job 来管理容器. kubectl run 语法: $ run NAME --image=image [--e ...
- TIMESTAMP类型字段在SQL Server和MySQL中的含义和使用
公众号上转的满天飞的一篇文章,MySQL优化相关的,无意中瞄到一句“尽量使用TIMESTAMP而非DATETIME”,之前对TIMESTAMP也不太熟悉,很少使用,于是查了一下两者的区别. 其实,不管 ...
- Spring核心之IOC
IOC是Spring的两大核心之一:IOC的核心就是解耦. 举个例子:有2个班级可以上课,校长指定老师去上课,代码如下 package com.hongcong.test; public class ...
- cdnbest常见问题
1.cdn配置了ssl证书,经常有用户说访问不了,如果cdn配置了ssl,源没有配置ssl,在cdn里添加源ip的写法: 如果源也配置了ssl证书,写法如下图: 2. cdn报504问题的原因: 50 ...
- pandas进行条件格式化以及线性回归的预测
条件格式化 需求1: 将三次考试的成绩小于60分的值找出来,并将字体变为红色 需求2: 将每次考试的第一名找出来,将背景变为绿色 需求3: 使用背景颜色的深浅来表示数值的大小 需求4: 使用数据条的长 ...