通过主机名和端口创建Socket,::select()显示无数据求协助
问题分析与解决
你遇到的问题核心有两处代码错误,加上对TCP连接逻辑的误解,导致select()返回无数据:
错误点1:FD_SET未添加目标Socket
在isSocketReady函数中,你把**标准输入(文件描述符0)**加入了读集合,而不是要检查的sockfd。这会导致select()一直监听键盘输入,而非目标Socket的状态。
错误点2:select()第一个参数使用错误
select()的第一个参数需要传入最大文件描述符值 + 1,而非目标Socket的描述符本身。如果传入sockfd,当sockfd大于当前监听的fd时,select()无法正确处理。
逻辑误解:TCP连接成功不代表有数据
连接到example.com的80端口后,HTTP服务器不会主动发送数据,需要你先发送HTTP请求(比如GET / HTTP/1.1\r\nHost: example.com\r\n\r\n),服务器才会返回响应。所以即使Socket连接成功,select()也会提示无数据,因为服务器还没有数据要发送。
修正后的代码
#include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <arpa/inet.h> #include <netinet/in.h> #include <sys/ioctl.h> #include <net/if.h> #include <netinet/tcp.h> #include <string> #include <iostream> bool isSocketReady(int sockfd) { fd_set rfds; struct timeval tv; FD_ZERO(&rfds); FD_SET(sockfd, &rfds); // 修正:加入目标Socket而非标准输入 tv.tv_sec = 2; tv.tv_usec = 0; // 修正:第一个参数用最大fd+1 const int retval = ::select(sockfd + 1, &rfds, NULL, NULL, &tv); if (retval == -1) { printf("select() error"); return false; } else if (retval) { printf("Data is available now.\n"); return true; } else { printf("No data within timeout.\n"); return false; } } int connectByHostName(const std::string& host, int port) { int sockfd = -1; struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; const std::string port_str = std::to_string(port); struct addrinfo* res{nullptr}; const int r = getaddrinfo(host.c_str(), port_str.c_str(), &hints, &res); if(r < 0) { return -1; } for (struct addrinfo* address = res; address != nullptr; address = address->ai_next) { sockfd = socket(address->ai_family, address->ai_socktype, address->ai_protocol); if (sockfd < 0) { continue; } int flag = 1; setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char*) &flag, sizeof(flag)); if(::connect(sockfd, address->ai_addr, address->ai_addrlen) < 0) { close(sockfd); // 修正:连接失败时关闭Socket,避免资源泄漏 sockfd = -1; continue; } else { // 发送HTTP请求,触发服务器响应 const std::string request = "GET / HTTP/1.1\r\nHost: " + host + "\r\nConnection: close\r\n\r\n"; send(sockfd, request.c_str(), request.size(), 0); if(isSocketReady(sockfd)) { break; } else { close(sockfd); sockfd = -1; } } } freeaddrinfo(res); return sockfd; } int main() { int sock = connectByHostName("example.com", 80); std::cout << sock << std::endl; // 如果连接成功,读取响应 if(sock != -1) { char buffer[1024]; ssize_t bytes_read = recv(sock, buffer, sizeof(buffer)-1, 0); if(bytes_read > 0) { buffer[bytes_read] = '\0'; std::cout << "Received response:\n" << buffer << std::endl; } close(sock); } return 0; }
额外修正点
- 连接失败时关闭Socket,避免文件描述符泄漏
- 添加HTTP请求发送逻辑,确保服务器会返回数据供
select()检测
内容的提问来源于stack exchange,提问作者intrigued_66
相关产品推荐
相关产品推荐

