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); }
额外注意事项
- 完善错误处理:原代码中
bind、listen失败后仍继续执行后续逻辑,修复后在失败时及时关闭套接字并返回,避免无效操作。 - 缓冲区初始化:原代码缓冲区未初始化,可能导致打印垃圾数据,修复后初始化为0,并在接收后添加字符串结束符。
- 端口占用验证:可在AOSP环境中执行
netstat -tulnp | grep 端口号,检查端口是否被其他进程占用。 - SELinux权限排查:AOSP服务可能受SELinux限制,可临时执行
setenforce 0关闭SELinux测试,若问题解决需添加对应SELinux规则。
内容的提问来源于stack exchange,提问作者Milana
相关产品推荐
相关产品推荐

