httpに従って、
HEADリクエストでヘッダー情報取得
↓
そこから必要な容量を読み取り、バッファを確保
↓
GETリクエストでデータを取得
ということをやりたいのですが、どうやら持続的接続ができていないようなのです。
GETリクエストを送信した後に受信するデータ量が0なのです。
一旦接続し直してからGETリクエストを送ると正常にデータを受信することができます。
以下ソースコードです。(関数などをできるだけ展開してみました)
main.cpp
► スポイラーを表示
#define _CRT_SECURE_NO_DEPRECATE
#define WIN32_LEAN_AND_MEAN
/*
#include "DxLib.h"
#define FW_DX_DEF_
//*/
#define FW_MAIN_
#define FW_STD_DEF_
//*
#define FW_STD_PROGRAMABLE_DEF_
#define FW_DX_PROGRAMABLE_DEF_
//*/
#include "../safe_fireworks/fireworks.h"
#include "includes.h"
void __cdecl cleanup();
int main()
{
std::string url("localhost/index.html");
vuchar content;
std::string domain;
std::string uri;
SOCKET socket;
SOCKADDR_IN hostinfo;
// Init Winsock
{
const char lobyte = 2;
const char hibyte = 0;
WSADATA wsd;
bool wsdres = WSAStartup(MAKEWORD(lobyte,hibyte), &wsd) == 0;
if(wsdres)
{
bool match = LOBYTE(wsd.wVersion)==lobyte && HIBYTE(wsd.wVersion)==hibyte;
if(match==false)
{
return -1;
}
}
else
{
return -1;
}
atexit(cleanup);
}
// Create Socket
{
socket = ::socket(AF_INET, SOCK_STREAM, 0);
if(socket == INVALID_SOCKET)
{
return -1;
}
}
// Get Domain and URI
{
uint slash = url.find('/');
domain = url.substr(0, slash);
uri = url.substr(slash);
}
// Get IP
{
hostinfo;
hostinfo.sin_family = AF_INET;
hostinfo.sin_port = htons(short(80) );
ULONG & ref = hostinfo.sin_addr.S_un.S_addr;
ref = inet_addr(domain.c_str() );
if(ref==INADDR_NONE)
{
HOSTENT * hostent = gethostbyname(domain.c_str() );
if(hostent==NULL)
{
return -1;
}
ref = *fw::pointer_cast<uint *>(hostent->h_addr_list[0]);
}
}
// Connect to Server
{
if(::connect(socket, fw::pointer_cast<sockaddr *>(&hostinfo), sizeof(hostinfo) ) == SOCKET_ERROR)
{
return -1;
}
}
// HEAD Request
{
std::string request
=
fw::cnct() <<
"HEAD " << uri << " HTTP/1.1" << "\r\n" <<
"Host: " << domain << "\r\n" <<
"Content-Length: 0" << "\r\n" <<
"Connection: Keep-Alive" << "\r\n" <<=
"\r\n";
if(::send(socket, request.c_str(), request.length(), 0) == SOCKET_ERROR)
{
return -1;
}
}
// Receive Header
{
HTTPheader header;
header.buffer.setsize(1024);
uint HeadSize = 0;
while(true)
{
int nBytesRecv = recv(socket, header.bufhead(), header.buffer.size(), 0);
HeadSize += nBytesRecv;
if(nBytesRecv == SOCKET_ERROR)
{
return -1;
}
else
{
if(nBytesRecv == 0) break;
}
}
header.buffer.setsize(HeadSize);
header.analyze();
// Show Header
header.buffer.add('\0');
printf("header:\n%s\n\n", header.bufhead() );
header.buffer.pop();
// Require Buffer for Header and Body
if(header.UsefulContentLength() )
{
content.setsize(HeadSize + header.ContentLength() );
printf("Size of Header and Body:%d\n", content.size() );
}
else
{
printf("Not Found UsefulContentLength\n");
return -1;
}
}
// GET Request
{
std::string request
=
fw::cnct() <<
"GET " << uri << " HTTP/1.1" << "\r\n" <<
"Host: " << domain << "\r\n" <<
"Content-Length: 0" << "\r\n" <<
"Connection: Keep-Alive" << "\r\n" <<=
"\r\n";
if(::send(socket, request.c_str(), request.length(), 0) == SOCKET_ERROR)
{
printf("Failed to Send 'GET Request'\n");
return -1;
}
}
// Receive Header and Body
{
uint total = 0;
while(true)
{
int nBytesRecv = recv(socket, fw::pointer_cast<char *>(content.head() ), content.size(), 0);
total += nBytesRecv;
if(nBytesRecv == SOCKET_ERROR)
{
printf("SOCKET ERROR\n");
return -1;
}
else
{
if(nBytesRecv == 0) break;
}
}
content.setsize(total);
// Show Header and Body
content.add('\0');
printf("Header and Body:\n%s\n", content.head() );
content.pop();
}
// Disconnect
{
shutdown(socket, SD_BOTH);
closesocket(socket);
}
return 0;
}
void __cdecl cleanup(){ WSACleanup(); }
► スポイラーを表示
► スポイラーを表示
#pragma once
class HTTPheader
{
public:
vuchar buffer;
HTTPheader()
:
strContentLength("Content-Length"),
strConnection("Connection"),
strLocation("Location")
{}
char * bufhead(){ return fw::pointer_cast<char *>(buffer.head() ); }
uint bufsize() const { return buffer.size(); }
void analyze(const char * str)
{
//content-valueの中に,が入る物があるとリストと区別できない。また、その場合正しく分割できていない
fw::slice lines;
lines(str, "\r\n");
for(uint i=lines.size()-1;i>1;--i)
{
const char first = lines[i][0];
if(first==' ' || first=='\t')
{
lines[i-1] += lines[i];
lines.pop();
}
}
char phrase[32];
sscanf(lines[0].c_str(),"HTTP/%s %s %s", Version,Code,phrase);
for(uint i=1;i<lines.size();++i)
{
uint colon = lines[i].find(':');
uint beg = lines[i].find_first_not_of(" \t", colon+1);
fw::slice param;
param(lines[i].substr(beg), ",");
vstring & ref = table[lines[i].substr(0, colon)];
for(uint j=0;j<param.size();++j)
{
ref.add(param[j].substr(param[j].find_first_not_of(" \t") ) );
uint spht = ref.last().find_first_of(" \t");
ref.last() = ref.last().substr(0, spht);
}
}
}
void analyze()
{
buffer[buffer.size()-2] = uchar('\0');
analyze(bufhead() );
}
bool ResponseIs2XX() const { return Code[0]=='2'; }
bool ResponseIs3XX() const { return Code[0]=='3'; }
bool UsefulContentLength() const { return table[strContentLength].size()>0; }
uint ContentLength() const { return atoi(table[strContentLength][0].c_str() ); }
bool UsefulConnection() const { return table[strConnection].size()>0; }
bool ConnectionIsKeepAlive() const { return table[strConnection][0]=="Keep-Alive"; }
bool UsefulLocation() const { return table[strLocation].size()>0; }
const std::string & Location() const { return table[strLocation][0]; }
private:
mutable std::map<std::string, vstring> table;
char Version[4];
char Code[4];
const std::string strContentLength;
const std::string strConnection;
const std::string strLocation;
};
safe_fireworksのみ
safe_fireworks + ソースコードファイル(3つ全て)
※クリックした瞬間ダウンロードされます