Считать значение файла и записать его в переменную по URL C++
Ознакомилась с различными методами в вопросах 1, 2 и 3, но хотелось бы метод на чистом С++ без сторонних библиотек. Из всех вышеперечисленных методов я извлекла три на чистом С++, но в двух из них возникают ошибки на этапе компиляции, а в 1 возникает ошибка в коде. Ниже я вставлю код этих методов и какие в них возникают ошибки.
Первый метод:
#include <windows.h>
#include <string>
#include <stdio.h>
using std::string;
#pragma comment(lib,"ws2_32.lib")
HINSTANCE hInst;
WSADATA wsaData;
void mParseUrl(char* mUrl, string& serverName, string& filepath, string& filename);
SOCKET connectToServer(char* szServerName, WORD portNum);
int getHeaderLength(char* content);
char* readUrl2(char* szUrl, long& bytesReturnedOut, char** headerOut);
int main()
{
const int bufLen = 1024;
char* szUrl = "http://stackoverflow.com";
long fileSize;
char* memBuffer, * headerBuffer;
FILE* fp;
memBuffer = headerBuffer = NULL;
if (WSAStartup(0x101, &wsaData) != 0)
return -1;
memBuffer = readUrl2(szUrl, fileSize, &headerBuffer);
printf("returned from readUrl\n");
printf("data returned:\n%s", memBuffer);
if (fileSize != 0)
{
printf("Got some data\n");
fp = fopen("downloaded.file", "wb");
fwrite(memBuffer, 1, fileSize, fp);
fclose(fp);
delete(memBuffer);
delete(headerBuffer);
}
WSACleanup();
return 0;
}
void mParseUrl(char* mUrl, string& serverName, string& filepath, string& filename)
{
string::size_type n;
string url = mUrl;
if (url.substr(0, 7) == "http://")
url.erase(0, 7);
if (url.substr(0, 8) == "https://")
url.erase(0, 8);
n = url.find('/');
if (n != string::npos)
{
serverName = url.substr(0, n);
filepath = url.substr(n);
n = filepath.rfind('/');
filename = filepath.substr(n + 1);
}
else
{
serverName = url;
filepath = "/";
filename = "";
}
}
SOCKET connectToServer(char* szServerName, WORD portNum)
{
struct hostent* hp;
unsigned int addr;
struct sockaddr_in server;
SOCKET conn;
conn = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (conn == INVALID_SOCKET)
return NULL;
if (inet_addr(szServerName) == INADDR_NONE)
{
hp = gethostbyname(szServerName);
}
else
{
addr = inet_addr(szServerName);
hp = gethostbyaddr((char*)&addr, sizeof(addr), AF_INET);
}
if (hp == NULL)
{
closesocket(conn);
return NULL;
}
server.sin_addr.s_addr = *((unsigned long*)hp->h_addr);
server.sin_family = AF_INET;
server.sin_port = htons(portNum);
if (connect(conn, (struct sockaddr*)&server, sizeof(server)))
{
closesocket(conn);
return NULL;
}
return conn;
}
int getHeaderLength(char* content)
{
const char* srchStr1 = "\r\n\r\n", * srchStr2 = "\n\r\n\r";
char* findPos;
int ofset = -1;
findPos = strstr(content, srchStr1);
if (findPos != NULL)
{
ofset = findPos - content;
ofset += strlen(srchStr1);
}
else
{
findPos = strstr(content, srchStr2);
if (findPos != NULL)
{
ofset = findPos - content;
ofset += strlen(srchStr2);
}
}
return ofset;
}
char* readUrl2(char* szUrl, long& bytesReturnedOut, char** headerOut)
{
const int bufSize = 512;
char readBuffer[bufSize], sendBuffer[bufSize], tmpBuffer[bufSize];
char* tmpResult = NULL, * result;
SOCKET conn;
string server, filepath, filename;
long totalBytesRead, thisReadSize, headerLen;
mParseUrl(szUrl, server, filepath, filename);
///////////// step 1, connect //////////////////////
conn = connectToServer((char*)server.c_str(), 80);
///////////// step 2, send GET request /////////////
sprintf(tmpBuffer, "GET %s HTTP/1.0", filepath.c_str());
strcpy(sendBuffer, tmpBuffer);
strcat(sendBuffer, "\r\n");
sprintf(tmpBuffer, "Host: %s", server.c_str());
strcat(sendBuffer, tmpBuffer);
strcat(sendBuffer, "\r\n");
strcat(sendBuffer, "\r\n");
send(conn, sendBuffer, strlen(sendBuffer), 0);
// SetWindowText(edit3Hwnd, sendBuffer);
printf("Buffer being sent:\n%s", sendBuffer);
///////////// step 3 - get received bytes ////////////////
// Receive until the peer closes the connection
totalBytesRead = 0;
while (1)
{
memset(readBuffer, 0, bufSize);
thisReadSize = recv(conn, readBuffer, bufSize, 0);
if (thisReadSize <= 0)
break;
tmpResult = (char*)realloc(tmpResult, thisReadSize + totalBytesRead);
memcpy(tmpResult + totalBytesRead, readBuffer, thisReadSize);
totalBytesRead += thisReadSize;
}
headerLen = getHeaderLength(tmpResult);
long contenLen = totalBytesRead - headerLen;
result = new char[contenLen + 1];
memcpy(result, tmpResult + headerLen, contenLen);
result[contenLen] = 0x0;
char* myTmp;
myTmp = new char[headerLen + 1];
strncpy(myTmp, tmpResult, headerLen);
myTmp[headerLen] = NULL;
delete(tmpResult);
*headerOut = myTmp;
bytesReturnedOut = contenLen;
closesocket(conn);
return(result);
}
В нём возникает ошибка на строке 21: значение типа const char* нельзя присвоить сущности типа char *
Второй метод:
#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")
int main(void) {
WSADATA wsaData;
SOCKET Socket;
SOCKADDR_IN SockAddr;
int lineCount = 0;
int rowCount = 0;
struct hostent* host;
locale local;
char buffer[10000];
int i = 0;
int nDataLength;
string website_HTML;
// website url
string url = "www.google.com";
//HTTP GET
string get_http = "GET / HTTP/1.1\r\nHost: " + url + "\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(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 GET / HTTP
send(Socket, get_http.c_str(), strlen(get_http.c_str()), 0);
// recieve html
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();
// Display HTML source
cout << website_HTML;
// pause
cout << "\n\nPress ANY key to close.\n\n";
cin.ignore(); cin.get();
return 0;
}
В нём возникают ошибки на этапе компиляции: строка 42: error C4996: 'gethostbyname': Use getaddrinfo() or GetAddrInfoW() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings
#define _WINSOCK_DEPRECATED_NO_WARNINGS не решает проблему.
И третий метод:
#include <winsock2.h>
#include <windows.h>
#include <string>
#include <iostream>
#include <cstring>
#pragma comment(lib, "ws2_32.lib")
char* parse_url(char* d, const char* url);
int ReadUrl(const char* url, std::string& dst, DWORD msec = WSA_INFINITE);
int main(void){
WSADATA wd = {0};
if(WSAStartup(MAKEWORD(2, 2), &wd) != 0)
return EXIT_FAILURE;
std::string buf;
char url[] = "http://mysite.ru/version.txt";
int err = ::ReadUrl(url, buf, 12000);
if(err == ERROR_SUCCESS)
std::cout << buf;
else
std::cerr << "error, code: " << err;
std::cout << std::endl;
WSACleanup();
std::cin.get();
return 0;
}
int ReadUrl(const char* url, std::string& dst, DWORD msec){
int ret;
char host[64];
SOCKET sock;
WSAEVENT hevent;
if(! *parse_url(host, url))
return WSAEFAULT;
hevent = WSACreateEvent();
if(hevent == WSA_INVALID_EVENT)
return WSAGetLastError();
// создаём сокет
sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,
NULL, 0, WSA_FLAG_OVERLAPPED);
if(sock == INVALID_SOCKET){
ret = WSAGetLastError();
WSACloseEvent(hevent);
return ret;
}
//получаем IP
hostent* phost = gethostbyname(host);
if(phost == NULL){
ret = WSAGetLastError();
WSACloseEvent(hevent);
closesocket(sock);
return ret;
}
sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_port = htons(80);
CopyMemory(&addr.sin_addr, phost->h_addr_list[0], phost->h_length);
// коннектимся к хосту
ret = connect(sock, (const sockaddr*)&addr, sizeof(addr));
if(ret == SOCKET_ERROR) {
ret = WSAGetLastError();
WSACloseEvent(hevent);
closesocket(sock);
return ret;
}
// задаём запрос
dst = "GET ";
dst += url;
dst += "\r\n\r\n";
ret = send(sock, &dst[0], dst.length(), 0);
dst = "";
Sleep(50);
if(ret == SOCKET_ERROR) {
ret = WSAGetLastError();
WSACloseEvent(hevent);
closesocket(sock);
return ret;
}
//***
WSAOVERLAPPED wso;
WSABUF wbuf;
DWORD len, flag;
char buf[512];
wbuf.buf = &buf[0];
wbuf.len = sizeof(buf) - 1;
//чтение
while(1){
ZeroMemory(&wso, sizeof(wso));
wso.hEvent = hevent;
len = flag = 0;
ret = WSARecv(sock, &wbuf, 1, &len, &flag, &wso, NULL);
if(ret == SOCKET_ERROR){
if((ret = WSAGetLastError()) != WSA_IO_PENDING)
break;
}
ret = WSAWaitForMultipleEvents(1, &hevent, FALSE, msec, FALSE);
if((ret == WSA_WAIT_FAILED) || (ret == WSA_WAIT_TIMEOUT)){
ret = (! dst.length()) ? SOCKET_ERROR : 0;
break;
}
WSAResetEvent(hevent);
ret -= WSA_WAIT_EVENT_0;
if(ret < 0 || ret > 0){
ret = (! dst.length()) ? SOCKET_ERROR : 0;
break;
}
len = 0;
ret = WSAGetOverlappedResult(sock, &wso, &len, FALSE, &flag);
if((! len) || (! ret)){
if((ret = WSAGetLastError()) != WSA_IO_INCOMPLETE)
break;
continue;
}
if(len > 0){
buf[len] = '\0';
dst.append(buf, buf + len);
}
}
WSASetEvent(hevent);
WSACloseEvent(hevent);
closesocket(sock);
return (ret == SOCKET_ERROR) ? WSAGetLastError() : ERROR_SUCCESS;
}
char* parse_url(char* d, const char* url){
char* t = d;
if(! strnicmp(url, "http://", 7))
url += 7;
while(*url && (*url != '/'))
*d++ = *url++;
*d = '\0';
return t;
}
В нём возникают ошибки на этапе компиляции: строка 57: та же ошибка, что и в предыдущем: error C4996: 'gethostbyname': Use getaddrinfo() or GetAddrInfoW() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings. Также возникает ошибка на строке 153: error C4996: 'strnicmp': The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name: _strnicmp. See online help for details., но она легко решается заменой strnicmp на _strnicmp.
Так вот, хотелось бы узнать, какой метод лучше использовать для считывания значения с файла на сервере и как исправить ошибки? Хотя возможно есть и другой(-е) метод(-ы), которые лучше подойдут для этой задачи...