3D Scanner + Obj Loader -> Efficient Modeling

本项目介绍了一个使用NextEngine 3D扫描仪将现实中的物体数字化,并将其转化为计算机可读的OBJ格式文件的过程。通过OpenGL应用程序展示了扫描后的3D模型,并详细介绍了使用的GLM ObjLoader加载器。

 

This is a team project for my OpenGL class.

 

Project Description : Use NextEngine(R) 3D Scanner to scan some figure in real life you are interested into computer and export the data into obj format. Then adopt some 3rd-party OBJ loader into you OpenGL app. to display the figure.

 

1. Scanning: the figure cannot be too shiny or too big. Also, marking dots will help a lot for your later matching operation.

2. Obj Loader: We use GLM.

3. OGL framework: no big deal.

 

Now check it out :

  

 

arp_scanner.c:/* Copyright (c) 2009-2025 TP-LINK Technologies CO.,LTD. * * file None * brief None * details None * * author Wei Gan <ganwei@tp-link.com.hk> * version 1.0.0 * date 31Jul25 * * history \arg version, date, author, modification */ /**************************************************************************************************/ /* INCLUDE */ /**************************************************************************************************/ #include <sys/socket.h> #include <linux/if_packet.h> #include <net/ethernet.h> #include <sys/ioctl.h> #include <netinet/in.h> #include <arpa/inet.h> #include <net/if.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "arp_scanner.h" /**************************************************************************************************/ /* DEFINES */ /**************************************************************************************************/ /**************************************************************************************************/ /* TYPES */ /**************************************************************************************************/ /**************************************************************************************************/ /* VARIABLES */ /**************************************************************************************************/ /**************************************************************************************************/ /* FUNCTIONS */ /**************************************************************************************************/ /* 创建原始socket */ int create_arp_socket() { int sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP)); if (sock < 0) { perror("socket"); return -1; } return sock; } /* * fn static int send_arp_request(int sockfd, const char *src_ip, const char *dest_ip, const char *ifname) * brief 发送ARP请求 * details None * * param[in] sockfd 套接字 * param[in] src_ip 源ip * param[in] ifname 网卡名 * param[out]None * return None * * retval None * note None */ static int send_arp_request(int sockfd, const char *src_ip, const char *dest_ip, const char *ifname) { // 获取接口索引 struct ifreq ifr; strncpy(ifr.ifr_name, ifname, IFNAMSIZ); if (ioctl(sockfd, SIOCGIFINDEX, &ifr) < 0) { perror("ioctl(SIOCGIFINDEX)"); return -1; } // 获取接口MAC地址 if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) < 0) { perror("ioctl(SIOCGIFHWADDR)"); return -1; } uint8_t src_mac[6]; memcpy(src_mac, ifr.ifr_hwaddr.sa_data, 6); // 构建以太网帧和ARP包 unsigned char packet[60] = {0}; struct ether_header *eth = (struct ether_header *)packet; struct ether_arp *arp = (struct ether_arp *)(packet + sizeof(struct ether_header)); /************** 填充以太网帧头 **************/ // 目标MAC: 广播地址 (FF:FF:FF:FF:FF:FF) memset(eth->ether_dhost, 0xFF, 6); // 源MAC: 接口MAC地址 memcpy(eth->ether_shost, src_mac, 6); // 以太网类型: ARP (0x0806) eth->ether_type = htons(ETHERTYPE_ARP); /************** 填充ARP包 **************/ // 硬件类型: 以太网 (1) arp->arp_hrd = htons(ARPHRD_ETHER); // 协议类型: IPv4 (0x0800) arp->arp_pro = htons(ETHERTYPE_IP); // 硬件地址长度: 6字节 (MAC) arp->arp_hln = 6; // 协议地址长度: 4字节 (IPv4) arp->arp_pln = 4; // 操作码: ARP请求 (1) arp->arp_op = htons(ARPOP_REQUEST); // 源MAC: 接口MAC地址 memcpy(arp->arp_sha, src_mac, 6); // 源IP: 将字符串转换为网络字节序 struct in_addr src_addr; if (inet_pton(AF_INET, src_ip, &src_addr) <= 0) { perror("inet_pton(src_ip)"); return -1; } memcpy(arp->arp_spa, &src_addr.s_addr, 4); // 目标MAC: ARP请求中设为全0 (未知) memset(arp->arp_tha, 0, 6); // 目标IP: 将字符串转换为网络字节序 struct in_addr dest_addr; if (inet_pton(AF_INET, dest_ip, &dest_addr) <= 0) { perror("inet_pton(dest_ip)"); return -1; } memcpy(arp->arp_tpa, &dest_addr.s_addr, 4); /************** 发送数据包 **************/ struct sockaddr_ll sa = { .sll_family = AF_PACKET, .sll_ifindex = ifr.ifr_ifindex, .sll_halen = ETH_ALEN, .sll_addr = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF} // 广播 }; if (sendto(sockfd, packet, sizeof(packet), 0, (struct sockaddr*)&sa, sizeof(sa)) < 0) { perror("sendto"); return -1; } return 0; } /* 处理ARP响应 */ static void process_arp_response(arp_scanner_t *scanner, unsigned char *buffer, size_t len) { struct ether_arp *arp = (struct ether_arp *)(buffer + sizeof(struct ether_header)); // 提取IP和MAC char ip_str[INET_ADDRSTRLEN]; inet_ntop(AF_INET, arp->arp_spa, ip_str, sizeof(ip_str)); pthread_mutex_lock(&scanner->lock); // 检查是否是新主机 int is_new = 1; arp_entry_t *entry = scanner->entries; while (entry) { if (strcmp(entry->ip, ip_str) == 0) { memcpy(entry->mac, arp->arp_sha, 6); entry->last_seen = time(NULL); is_new = 0; break; } entry = entry->next; } // 发现新主机 if (is_new) { arp_entry_t *new_entry = malloc(sizeof(arp_entry_t)); strcpy(new_entry->ip, ip_str); memcpy(new_entry->mac, arp->arp_sha, 6); new_entry->last_seen = time(NULL); new_entry->next = scanner->entries; scanner->entries = new_entry; // 打印到串口 printf("[NEW HOST] IP: %s, MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", ip_str, arp->arp_sha[0], arp->arp_sha[1], arp->arp_sha[2], arp->arp_sha[3], arp->arp_sha[4], arp->arp_sha[5]); } pthread_mutex_unlock(&scanner->lock); } /* 清理过期条目 */ static void clean_expired_entries(arp_scanner_t *scanner) { time_t now = time(NULL); pthread_mutex_lock(&scanner->lock); arp_entry_t **pp = &scanner->entries; // **pp 保存的是链表头节点地址 while (*pp) { arp_entry_t *entry = *pp; if (now - entry->last_seen > scanner->config.valid_time) { *pp = entry->next; free(entry); } else { pp = &entry->next; } } pthread_mutex_unlock(&scanner->lock); } /* 接收ARP响应 */ void *arp_scan_thread(void *arg) { arp_scanner_t *scanner = (arp_scanner_t *)arg; scanner->scanning = SCANNING_ON; while (scanner->scanning) { // 清理过期条目 clean_expired_entries(scanner); // 遍历IP范围 for (uint32_t ip = inet_addr(scanner->config.start_ip); ip <= inet_addr(scanner->config.end_ip); ip = ntohl(ntohl(ip) + 1)) { if (!scanner->scanning) break; // scanning为0,停止扫描 // 发送ARP请求 char dest_ip[16]; inet_ntop(AF_INET, &ip, dest_ip, sizeof(dest_ip)); send_arp_request(scanner->sockfd, SOURCE_IP, dest_ip, IFNAME); // 接收响应 unsigned char buffer[ETH_FRAME_LEN]; struct sockaddr_ll saddr; socklen_t saddr_len = sizeof(saddr); fd_set fds; // 设置发包间隔 struct timeval tv = { .tv_usec = scanner->config.send_interval * 1000 }; FD_ZERO(&fds); FD_SET(scanner->sockfd, &fds); if (select(scanner->sockfd + 1, &fds, NULL, NULL, &tv) > 0) { ssize_t len = recvfrom(scanner->sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&saddr, &saddr_len); if (len > 0) { process_arp_response(scanner, buffer, len); } } } // 等待扫描间隔 int sleep_count = scanner->config.scan_interval; while (sleep_count > 0 && scanner->scanning) { sleep(1); sleep_count--; } } close(scanner->sockfd); scanner->sockfd = -1; scanner->scanning = SCANNING_OFF; return NULL; }
最新发布
08-26
<think>好的,用户让我基于他们提供的arp.c和arp_scanner.c代码写一个技术文档。现在用户又提供了arp_scanner.c的内容,我需要结合之前的arp.c来整合文档。 首先,我需要通读这两份代码,理解它们的功能和结构。arp.c主要处理配置管理、线程控制、ubus接口等,而arp_scanner.c则涉及底层的ARP请求发送、响应处理以及扫描线程的具体实现。两者共同构成了一个ARP扫描模块。 接下来,我要确定文档的结构。之前的回答已经有一个arp.c的技术文档,现在需要将arp_scanner.c的内容整合进去。可能需要新增章节,比如底层实现细节、网络通信部分、线程处理等。 要注意用户可能的需求:他们可能希望文档详细说明模块的工作原理、各个组件的交互、数据结构、接口定义,以及潜在的问题和优化建议。同时,用户可能希望文档结构清晰,便于开发人员理解和维护。 在分析代码时,发现arp_scanner.c中的send_arp_request函数负责构建和发送ARP请求,process_arp_response处理响应,arp_scan_thread是主扫描线程。这些部分需要详细描述其工作流程和实现细节。 另外,需要整合两部分的错误处理和线程安全机制。例如,arp_scanner.c中的清理过期条目和互斥锁的使用,以及arp.c中的配置持久化和ubus接口注册。 还需要考虑潜在的问题,比如IP范围遍历时的越界问题,发送间隔和扫描间隔的协调,以及内存管理是否安全。在相关问题部分,提出这些问题可以帮助用户进一步思考优化。 最后,确保文档涵盖所有关键点,包括模块架构、数据结构、核心功能、接口说明、线程安全、错误处理和优化建议,并在最后列出相关问题供用户参考。</think>### ARP扫描模块技术文档(完整版) --- #### 1. 模块架构全景 ``` +-------------------------+ +------------------------+ | 管理接口层 | | 网络通信层 | | (Ubus/DMS) |<--->| (Socket API) | +-------------------------+ +------------------------+ | | +-------------------------+ +------------------------+ | 核心控制层 | | 协议处理层 | | (arp_scanner_t) | | (ARP协议编解码) | +-------------------------+ +------------------------+ | | +-------------------------+ +------------------------+ | 持久化存储层 | | 系统资源层 | | (Flash配置管理) | | (线程/内存管理) | +-------------------------+ +------------------------+ ``` --- #### 2. 核心数据流分析 ```mermaid graph TD A[ARP请求] -->|原始套接字| B(以太网帧构建) B --> C{广播发送} C --> D[ARP响应捕获] D --> E[协议解析] E --> F{新设备检测} F -->|是| G[链表插入] F -->|否| H[更新时间戳] G --> I[串口输出] H --> J[结果缓存] ``` --- #### 3. 关键实现细节 ##### 3.1 ARP请求构建 ```c // 以太网帧头构造 ether_header->ether_dhost = 广播地址(FF:FF:FF:FF:FF:FF) ether_header->ether_shost = 本机MAC ether_header->ether_type = ETH_P_ARP(0x0806) // ARP包构造 arp_hrd = ARPHRD_ETHER(1) arp_pro = ETH_P_IP(0x0800) arp_op = ARPOP_REQUEST(1) arp_sha = 本机MAC arp_spa = 源IP地址 arp_tha = 00:00:00:00:00:00 arp_tpa = 目标IP地址 ``` ##### 3.2 IP地址遍历算法 ```c for (uint32_t ip = inet_addr(start_ip); ip <= inet_addr(end_ip); ip = ntohl(ntohl(ip) + 1)) { // 处理每个IP地址 } ``` ⚠️ 注意:该实现可能存在IP地址越界风险,建议增加: ```c if (ntohl(ip) == 0xFFFFFFFF) break; // 防止地址回绕 ``` --- #### 4. 线程状态机 ``` [STOPPED] --start_scan--> [SCANNING] --stop_scan--> [STOPPED] ↑ ↓ └----[CLEANUP]←定期清理←┘ ``` --- #### 5. 内存管理策略 1. **链表节点分配**:每次发现新设备时动态分配`arp_entry_t` 2. **内存回收机制**: - `clean_expired_entries()`定期清理过期节点 - `clear_result()`强制清除所有节点 3. **潜在风险**: - 未限制最大节点数可能导致内存耗尽 - 建议增加LRU缓存机制 --- #### 6. 性能关键参数 | 参数 | 默认值 | 调整建议 | 影响分析 | |------------------|----------|-------------------------|------------------------| | send_interval | 100ms | ≥50ms | 网络负载/扫描速度 | | scan_interval | 30s | ≥10s | 资源占用/实时性 | | valid_time | 60s | 2×scan_interval | 结果准确性 | | MAX_RES_BUFF | 100 | 根据网络规模动态调整 | 结果存储容量 | --- #### 7. 安全增强建议 1. **输入验证**: - 增加IP地址合法性检查 - 限制配置参数取值范围 2. **资源保护**: ```c // 建议在socket创建时增加SO_RCVTIMEO struct timeval timeout = {1, 0}; setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); ``` 3. **异常处理**: - 增加信号处理机制防止崩溃 - 实现配置回滚功能 --- #### 8. 典型调用序列 ```mermaid sequenceDiagram 用户->>Ubus: set_arp_config Ubus->>模块: 配置更新 模块->>Flash: 持久化存储 用户->>Ubus: start_scan Ubus->>线程管理: 创建扫描线程 线程管理->>网络层: 发送ARP请求 网络层->>协议层: 接收响应 协议层->>核心逻辑: 更新设备列表 核心逻辑->>用户: 返回扫描结果 ``` --- #### 9. 已知问题与限制 1. **IPv4地址限制**:不支持IPv6地址扫描 2. **单网卡绑定**:目前只能绑定默认接口 3. **无QoS控制**:可能影响其他网络服务 4. **配置同步问题**:动态配置更新可能存在延迟 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值