向HTTP服务器发送POST请求时发生Winsock send()错误

Winsock send() error when sending POST request to HTTP server

本文关键字:send Winsock 错误 请求 服务器 HTTP POST      更新时间:2024-09-30

在发送POST字符串时,我无法让send()返回除-1以外的任何内容:

#include <vector>
#include <iostream>
#include <string>
#include <WS2tcpip.h>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
SOCKET socket_create_http()
{
SOCKET sock;
SOCKADDR_IN SockAddr;
struct hostent* host;
char url[] = "domain.net";
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
host = gethostbyname(url);
SockAddr.sin_port = htons(54000);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);
int bound = bind(sock, (SOCKADDR*)(&SockAddr), sizeof(SockAddr));

return(sock);
}
int main()
{
WSADATA ws_data;
WORD ws_version = MAKEWORD(2, 2);
int startup = WSAStartup(ws_version, &ws_data);
SOCKET sock_http = socket_create_http();
string data = "action=0&data=0";
string request_string = "POST ";
request_string += "stuff://domain.net/script.php?";
request_string += " HTTP/1.1rn"; // or HTTP/1.0
request_string += "Host: domain.netrn";
request_string += "Content-Length: " + to_string(data.size()) + "rn";
request_string += "rn";
request_string += data;
int sent = send(sock_http, request_string.c_str(), strlen(request_string.c_str()), 0);
cout << "SENT: " << sent << endl;
closesocket(sock_http);
return 0;
}

我可能需要预处理器定义中的_WINSOCK_DEPRECATED_NO_WARNINGS来运行它

我已经做了几天了。有没有什么想法我可能会在套接字设置或post格式方面出错,或者两者兼而有之?


更新:我已经更新了代码,现在我在发送POST字符串时收到400 bad request

#include <vector>
#include <iostream>
#include <string>
#include <sstream>
#include <winsock2.h>
#include <WS2tcpip.h>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
SOCKET sock_http;
SOCKET socket_create_http(const char* hostname, unsigned short port)
{
hostent* host = gethostbyname(hostname);
if (host)
{
cout << "HTTP HOST: " << host << endl;
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock != INVALID_SOCKET)
{
SOCKADDR_IN SockAddr = {};
SockAddr.sin_family = AF_INET;
SockAddr.sin_port = htons(port);
SockAddr.sin_addr.s_addr = *reinterpret_cast<unsigned long*>(host->h_addr);
if (connect(sock, reinterpret_cast<SOCKADDR*>(&SockAddr), sizeof(SockAddr)) != SOCKET_ERROR)
{
cout << "HTTP SOCKET CREATED: " << sock << endl << endl;
return sock;
}

//closesocket(sock); //safety
}
}
}

bool http_post(string data)
{
char bb_receive[4096];

ostringstream request; 
request << "POST stuff://domain.net/script.php HTTP/1.1rn"; //stuff is https
request << "Host: domain.netrn";
request << "Content-Length: " << data.size() << "rn";
request << "Content-Type: application/x-www-form-urlencodedrn";
request << "Connection: closern";
request << "rn";
request << data;
string request_string = request.str();
size_t data_size = request_string.size();

const char* pdata = static_cast<const char*>(request_string.c_str());

bool all_sent = false;

while (data_size > 0)
{
int sent = send(sock_http, pdata, data_size, 0);
if (sent == SOCKET_ERROR)
{
cout << "SOCKET FAILED IN SEND LOOP" << endl;
break;
}
pdata += sent;
data_size -= sent;
} //SEND

if (data_size <= 0) { all_sent = true; }

if (all_sent)
{
ZeroMemory(bb_receive, 4096);
int bytes_received = recv(sock_http, bb_receive, 4096, 0);

if (bytes_received > 0)
{
cout << "Bytes received (Socket " << sock_http << "): " << bytes_received << endl;
}

for (int i = 0; i < bytes_received; i++) { cout << bb_receive[i]; }
} //RECEIVE

return all_sent;
}
int main()
{
WSADATA ws_data;
WORD ws_version = MAKEWORD(2, 2);
int startup = WSAStartup(ws_version, &ws_data); if (startup != 0) { cout << "WSA FAILED" << endl; }
sock_http = socket_create_http("domain.net", 443);
bool success = http_post("action=0&data=0");
cout << "WSA Last Error: " << WSAGetLastError() << endl;
closesocket(sock_http);
return 0;
}

以下是recv()的输出——服务器的响应:

Bytes received (Socket 532): 4096
HTTP/1.1 400 Bad Request
Date: Mon, 15 Aug 2022 18:23:43 GMT
Server: Apache
Upgrade: h2,h2c
Connection: Upgrade, close
Accept-Ranges: bytes
Vary: Accept-Encoding
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0
Content-Type: text/html

代码的主要问题是您没有调用connect()函数来建立与HTTP服务器IP/端口的连接。您使用的是bind()函数,该函数仅建立套接字的本地IP/端口,但不能将套接字bind()连接到远程IP/端口。这就是connect()的作用。

当套接字函数失败时,请使用WSAGetLastError()查找原因。在您的情况下,send()将失败,并出现WSAENOTCONN错误:

https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-send

返回值

如果没有发生错误,send将返回发送的字节总数,该总数可以小于len参数中请求发送的字节数否则返回值SOCKET_ERROR,调用WSAGetLastError可以检索到特定的错误代码

含义
错误代码
WSAENOTCONN 插座未连接