len = ntohl(len); struct Msg *msg = malloc(sizeof(struct Msg) + len); if (msg == NULL) { fprintf(stderr, "malloc() failed\n"); return NULL; } msg->len = len; uint32_t total_bytes_received = 0; uint32_t bytes_received = 0; while (total_bytes_received < UINT32_MAX) { bytes_received = recv(sockfd, msg->buf + total_bytes_received, len - total_bytes_received, 0); if (bytes_received == -1) { fprintf(stderr, "recv() failed\n"); return NULL; } total_bytes_received += bytes_received; if (total_bytes_received == len) { break; } } return msg; } 解释一下这段代码
时间: 2023-06-20 13:08:22 浏览: 78
这段代码实现了一个从网络套接字 sockfd 中接收一个消息的功能。具体来说,它首先接收一个 32 位的整数 len,表示消息的长度(以字节为单位)。接着,它分配一个大小为 len+sizeof(struct Msg) 的缓冲区,并将消息长度 len 存储在这个缓冲区的前 4 个字节中。然后,它使用 recv() 函数从 sockfd 中接收剩余的消息内容,并将其存储在缓冲区的剩余部分中。
该函数使用了一个循环来确保接收到完整的消息。在每次循环中,它尝试接收剩余的字节数,直到接收到的字节数达到了消息长度 len。如果 recv() 函数返回 -1,则表示接收失败,函数返回 NULL。否则,它返回一个指向该消息的指针,该指针指向一个 Msg 结构体,其中包含消息的长度和内容。
相关问题
unsigned int getRRs(char *q, dns_rr *rRecord){ uint32_t ipAddr; rRecord->ttl = ntohl(*(uint32_t*)(q)); //这里是ntohl,32bit数字的转化 char str[INET_ADDRSTRLEN]; struct in_addr addr; q+=sizeof(rRecord->ttl); rRecord->data_len = ntohs(*(uint16_t*)(q)); q+=sizeof(rRecord->data_len); if(rRecord->type == MX_TYPE){ q += 2; //将Preferencre的长度空出去 } if(rRecord->type == A_TYPE){ ipAddr = *(uint32_t*)(q); memcpy(&addr, &ipAddr, 4); char *ptr = inet_ntop(AF_INET, &addr, str, sizeof(str)); //转化为十进制点分值的IP地址 rRecord->rdata = (char*)malloc((strlen(ptr)+1)*sizeof(char)); strcpy(rRecord->rdata,ptr); return 4 + 2 + rRecord->data_len; } else if(rRecord->type == CNAME_TYPE){ char domainName[100]; memset(domainName, 0, 100); char *d = domainName; uint8_t count = 0; int i = 0; //完成报文中数字加域名形式至点分值的转换 while(1){ if(*q!='\0'){ count = *(uint8_t*)(q); q++; while(count){ memcpy(&(domainName[i]), q, sizeof(char)); count--; q++; i++; } domainName[i] = '.'; //加点 i++; } else{ domainName[i-1] = '\0'; //标注结束 q++; break; } } rRecord->rdata = (char*)malloc(i*sizeof(char)); memcpy(rRecord->rdata, domainName, i); //此时的i便为转换后变长字符串的长度了,经过了循环遍历 return 4 + 2 + rRecord->data_len +1; } else if(rRecord->type == MX_TYPE){ int firstlen = rRecord->data_len - 5; char domainName[100]; memset(domainName, 0, 100); char *d = domainName; //printf("d: %s\n", d); uint8_t count = 0; int i = 0; //count = ntohs(*(uint8_t*)(q)); //完成报文中数字加域名形式至点分值的转换 while(1){ if(*q!='\0'){ count = *(uint8_t*)(q); //printf("count:%d\n", count); q++; while(count){ //printf("i: %d\n", i); //printf("char1:%c\n", *q); memcpy(&(domainName[i]), q, sizeof(char)); //printf("domain name i: %c\n", domainName[i]); count--; q++; i++; } domainName[i] = '.'; //加点 i++; domainName[i] = '\0'; i++; break; } } strcpy(domainName, strcat(domainName, rRecord->name)); //由于压缩了指针,对两字符串进行拼接 //printf("Converted domain name: %s\n", domainName); int totalen = strlen(rRecord->name) + i; //拼接后总长度 rRecord->rdata = (char*)malloc(totalen*sizeof(char)); memcpy(rRecord->rdata, domainName, totalen); return 12+rRecord->data_len; } }
这段代码是一个函数,目的是从 DNS 报文中获取资源记录信息。输入参数 q 是一个指向 DNS 报文中资源记录段的指针,rRecord 是一个结构体,用于存储获取到的资源记录信息。该函数首先通过指针 q 获取资源记录的 TTL 字段,并使用 ntohl 函数将其转换为主机字节序,然后再获取数据长度字段,并使用 ntohs 函数将其转换为主机字节序。接下来,根据资源记录类型不同,分别进行不同的处理。如果是 A 记录类型,则将 IP 地址转换成十进制点分值的 IP 地址,并存储在 rRecord 结构体中,然后返回占用的字节数。如果是 CNAME 记录类型,则将域名进行数字加域名形式至点分值的转换,并存储在 rRecord 结构体中,然后返回占用的字节数。如果是 MX 记录类型,则先获取 Preference 字段的长度,然后再将域名进行转换,并将其与记录中的名称拼接起来,存储在 rRecord 结构体中,最后返回占用的字节数。
阅读全文