bt peer通信协议报文格式

本文深入解析了P2P文件共享协议的结构、关键消息类型及其应用场景,包括keep-alive、choke、unchoke等报文的定义与作用,以及如何通过bitfield报文了解对端已下载的片段信息。

接下来协议的所有报文采用如下的结构:<length prefix><message ID><payload>。length prefix(长度前缀)是一个4字节的大端(big-endian)值。message ID是单个十进制值。playload与消息相关。

l  keep-alive: <len=0000>

keep-alive消息是一个0字节的消息,将length prefix设置成0。没有message ID和payload。如果peers在一个固定时间段内没有收到任何报文(keep-alive或其他任何报文),那么peers应该关掉这个连接,因此如果在一个给定的时间内没有发出任何命令的话,peers必须发送一个keep-alive报文保持这个连接激活。通常情况下,这个时间是2分钟。

l  choke: <len=0001><id=0>

choke报文长度固定,并且没有payload。

l  unchoke: <len=0001><id=1>

unchoke报文长度固定,并且没有payload。

l  interested: <len=0001><id=2>

interested报文长度固定,并且没有payload。

l  not interested: <len=0001><id=3>

not interested报文长度固定,并且没有payload。

l  have: <len=0005><id=4><piece index>

have报文长度固定。payload是piece(片)的从零开始的索引,该片已经成功下载并且通过hash校验。

实现者注意:实际上,一些客户端必须严格实现该定义。因为peers不太可能下载他们已经拥有的piece(片),一个peer不应该通知另一个peer它拥有一个piece(片),如果另一个peer拥有这个piece(片)。最低限度”HAVE suppresion”会使用have报文数量减半,总的来说,大致减少25-35%的HAVE报文。同时,给一个拥有piece(片)的peer发送HAVE报文是值得的,因为这有助于决定哪个piece是稀缺的。

一个恶意的peer可能向其他的peer广播它们不可能下载的piece(片)。Due to this attempting to model peers using this information is a bad idea.

l  bitfield: <len=0001+X><id=5><bitfield>

bitfield报文可能仅在握手序列发送之后,其他消息发送之前立即发送。它是可选的,如果一个客户端没有piece(片),就不需要发送该报文。

bitfield报文长度可变,其中x是bitfield的长度。payload是一个bitfield,该bitfield表示已经成功下载的piece(片)。第一个字节的高位相当于piece索引0。设置为0的位表示一个没有的piece,设置为1的位表示有效的和可用的piece。末尾的冗余位设置为0。

长度不对的bitfield将被认为是一个错误。如果客户端接收到长度不对的bitfield或者bitfield有任一冗余位集,它应该丢弃这个连接。

l  request: <len=0013><id=6><index><begin><length>

request报文长度固定,用于请求一个块(block)。payload包含如下信息:

n  index: 整数,指定从零开始的piece索引。

n  begin: 整数,指定piece中从零开始的字节偏移。

n  length: 整数,指定请求的长度。

l  piece: <len=0009+X><id=7><index><begin><block>

piece报文长度可变,其中x是块的长度。payload包含如下信息:

n  index: 整数,指定从零开始的piece索引。

n  begin: 整数,指定piece中从零开始的字节偏移。

n  block: 数据块,它是由索引指定的piece的子集。

l  cancel: <len=0013><id<=8><index><begin><length>

cancel报文长度固定,用于取消块请求。playload与request报文的playload相同。一般情况下用于结束下载。

l  port: <len=0003><id=9><listen-port>

port报文由新版本的Mainline发送,新版本Mainline实现了一个DHT tracker。该监听端口是peer的DHT节点正在监听的端口。这个peer应该插入本地路由表(如果支持DHT tracker的话)。

154 /******************************************************************************* 155 * 156 * Function avdt_ccb_hdl_discover_cmd 157 * 158 * Description This function is called when a discover command is 159 * received from the peer. It gathers up the stream 160 * information for all allocated streams and initiates 161 * sending of a discover response. 162 * 163 * 164 * Returns void. 165 * 166 ******************************************************************************/ 167 void avdt_ccb_hdl_discover_cmd(AvdtpCcb* p_ccb, tAVDT_CCB_EVT* p_data) { 168 tAVDT_SEP_INFO sep_info[AVDT_NUM_SEPS]; 169 AvdtpScb* p_scb = &(p_ccb->scb[0]); 170 171 bool codecs_cached = false; 172 char value[PROPERTY_VALUE_MAX]; 173 log::verbose("p_ccb index={}", avdt_ccb_to_idx(p_ccb)); 174 175 p_data->msg.discover_rsp.p_sep_info = sep_info; 176 p_data->msg.discover_rsp.num_seps = 0; 177 178 if (p_ccb != NULL) { 179 std::string bdstr = p_ccb->peer_addr.ToString(); 180 int size = sizeof(value); 181 if (btif_config_get_str(bdstr, BTIF_STORAGE_KEY_FOR_SUPPORTED_CODECS, value, &size)) { 182 log::verbose("cached remote supported codec -> {}", value); 183 codecs_cached = true; 184 } 185 } 186 187 /* for all allocated scbs */ 188 for (int i = 0; i < AVDT_NUM_SEPS; i++, p_scb++) { 189 if (p_scb->allocated) { 190 /* copy sep info */ 191 192 const char *codec_name; 193 codec_name = A2DP_CodecName(p_scb->stream_config.cfg.codec_info); 194 if (codecs_cached){ 195 bool codec_support = false; 196 char *tok = NULL; 197 char *tmp_token = NULL; 198 int size = sizeof(value); 199 std::string bdstr = p_ccb->peer_addr.ToString(); 200 btif_config_get_str(bdstr, BTIF_STORAGE_KEY_FOR_SUPPORTED_CODECS, value, &size); 201 log::verbose("print remote suppo
最新发布
03-08
### 蓝牙A2DP协议中的`avdt_ccb_hdl_discover_cmd`函数 #### 函数作用 `avdt_ccb_hdl_discover_cmd`负责处理来自远程设备的发现请求命令。当接收到此类命令时,该函数会遍历本地支持的服务并收集相关信息,随后构建一个包含所有可用服务描述符列表的消息作为回应返回给发起方[^4]。 #### 处理流程概述 - 接收到来自L2CAP层传递过来的数据包后触发此函数执行; - 解析数据包内的参数以获取必要的上下文信息; - 遍历当前已注册的所有媒体传输路径(Stream Endpoints),提取其属性和服务能力; - 将上述信息封装成标准格式,并通过相同的信道反馈回去; #### 关键操作解析 为了完成这些任务,具体来说: 1. **初始化响应结构体** 创建一个新的AVDT Discover Response消息实例用于填充后续所需的信息。 2. **枚举端点** 使用循环迭代访问每一个存在于系统内配置好的SEID (Service Endpoint Identifier),对于每个有效的SEID: - 获取对应Media Transport特性集; - 记录下诸如Mandatory Capabilities等重要字段值; 3. **组装回复报文** 把前面准备好的各项内容按照规定顺序写入到先前创建的Response Message对象里边去。 4. **发送应答帧** 利用底层通信接口将最终形成的完整Discover Response传送给对方节点。 ```c void avdt_ccb_hdl_discover_cmd(tAVDT_CCB *p_ccb, BT_HDR *p_msg) { tAVDT_MSG msg; // 初始化discover response message... for (int i = 0; i < MAX_SEPS; ++i) { if (valid_sep(i)) { append_to_response(&msg, get_capabilities_for_seid(i)); } } send_message(p_ccb->peer_addr, &msg); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值