Linux BT下载(12)-消息处理模块

全志V853开发板异构多核架构与Tina Linux系统优化实践 异构多核架构是嵌入式系统设计的先进方案,通过不同架构处理器核的协同工作实现性能与能效的平衡。全志V853开发板创新性地集成了Arm Cortex-A7、RISC-V E907和NPU三核架构,其中A7处理通用计算,RISC-V专注实时任务,NPU加速AI推理。这种架构在智能视觉、边缘计算等场景优势明显。基于Linux 4.9内核定制的Tina Linux系统为开发板提供完善支持,通过内核裁剪、启动流程优化等技术可将启动时间缩短30%。开发中需特别注意多核通信(RPMSG框架)、NPU加速(专用AI框架)以及 阅读详情

消息处理模块

消息处理模块由message.h和message.c组成,负责根据当前的状态生成并发送消息,接收以及处理消息。

以下是message.h的代码:
//message.h
#ifndef MESSAGE_H
#define MESSAGE_H
#include "peer.h"

int int_to_char(int i, unsigned char c[4]);  // 将整型变量i的四个字节存放到数组c中
int char_to_int(unsigned char c[4]);         // 将数组c中的四个字节转换为一个整型数

// 以下函数创建各个类型的消息,创建消息的函数参照BT协议
int create_handshake_msg(char *info_hash,char *peer_id,Peer *peer);
int create_keep_alive_msg(Peer *peer);
int create_chock_interested_msg(int type,Peer *peer);
int create_have_msg(int index,Peer *peer);
int create_bitfield_msg(char *bitfield,int bitfield_len,Peer *peer);
int create_request_msg(int index,int begin,int length,Peer *peer);
int create_piece_msg(int index,int begin,char *block,int b_len,Peer *peer);
int create_cancel_msg(int index,int begin,int length,Peer *peer);
int create_port_msg(int port,Peer *peer);

// 打印消息缓冲区中的消息, 用于调试
int print_msg_buffer(unsigned char *buffer, int len);
// 为发送have消息作准备,have消息较为特殊,它要发送给所有peer
int prepare_send_have_msg();
// 判断缓冲区中是否存放了一个完整的消息
int is_complete_message(unsigned char *buff,unsigned int len,int *ok_len);
// 处理收到的消息,接收缓冲区中存放着一个完整的消息
int parse_response(Peer *peer);
// 处理受到的消息,接收缓冲区中除了存放一个完整的消息外,还有不完整的消息
int parse_response_uncomplete_msg(Peer *p,int ok_len);
// 创建响应消息
int create_response_message(Peer *peer);
// 即将与peer断开时,丢弃发送缓冲区中的消息
void discard_send_buffer(Peer *peer);

#endif

message.c的文件的头部包含的代码如下:
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <sys/socket.h>
#include "parse_metafile.h"
#include "bitfield.h"
#include "peer.h"
#include "data.h"
#include "policy.h"
#include "message.h"

#define HANDSHAKE   -2					//握手消息
#define KEEP_ALIVE  -1					//keep_alive消息
#define CHOKE        0					//chock消息
#define UNCHOKE      1					//uchock消息
#define INTERESTED   2					//interested消息
#define UNINTERESTED 3					//uninterested消息
#define HAVE         4					//have消息
#define BITFIELD     5					//bitfield消息
#define REQUEST      6					//request消息
#define PIECE        7					//piece消息
#define CANCEL       8					//cancel消息	
#define PORT         9					//port消息

// 如果45秒未给某peer发送消息,则发送keep_alive消息
#define KEEP_ALIVE_TIME 45

extern Bitmap *bitmap;								// 在bitmap.c中定义,指向己方的位图
extern char    info_hash[20];					// 在parse_metafile.c中定义,存放info_hash
extern char    peer_id[20];						// 在parse_metafile.c中定义,存放peer_id
extern int     have_piece_index[64];	// 在data.c中定义,存放下载到的piece的index
extern Peer   *peer_head;							// 在peer.c中定义,指向peer链表

message.c中的函数代码如下:
int int_to_char(int i, unsigned char c[4])
将int型的i保存到字符数组c[4]中。
/*
*功能:将int型的各个字节放到char型数组里
*传入参数:i的各个字节,
*传出参数:字符数组c
*返回值:
*	0	保存成功
*/
int int_to_char(int i, unsigned char c[4])
{
	c[3] = i%256;
	c[2] = (i-c[3])/256%256;
	c[1] = (i-c[3]-c[2]*256)/256/256%256;
	c[0] = (i-c[3]-c[2]*256-c[1]*256*256)/256/256/256%256;

	return 0;
}
程序说明:假设i = 123456789,若以16进制表示数为0x75BCD15,则c[0] = 07,c[1] = 5B,c[2] = CD,c[3] = 15.

int char_to_int(unsigned char c[4])
功能刚好和上面的函数相反。
/*
*功能:将char型数组放到int型中
*传入参数:字符数组c
*传出参数:
*返回值:
*	i	转换结果
*/
int char_to_int(unsigned char c[4])
{
	int i;

	i = c[0]*256*256*256 + c[1]*256*256 + c[2]*256 + c[3];
	
	return i;
}

int create_handshake_msg(char *info, char *peer_id, Peer *peer)
/*
*功能:创建握手消息
*传入参数:
*	info_hash在parse_metafile.c中由种子文件计算而得
*	peer_id也在parse_metafile.c中生成
*	peer为要发送握手消息给某一个peer的指针变量
* 返回:
*	创建消息成功返回0,创建失败返回-1
*/
int create_handshake_msg(char *info_hash,char *peer_id,Peer *peer)
{
	int            i;
	unsigned char  keyword[20] = "BitTorrent protocol", c = 0x00;
	
	//发送缓存区大小16K(slice)+2K(其他消息)
	//跳过slice在缓冲区后追加其他消息
	unsigned char  *buffer = peer->out_msg + peer->msg_len;
	int            len = MSG_SIZE - peer->msg_len;

	if(len < 68)  
		return -1;  // 68为握手消息的固定长度

	buffer[0] = 19;
	for(i = 0; i < 19; i++)  buffer[i+1]  = keyword[i];
	for(i = 0; i < 8;  i++)  buffer[i+20] = c;
	for(i = 0; i < 20; i++)  buffer[i+28] = info_hash[i];
	for(i = 0; i < 20; i++)  buffer[i+48] = peer_id[i];

	peer->msg_len += 68;
	return 0;
}
程序说明:将生成的握手消息存放在peer结点的发送缓冲区中(即msg_out),其中msg_out[0]~msg_out[msg_len - 1]已存放了其他消息。函数中变量len指明缓冲区还有多少空闲空间。

int create_keep_alive_msg(Peer *peer)
/*
*功能:创建keep_alive消息
*传入参数:Peer
*传出参数:
*返回值:
*	1	成功
*/
int create_keep_alive_msg(Peer *peer)
{
	unsigned char  *buffer = peer->out_msg + peer->msg_len;
	int            len = MSG_SIZE - peer->msg_len;

	if(len < 4)  
		return -1;  // 4为keep_alive消息的固定长度

	memset(buffer,0,4);
	peer->msg_len += 4;
	return 0;
}

