C语言 在 C 中使用套接字的 HTTP 请求
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30470505/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
HTTP Request using Sockets in C
提问by David Merinos
SO. I'm trying to make a C application that retrieves the .html file from a server, for example www.example.com. For this I'm using Sockets and connectsendand recvmethods. My implementation looks like this:
所以。我正在尝试制作一个从服务器检索 .html 文件的 C 应用程序,例如www.example.com。为此,我使用套接字connectsend和recv方法。我的实现是这样的:
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(void) {
//Stream sockets and rcv()
struct addrinfo hints, *res;
int sockfd;
char buf[2056];
int byte_count;
//get host info, make socket and connect it
memset(&hints, 0,sizeof hints);
hints.ai_family=AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
getaddrinfo("www.example.com","80", &hints, &res);
sockfd = socket(res->ai_family,res->ai_socktype,res->ai_protocol);
printf("Connecting...\n");
connect(sockfd,res->ai_addr,res->ai_addrlen);
printf("Connected!\n");
char *header = "GET /index.html HTTP/1.1\nHost: www.example.com\n";
send(sockfd,header,sizeof header,0);
printf("GET Sent...\n");
//all right ! now that we're connected, we can receive some data!
byte_count = recv(sockfd,buf,sizeof buf,0);
printf("recv()'d %d bytes of data in buf\n",byte_count);
printf("%s",buf);
return 0;
}
But the thing is that it gets stuck at the recvfor some seconds, then the buffer bufis filled with this:
但问题是它卡在了recv几秒钟,然后缓冲区buf充满了这个:
HTTP/1.0 408 Request Timeout
Content-Type: text/html
Content-Length: 431
Connection: close
Date: Tue, 26 May 2015 23:08:46 GMT
Server: ECSF (fll/0781)
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>408 - Request Timeout</title>
</head>
<body>
<h1>408 - Request Timeout</h1>
<div>Server timeout waiting for the HTTP request from the client.</div>
</body>
</html>
Apparently the server never gets my GET string or it might be mal-formed, what is the correct way to go around with this?
显然服务器永远不会得到我的 GET 字符串或者它可能是格式错误的,解决这个问题的正确方法是什么?
I already downloaded libcurl and even got the http response in a file (which is great so I can process it later) but I was eager to do it all by hand.
我已经下载了 libcurl,甚至在一个文件中得到了 http 响应(这很好,所以我可以稍后处理它),但我很想手工完成这一切。
What am I missing here?
我在这里缺少什么?
回答by Remy Lebeau
The reason the server is timing out is because you are not sending a valid request. Like Halim pointed out, your request data incomplete, you are using LFinstead of CRLFfor the line breaks, and missing the final line break to end the request header.
服务器超时的原因是您没有发送有效的请求。就像 Halim 指出的那样,您的请求数据不完整,您使用的是LF代替CRLF换行符,并且缺少最后的换行符来结束请求标头。
But, even after fixing that, your code is STILL not sending the request correctly. This is because you are using a char*to point at your request data, and then passing sizeof(char*)as the data length to send(). So you are only sending 4 bytes ("GET ") or 8 bytes ("GET /ind"), depending on whether you are compiling a 32bit or 64bit executable. You need to use strlen()instead of sizeof():
但是,即使修复了该问题,您的代码仍然无法正确发送请求。这是因为您使用 achar*指向您的请求数据,然后将sizeof(char*)数据长度传递给send(). 因此,您只发送 4 个字节 ( "GET ") 或 8 个字节 ( "GET /ind"),具体取决于您是编译 32 位还是 64 位可执行文件。您需要使用strlen()代替sizeof():
char *header = "GET /index.html HTTP/1.1\r\nHost: www.example.com\r\n\r\n";
send(sockfd,header,strlen(header),0);
Once you get that part working, your recv()logic is not parsing the server's response at all, which I assume is you simply not having gotten that far yet. But more importantly, the data being received is not null-terminated, but your call to printf()after recv()assumes that it is. You need to fix that as well, either like this:
一旦你让那部分工作,你的recv()逻辑就根本没有解析服务器的响应,我认为你只是还没有走那么远。但更重要的是,正在接收的数据不是以 null 结尾的,但您对printf()after的调用recv()假定它是。你也需要解决这个问题,或者像这样:
byte_count = recv(sockfd,buf,sizeof(buf)-1,0); // <-- -1 to leave room for a null terminator
buf[byte_count] = 0; // <-- add the null terminator
printf("recv()'d %d bytes of data in buf\n",byte_count);
printf("%s",buf);
Or, like this:
或者,像这样:
byte_count = recv(sockfd,buf,sizeof(buf),0);
printf("recv()'d %d bytes of data in buf\n",byte_count);
printf("%.*s",byte_count,buf); // <-- give printf() the actual data size
And, of course, none of your code has any error handling in it at all. You really need to do that.
而且,当然,您的代码中根本没有任何错误处理。你真的需要这样做。
回答by Halim Qarroum
Each header must end with a \r\ninstead of \n. And there is an additional \r\nto add at the end of the request :
每个标头必须以一个\r\n而不是结束\n。\r\n在请求的末尾还有一个额外的添加:
GET /index.html HTTP/1.1\r\n
Host: www.example.com\r\n
\r\n

