多线程环境下安全拆分IP:Port的C语言实现求助
稳定拆分IP:Port字符串的多线程安全方案
问题背景
在多线程程序中需批量拆分IP:Port格式字符串,提取IP字符串与端口整数。原方案使用strtok频繁出现错误和段错误,且依赖strdup处理指针操作繁琐;尝试strchr仅能获取端口部分,无法提取IP。需实现永不段错误、稳定可靠的拆分方案。
原代码与报错
线程启动函数
void* startthread() { do { char* proxy = "127.0.0.1:443"; char* buffered = strdup(proxy); char* host = strtok(buffered,":"); int port = atoi(strtok(NULL,":")); printf("%s:%d",host,port); }while(1); }
GDB报错信息
Thread 8 "main" received signal SIGSEGV, Segmentation fault. [Switching to Thread 0x7ffff4a34700 (LWP 47410)] __GI_____strtol_l_internal (nptr=0x0, endptr=endptr@entry=0x0,
原代码问题分析
strtok线程不安全:依赖静态存储区维护状态,多线程并发调用会互相干扰,导致strtok(NULL, ":")返回空指针,传入atoi后触发段错误。- 无错误处理:未检查
strdup内存分配失败、strtok返回空指针的情况,直接操作空指针引发崩溃。 - 内存泄漏:
strdup分配的内存未释放,长期运行会耗尽内存。
解决方案
方案一:strchr手动拆分(线程安全,无动态分配)
通过strchr定位冒号,手动截取IP部分,用strtol校验端口合法性:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <netinet/in.h> void* startthread(void* arg) { do { const char* proxy = "127.0.0.1:443"; // 实际场景可替换为传入参数 char host[INET_ADDRSTRLEN] = {0}; // IPv4用INET_ADDRSTRLEN,IPv6用INET6_ADDRSTRLEN int port = 0; // 定位冒号位置 const char* colon_pos = strchr(proxy, ':'); if (colon_pos == NULL) { continue; // 格式错误,跳过 } // 截取IP部分,防止缓冲区溢出 size_t host_len = colon_pos - proxy; if (host_len >= sizeof(host)) { continue; // IP过长,跳过 } memcpy(host, proxy, host_len); host[host_len] = '\0'; // 确保字符串终止 // 提取并校验端口 char* endptr = NULL; port = strtol(colon_pos + 1, &endptr, 10); if (endptr == colon_pos + 1 || port < 1 || port > 65535) { continue; // 端口无效,跳过 } printf("%s:%d\n", host, port); } while (1); return NULL; }
方案二:sscanf简洁拆分(线程安全)
利用sscanf的格式控制直接提取IP和端口,代码更简洁:
#include <stdio.h> #include <string.h> #include <netinet/in.h> void* startthread(void* arg) { do { const char* proxy = "127.0.0.1:443"; char host[INET_ADDRSTRLEN] = {0}; int port = 0; // 格式匹配:读取除冒号外的字符,再读取端口 if (sscanf(proxy, "%255[^:]:%d", host, &port) != 2) { continue; // 格式错误,跳过 } // 校验端口范围 if (port < 1 || port > 65535) { continue; } printf("%s:%d\n", host, port); } while (1); return NULL; }
方案三:strtok_r线程安全拆分(兼容strtok逻辑)
若需保留类似strtok的拆分逻辑,使用POSIX标准的strtok_r(线程安全,需传入独立状态指针):
#include <stdio.h> #include <string.h> #include <stdlib.h> void* startthread(void* arg) { do { const char* proxy = "127.0.0.1:443"; char* buffered = strdup(proxy); if (buffered == NULL) { continue; // 内存分配失败,跳过 } char* saveptr = NULL; char* host = strtok_r(buffered, ":", &saveptr); if (host == NULL) { free(buffered); continue; } char* port_str = strtok_r(NULL, ":", &saveptr); if (port_str == NULL) { free(buffered); continue; } // 校验端口 char* endptr = NULL; int port = strtol(port_str, &endptr, 10); if (endptr == port_str || port < 1 || port > 65535) { free(buffered); continue; } printf("%s:%d\n", host, port); free(buffered); // 释放动态分配的内存 } while (1); return NULL; }
内容的提问来源于stack exchange,提问作者user20223390
相关产品推荐
相关产品推荐