int create_chock_interested_msg(int type,Peer *peer)
创建chock消息。
/*
*功能:创建chock消息
*传入参数:type peer
*传出参数:
*返回值:
*	0	保存成功
*/
int create_chock_interested_msg(int type,Peer *peer)
{
	unsigned char  *buffer = peer->out_msg + peer->msg_len;
	int            len = MSG_SIZE - peer->msg_len;

	// 5为choke、unchoke、interested、uninterested消息的固定长度
	if(len < 5)  return -1;

	memset(buffer,0,5);
	buffer[3] = 1;
	buffer[4] = type;

	peer->msg_len += 5;
	return 0;
}

程序说明:chock消息的type值为0,unchoke消息1,interested消息为2,uninterested消息为3。

int create_have_msg(int index, Peer *peer)
/*
*功能:创建have消息
*传入参数:index peer
*传出参数:
*返回值:
*	0	创建成功
*/
int create_have_msg(int index,Peer *peer)
{
	unsigned char  *buffer = peer->out_msg + peer->msg_len;
	int            len = MSG_SIZE - peer->msg_len;
	unsigned char  c[4];

	if(len < 9)  return -1;  // 9为have消息的固定长度
	
	memset(buffer,0,9);	
	buffer[3] = 5;
	buffer[4] = 4;
	
	int_to_char(index,c);	// index为piece的下标
	buffer[5] = c[0];
	buffer[6] = c[1];
	buffer[7] = c[2];
	buffer[8] = c[3];
	
	peer->msg_len += 9;
	return 0;
}

int create_bitfield_msg(char *bitfield,int bitfield_len, Peer *peer)
/*
*功能:创建bitfield消息
*传入参数:bitfield bifield_len Peer
*传出参数:
*返回值:
*	0	创建成功
*/
int create_bitfield_msg(char *bitfield,int bitfield_len,Peer *peer)
{
	int            i;
	unsigned char  c[4];
	unsigned char  *buffer = peer->out_msg + peer->msg_len;
	int            len = MSG_SIZE - peer->msg_len;

	if( len < bitfield_len+5 )  {  // bitfield消息的长度为bitfield_len+5
		printf("%s:%d buffer too small\n",__FILE__,__LINE__); 
		return -1;
	}

	int_to_char(bitfield_len+1,c);
	//组装位图消息
	for(i = 0; i < 4; i++)  
		buffer[i] = c[i];
		
	buffer[4] = 5;
	创建bitfield消息
	for(i = 0; i < bitfield_len; i++) 
		buffer[i+5] = bitfield[i];

	peer->msg_len += bitfield_len+5;  
	
	return 0;
}

int create_request_msg(int index,int begin, int length,Peer *peer)
/*
*功能:创建数据请求消息
*传入参数:
					index为请求的piece的下标
					begin为piece内的偏移量
					length为请求数据的长度
*返回:0 创建成功
*/
int create_request_msg(int index,int begin,int length,Peer *peer)
{
	int            i;
	unsigned char  c[4];
	unsigned char  *buffer = peer->out_msg + peer->msg_len;
	int            len = MSG_SIZE - peer->msg_len;

	if(len < 17)  return -1;  // 17为request消息的固定长度

	memset(buffer,0,17);
	buffer[3] = 13;
	buffer[4] = 6;
	int_to_char(index,c);
	for(i = 0; i < 4; i++)  buffer[i+5]  = c[i];
	int_to_char(begin,c);
	for(i = 0; i < 4; i++)  buffer[i+9]  = c[i];
	int_to_char(length,c);
	for(i = 0; i < 4; i++)  buffer[i+13] = c[i];

	peer->msg_len += 17;
	
	return 0;
}

int create_piece_msg(int index,int begin,char *block,int b_len,Peer *peer)
/*
*功能:创建piece消息
*传入参数:
					block指向待发送的数据
					b_len为block所指向的数据的长度
*返回: 0 创建成功
* 		-1 创建失败
*/
int create_piece_msg(int index,int begin,char *block,int b_len,Peer *peer)
{
	int            i;
	unsigned char  c[4];
	unsigned char  *buffer = peer->out_msg + peer->msg_len;
	int            len = MSG_SIZE - peer->msg_len;

	if( len < b_len+13 ) {  // piece消息的长度为b_len+13
		printf("IP:%s len:%d\n",peer->ip,len);
		printf("%s:%d buffer too small\n",__FILE__,__LINE__); 
		return -1;
	}
	
	int_to_char(b_len+9,c);
	for(i = 0; i < 4; i++)     
	 buffer[i]    = c[i];
	 
	buffer[4] = 7;
	
	int_to_char(index,c);
	for(i = 0; i < 4; i++)      
		buffer[i+5]  = c[i];
	
	int_to_char(begin,c);
	for(i = 0; i < 4; i++)      
		buffer[i+9]  = c[i];
		
	for(i = 0; i < b_len; i++)  
		buffer[i+13] = block[i];

	peer->msg_len += b_len+13;
	  
	return 0;
}

int create_cancel_msg(int index,int begin,Peer *peer)
/*
*功能:创建cancel消息
*传入参数:index bdegin length peer
*传出参数:
*返回值:
*	0	创建成功
*/
int create_cancel_msg(int index,int begin,int length,Peer *peer)
{
	int            i;
	unsigned char  c[4];
	unsigned char  *buffer = peer->out_msg + peer->msg_len;
	int            len = MSG_SIZE - peer->msg_len;
	
	if(len < 17)  return -1;  // 17为cancel消息的固定长度
	
	memset(buffer,0,17);
	buffer[3] = 13;
	buffer[4] = 8;
	
	int_to_char(index,c);
	for(i = 0; i < 4; i++)  
		buffer[i+5]  = c[i];
	
	int_to_char(begin,c);
	for(i = 0; i < 4; i++)  
		buffer[i+9]  = c[i];
		
	int_to_char(length,c);
	for(i = 0; i < 4; i++)  
		buffer[i+13] = c[i];

	peer->msg_len += 17;	
	
	return 0;
}

int create_port_msg(int port,Peer *peer)
/*
*功能:创建Port消息
*传入参数: port peer
*传出参数:
*返回值:
*	0	创建成功
*/
int create_port_msg(int port,Peer *peer)
{
	unsigned char  c[4];
	unsigned char  *buffer = peer->out_msg + peer->msg_len;
	int            len = MSG_SIZE - peer->msg_len;

	if( len < 7)  return 0;  // 7为port消息的固定长度

	memset(buffer,0,7);
	buffer[3] = 3;
	buffer[4] = 9;
	int_to_char(port,c);
	buffer[5] = c[2];
	buffer[6] = c[3];

	peer->msg_len += 7;
	
	return 0;
}
PS:事实上从未发送过本消息,因为根据BT协议,该消息是为那些以DHT的方式获取peer地址的应用程序所准备。

