简体   繁体   English

在C中使用套接字的HTTP请求

[英]HTTP Request using Sockets in C

SO. 所以。 I'm trying to make a C application that retrieves the .html file from a server, for example www.example.com . 我正在尝试创建一个从服务器检索.html文件的C应用程序,例如www.example.com For this I'm using Sockets and connect send and recv methods. 为此,我使用套接字并connect sendrecv方法。 My implementation looks like this: 我的实现看起来像这样:

#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 recv for some seconds, then the buffer buf is 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? 我在这里错过了什么?

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 LF instead of CRLF for 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() . 这是因为您使用char*指向您的请求数据,然后将sizeof(char*)作为数据长度传递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. 因此,您只发送4个字节( "GET " )或8个字节( "GET /ind" ),具体取决于您是编译32位还是64位可执行文件。 You need to use strlen() instead of sizeof() : 您需要使用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. 一旦你使这个部分工作,你的recv()逻辑根本不解析服务器的响应,我认为你根本就没有那么远。 But more importantly, the data being received is not null-terminated, but your call to printf() after recv() assumes that it is. 但更重要的是,接收的数据不是以空值终止的,但是在recv()之后调用printf() recv()假设它是。 You need to fix that as well, either like this: 您也需要解决这个问题,或者像这样:

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. 你真的需要这样做。

Each header must end with a \\r\\n instead of \\n . 每个标头必须以\\r\\n而不是\\n结尾。 And there is an additional \\r\\n to add at the end of the request : 并且在请求结束时还有一个额外的\\r\\n要添加:

GET /index.html HTTP/1.1\r\n
Host: www.example.com\r\n
\r\n

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM