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

AOSP服务中C++本地TCP无法接收文本问题求助

TCP接收问题排查:AOSP服务C++环境无法接收Ubuntu发送的文本

问题背景

本地TCP文本发送功能正常(Ubuntu可向AOSP发送文本),第三方APK能正常接收,但AOSP服务内的C环境无法接收,报错为Connection refused或Failed recv: Transport endpoint is not connected。已确认服务已获取android.permission.INTERNET等相关网络权限,尝试过5030-5033端口,C代码中指定过手机本地IP(192.168.2.110)及INADDR_ANY,仍未解决。

接收失败的C++代码

std::string receiveTextTcp(int port) {

    struct sockaddr_in serv_addr;
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0) {
        ALOGI("Failed socket: %s", strerror(errno));
        return "";
    }
    ALOGI("fd : %d, port:%d", fd, port);
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(port);
    int reuse_flag = 1;

    int result = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse_flag, sizeof(reuse_flag));
    if (result < 0) {
        ALOGI("Failed setsockopt: %s, port:%d", strerror(errno), port);
    }

    int bind_result = bind(fd, reinterpret_cast<sockaddr*>(&serv_addr), sizeof(serv_addr));

    if (bind_result < 0) {
        ALOGI("Failed bind: %s, port:%d", strerror(errno), port);
    }

    result = listen(fd, 1);
    if (result < 0) {
        ALOGI("Failed listen: %s, port:%d", strerror(errno), port);
    }

    char buffer[1024];
    int bytes_received = recv(fd, buffer, sizeof(buffer), 0);
    if (bytes_received < 0) {
        ALOGI("Failed recv: %s, port:%d", strerror(errno), port);
        
    }

    ALOGI("Failed buffer: %s, port:%d", buffer, port);


    close(fd);


    return "";
}

发送成功的C++代码

bool SendData(const std::string& ip, int port, const std::string& text) {

    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        ALOGI("Failed to create socket: %s, sockfd:%d", strerror(errno), sockfd);
        return false;
    }

    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(port);

    // Use inet_pton instead of inet_addr
    if (inet_pton(AF_INET, ip.c_str(), &servaddr.sin_addr) <= 0) {
        ALOGI("Invalid IP address: %s", ip.c_str() );
        close(sockfd);
        return false;
    }

    if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {
        ALOGI("Failed to connect to server: %s", strerror(errno) );
        close(sockfd);
        return false;
    }


    const char* message = text.c_str();
    size_t message_len = strlen(message);

    if (send(sockfd, message, message_len, 0) < 0) {
        ALOGI("Failed send, err: %s . message:%s", strerror(errno), message );
        close(sockfd);
        return false;
    } else{
        ALOGI("send ok. message:%s", message );
    } 

    close(sockfd);

    return true;
}

问题分析与解决方案

核心问题:TCP服务端流程缺失关键步骤

TCP是面向连接的协议,服务端在listen之后必须调用accept来接受客户端的连接请求,才能得到用于数据收发的连接套接字。当前接收代码直接在listen后调用recv,而recv仅能用于已建立连接的套接字,监听套接字(fd)无法直接接收数据,这就是报错Transport endpoint is not connected的核心原因。

修复后的接收代码

std::string receiveTextTcp(int port) {
    struct sockaddr_in serv_addr, cli_addr;
    socklen_t cli_len = sizeof(cli_addr);
    
    // 创建监听套接字
    int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_fd < 0) {
        ALOGI("Failed socket: %s", strerror(errno));
        return "";
    }
    ALOGI("listen_fd : %d, port:%d", listen_fd, port);

    // 设置地址复用
    int reuse_flag = 1;
    int result = setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuse_flag, sizeof(reuse_flag));
    if (result < 0) {
        ALOGI("Failed setsockopt: %s, port:%d", strerror(errno), port);
    }

    // 绑定地址
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(port);
    
    int bind_result = bind(listen_fd, reinterpret_cast<sockaddr*>(&serv_addr), sizeof(serv_addr));
    if (bind_result < 0) {
        ALOGI("Failed bind: %s, port:%d", strerror(errno), port);
        close(listen_fd);
        return "";
    }

    // 开始监听
    result = listen(listen_fd, 1);
    if (result < 0) {
        ALOGI("Failed listen: %s, port:%d", strerror(errno), port);
        close(listen_fd);
        return "";
    }

    // 接受客户端连接,得到连接套接字
    int conn_fd = accept(listen_fd, reinterpret_cast<sockaddr*>(&cli_addr), &cli_len);
    if (conn_fd < 0) {
        ALOGI("Failed accept: %s, port:%d", strerror(errno), port);
        close(listen_fd);
        return "";
    }

    // 从连接套接字接收数据
    char buffer[1024] = {0}; // 初始化缓冲区避免垃圾数据
    int bytes_received = recv(conn_fd, buffer, sizeof(buffer)-1, 0); // 留1位存字符串结束符
    if (bytes_received < 0) {
        ALOGI("Failed recv: %s, port:%d", strerror(errno), port);
        close(conn_fd);
        close(listen_fd);
        return "";
    } else if (bytes_received == 0) {
        ALOGI("Client closed connection, port:%d", port);
        close(conn_fd);
        close(listen_fd);
        return "";
    }

    buffer[bytes_received] = '\0'; // 添加字符串结束符
    ALOGI("Received buffer: %s, port:%d", buffer, port);

    // 先关闭连接套接字,再关闭监听套接字
    close(conn_fd);
    close(listen_fd);

    return std::string(buffer);
}

额外注意事项

  1. 完善错误处理:原代码中bind、listen失败后仍继续执行后续逻辑,修复后在失败时及时关闭套接字并返回,避免无效操作。
  2. 缓冲区初始化:原代码缓冲区未初始化,可能导致打印垃圾数据,修复后初始化为0,并在接收后添加字符串结束符。
  3. 端口占用验证:可在AOSP环境中执行netstat -tulnp | grep 端口号,检查端口是否被其他进程占用。
  4. SELinux权限排查:AOSP服务可能受SELinux限制,可临时执行setenforce 0关闭SELinux测试,若问题解决需添加对应SELinux规则。

内容的提问来源于stack exchange,提问作者Milana

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 18:24:49