int is_complete_message(unsigned char *buff, unsigned int len, int *ok_len)
/*
*功能:判断缓冲区中是否存放了一条完整的消息
*传入参数:buff len ok_len
*传出参数:
*返回值:
*	1	是
*	-1  否
*/
int is_complete_message(unsigned char *buff,unsigned int len,int *ok_len)
{
	unsigned int   i;
	char           btkeyword[20];

	unsigned char  keep_alive[4]   = { 0x0, 0x0, 0x0, 0x0 };
	unsigned char  chocke[5]       = { 0x0, 0x0, 0x0, 0x1, 0x0};
	unsigned char  unchocke[5]     = { 0x0, 0x0, 0x0, 0x1, 0x1};
	unsigned char  interested[5]   = { 0x0, 0x0, 0x0, 0x1, 0x2};
	unsigned char  uninterested[5] = { 0x0, 0x0, 0x0, 0x1, 0x3};
	unsigned char  have[5]         = { 0x0, 0x0, 0x0, 0x5, 0x4};
	unsigned char  request[5]      = { 0x0, 0x0, 0x0, 0xd, 0x6};
	unsigned char  cancel[5]       = { 0x0, 0x0, 0x0, 0xd, 0x8};
	unsigned char  port[5]         = { 0x0, 0x0, 0x0, 0x3, 0x9};
	
	if(buff==NULL || len<=0 || ok_len==NULL)  
		return -1;
		
	*ok_len = 0;
	
	btkeyword[0] = 19;
	memcpy(&btkeyword[1],"BitTorrent protocol",19);  // BitTorrent协议关键字

	unsigned char  c[4];
	unsigned int   length;
	
	for(i = 0; i < len; ) 
	{
		// 握手、chocke、have等消息的长度是固定的
		if( i+68<=len && memcmp(&buff[i],btkeyword,20)==0 )         i += 68;
		else if( i+4 <=len && memcmp(&buff[i],keep_alive,4)==0 )    i += 4;
		else if( i+5 <=len && memcmp(&buff[i],chocke,5)==0 )        i += 5;
		else if( i+5 <=len && memcmp(&buff[i],unchocke,5)==0 )      i += 5;
		else if( i+5 <=len && memcmp(&buff[i],interested,5)==0 )    i += 5;
		else if( i+5 <=len && memcmp(&buff[i],uninterested,5)==0 )  i += 5;
		else if( i+9 <=len && memcmp(&buff[i],have,5)==0 )          i += 9;
		else if( i+17<=len && memcmp(&buff[i],request,5)==0 )       i += 17;
		else if( i+17<=len && memcmp(&buff[i],cancel,5)==0 )        i += 17;
		else if( i+7 <=len && memcmp(&buff[i],port,5)==0 )          i += 7;
		// bitfield消息的长度是变化的
		else if( i+5 <=len && buff[i+4]==5 )  
		{
			c[0] = buff[i];   
			c[1] = buff[i+1];
			c[2] = buff[i+2]; 
			c[3] = buff[i+3];
			
			length = char_to_int(c);	
			
			// 消息长度占4字节,消息本身占length个字节
			if( i+4+length <= len )  
				i += 4+length;
			else 
			{ 
				*ok_len = i; 
				
				return -1; 
			}
		}
		// piece消息的长度也是变化的
		else if( i+5 <=len && buff[i+4]==7 )  
		{
			c[0] = buff[i];  
			c[1] = buff[i+1];
			c[2] = buff[i+2]; 
			c[3] = buff[i+3];
			
			length = char_to_int(c);
			// 消息长度占4字节,消息本身占length个字节
			if( i+4+length <= len )  
				i += 4+length;
			else 
			{ 
				*ok_len = i; 
				return -1; 
			}
		}
		else 
		{
			// 处理未知类型的消息
			if(i+4 <= len) 
			{
				c[0] = buff[i];   
				c[1] = buff[i+1];
				c[2] = buff[i+2]; 
				c[3] = buff[i+3];
				length = char_to_int(c);
				
				// 消息长度占4字节,消息本身占length个字节
				if(i+4+length <= len)  
				{ 
					i += 4+length; 
					continue; 
				}
				else 
				{ 
					*ok_len = i; 
					return -1; 
				}
				
			}
			// 如果也不是未知消息类型,则认为目前接收的数据还不是一个完整的消息
			*ok_len = i;
			return -1;
		}
	}
	
	*ok_len = i;
	return 1;
}

int print_mdg_buffer(unsigned char *buffer, int len)
/*
*功能:以十六进制的形式打印消息的内容,用于调试
*传入参数:buffer len
*传出参数:
*返回值:
*	0	创建成功
*/
int print_msg_buffer(unsigned char *buffer, int len)
{
	int i;

	for(i = 0; i < len; i++) 
	{
		printf("%.2x ",buffer[i]);
		if( (i+1) % 16 == 0 )  
			printf("\n");
	}
	printf("\n");

	return 0;
}

处理的消息程序如下:
/*
*功能:处理接收到的一条握手消息
*传入参数:
					从peer接收到这条握手消息
					buff指向握手消息
					len为buff的长度
*传出参数:
*返回值:
*	0  
*/
int process_handshake_msg(Peer *peer,unsigned char *buff,int len)
{
	if(peer==NULL || buff==NULL)  return -1;

	if(memcmp(info_hash,buff+28,20) != 0) 
	{ 
		peer->state = CLOSING;//表明处于即将与Peer断开状态
		// 丢弃发送缓冲区中的数据
		discard_send_buffer(peer);
		clear_btcache_before_peer_close(peer);
		close(peer->socket);
		return -1;
	}
	
	//获得Peer的ID
	memcpy(peer->id,buff+48,20);
	(peer->id)[20] = '\0';
	
	// 若当前处于Initial状态,则发送握手消息给peer
	if(peer->state == INITIAL) 
	{
		peer->state = HANDSHAKED;//表明处于全握手状态
		create_handshake_msg(info_hash,peer_id,peer);
	}
	
	// 若握手消息已发送,则状态转换为已握手状态
	if(peer->state == HALFSHAKED)  
		peer->state = HANDSHAKED;

	// 记录最近收到该peer消息的时间
	// 若一定时间内(如两分钟)未收到来自该peer的任何消息,则关闭连接
	peer->start_timestamp = time(NULL);
	return 0;
}

/*
*功能:处理刚刚接收到的来自peer的keepv_alive消息
*传入参数:peer  buff len
*传出参数:
*返回值:
*	0  处理成功
*/
int process_keep_alive_msg(Peer *peer,unsigned char *buff,int len)
{
	if(peer==NULL || buff==NULL)  return -1;

	peer->start_timestamp = time(NULL);
	return 0;
}

