gpt4 book ai didi

c - 什么时候在 C 语言中使用 ntohs 和 ntohl?

转载 作者:太空狗 更新时间:2023-10-29 16:01:33 26 4
gpt4 key购买 nike

我对何时使用 ntohs 和 ntohl 感到很困惑。我知道何时将 ntohs 用于 uint16_t 和 ntohl uint32_t。但是那些具有 unsigned int 或指定了特定位数的那些(例如 u_int16_t doff:4;)呢?

这是我用来演示问题的工作代码:

// Utility/Debugging method for dumping raw packet data
void dump(const unsigned char *data, int length) {
unsigned int i;
static unsigned long pcount = 0;

// Decode Packet Header
struct ether_header *eth_header = (struct ether_header *) data;

printf("\n\n === PACKET %ld HEADER ===\n", pcount);

printf("\nSource MAC: ");
for (i = 0; i < 6; ++i) {
printf("%02x", eth_header->ether_shost[i]);
if (i < 5) {
printf(":");
}
}

printf("\nDestination MAC: ");
unsigned short ethernet_type = ntohs(eth_header->ether_type);
printf("\nType: %hu\n", ethernet_type); //Why not nthos?

if (ethernet_type == ETHERTYPE_IP) { //IP Header
printf("\n == IP HEADER ==\n");
struct ip *ip_hdr = (struct ip*) (data + sizeof(struct ether_header));
unsigned int size_ip = ip_hdr->ip_hl * 4; //why no nthos or nthol
printf("\nip_hdr->ip_hl: %u", ip_hdr->ip_hl); //why no nthos or nthol
printf("\nIP Version: %u", ip_hdr->ip_v); //why no nthos or nthol
printf("\nHeader Length: %u", ip_hdr->ip_hl); //why no nthos or nthol
printf("\nTotal Length: %hu", ntohs(ip_hdr->ip_len)); //?is this right?

// TCP Header
printf("\n== TCP HEADER ==\n");
struct tcphdr *tcp_hdr = (struct tcphdr*) (data + sizeof(struct ether_header) + size_ip);
unsigned int size_tcp = tcp_hdr->doff * 4; //why no nthos or nthol
printf("\n Source Port: %" PRIu16, ntohs(tcp_hdr->th_sport));
printf("\n Destination Port: %" PRIu16, ntohs(tcp_hdr->th_dport));
printf("\n fin: %" PRIu16, tcp_hdr->fin ); //As this is 1 bit, both nthos or nthol will work
printf("\n urg: %" PRIu16, tcp_hdr->urg ); //As this is 1 bit, both nthos or nthol will work
printf("\n ack_seq: %" PRIu32, ntohl(tcp_hdr->ack_seq));

u_int16_t sourcePort = ntohs(tcp_hdr->th_sport);
u_int16_t destinationPort = ntohs(tcp_hdr->th_sport);

if (sourcePort == 80 || destinationPort == 80){
printf("\n\nPORT 80!!!\n");

//Transport payload!
printf("\n\ === TCP PAYLOAD DATA == \n");

// Decode Packet Data (Skipping over the header)
unsigned int headers_size = ETH_HLEN + size_ip + size_tcp;
unsigned int data_bytes = length - headers_size;
const unsigned char *payload = data + headers_size;

const static int output_sz = 500; // Output this many bytes at a time
while (data_bytes > 0) {
int output_bytes = data_bytes < output_sz ? data_bytes : output_sz;
// Print data in raw hexadecimal form
printf("| ");
// Print data in ascii form
for (i = 0; i < output_bytes; ++i) {
char byte = payload[i];
if ( (byte > 31 && byte < 127) || byte == '\n') {
// Byte is in printable ascii range
printf("%c", byte); //why no nthos or nthol
} else {
printf(".");
}
}
payload += output_bytes;
data_bytes -= output_bytes;
}
}

}

pcount++;
}

如您所见,有时我使用 ntohs/ntohl,有时两者都不用。我不明白什么时候使用哪个。

最佳答案

But what about those with unsigned int

原则上,如前所述,C 不保证 unsigned int 的大小。 ;有平台可以intunsigned int是 16 位的,例如 PDP-11,以及带有一些编译器的摩托罗拉 68k 处理器(其他编译器使它们成为 32 位),并且对于某些 16 位微处理器来说,情况可能仍然如此。

因此,如果您通过网络发送数据,最好使用 <stdint.h> 中定义的类型如果可以的话。

实际上,您使用的机器几乎肯定有一个 32 位 unsigned int , although some Cray machines have 64-bit int and even short !但最好还是使用 <stdint.h> 中定义的类型.

or those where a specific amount of bits is specified (e.g. u_int16_t doff:4;).

如果一个值比一个字节短,如 4 位字段的情况,则字节顺序无关紧要。

但是,请注意位字段 1、2 或 4 字节序列中的顺序不是由 C 指定的, 所以你不应该在通过网络发送的数据中使用位域。 (是的,一些 UN*Xes 碰巧在 IPv4 和 TCP header 的结构中使用它们,但这只有在供应商用于他们支持的体系结构的编译器都以相同的顺序放置位域的情况下才有效,并且如果第三方GCC 等编译器做同样的事情。)

所以处理 IPv4 header 的正确方法是做一些事情,比如

struct ip {
uint8_t ip_vhl; /* header length, version */
#define IP_V(ip) (((ip)->ip_vhl & 0xf0) >> 4)
#define IP_HL(ip) ((ip)->ip_vhl & 0x0f)
uint8_t ip_tos; /* type of service */
uint16_t ip_len; /* total length */
uint16_t ip_id; /* identification */
uint16_t ip_off; /* fragment offset field */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
uint8_t ip_ttl; /* time to live */
uint8_t ip_p; /* protocol */
uint16_t ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */
};

使用那个结构来声明你的ip_hdr指向 IP header 的指针,以及:

  • 要提取版本,请使用 IP_V(ip_hdr) ;
  • 要提取 header 长度,请使用 IP_HL(ip_hdr) .

如果您的供应商的 ip.h header 使用位域,不要使用供应商的 ip.h header ;使用你自己的标题。事实上,即使您的供应商的 ip.h header 使用位域,不要使用供应商的ip.h header ;使用你自己的标题。毕竟,IP header 的定义并不依赖于操作系统......

(这就是 tcpdump 现在为几个版本所做的;以上内容摘自它的 ip.h。)

关于c - 什么时候在 C 语言中使用 ntohs 和 ntohl?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27299634/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com