You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多线程环境下安全拆分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,

原代码问题分析

  1. strtok线程不安全:依赖静态存储区维护状态,多线程并发调用会互相干扰,导致strtok(NULL, ":")返回空指针,传入atoi后触发段错误。
  2. 无错误处理:未检查strdup内存分配失败、strtok返回空指针的情况,直接操作空指针引发崩溃。
  3. 内存泄漏: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 14:15:31