/*
*功能:处理收到的choke消息
*传入参数:peer buff len
*传出参数:
*返回值:
*	0   处理成功
*   -1  没有
*/
int process_choke_msg(Peer *peer,unsigned char *buff,int len)
{
	if(peer==NULL || buff==NULL)  return -1;

	if( peer->state!=CLOSING && peer->peer_choking==0 ) 
	{
		peer->peer_choking = 1;//被Peer阻塞
		peer->last_down_timestamp = 0;//最近下载数据开始时间
		peer->down_count          = 0;//下载的字节数
		peer->down_rate           = 0;//下载速度
	}

	peer->start_timestamp = time(NULL);//最近一次接收Peer消息的时间
	
	return 0;
}

/*
*功能:处理unchoke消息
*传入参数:peer buff len
*传出参数:
*返回值:
*	0   处理成功
*/
int process_unchoke_msg(Peer *peer,unsigned char *buff,int len)
{
	if(peer==NULL || buff==NULL)  return -1;

	// 若原来处于choke状态且与该peer的连接未被关闭
	if( peer->state!=CLOSING && peer->peer_choking==1 ) 
	{
		peer->peer_choking = 0;//Peer解除对客服端的阻塞
		//客服端对Peer感兴趣,则构造request消息请求peer发送数据
		if(peer->am_interested == 1)  
			create_req_slice_msg(peer);
		else 
		{
			peer->am_interested = is_interested(&(peer->bitmap), bitmap);
			if(peer->am_interested == 1) 
				create_req_slice_msg(peer);
			else 
				printf("Received unchoke but Not interested to IP:%s \n",peer->ip);
		}

		peer->last_down_timestamp = 0;
		peer->down_count          = 0;
		peer->down_rate           = 0;
	}

	peer->start_timestamp = time(NULL);//最近一次接收Peer消息的时间
	
	return 0;
}

/*
*功能:处理收到的interested消息
*传入参数:peer buff len
*传出参数:
*返回值:
*	0   处理成功
*/
int process_interested_msg(Peer *peer,unsigned char *buff,int len)
{
	if(peer==NULL || buff==NULL)  return -1;

	//客户端与peer的连接未被关闭且交换数据状态
	if( peer->state!=CLOSING && peer->state==DATA ) 
	{
		peer->peer_interested = is_interested(bitmap, &(peer->bitmap));
		if(peer->peer_interested == 0)  
			return -1;
		if(peer->am_choking == 0) 
			create_chock_interested_msg(1,peer);//创建非阻塞消息
	}

	peer->start_timestamp = time(NULL);
	
	return 0;
}

/*
*功能:处理收到的uninterested消息
*传入参数:peer buff len
*传出参数:
*返回值:
*	0   处理成功
*	-1	出错
*/
int process_uninterested_msg(Peer *peer,unsigned char *buff,int len)
{
	if(peer==NULL || buff==NULL)  
		return -1;

	if( peer->state!=CLOSING && peer->state==DATA ) 
	{
		peer->peer_interested = 0;//Peer对客服端不感兴趣
		cancel_requested_list(peer);//撤销请求队列
	}

	peer->start_timestamp = time(NULL);
	
	return 0;
}

/*
*功能:处理have消息
*传入参数:peer buff len
*传出参数:
*返回值:
*	0   处理成功
*/
int process_have_msg(Peer *peer,unsigned char *buff,int len)
{
	int           rand_num;
	unsigned char c[4];

	if(peer==NULL || buff==NULL)  return -1;

	srand(time(NULL));
	rand_num = rand() % 3;

	if( peer->state!=CLOSING && peer->state==DATA ) 
	{
		c[0] = buff[5]; 
		c[1] = buff[6];
		c[2] = buff[7]; 
		c[3] = buff[8];		
		
		if(peer->bitmap.bitfield != NULL)
			set_bit_value(&(peer->bitmap),char_to_int(c),1);//更新位图

		if(peer->am_interested == 0) 
		{
			peer->am_interested = is_interested(&(peer->bitmap), bitmap);
			// 由原来的对peer不感兴趣变为感兴趣时,发interested消息
			if(peer->am_interested == 1) 
				create_chock_interested_msg(2,peer);	
		} 
		else 
		{  // 收到三个have则发一个interested消息
			if(rand_num == 0) 
				create_chock_interested_msg(2,peer);
		}
	}

	peer->start_timestamp = time(NULL);
	
	return 0;
}

/*
*功能:处理cancel消息
*传入参数:peer buff len
*传出参数:
*返回值:
*	0   处理成功
*	-1  出错
*/
int process_cancel_msg(Peer *peer,unsigned char *buff,int len)
{
	unsigned char c[4];
	int           index, begin, length;

	if(peer==NULL || buff==NULL)  
		return -1;
	
	c[0] = buff[5];  
	c[1] = buff[6];
	c[2] = buff[7];  
	c[3] = buff[8];
	index = char_to_int(c);//获得index
	
	c[0] = buff[9];  
	c[1] = buff[10];
	c[2] = buff[11]; 
	c[3] = buff[12];
	begin = char_to_int(c);//获得begin
	
	c[0] = buff[13]; 
	c[1] = buff[14];
	c[2] = buff[15]; 
	c[3] = buff[16];
	length = char_to_int(c);//获得Length
	
	// 在被请求队列中删除指定的请求
	Request_piece *p, *q;
	p = q = peer->Requested_piece_head;//取得Peer请求队列头指针
	while(p != NULL) 
	{ 
		if( p->index==index && p->begin==begin && p->length==length ) 
		{
			if(p == peer->Requested_piece_head) 
				peer->Requested_piece_head = p->next;
			else
				q->next = p->next;
			free(p);
			break;
		}
		q = p;
		p = p->next;
	}	

	peer->start_timestamp = time(NULL);
	return 0;
}

/*
*功能:处理收到的位图消息
*传入参数:peer buff len
*传出参数:
*返回值:
*	0   处理成功
*	-1  出错
*/
int process_bitfield_msg(Peer *peer,unsigned char *buff,int len)
{
	unsigned char c[4];

	if(peer==NULL || buff==NULL)  return -1;
	//握手和已发送位图状态
	if(peer->state==HANDSHAKED || peer->state==SENDBITFIELD) 
	{
		c[0] = buff[0];   
		c[1] = buff[1];
		c[2] = buff[2];   
		c[3] = buff[3];			
		
		// 若原先已收到一个位图消息,则清空原来的位图
		if( peer->bitmap.bitfield != NULL ) 
		{
			free(peer->bitmap.bitfield);
			peer->bitmap.bitfield = NULL;
		}
		
		peer->bitmap.valid_length = bitmap->valid_length;
		
		// 若收到的一个错误位图
		if(bitmap->bitfield_length != char_to_int(c)-1) 
		{
			peer->state = CLOSING;
			// 丢弃发送缓冲区中的数据
			discard_send_buffer(peer);
			clear_btcache_before_peer_close(peer);
			close(peer->socket);
			return -1;
		}
		// 生成该peer的位图
		peer->bitmap.bitfield_length = char_to_int(c) - 1;
		peer->bitmap.bitfield = (unsigned char *)malloc(peer->bitmap.bitfield_length);
		memcpy(peer->bitmap.bitfield,&buff[5],peer->bitmap.bitfield_length);
	
		// 如果原状态为已握手,收到位图后应该向peer发位图
		if(peer->state == HANDSHAKED) 
		{
			create_bitfield_msg(bitmap->bitfield,bitmap->bitfield_length,peer);
			peer->state = DATA;
		}
		// 如果原状态为已发送位图,收到位图后可以准备交换数据
		if(peer->state == SENDBITFIELD) 
		{
			peer->state = DATA;
		}

		// 判断peer是否对我们感兴趣
		peer->peer_interested = is_interested(bitmap,&(peer->bitmap));
		// 判断对peer是否感兴趣,若是则发送interested消息
		peer->am_interested = is_interested(&(peer->bitmap), bitmap);
		if(peer->am_interested == 1) 
			create_chock_interested_msg(2,peer);
	}
	
	peer->start_timestamp = time(NULL);
	
	return 0;
}

