无法从 winsock 获取所有响应字节
Having trouble getting all bytes of response from winsock
我正在使用 winsocks 来执行我的 HTTP 请求。在我的服务器端,我 运行 PHP 获取文件内容的代码,base64 的内容,并打印它(回显)。在我的客户端 C++ 代码中,我执行了一个简单的 HTTP get 请求。我已经确认问题不在我的服务器端,而是在客户端。
客户端套接字代码:
locale local;
char buffer[1000000];
int i = 0;
string get_Website(string url, string path = "/", string useragent = "Mozilla") {
string website_HTML;
WSADATA wsaData;
SOCKET Socket;
SOCKADDR_IN SockAddr;
int lineCount = 0;
int rowCount = 0;
struct hostent *host;
string get_http;
get_http = "GET " + path + " HTTP/1.0\r\nHost: " + url + "\r\nUser-Agent: " + useragent + "\r\nConnection: close\r\n\r\n";
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
cout << "WSAStartup failed.\n";
system("pause");
//return 1;-
}
Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
host = gethostbyname(url.c_str());
SockAddr.sin_port = htons(44980);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);
if (connect(Socket, (SOCKADDR*)(&SockAddr), sizeof(SockAddr)) != 0) {
cout << "Could not connect";
system("pause");
//return 1;
}
send(Socket, get_http.c_str(), strlen(get_http.c_str()), 0);
int nDataLength;
while ((nDataLength = recv(Socket, buffer, 1000000, 0)) > 0) {
int i = 0;
while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
website_HTML += buffer[i];
i += 1;
}
}
closesocket(Socket);
WSACleanup();
return website_HTML;
}
响应长度一直在变化,尽管我 return 每次服务器端的响应都是一样的。大缓冲区的原因是我认为这可能是问题所在,因为我正在检索整个文件 base64 编码形式。
本质上,问题是我没有收到 full/correct 响应。
while ((nDataLength = recv(Socket, buffer, 1000000, 0)) > 0) {
这是从套接字中读取的。读取的字节数进入`nDataLength。紧接着:
int i = 0;
while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
website_HTML += buffer[i];
i += 1;
}
这个逻辑完全忽略了nDataLength
中的字节数,只是盲目地读取缓冲区的内容,连续读取,直到第一个不是换行符或回车符的控制字符return。
除了对您的 HTTP 请求的响应肯定可以包含二进制字符这一事实之外,对您的 HTTP 请求的响应将以多个不同大小的数据包到达,这些数据包将一个接一个地写在彼此之上,连续地, buffer
。分配的 buffer
似乎在静态存储中,因此它将被零初始化,并且单个数据包不太可能超过 999999 字节;所以循环不太可能 运行 离开缓冲区的末尾。它会在某个时候达到 [=15=]
。
但是,由于响应的数据包大小不一,较短的数据包将用其内容替换前一个数据包的初始较长内容;但是损坏的逻辑将无法检测到它,并且会吞掉新数据包,然后是前一个数据包的尾部。
有点乱。通过使用 nDataLength
来解决这个问题,将每个数据包的内容复制并附加到您的字符串中。
我正在使用 winsocks 来执行我的 HTTP 请求。在我的服务器端,我 运行 PHP 获取文件内容的代码,base64 的内容,并打印它(回显)。在我的客户端 C++ 代码中,我执行了一个简单的 HTTP get 请求。我已经确认问题不在我的服务器端,而是在客户端。
客户端套接字代码:
locale local;
char buffer[1000000];
int i = 0;
string get_Website(string url, string path = "/", string useragent = "Mozilla") {
string website_HTML;
WSADATA wsaData;
SOCKET Socket;
SOCKADDR_IN SockAddr;
int lineCount = 0;
int rowCount = 0;
struct hostent *host;
string get_http;
get_http = "GET " + path + " HTTP/1.0\r\nHost: " + url + "\r\nUser-Agent: " + useragent + "\r\nConnection: close\r\n\r\n";
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
cout << "WSAStartup failed.\n";
system("pause");
//return 1;-
}
Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
host = gethostbyname(url.c_str());
SockAddr.sin_port = htons(44980);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);
if (connect(Socket, (SOCKADDR*)(&SockAddr), sizeof(SockAddr)) != 0) {
cout << "Could not connect";
system("pause");
//return 1;
}
send(Socket, get_http.c_str(), strlen(get_http.c_str()), 0);
int nDataLength;
while ((nDataLength = recv(Socket, buffer, 1000000, 0)) > 0) {
int i = 0;
while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
website_HTML += buffer[i];
i += 1;
}
}
closesocket(Socket);
WSACleanup();
return website_HTML;
}
响应长度一直在变化,尽管我 return 每次服务器端的响应都是一样的。大缓冲区的原因是我认为这可能是问题所在,因为我正在检索整个文件 base64 编码形式。
本质上,问题是我没有收到 full/correct 响应。
while ((nDataLength = recv(Socket, buffer, 1000000, 0)) > 0) {
这是从套接字中读取的。读取的字节数进入`nDataLength。紧接着:
int i = 0;
while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
website_HTML += buffer[i];
i += 1;
}
这个逻辑完全忽略了nDataLength
中的字节数,只是盲目地读取缓冲区的内容,连续读取,直到第一个不是换行符或回车符的控制字符return。
除了对您的 HTTP 请求的响应肯定可以包含二进制字符这一事实之外,对您的 HTTP 请求的响应将以多个不同大小的数据包到达,这些数据包将一个接一个地写在彼此之上,连续地, buffer
。分配的 buffer
似乎在静态存储中,因此它将被零初始化,并且单个数据包不太可能超过 999999 字节;所以循环不太可能 运行 离开缓冲区的末尾。它会在某个时候达到 [=15=]
。
但是,由于响应的数据包大小不一,较短的数据包将用其内容替换前一个数据包的初始较长内容;但是损坏的逻辑将无法检测到它,并且会吞掉新数据包,然后是前一个数据包的尾部。
有点乱。通过使用 nDataLength
来解决这个问题,将每个数据包的内容复制并附加到您的字符串中。