bon*_*nii 3 c++ sockets http request
我正在尝试在 Linux 上使用套接字执行 HTTP 请求,我的函数现在可以工作,但只能使用简单的域 aswww.google.com或webpage.000webhostapp.com。当我尝试添加路径和查询时webpage.000webhostapp.com/folder/file.php?parameter=value,它开始失败。
这是我的代码:
#include <iostream>
#include <cstring>
#include <string>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
int main(){
int socket_desc;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[4096];
std::string url = "www.exampleweb.com/folder/file.php";
socket_desc = socket(AF_INET, SOCK_STREAM, 0);
if(socket_desc < 0){
std::cout<<"failed to create socket"<<std::endl;
}
server = gethostbyname(url.c_str());
if(server==NULL){std::cout<<"could Not resolve hostname :("<<std::endl;}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(80);
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
if(connect(socket_desc, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
std::cout<<"connection failed :("<<std::endl;
}
std::string request = "GET / HTTP/1.1\r\nHost: " + url + "\r\nConnection: close\r\n\r\n";
if(send(socket_desc, request.c_str(), strlen(request.c_str())+1, 0) < 0){
std::cout<<"failed to send request..."<<std::endl;
}
int n;
std::string raw_site;
while((n = recv(socket_desc, buffer, sizeof(buffer)+1, 0)) > 0){
int i = 0;
while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r'){
raw_site+=buffer[i];
i += 1;
}
}
std::cout<<raw_site<<std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
使用www.google.com,它可以完美地满足请求。
使用www.example.com/folder/file.php?parameter=value¶meter2=value2,它会失败并返回"could not resolve hostname"。
关于如何修复它有什么想法吗?
我没有使用curl,也不能将它用于这个项目。
gethostbyname() (which BTW is deprecated, you should be using getaddrinfo() instead) does not work with URLs, only with host names.
Given a URL like http://www.exampleweb.com/folder/file.php?parameter=value¶meter2=value2, you need to first break it up into its constituent pieces (read RFC 3986), eg:
httpwww.exampleweb.com/folder/file.php?parameter=value¶meter2=value2You can then resolve the IP address for the host, connect to that IP address on port 80 (the default port for HTTP) since the URL doesn't specify a different port, and finally send a GET request for the resource and query.
Also, note that the Host header in the GET request must specify only the host name (and port, if different than the default), not the whole URL. And also that HTTP requests are not null-terminated strings, so do not send the null terminator. Read RFC 2616.
Try this instead:
#include <iostream>
#include <cstring>
#include <string>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
int main(){
int socket_desc;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[4096];
std::string host = "www.exampleweb.com";
std::string port = "80";
std::string resource = "/folder/file.php";
std::string query = "?parameter=value¶meter2=value2";
socket_desc = socket(AF_INET, SOCK_STREAM, 0);
if (socket_desc < 0){
std::cout << "failed to create socket" << std::endl;
return 0;
}
server = gethostbyname(host.c_str());
if (server == NULL){
std::cout << "could Not resolve hostname :(" << std::endl;
close(socket_desc);
return 0;
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(std::stoi(port));
bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
if (connect(socket_desc, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
std::cout << "connection failed :(" << std::endl;
close(socket_desc);
return 0;
}
std::string request = "GET " + resource + query + " HTTP/1.1\r\nHost: " + host + "\r\nConnection: close\r\n\r\n";
if (send(socket_desc, request.c_str(), request.size(), 0) < 0){
std::cout << "failed to send request..." << std::endl;
close(socket_desc);
return 0;
}
int n;
std::string raw_site;
while ((n = recv(socket_desc, buffer, sizeof(buffer), 0)) > 0){
raw_site.append(buffer, n);
}
close(socket_desc);
std::cout << raw_site << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)