/*
*功能:处理收到的request消息
*传入参数:peer buff len
*传出参数:
*返回值:
*	0   处理成功
*	-1	出错
*/
int process_request_msg(Peer *peer,unsigned char *buff,int len)
{
	unsigned char  c[4];
	int            index, begin, length;
	Request_piece  *request_piece, *p;
	
	if(peer==NULL || buff==NULL)  return -1;

	if(peer->am_choking==0 && peer->peer_interested==1) 
	{
		c[0] = buff[5];  c[1] = buff[6];
		c[2] = buff[7];  c[3] = buff[8];
		index = char_to_int(c);
		c[0] = buff[9];  c[1] = buff[10];
		c[2] = buff[11]; c[3] = buff[12];
		begin = char_to_int(c);
		c[0] = buff[13]; c[1] = buff[14];
		c[2] = buff[15]; c[3] = buff[16];
		length = char_to_int(c);

		// 错误的slice请求
		if( begin%(16*1024) != 0 ) 
		{
			return 0;
		}
		
		// 查看该请求是否已存在,若已存在,则不进行处理
		p = peer->Requested_piece_head;
		while(p != NULL) 
		{
			if(p->index==index && p->begin==begin && p->length==length) 
			{
				break;
			}
			p = p->next;
		}
		if(p != NULL)  //请求存在
			return 0;

		// 将请求加入到请求队列中
		request_piece = (Request_piece *)malloc(sizeof(Request_piece));
		if(request_piece == NULL)  
		{ 
			printf("%s:%d error",__FILE__,__LINE__); 
			return 0; 
		}
		request_piece->index  = index;
		request_piece->begin  = begin;
		request_piece->length = length;
		request_piece->next   = NULL;
		
		if( peer->Requested_piece_head == NULL ) 
			peer->Requested_piece_head = request_piece;
		else 
		{
			p = peer->Requested_piece_head;
			while(p->next != NULL)  
				p = p->next;
			p->next = request_piece;
		}
		//printf("*** add a request FROM IP:%s index:%-6d begin:%-6x ***\n",
		//       peer->ip,index,begin);
	}

	peer->start_timestamp = time(NULL);
	
	return 0;
}

/*
*功能:处理收到的piece消息
*传入参数:peer buff len
*传出参数:
*返回值:
*	0   处理成功
*	-1  出错
*/
int process_piece_msg(Peer *peer,unsigned char *buff,int len)
{
	unsigned char  c[4];
	int            index, begin, length;
	Request_piece  *p;

	if(peer==NULL || buff==NULL)  
		return -1;
	
	if(peer->peer_choking==0) 
	{
		c[0] = buff[0];    c[1] = buff[1];
		c[2] = buff[2];    c[3] = buff[3];
		length = char_to_int(c) - 9;
		c[0] = buff[5];    c[1] = buff[6];
		c[2] = buff[7];    c[3] = buff[8];
		index = char_to_int(c);
		c[0] = buff[9];    c[1] = buff[10];
		c[2] = buff[11];   c[3] = buff[12];
		begin = char_to_int(c);

		//查看请求是否存在
		p = peer->Request_piece_head;
		while(p != NULL) 
		{
			if(p->index==index && p->begin==begin && p->length==length)
				break;
			p = p->next;
		}
		if(p == NULL) 
		{
			printf("did not found matched request\n"); 
			return -1;
		}

		if(peer->last_down_timestamp == 0)
			peer->last_down_timestamp = time(NULL);
		peer->down_count += length;
		peer->down_total += length;

		//将slice写入缓存区
		write_slice_to_btcache(index,begin,length,buff+13,length,peer);

		create_req_slice_msg(peer);
	}

	peer->start_timestamp = time(NULL);
	return 0;
}


/*
*功能:处理收到的消息(peer的接收缓冲区中可能存放着多条消息)
*传入参数:peer 
*传出参数:
*返回值:
*	0   处理成功
*	-1 	出错
*/
int parse_response(Peer *peer)
{
	unsigned char  btkeyword[20];
	unsigned char  keep_alive[4] = { 0x0, 0x0, 0x0, 0x0 };
	int            index;
	unsigned char  *buff = peer->in_buff;//获取接收到的消息
	int            len = peer->buff_len;//缓冲区的长度

	if(buff==NULL || peer==NULL)  
		return -1;

	btkeyword[0] = 19;
	memcpy(&btkeyword[1],"BitTorrent protocol",19);  // BitTorrent协议关键字

	// 分别处理12种消息
	for(index = 0; index < len; ) 
	{	

		if( (len-index >= 68) && (memcmp(&buff[index],btkeyword,20) == 0) ) 
		{
			process_handshake_msg(peer,buff+index,68);
			index += 68;
		} 
		else if( (len-index >= 4) && (memcmp(&buff[index],keep_alive,4) == 0))
		{
			process_keep_alive_msg(peer,buff+index,4);
			index += 4; 
		}
		else if( (len-index >= 5) && (buff[index+4] == CHOKE) ) 
		{
			process_choke_msg(peer,buff+index,5);
			index += 5;
		}
		else if( (len-index >= 5) && (buff[index+4] == UNCHOKE) ) 
		{
			process_unchoke_msg(peer,buff+index,5);
			index += 5;
		}
		else if( (len-index >= 5) && (buff[index+4] == INTERESTED) ) 
		{
			process_interested_msg(peer,buff+index,5);
			index += 5;
		}
		else if( (len-index >= 5) && (buff[index+4] == UNINTERESTED) ) 
		{
			process_uninterested_msg(peer,buff+index,5);
			index += 5;
		}
		else if( (len-index >= 9) && (buff[index+4] == HAVE) ) 
		{
			process_have_msg(peer,buff+index,9);
			index += 9;
		}
		else if( (len-index >= 5) && (buff[index+4] == BITFIELD) ) 
		{
			process_bitfield_msg(peer,buff+index,peer->bitmap.bitfield_length+5);
			index += peer->bitmap.bitfield_length + 5;
		}
		else if( (len-index >= 17) && (buff[index+4] == REQUEST) ) 
		{
			process_request_msg(peer,buff+index,17);
			index += 17;
		}
		else if( (len-index >= 13) && (buff[index+4] == PIECE) ) 
		{
			unsigned char  c[4];
			int            length;
			
			c[0] = buff[index];    c[1] = buff[index+1];
			c[2] = buff[index+2];  c[3] = buff[index+3];
			length = char_to_int(c) - 9;
			
			process_piece_msg(peer,buff+index,length+13);
			index += length + 13; // length+13为piece消息的长度
		}
		else if( (len-index >= 17) && (buff[index+4] == CANCEL) ) 
		{
			process_cancel_msg(peer,buff+index,17);
			index += 17;
		}
		else if( (len-index >= 7) && (buff[index+4] == PORT) ) 
		{
			index += 7;
		}
		else 
		{
			// 如果是未知的消息类型,则跳过不予处理
			unsigned char c[4];
			int           length;
			if(index+4 <= len) 
			{
				c[0] = buff[index];   c[1] = buff[index+1];
				c[2] = buff[index+2]; c[3] = buff[index+3];
				length = char_to_int(c);
				if(index+4+length <= len)  
				{ 
					index += 4+length; 
					continue; 
				}
			}
			// 如果是一条错误的消息,清空接收缓冲区
			peer->buff_len = 0;
			
			return -1;
		}
	} // end for

	// 接收缓冲区中的消息处理完毕后,清空接收缓冲区
	peer->buff_len = 0;

	return 0;
}

