不完全详解os block header

本文介绍了Oracle数据库中OSBlockHeader的基本概念及其包含的关键信息,并通过实际案例演示了如何使用bbed工具进行OSBlockHeader的分析与修复。

原帖地址 http://www.killdb.com/?p=390

什么是os block header?它有哪些作用?如果它损害了怎么办?

下面是关于os block header的解释,来自MOS。
The OS Block Header is in the first datafile block. It is used by Oracle
to store Operating System information.
It is the Block Zero. It is not the datafile header which is in Oracle Block 1.
Corruption in Block Zero will not cause damage to the data and it is not detected
by dbverify/rman. When this block is corrupted the database may be opened with no
errors. This block contains a magic number to identify the platform, the size of
the datafile in
我这里使用bbed来进行分析,当然你也可以使用UE或dd等命令来进行操作。
BBED> info
File# Name Size(blks)
----- ---- ----------
 1 /oracle/product/oradata/roger/system01.dbf 61440
 2 /oracle/product/oradata/roger/undotbs01.dbf 137600
 3 /oracle/product/oradata/roger/sysaux01.dbf 32000
 4 /oracle/product/oradata/roger/users01.dbf 12800
 5 /oracle/product/oradata/roger/roger1.dbf 2560
BBED> set file 5 block 0
 FILE# 5
 BLOCK# 0
