使用C语言进行套接字编程时,如何获取请求的地址?

8
我正在使用类似以下的代码来使用C语言创建服务器。当我在浏览器中输入127.0.0.1:5000时,我可以看到"Hello Worlds",因为我将其作为缓冲区发送。但是我想让127.0.0.1:5000/filename.html也能够工作。但是我不知道如何在C语言中获取出现在127.0.0.1:5000后面的filename
我正在使用以下代码进行连接:
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  serv_addr.sin_port = htons(5000);

  bind(listenfd, (struct sockaddr*)&serv_addr,sizeof(serv_addr));

  connfd = accept(listenfd, (struct sockaddr*)NULL ,NULL);

你正在实现HTTP服务器吗? - Grijesh Chauhan
@sadaf2605:我更新了我的答案,不知道为什么无法对其进行评论。 - dreamlax
3个回答

6
浏览器将向您的服务器发送一个包含所需URL的HTTP请求。请求可能如下所示:
GET /filename.html HTTP/1.1
Host: 127.0.0.1:5000

你的C程序必须从套接字读取此请求并进行解析以查找URL。请注意,请求可能包含比上述更多的信息,但它应始终以空行结尾(因此您知道在何处停止解析)。HTTP请求中的行应以回车和换行符("\r\n")结束。
你通过与发送数据使用相同的套接字接收数据。读取HTTP请求的步骤可能如下:
  1. Declare a buffer of a sufficient size, perhaps 4096 bytes or more.

  2. Read data into this buffer using read and your connfd until:

    1. You have received 4095 bytes (in which case your server should respond with error 413)

    2. You have encountered the characters "\r\n\r\n" (this indicates a blank line)

    3. Some amount of time has passed and neither of the above has occurred. In order to implement a timeout you will need to use select() or poll().

  3. Once you have received the HTTP request into your buffer, parse it:

    1. The first line is the request line which dictates the method of the request, the URI, and the protocol version number. A possible way to parse this line is to split it by space.

    2. Subsequent lines represent HTTP header fields, and can generally be parsed as Key: Value\r\n. These header fields contain cookies, information about the client making the request, etc.

  4. You need to form your HTTP response as well. A response for when the URI specifies a valid resource (such as filename.html) might be:

    HTTP/1.1 200 OK
    Date: Thu, 25 Jul 2013 03:55:00 GMT
    Server: sadaf2605-server/1.0
    Content-Type: text/html
    Content-Length: 40595
    
    < contents of filename.html follows here >
    

    In the above, Content-Length refers to the number of bytes in the filename.html file. Just like the request, a response is separated from data using a blank line.


请问您能再帮我一下吗?我该如何在 C 语言中获取/读取/接收那个 GET 请求呢?我还在继续搜索! :/ - sadaf2605
读取它的代码应该是什么?代码比冗长的解释更容易理解。 - Jones G
@JamesGuana,你的第一个回答措辞得当,但并没有回答OP的问题。@sadaf2605和Jones G正在努力理解如何使用recv。与其傲慢无礼,为什么不发表一个有用的例子或者干脆什么都不说呢?@JamesGuana,看看我下面的例子... - Clay

1
当数据处于正确状态时,尝试将其解析为http请求。在解析任何内容之前,请等待CRLF CRLF(表示http头的结束)。
#define CRLF "\r\n"

那么你应该使用字符串中的字符串搜索

strnstr(data,CRLF CRLF,data_len)

那么url就在它旁边,加1就能找到它。


我的问题是如何获取请求者的URL:/ - sadaf2605

0

我发现最高评分的答案对于理解概念上需要做什么非常有帮助,但它没有帮助新的C/C++开发人员了解如何读取头文件。

诀窍在于意识到大多数通过Google可以找到的TCP服务器示例都没有展示如何实际接收请求!您需要使用recv方法并将请求读入可以解析的内容。在下面的示例中,我将其读入名为but(缩写为buffer)的vector<char>中,并使用buf.data()访问底层字符数组以打印到控制台。

假设您有一个新的客户端套接字...

listen(sock, 5);
while (1) {

    // Make a new socket for the client that just tried to connect
    client_fd = accept(sock, (struct sockaddr *) &cli_addr, &sin_len);

    char buffer[1024] = {0};
    int server_fd, new_socket, valread;
    valread = read(sock , buffer, 1024);
    std::cout << buffer << std::endl;

    printf("got connection\n");

    // Handle a case where you can't accept the request
    if (client_fd == -1) {
        perror("Can't accept");
        continue;
    }

    // Recieve data from the new socket that we made for the client
    // We are going to read the header into the vector<char>, and then
    // you can implement a method to parse the header.
    vector<char> buf(5000); // you are using C++ not C
    int bytes = recv(client_fd, buf.data(), buf.size(), 0);
    std::cout << bytes << std::endl;

    std::cout << sizeof(buf);
    std::cout << buf.data() << buf[0] << std::endl;

如果想要了解更多有关套接字 API 的内容,维基百科文章是一个出人意料的好资源。https://en.wikipedia.org/wiki/Berkeley_sockets


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接