/*
*功能:处理收到的不完整的消息
*传入参数:
					ok_len为接收缓冲区中完整消息的长度
*传出参数:
*返回值:
*	0   处理成功
*	-1	出错
*/
int parse_response_uncomplete_msg(Peer *p,int ok_len)
{
	char *tmp_buff;
	int   tmp_buff_len;

	// 分配存储空间,并保存接收缓冲区中不完整的消息
	tmp_buff_len = p->buff_len - ok_len;
	if(tmp_buff_len <= 0)  
		return -1;
	tmp_buff = (char *)malloc(tmp_buff_len);
	if(tmp_buff == NULL) 
	{
		printf("%s:%d error\n",__FILE__,__LINE__);
		return -1;
	}
	memcpy(tmp_buff,p->in_buff+ok_len,tmp_buff_len);
	
	// 处理接收缓冲区中前面完整的消息
	p->buff_len = ok_len;
	parse_response(p);

	// 将不完整的消息拷贝到接收缓冲区的开始处
	memcpy(p->in_buff,tmp_buff,tmp_buff_len);
	p->buff_len = tmp_buff_len;
	if(tmp_buff != NULL)  
		free(tmp_buff);

	return 0;
}

int prepare_send_have_msg()
/*
*功能:当下载完一个piece时,应该向所有的peer发送have消息
*传入参数:
*传出参数:
*返回值:
*	0   处理成功
*	-1	出错
*/
int prepare_send_have_msg()
{
	Peer *p = peer_head;//获得当前与客服端通信的Peer链表头指针
	int  i;

	if(peer_head == NULL)  
		return -1;
	if(have_piece_index[0] == -1)  
		return -1;

	while(p != NULL) 
	{
		for(i = 0; i < 64; i++) 
		{
			if(have_piece_index[i] != -1) 
			{
				create_have_msg(have_piece_index[i],p);
			}
			else 
			{
				break;
			}
		}
		p = p->next;
	}

	for(i = 0; i < 64; i++) 
	{
		if(have_piece_index[i] == -1) 
		{
			break;
		}
		else 
		{
			have_piece_index[i] = -1;
		}
	}
	
	return 0;
}

int create_response_message(Peer *peer)
/*
*功能:主动创建发送给peer的消息,而不是等收到某个消息再作出响应
*传入参数:peer 
*传出参数:
*返回值:
*	0   处理成功
*/
int create_response_message(Peer *peer)
{
	if(peer==NULL)  return -1;

	if(peer->state == INITIAL) 
	{
		//创建握手消息
		create_handshake_msg(info_hash,peer_id,peer);
		peer->state = HALFSHAKED;
		return 0;
	}

	if(peer->state == HANDSHAKED) 
	{
		if(bitmap == NULL)  
			return -1;
		//创建位图消息
		create_bitfield_msg(bitmap->bitfield,bitmap->bitfield_length,peer);
		peer->state = SENDBITFIELD;
		return 0;
	}

	// 发送piece消息,即发送下载文件的内容
	if( peer->am_choking==0 && peer->Requested_piece_head!=NULL ) 
	{
		Request_piece *req_p = peer->Requested_piece_head;
		//从缓存区获取slice消息
		int ret = read_slice_for_send(req_p->index,req_p->begin,req_p->length,peer);
		if(ret < 0 )
		{ 
			printf("read_slice_for_send ERROR\n");
		}
		else
		{
			//更新Peer结构体中的信息
			if(peer->last_up_timestamp == 0) 
				peer->last_up_timestamp = time(NULL);
			peer->up_count += req_p->length;
			peer->up_total += req_p->length;
			peer->Requested_piece_head = req_p->next;

			//printf("********* sending a slice TO:%s index:%-5d begin:%-5x *********\n",
			//peer->ip,req_p->index,req_p->begin);

			free(req_p);
			return 0;
		}
	}

	// 如果3分钟没有收到任何消息关闭连接
	time_t now = time(NULL);  // 获取当前时间
	long interval1 = now - peer->start_timestamp;
	if( interval1 > 180 ) 
	{
		peer->state = CLOSING;
		discard_send_buffer(peer);  // 丢弃发送缓冲区中的数据
		clear_btcache_before_peer_close(peer);
		close(peer->socket);
	}
	// 如果45秒没有发送和接收消息,则发送一个keep_alive消息
	long interval2 = now - peer->recet_timestamp;
	if( interval1>45 && interval2>45 && peer->msg_len==0)
		create_keep_alive_msg(peer);

	return 0;
}

void discard_send_buffer(Peer *peer)
/*
*功能:即将与peer断开时,丢弃发送缓冲区中的消息
*传入参数:peer
*传出参数:
*返回值:
*/
void discard_send_buffer(Peer *peer)
{
	struct linger  lin;
	int            lin_len;
	
	lin.l_onoff  = 1;
	lin.l_linger = 0;
	lin_len      = sizeof(lin);
	
	if(peer->socket > 0)
	{
		setsockopt(peer->socket,SOL_SOCKET,SO_LINGER,(char *)&lin,lin_len);
	}
}

