Winsock发送POST请求时send()返回-1及400错误排查求助
问题分析与解决方案
初始代码:send()返回-1的原因
Socket配置错误
- 客户端不需要调用
bind():bind()是服务器端用来绑定本地端口的操作,客户端直接调用connect()连接服务器即可。错误绑定会导致Socket无法正常建立与服务器的连接,send()自然失败。 - 未调用
connect():创建Socket后没有连接到目标服务器,处于未连接状态的Socket无法发送数据。 - 端口设置错误:代码中用了54000端口,若服务器未使用该端口,会导致连接失败。默认HTTP用80端口,HTTPS用443端口。
- 缺乏错误检查:
socket()、gethostbyname()的返回值未做校验,比如gethostbyname()失败返回NULL时,直接访问host->h_addr会引发崩溃。
POST请求格式错误
- 请求行路径错误:HTTP请求行的路径部分只需写相对于域名的路径,正确格式应为
POST /script.php HTTP/1.1,而非POST stuff://domain.net/script.php? HTTP/1.1。 - 换行符不符合HTTP规范:HTTP协议要求所有头字段和空行必须用
\r\n(CRLF)分隔,代码中用单独的\n会导致请求格式不被服务器识别。
更新后代码:400 Bad Request的原因
核心错误:HTTPS连接未做TLS握手
代码注释提到stuff is https且用了443端口,但直接通过普通TCP Socket发送明文HTTP请求。HTTPS要求先建立TLS/SSL加密会话,服务器收到非TLS握手数据时会返回400错误。
请求格式仍有问题
- 请求行路径错误:依然保留了
stuff://domain.net/script.php的错误格式,正确路径应为/script.php。 - 换行符可能仍不规范:代码中的换行如果还是用单独的
\n,会导致请求头格式错误。
其他潜在问题
socket_create_http()失败时无有效返回值:若connect()失败,函数未返回INVALID_SOCKET,会导致sock_http为未初始化的垃圾值。- 接收响应不完整:仅调用一次
recv(),无法保证接收完服务器的全部响应数据。 - 过时函数使用:
gethostbyname()已被淘汰,建议用getaddrinfo()替代,支持IPv6和更可靠的域名解析。
修正步骤
处理HTTPS连接:
Windows平台可使用系统自带的Schannel库,或第三方库如OpenSSL,在TCP连接成功后建立SSL/TLS会话,通过SSL套接字发送接收数据,不能直接用普通TCP Socket发送明文请求到443端口。修正请求格式:
正确的POST请求格式示例:request << "POST /script.php HTTP/1.1\r\n"; request << "Host: domain.net\r\n"; request << "Content-Length: " << data.size() << "\r\n"; request << "Content-Type: application/x-www-form-urlencoded\r\n"; request << "Connection: close\r\n"; request << "\r\n"; // 头与正文的分隔空行 request << data;完善Socket错误处理:
socket_create_http()函数在任何步骤失败时返回INVALID_SOCKET,main()中检查返回值:SOCKET socket_create_http(const char* hostname, unsigned short port) { struct addrinfo hints = {}, *result; hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; int res = getaddrinfo(hostname, nullptr, &hints, &result); if (res != 0) return INVALID_SOCKET; SOCKET sock = INVALID_SOCKET; for (struct addrinfo* ptr = result; ptr != nullptr; ptr = ptr->ai_next) { sock = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); if (sock == INVALID_SOCKET) continue; if (connect(sock, ptr->ai_addr, (int)ptr->ai_addrlen) != SOCKET_ERROR) { break; } closesocket(sock); sock = INVALID_SOCKET; } freeaddrinfo(result); return sock; }
循环接收完整响应:
string full_response; char buffer[4096]; int bytes_received; while ((bytes_received = recv(sock_http, buffer, sizeof(buffer), 0)) > 0) { full_response.append(buffer, bytes_received); } cout << full_response << endl;
内容的提问来源于stack exchange,提问作者user19747167
相关产品推荐
相关产品推荐