BBED> map /v
File: /oracle/product/oradata/roger/roger1.dbf (5)
Block: 0 Dba:0x01400000
------------------------------------------------------------
BBED-00400: invalid blocktype (00)
BBED> d /v
File: /oracle/product/oradata/roger/roger1.dbf (5)
Block: 0 Offsets: 0 to 511 Dba:0x01400000
-------------------------------------------------------
00a20000 0000c0ff 00000000 00000000 l .?...?........
66f00000 00200000 000a0000 7d7c7b7a l f?.. ......}|{z
a0810000 00000000 00000000 00000000 l ?..............
00000000 00000000 00000000 00000000 l ................
00000000 00000000 00000000 00000000 l ................
........
00000000 00000000 00000000 00000000 l ................
<16 bytes per line>
我们可以看到大部分地方是没信息的,只有几个地方,分别是如下:
offset 1~2 00a2
offset 7~8 c0ff
offset 17~18 66f0
offset 22~23 2000
offset 26~27 0a00
offset 29~32 7d7c7b7a
offset 33~34 a081
offset 22~23 的两个byte,这里对应的是block大小,如下:
SQL> select to_number(2000,'XXXX') from dual;
TO_NUMBER(2000,'XXXX')
----------------------
 8192
offset 26~27 的0a00 是对应的datafile的大小,实际上是block个数,如下:
SQL> select to_char(2560,'xxx') from dual;
TO_C
----
a00
SQL> !
[oracle@roger ~]$ ls -ltr /oracle/product/oradata/roger/roger1.dbf
-rw-r----- 1 oracle dba 20979712 Sep 4 18:09 /oracle/product/oradata/roger/roger1.dbf
[oracle@roger ~]$
20979712/8192 - 1个os block header =2560
offset 29~32 的4个byte是magic number,10g版本所有平台该4个byte值都完全一样。
至于说其他版本比如9i,11gR1,11gR2我还没进行测试。
[oracle@roger ~]$ dbfsize /oracle/product/oradata/roger/roger1.dbf
Database file: /oracle/product/oradata/roger/roger1.dbf
Database file type: file system
Database file size: 2560 8192 byte blocks
[oracle@roger ~]$
如何才能知道下面这几个的含义呢?
offset 1~2 00a2
offset 7~8 c0ff
offset 17~18 66f0
于是我想到了将该datafile resize后来进行观察,看看发生了什么改变。
SQL> alter database datafile 5 resize 30m;
Database altered.
SQL>
BBED> d /v
File: /oracle/product/oradata/roger/roger1.dbf (5)
Block: 0 Offsets: 0 to 511 Dba:0x01400000
-------------------------------------------------------
00a20000 0000c0ff 00000000 00000000 l .?...?........
66f50000 00200000 000f0000 7d7c7b7a l f?.. ......}|{z
a0810000 00000000 00000000 00000000 l ?..............
00000000 00000000 00000000 00000000 l ................
00000000 00000000 00000000 00000000 l ................
...........
00000000 00000000 00000000 00000000 l ................
<16 bytes per line>

经过一对比,我们可以发现如下规律:
f566 62822
f066 61542 --->62822-61542=1280
SQL> select (blocks -2560) from dba_data_files where file_id=5;
(BLOCKS-2560)
-------------
 1280

所以我猜测ffset 17~18 这2个byte应该是跟datafile的增长相关,单位为block。
另外通过前面dbfsize的结果来看,我猜测offset 2的a2代表的应该是datafile类型。
至于其他一些offset的含义,目前我还不知道是什么意思,如果谁知道,记得告诉我。
最后来谈谈跟os block header相关的数据库恢复。
如果os block header出现损坏,你可以会遇到如下错误:
ORA-27047: unable to read the header block of file
出现该错误其实并不要紧,可以通过resize datafile来重新格式化os block header,
关于这点大家可以参考MOS文档,如果是文件系统本身损坏了,那么可能需要用fsck等
os工具去进行磁盘的修改,MOS文档如下:
How to detect and fix a corruption in the datafile OS header/Block Zero - ORA-27047 [ID 360032.1]
最后补充一点,因为的我的虚拟机是linux x86,属于little 平台,所以用bbed dump出来
的字节序是反的,如果觉得这样看着不方便,我们可以借助dd 和od命令来看,如下:
[oracle@roger ~]$ dd if=/oracle/product/oradata/roger/roger1.dbf bs=8192 count=1 | od -x | head -4
1+0 records in
1+0 records out
0000000 a200 0000 0000 ffc0 0000 0000 0000 0000
0000020 f566 0000 2000 0000 0f00 0000 7c7d 7a7b
0000040 81a0 0000 0000 0000 0000 0000 0000 0000
0000060 0000 0000 0000 0000 0000 0000 0000 0000
或者
[oracle@roger ~]$ od -x -N 64 /oracle/product/oradata/roger/roger1.dbf
0000000 a200 0000 0000 ffc0 0000 0000 0000 0000
0000020 f566 0000 2000 0000 0f00 0000 7c7d 7a7b
0000040 81a0 0000 0000 0000 0000 0000 0000 0000
0000060 0000 0000 0000 0000 0000 0000 0000 0000
0000100
[oracle@roger ~]$
<think>我们正在讨论Ymodem协议,它是Xmodem协议的扩展版本。Ymodem协议支持批量文件传输、更大的数据块(1024字节)以及更可靠的文件信息传输。根据引用[1]中提到的Xmodem协议基础,我们可以推断Ymodem在错误检测和纠正机制上与之类似,但有所增强。同时,引用[3]提到了Ymodem接收函数调用链,引用[4]则提供了升级状态的结构体,这些都与实现相关。 Ymodem协议工作原理: 1.初始化:接收方发送一个'C'(表示要求使用CRC校验)或NAK(要求使用校验和)来启动传输。通常现代实现使用CRC。 2.文件信息传输:发送方首先发送一个包含文件名、文件大小和时间戳等信息的首包(使用SOH或STX作为起始,SOH表示128字节块,STX表示1024字节块)。在Ymodem中,首包通常是128字节的块,包含文件名和文件大小等信息。3.数据块传输:后续数据块可以是128字节(SOH)或1024字节(STX)。每个数据块包括:-起始字节:SOH(0x01)或STX(0x02)-块编号:1字节,从1开始,模256(0-255,然后回到0)-块编号的补码:1字节(255-块编号)-数据:128或1024字节-校验:2字节CRC(或1字节校验和,但通常使用CRC) 4.确认机制:接收方对每个数据块进行校验,如果正确则发送ACK,然后发送方发送下一块;如果错误则发送NAK,发送方重发当前块。如果连续多次失败,发送方可能终止传输。 5.结束传输:当发送方发送完所有数据后,会发送一个EOT(Endof Transmission,0x04)信号。接收方收到EOT后,发送ACK确认。然后发送方会发送一个空文件头(即文件名长度为0)表示传输结束,接收方再次ACK后传输完成。 在Ymodem中,支持多个文件传输(批量传输),即在第一个文件传输完成后,发送方会继续发送下一个文件的首包,直到遇到空文件头。现在,我们提供C语言和Python的实现示例。由于完整实现较长,这里只给出关键部分的代码框架。 C语言实现示例(接收端):```c#include<stdint.h> #include<stdio.h>#include <string.h> //根据引用[4]的状态结构体typedefstruct {uint16_tpkg_num :12;//当前包号uint16_trunning :1;//是否正在运行uint16_terrno:3;//错误码} UPDATE_STATUS;//串口接收函数(需根据硬件平台实现) uint8_tUSART_ReceiveData(void) {//从串口读取一个字节//示例中省略具体实现return0; }//串口发送函数void USART_SendData(uint8_t data) {//向串口发送一个字节//示例中省略具体实现}//接收一个字节(带超时处理) intReceive_Byte(uint8_t*c, uint32_ttimeout){//实现超时等待接收一个字节//成功返回0,超时返回-1return0;} //计算CRC16uint16_tcalc_crc(constuint8_t *data,size_tlength){//实现CRC16计算(例如使用Xmodem的CRC16)return0; }//接收一个数据包intReceive_Packet(uint8_t*buf, size_t *size,uint32_t timeout) {uint8_theader[3];uint16_t crc;uint8_tblock_num, block_num_complement;//接收起始字节、块编号和补码if(Receive_Byte(&header[0], timeout) !=0) return-1; //超时if(header[0]!= SOH &&header[0]!= STX){//可能是EOTif (header[0]== EOT){*size =0;return0;//正常结束}return -2; //错误起始字节}if (Receive_Byte(&block_num,timeout)!=0)return -1;if(Receive_Byte(&block_num_complement,timeout)!=0)return -1;//检查块编号和补码是否匹配if((uint8_t)(~block_num) !=block_num_complement) {return-3;}//确定数据长度size_tdata_len= (header[0]== SOH)?128 :1024;for(size_t i=0; i< data_len;i++){if (Receive_Byte(&buf[i], timeout) !=0) return-1;}//接收2字节CRCuint8_t crc_bytes[2];if (Receive_Byte(&crc_bytes[0],timeout)!=0)return -1;if(Receive_Byte(&crc_bytes[1], timeout) !=0) return-1;crc= (crc_bytes[0]<<8)| crc_bytes[1];//计算数据的CRC并比较uint16_tcalc =calc_crc(buf, data_len);if(crc !=calc){return -4;// CRC错误}*size= data_len;returnblock_num; //返回块编号(从1开始) }// Ymodem接收主函数void Ymodem_Receive(void){uint8_t buf[1024];size_t size;uint8_tresponse= 'C';//初始要求使用CRCUPDATE_STATUS status= {0};status.running=1;while(status.running) {//发送'C'启动传输USART_SendData(response);//等待接收数据包intret =Receive_Packet(buf, &size,1000);//1秒超时if(ret==0 &&size ==0) {//收到EOTUSART_SendData(ACK);//继续等待下一个文件(或结束空包)continue;} elseif (ret >0){//成功接收到一个数据包//处理数据包(首包为文件信息,后续为数据)//这里简化处理:如果是首包,则解析文件名和大小if(status.pkg_num ==0){//首包,buf中前128字节包含文件名、文件大小等信息(以空格分隔,以0结束)char *filename =(char*)buf;if (filename[0]== '\0'){//空文件名表示传输结束USART_SendData(ACK);break;}//解析文件信息,然后准备接收数据//示例省略解析过程}else {//数据包,写入文件}status.pkg_num= (status.pkg_num+1)&0xFFF; //12位包号USART_SendData(ACK);}else {//错误处理USART_SendData(NAK);//错误计数等}}status.running =0; }``` Python实现示例(发送端): ```pythonimport serialimporttimeimport struct#CRC16计算(Xmodem) defcrc16(data):crc=0forbytein data:crc=crc^ (byte <<8)for _in range(8):if crc &0x8000:crc= (crc<<1)^0x1021else:crc =crc<<1crc &=0xFFFFreturncrcdefsend_packet(ser,block_num,data,block_size=1024):#块编号模256block_num_byte =block_num%256#起始字节:128字节用SOH(0x01),1024字节用STX(0x02)start_byte =b'\x01' ifblock_size==128 elseb'\x02'#构造数据包header= struct.pack('>BB',block_num_byte,0xFF- block_num_byte)#计算CRC16crc=crc16(data)packet =start_byte +header +data +struct.pack('>H', crc)ser.write(packet)def ymodem_send(ser, files):#等待'C'whileTrue:ifser.read(1) ==b'C':breakforfile_infoin files:#发送文件信息包(首包)#文件名和文件大小等信息filename =file_info['name'].encode()file_size =str(file_info['size']).encode()#首包数据:文件名、空格、文件大小、空格、时间戳(可选)等,最后补0header_data= filename+ b' '+ file_size +b'' +b'0'* (128 -len(filename) -len(file_size)-2)#首包使用128字节块send_packet(ser,0,header_data,128)#等待ACKifser.read(1) !=b'\x06':#ACKraise Exception("ACKnot receivedafter fileheader")#发送文件内容withopen(file_info['path'],'rb') asf:block_num =1while True:chunk =f.read(1024)ifnot chunk:break#足1024字节要填充0x1A(Ctrl-Z)if len(chunk) <1024:chunk+= b'\x1a' *(1024 -len(chunk))send_packet(ser, block_num,chunk,1024)#等待ACKack =ser.read(1)if ack !=b'\x06':raise Exception("ACKnot receivedafter datablock")block_num +=1#发送EOTser.write(b'\x04')#等待ACKifser.read(1) !=b'\x06':raise Exception("ACKnot receivedafter EOT")#发送空文件名包表示结束send_packet(ser,0,b'\x00'*128,128)#等待最后一个ACKser.read(1)#使用示例ser =serial.Serial('/dev/ttyUSB0',115200, timeout=1) files= [{'name': 'test.txt', 'size':os.path.getsize('test.txt'), 'path':'test.txt'}] ymodem_send(ser,files)ser.close() ```注意:以上代码仅为示例框架,实际应用中需要处理各种异常和超时情况,并且需要根据具体硬件平台调整串口通信部分。相关问题: 1. Ymodem协议与Xmodem协议的主要区别是什么?2.在Ymodem协议中,如何处理多个文件的传输?3.如何优化Ymodem协议在大文件传输时的性能?</think>### Ymodem协议详解 Ymodem协议是Xmodem协议的增强版本,主要改进包括: 1. **批处理传输**:支持多个文件连续传输 2. **数据块扩展**:支持1024字节数据块(Xmodem仅128字节) 3. **文件信息传输**:可携带文件名、大小和时间戳 4. **CRC校验**:默认使用16位CRC校验(比Xmodem的校验和更可靠) 5. **高效重传**:支持选择性重传错误数据块 #### 工作流程 1. **初始化** - 接收端发送字符`'C'`(要求使用CRC模式) - 发送端回应文件名信息包(128字节块) 2. **数据传输** ```mermaid graph TD A[发送1024字节数据块] --> B{接收端校验} B -->|成功| C[发送ACK] B -->|失败| D[发送NAK] C --> E[发送下一块] D --> A[重传当前块] ``` 3. **结束传输** - 发送端发送`EOT`(0x04)表示文件结束 - 接收端回应`ACK`后,发送端发送空文件名包表示会话结束 #### C语言实现示例(接收端) ```c #include <stdint.h> // 引用[4]的状态结构体 typedef struct { uint16_t pkg_num : 12; // 当前包号 uint16_t running : 1; // 传输状态标志 uint16_t errno : 3; // 错误代码 } UPDATE_STATUS; // 核心接收函数(基于引用[3]的调用链) uint8_t Ymodem_Receive(void) { UPDATE_STATUS status = {0}; status.running = 1; while(status.running) { uint8_t header = Receive_Byte(); if(header == SOH) { // 128字节块 ProcessBlock(128); } else if(header == STX) { // 1024字节块 ProcessBlock(1024); } else if(header == EOT) { Send_ACK(); status.running = 0; } } return status.errno; } // 数据块处理函数 void ProcessBlock(uint16_t size) { uint8_t data[1024]; uint16_t crc_received, crc_calculated; // 读取块编号和补码 uint8_t block_num = Receive_Byte(); uint8_t inv_block = Receive_Byte(); // 验证块编号有效性 if((block_num + inv_block) != 0xFF) { Send_NAK(); return; } // 读取数据 for(int i=0; i<size; i++) { data[i] = Receive_Byte(); } // 读取CRC (2字节) crc_received = (Receive_Byte() << 8) | Receive_Byte(); crc_calculated = Calculate_CRC(data, size); // 校验结果处理 if(crc_received == crc_calculated) { Save_Data(data, size); Send_ACK(); } else { Send_NAK(); } } ``` #### Python实现示例(发送端) ```python import serial import crcmod def ymodem_send(port, filename): ser = serial.Serial(port, 115200, timeout=1) crc16 = crcmod.predefined.Crc('xmodem') # 等待接收端'C'信号 while ser.read(1) != b'C': pass # 发送文件信息包 (128字节) file_info = f"{filename}\0{os.path.getsize(filename)}\0".encode() file_info += b'\x00'*(128 - len(file_info)) # 填充到128字节 send_block(ser, 0, file_info, 128) # 块号0表示文件头 # 发送文件数据 (1024字节块) block_num = 1 with open(filename, 'rb') as f: while chunk := f.read(1024): if len(chunk) < 1024: chunk += b'\x1A' * (1024 - len(chunk)) # 填充Ctrl-Z send_block(ser, block_num % 256, chunk, 1024) block_num += 1 # 发送结束序列 ser.write(b'\x04') # EOT ser.write(b'\x00'*128) # 空文件名包 def send_block(ser, block_num, data, size): header = bytes([0x02 if size==1024 else 0x01, block_num, 0xFF - block_num]) crc = crc16.new(data).crcValue packet = header + data + crc.to_bytes(2, 'big') ser.write(packet) # 等待ACK/NAK while (resp := ser.read(1)) not in (b'\x06', b'\x15'): pass if resp == b'\x15': # NAK send_block(ser, block_num, data, size) # 重传 ``` ### 关键特性对比 | 特性 | Xmodem | Ymodem | |--------------|--------------|----------------| | **数据块** | 128字节 | 128/1024字节 | | **文件信息** | 支持 | 支持 | | **多文件** | 单文件 | 批处理 | | **校验方式** | 校验和/CRC | 强制CRC | | **效率** | 较低 | 高(提升8倍) | ### 实际应用注意事项 1. **超时处理**:需实现超时重传机制(建议3秒) 2. **错误恢复**:连续10次NAK后应终止会话 3. **数据填充**:足块大小时填充`0x1A`(Ctrl-Z) 4. **文件名编码**:建议使用ASCII字符集 5. **波特率适配**:支持300-115200bps速率[^1][^2]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值