从命令行到内核:一条`ipmitool raw`命令在Linux服务器里究竟走了多远? 命令的完整执行路径,不仅能帮助解决实际问题,还能为设计自己的硬件管理系统提供宝贵参考。当你在终端看到那行简单的十六进制响应时,现在你应该知道,这背后是一场跨越多个软件层级和硬件组件的精密协作的结果。并按下回车时,这条看似简单的命令实际上触发了一场跨越用户态与内核态的精密协作。本文将带你深入探索这条命令背后的完整旅程,揭示从命令行输入到BMC硬件响应的每一个关键环节。这个阶段的数据流完全发生在用户空间,但已经为后续的内核交互做好了准备。将接收到的原始数据格式化输出到终端,完成整个命令的生命周期。 阅读详情

相关推荐

异构多核SoC架构解析:Arm、DSP与PRU协同设计在工业实时系统中的应用

在嵌入式系统设计中,异构多核片上系统(SoC)通过集成不同类型的处理器内核,实现了通用计算与专用实时任务的高效协同。其核心原理在于将任务按特性分配到最合适的处理单元:通用处理器(如Arm Cortex-A系列)负责运行复杂操作系统和上层应用,而数字信号处理器(DSP)则专注于计算密集型算法,可编程实时单元(PRU)处理微秒级确定性控制。这种架构的技术价值在于同时满足高性能计算、高实时性响应和低功耗需求,尤其适用于工业自动化、汽车电子和专业音频处理等场景。例如,在工业控制系统中,Arm核可运行Linux管理网

banglvfei0870的博客 458

Golang快速开发框架——新增500错误处理模块和其页面(六)

Golang快速开发框架——新增500错误处理模块和其页面(六) 背景 知识分享之Golang篇是我在日常使用Golang时学习到的各种各样的知识的记录,将其整理出来以文章的形式分享给大家,来进行共同学习。欢迎大家进行持续关注。 知识分享系列目前包含Java、Golang、Linux、Docker等等。 开发环境 系统:windows10 语言:Golang golang版本:1.17 代码仓库...

CN華少的博客 546

【经验分享】一种高内聚低耦合的消息分发模块的设计与实现

今天的话题是嵌入式的消息分发模块,你会怎么设计和实现?

一个专注于嵌入式IoT领域的架构师,深耕IoT领域多年,深度掌握IoT领域的相关技术栈,包括但不限于RTOS内核的实现及其移植、硬件驱动移植开发、网络通讯协议开发、编译构建原理及其实现、底层汇编及编译原理、编译优化及代码重构、嵌入式IoT系统的架构设计等。 6331

Linux下,使用C/C++一个简单的消息处理程序

<br />// all.h<br />#ifndef _ALL_H<br />#define _ALL_H<br />// ANSC C/C++<br />#include <stdio.h><br />#include <stdlib.h><br />#include <iostream.h><br />#include <assert.h><br />// linux<br />#include <unistd.h><br />#include <string.h><br />#include <sy

rznice的专栏 1059

【BlueZ】源码目录结构全解析:一分钟看懂各文件夹核心作用

BlueZ 作为 Linux 平台唯一官方蓝牙协议栈,采用模块化分层架构设计。绝大多数开发者编译裁剪失败、功能代码找不到、问题无从定位,本质是不熟悉源码目录职责边界。本文承接系列前文内核决定兼容上限、依赖库决定编译下限核心理论,基于 BlueZ 5.87 原版源码,系统性拆解全版本通用目录架构,打通目录结构→编译参数→功能模块→问题定位完整链路,是 BlueZ 源码阅读、二次开发、移植适配的官方级手册。

byte轻骑兵的技术小窝 1万+

【BlueZ】4.x vs 5.x 核心差异:为什么推荐开发首选 5.x 版本

本文对BlueZ4.x与5.87版本进行了深度对比分析,从架构模型、模块设计、通信机制等八个维度揭示核心差异。BlueZ5.x采用单守护进程架构、插件化设计、DBus标准化接口和ManagementInterface通信机制,在稳定性、兼容性、BLE支持和性能方面全面超越4.x版本。研究表明,5.x版本更适合工业级蓝牙开发,具备功能完整、API稳定、社区活跃等优势,而4.x版本由于架构缺陷已停止维护。文章为开发者提供了明确的版本选型依据和迁移指南,建议新项目直接采用5.x版本以获得长期技术红利。

byte轻骑兵的技术小窝 1万+

Linux BT下载(5)-系统结构设计

系统结构设计 整个系统模块结构如图: 整个系统的功能模块分布: (1)种子解析:负责解析种子文件,从中获取Tracker服务器的地址,待下载文件的文件名和长度,piece长度,各个piece的hash值。 (2)连接Tracker:根据HTTP协议构造获取Peer地址的请求,与Tracker建立连接,解析Tracker的回应消息,从而获取各个Peer的IP地址和端口

cslqm 1343

Linux下C语言实现聊天室:从socket到粘包处理的实战指南

网络编程是后端开发的核心技能,理解底层原理方能应对复杂的线上问题。Linux作为服务器端主流平台,其socket、多线程、I/O复用等机制构成了所有高并发框架的基石。通过一个经典的C语言聊天室项目,可以深入实践TCP/IP协议、消息分发、粘包与半包处理等关键问题。这种最小化工程实践覆盖了从socket初始化到广播消息的完整链路,并涉及gdb调试、valgrind内存检测等实用工具。无论完成课程设计还是备战技术面试,掌握这些基础都能为后续学习Java NIO或Go netpoller提供坚实支撑。聊天室虽小,

weixin_34032621的博客 442

Linux平台下基于BitTorrent应用层协议的下载软件开发--消息处理模块(signal_handler.c)

#include #include #include #include #include "signal_hander.h" #include "parse_metafile.h" #include "data.h" #include "bitfield.h" #include "peer.h" #include "tracker.h" #include "torrent.h" exte

airfer的专栏 1877

应用程序级消息处理模块[Msgdisposal.rar]-精品源代码

应用程序级消息处理模块[Msgdisposal.rar]-精品源代码

一个真正能用的信息系统消息处理模块

一个真正能用的信息系统消息处理模块,骗你是大傻!

Linux平台下基于BitTorrent应用层协议的下载软件开发--消息处理模块(message.c)

#include #include #include #include #include #include #include #include #include "parse_metafile.h" #include "bitfield.h" #include "peer.h" #include "data.h" #include "policy.h" #include "mess

airfer的专栏 1488

手把手教你安装 Vivado2022.2(附安装包)

Vivado 2022.2版本与之前的版本相比,具有以下几个显著的优势:电源设计管理器(PDM):Vivado 2022.2引入了全新的电源设计管理器(PDM),这是一个下一代功耗评估平台,为Versal® 和 Kria™ SOM提供了准确一致的功耗估计能力。PDM是Versal产品家族的首选功耗评估工具,为Versal ACAP硬IP块提供增强向导,简化从XPE向PDM的迁移,帮助用户获得准确的功耗评估。

dpwkj的博客 2万+

深入BTC++源码:从BT协议到P2P网络核心实现详解

