所以,长话短说:我的程序接收到一个代表网络数据包的原始字节(u_char)缓冲区。我正在尝试解析该数据包中的信息,并且正在使用系统定义的标头结构(ether_header、ip、ip6、tcphdr、udphdr)来解析。我已经在 Linux 和 AIX 上实现了它并且它工作,但由于某种原因,当我在 Solaris 上执行此操作时,我不断收到总线错误。
我获取数据的方式基本上只是将缓冲区的每个部分转换为结构之一并读取数据。例如,如果我有
u_char buffer[] = {...some bytes...};
struct ether_header *ethdr = (struct ether_header *)buffer;
struct ip *iphdr = (struct ip *) (buffer + sizeof(struct ether_header));
etc. etc.
然后我可以获得我需要的信息,例如:
iphdr->ip_v; //to get the version
etc->etc; //to get whatever piece of data I need
通常,在 Linux 和 AIX 上这可以正常工作(某些结构在系统中具有不同的名称,但这不是重点),但是在尝试在 Solaris 上运行它时,当它到达iphdr->ip_v;
after时,我不断收到总线错误struct ip *iphdr = (struct ip *) (buffer + sizeof(struct ether_header));
。经过一番调查,我发现这是由于试图访问未对齐的内存造成的。这是有道理的,因为以太网报头的大小只有 14 个字节,因此 IP 报头在数组中不是字节对齐的。
我尝试解决此问题的方法是在尝试阅读之前将相关部分复制到单独的缓冲区中
memcpy(&buffer_copy, buffer + sizeof(struct ether_header), sizeof(struct ip));
struct ip *iphdr = &buffer_copy;
iphdr->ip_v;
etc.
这有效,但我不明白为什么。为什么 memcpy 在尝试访问相同的内存位置时不抛出总线错误?我不太喜欢我想出的解决方案,我正在努力更好地了解情况,这样我就可以想出别的办法。我可能错过了一块拼图吗?