简单的HTTP获取与Winsock
Simple HTTP Get with Winsock
前段时间,我做了一个非常简单的方法,可以发出http请求并返回响应。这工作就像我的意图,但现在我想再次使用它,但我突然遇到了一个问题,我似乎无法弄清楚。每次我发出请求,它返回错误503:Service Unavailable.
有时起作用,有时不起作用。
我注意到,如果我在连接关闭后设置一个断点,然后稍等片刻然后继续,没有问题,一切正常。所以我的猜测是这与服务器的定时/延迟有关。
有人有这方面的经验吗?
提前感谢!
string HttpHelper::HttpGet(string host, string path)
{
WSADATA wsaData;
int result;
// Initialize Winsock
result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (result != 0)
throw SocketError(L"WSAStartUp", result);
// Resolve the server address and port
addrinfo * pAddrInfo;
result = getaddrinfo(host.c_str(), "80", 0, &pAddrInfo);
if (result != 0)
throw SocketError(L"addrinfo", result);
//Create the socket
SOCKET sock = socket(pAddrInfo->ai_family, pAddrInfo->ai_socktype, pAddrInfo->ai_protocol);
if (sock == INVALID_SOCKET)
throw SocketError(L"Socket", WSAGetLastError());
// Connect to server.
result = connect(sock, pAddrInfo->ai_addr, pAddrInfo->ai_addrlen);
if (result != 0)
throw SocketError(L"Connect", WSAGetLastError());
const string request = "GET " + path + " HTTP/1.1nHost: " + host + "nn";
// Send an initial buffer
result = send(sock, request.c_str(), request.size(), 0);
if (result == SOCKET_ERROR)
throw SocketError(L"Send", WSAGetLastError());
// shutdown the connection since no more data will be sent
result = shutdown(sock, SD_SEND);
if (result == SOCKET_ERROR)
throw SocketError(L"Close send connection", WSAGetLastError());
// Receive until the peer closes the connection
string response;
char buffer[50];
int bytesRecv = 0;
for (;;)
{
result = recv(sock, buffer, sizeof(buffer), 0);
if (result == SOCKET_ERROR)
throw SocketError(L"Recv", WSAGetLastError());
if (result == 0)
break;
response += string(buffer, result);
wstringstream stream;
stream << L"HttpGet() > Bytes received: " << bytesRecv;
DebugLog::Log(stream.str(), LogType::INFO);
bytesRecv += result;
}
wstringstream stream;
stream << L"HttpGet() > Bytes received: " << bytesRecv;
DebugLog::Log(stream.str(), LogType::INFO);
// cleanup
result = closesocket(sock);
if (result == SOCKET_ERROR)
throw SocketError(L"Closesocket", WSAGetLastError());
result = WSACleanup();
if (result == SOCKET_ERROR)
throw SocketError(L"WSACleanup", WSAGetLastError());
freeaddrinfo(pAddrInfo);
DebugLog::Log(L"HttpGet() > Cleanup Successful ", LogType::INFO);
return response;
}
wstring SocketError::ErrorMessage(const wstring & context, const int errorCode) const
{
wchar_t buf[1024];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, errorCode, 0, buf, sizeof(buf), 0);
wchar_t * newLine = wcsrchr(buf, 'r');
if (newLine) *newLine = ' ';
wstringstream stream;
stream << L"Socket error in " << context << L" (" << errorCode << L"): " << buf;
return stream.str();
}
不好说…
下面是一段简单而通用的winsock代码,你可以尝试一下,看看在使用这段代码时是否也存在这个问题。
#include <string.h>
#include <winsock2.h>
#include <windows.h>
#include <iostream>
#include <vector>
#include <locale>
#include <sstream>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
string website_HTML;
locale local;
void get_Website(string url );
char buffer[10000];
int i = 0 ;
//****************************************************
int main( void ){
get_Website("www.stackoverflow.com" );
cout<<website_HTML;
cout<<"nnPress ANY key to close.nn";
cin.ignore(); cin.get();
return 0;
}
//****************************************************
void get_Website(string url ){
WSADATA wsaData;
SOCKET Socket;
SOCKADDR_IN SockAddr;
int lineCount=0;
int rowCount=0;
struct hostent *host;
string get_http;
get_http = "GET / HTTP/1.1rnHost: " + url + "rnConnection: closernrn";
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(80);
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,10000,0)) > 0){
int i = 0;
while (buffer[i] >= 32 || buffer[i] == 'n' || buffer[i] == 'r'){
website_HTML+=buffer[i];
i += 1;
}
}
closesocket(Socket);
WSACleanup();
}
您必须以以下格式发送windows tcp套接字:
GET /romeo.txt HTTP/1.1rnHost: data.pr4e.orgrnrn
/romeo.txt是主机url的路径,data.pr4e.org是host
感谢某人:)
我将假设如果您将相同的主机名放入web浏览器,您将返回有效内容,而不是503。
三次随机猜测:
1)你需要一个User-Agent报头。将请求字符串构建为:
const string request = "GET " + path + " HTTP/1.1n"
request += "Host: " + host + "n";
request += "User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36n";
request += "n";
2)正如我在评论中提到的,确保send
发送所有数据:
size_t sent = 0;
size_t remaining = request.size();
while (remaining > 0)
{
const char* data = request.c_str() + sent;
result = send(sock, data, remaining, 0);
if (result == SOCKET_ERROR)
throw SocketError(L"Send", WSAGetLastError());
sent += result;
remaining -= result;
}
3)唯一的其他事情可能是shutdown
调用。
只是删除下面的行。从理论上讲,这不会有什么不同。但值得一试。
result = shutdown(sock, SD_SEND);
相关文章:
- C++为构建时间获取QDateTime的可靠方法
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 如何使用 < 和 > 命令获取 c++ 中的输入和输出?
- 使用指针从C++中的数组中获取最大值
- 如何获取std::result_of函数的返回类型
- 如何在openssl-ecc中获取十六进制格式的私钥
- 使用Unreal C++获取VR耳机的世界位置/方向
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 从C字符串中获取奇怪的字符串长度
- 为什么我的for循环不能正确获取argv
- 从python中调用C++函数并获取返回值
- 如何获取一个数字的前3位
- 获取字符串的长度并将其分配给数组
- 无法获取菜单选择以运行函数.C++
- 数组长度,为什么从命令行获取时不能使用它?
- 获取网站来源,获取额外的符号,winsock
- 如何在 winsock 编程中从 recv() 获取确切的消息
- WinSock-在long中获取本地IP地址
- 简单的HTTP获取与Winsock
- 使用Winsock获取随机/奇怪的数据