P2P网络是一种去中心化的网络架构,其核心原理在于节点之间直接通信与资源共享,无需依赖中心服务器。这种设计赋予了系统高度的抗单点故障能力和可扩展性,技术价值在于能够构建高效、健壮的分布式应用。在文件共享、内容分发和区块链等领域,P2P网络是实现数据高效同步与传播的基础设施。BT协议作为P2P网络中最经典的应用层协议之一,通过定义节点发现、数据分片、传输调度与校验等机制,实现了大规模文件的高效协同下载。本文聚焦于BTC++这一C++实现的BT协议库,通过剖析其源码,深入讲解协议消息处理、Piece选择策略等核

cixu3288的博客 339

工业机器人关节拆装流程_一文读懂模块化直驱电机及机器人关节模组

私信“干货”二字,即可领取138G伺服与机器人专属及电控资料!如果说芯片是智能行业最为重要的核心元件,那么电机几乎可以说是支撑了整个自动化和大工业生产以及现代社会最为重要的部件,全世界90%的能源是由电机发出来的,而70%是由电机消耗调的,电机可以说是整个人类社会能源循环的占有绝对地位的产品。普通伺服电机伺服电机其实已经算是电动机中比较高端的类型,特别是永磁同步类型的伺服电机,由于其启动快速,惯量...

weixin_32159771的博客 2155

手势控制 Python !Leap Motion Python 开发教程 (二)

手势控制 Python !Leap Motion Python 开发教程 (二) 现在进入正题,我来给大家总结一下我在使用 Leap Motion 开发过程中的经验以及学到的东西,其中我会概括以及翻译官方给出的注释,为了让这些注释更加通俗易懂,让大家更好理解。 回顾 在上一篇文章中我们讲了如何配置 Leap Motion 的 Python 2.7 的开发环境,如果您还没有配置好您的开发环境,可以参...

成畅的博客 3193

终极指南:如何在Windows、macOS和Linux上完全控制索尼耳机

还在为索尼耳机只能在手机上使用官方APP而烦恼吗?SonyHeadphonesClient这款开源神器彻底改变了这一局面!无论你使用的是Windows、macOS还是Linux系统,都能轻松实现对索尼耳机的专业级控制。这个跨平台客户端让你在桌面端也能享受完整的索尼耳机控制体验,包括环境声控制、降噪调节等核心功能。 ## 🎯 项目概述:打破平台限制的索尼耳机控制方案 SonyHeadphone

gitblog_01158的博客 934

c#仿热血江湖

Int32_1 = (int) table.Rows[i]["FLD_初级附魂"],Int32_2 = (int) table.Rows[i]["FLD_中级附魂"],Int32_3 = (int) table.Rows[i]["FLD_是否绑定"],Int32_0 = (int) table.Rows[i]["FLD_进化"],Form1.smethod_1(2, "加载百宝阁物品----没有百宝阁数据");Form1.smethod_1(2, "加载物品商店----没有物品数据");

weixin_42132177的博客 142

12.3-ros遥操作teleop

ROS使用XBOX ONE 手柄 前言 基础知识 ROS使用XBOX ONE 手柄前言参考学习记录安装相关包配置LinuxROS包使用手柄控制P3AT的roslaunch文件自定义使用关于xbone BT wireless controllerTOC 参考 ros wiki Tutorial Msg Remapper Linux ...

weixin_30740295的博客 1233

27、物联网中的量子密钥分发:安全通信新范式

本文探讨了物联网(IoT)快速发展所带来的安全挑战,并提出量子密钥分发(QKD)作为应对新兴威胁的新范式。文章详细介绍了QKD的基础原理、BB84协议的实现流程以及其在物联网中的应用前景,同时强调了安全专业人员提升技能、制定标准化指南以及跨学科合作的重要性。通过利用量子力学特性,QKD能够提供更高的通信安全性,抵御量子计算等未来威胁,为物联网的安全发展提供保障。

tequila的博客 156

多模型机器学习生存预测分析:AUC比较、生存分层与SHAP解释

本文研究了多种机器学习模型在心力衰竭患者生存预测中的应用。通过比较逻辑回归、随机森林、XGBoost、LightGBM和梯度提升机五种模型的AUC表现,选择最优预测模型。基于最优模型的预测概率对患者进行风险分层,并使用Kaplan-Meier生存分析和log-rank检验验证分层的有效性。最后采用SHAP方法解释模型决策过程,识别关键预测因素。研究提供了从模型构建、评估到解释的完整技术流程,为临床预后预测提供了可复现的分析框架。

AI的内部世界的博客 157

IPMI从驱动到应用(上篇)

3869人阅读 很多企业的核心业务大都运行在服务器系上,一旦系统出现非预料的宕机,很可能造成数据出错甚至丢失,这种情况如果发生在金融和银行系统上,将会造成不可估量的损失。为此,有必要实时检测服务器的健康状态,包括风扇转速、CPU和主板的温度、核心电压、电源模块的状态等,进而及时预报各种可能出现的错误。系统管理软件(system mana...

weixin_33939380的博客 1485

OpenClaw零基础教程:30分钟搭建你的第一个AI自动化助手

别再看那些满是代码、专业术语的教程了,那些都是给程序员看的。这篇教程,我把所有步骤拆到了极致,你跟着点鼠标就行,点错了都没关系,大不了重装一遍,5分钟的事。

2601_94871597的博客 96

Linux环境下IPMI密码重置实战指南:从初始密码到安全配置

本文提供了一份详尽的Linux环境下IPMI密码重置实战指南。针对服务器管理员遗忘或需重置IPMI密码的常见问题,文章从工具准备、用户列表查看、尝试初始密码,到核心的ipmitool命令行密码重置操作,进行了逐步解析。最后,还给出了全面的IPMI安全配置建议,帮助用户在恢复访问权限后,立即加固管理接口,防范安全风险。

efc123456的博客 427

SCI论文发表很容易【5】:比较容易中的期刊

整理了一些经管方面比较容易中稿的期刊,可供大家参考

qq_25018077的博客 1678

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

C++11/14标准库实现线程池:生产者-消费者模型与异步消息处理

并发编程是现代软件开发的核心技术之一,其核心在于通过多线程协作提升程序执行效率。其基本原理是创建多个执行流,通过同步机制协调对共享资源的访问,避免数据竞争。在工程实践中,线程池作为一种重要的并发模式,通过复用线程减少创建销毁开销,显著提升系统吞吐量,尤其适用于网络请求、日志处理、文件I/O等异步消息处理场景。本文聚焦于使用C++标准库组件,如std::thread、std::mutex和std::condition_variable,手动构建一个轻量级、可移植的线程池,深入剖析其如何实现经典的生产者-消费者

aaa1231722的博客 309

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

上一篇: Linux BT下载(11)-信号处理模块和Peer管理模块
下一篇: Linux BT下载(13)-缓存管理模块设计与实现
cslqm
博客等级 码龄11年 32粉丝 92原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值