Get requested address in socket programming with C
Asked Answered
U

3

8

I am using something like this to create a server using C. When I go to 127.0.0.1:5000 from my browser I can see "Hello Worlds" as I am sending it as buffer. But I want 127.0.0.1:5000/filename.html to work. But I don't know how to get filename that comes after 127.0.0.1:5000 in C.

I am using this to make connection:

  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);
Unveiling answered 25/7, 2013 at 6:37 Comment(2)
are you implementing http server?Sourwood
@sadaf2605: I updated my answer, for some reason I can't comment on itMitziemitzl
M
6

The browser will be sending your server an HTTP request that contains the URL it is after. The request could look like this:

GET /filename.html HTTP/1.1
Host: 127.0.0.1:5000

Your C program must read this request from the socket and parse it to find the URL. Note that the request will likely contain more information than the above, but it should always end with a blank line (so you know where to stop parsing). Lines in HTTP requests should end with both a carriage return and line feed ("\r\n").

You receive data through the same socket that you use to send data. The steps to read an HTTP request could be something like this:

  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.

Mitziemitzl answered 25/7, 2013 at 6:41 Comment(3)
Can you please help me a little more? How would I get/read/receive that GET request in C? I am still searching! :/Unveiling
What should be the code to read it? Code is much easier to understand than lengthy explanationBibliography
@JamesGuana, your first answer was well worded, did not address the OP's question. @Unveiling and Jones G are struggling to understand how to use recv. Rather than being snooty, why not just post a helpful example or nothing at all? @JamesGuana, see my example below...Neb
E
1

When data is received in the correct state, try to parse it as http request. Wait for CRLF CRLF (indicating end of http headers) before parsing anything,

#define CRLF "\r\n"

then you should search string within a string using

strnstr(data,CRLF CRLF,data_len)

Then url is just next to that, do +1 and you will find there.

Everyway answered 25/7, 2013 at 7:26 Comment(1)
My question was how would I retrieve requester url :/Unveiling
N
0

I found the highest rated answer helpful for understanding what needs to be done conceptually, but it falls short of helping new C/C++ developers understand how to read the header.

The trick is to realize that most TCP server examples you can find via Google stop short of showing the reader how to actually receive a request! You need to use the recv method and read the request into something that you can parse. In the below example, I am reading that into a vector<char> called but (short for buffer) and using the buf.data() to access the underlying char array for printing to the console.

Assume you have a new socket for client...

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;

To read more about the sockets API, the Wikipedia article is a surprisingly good resource. https://en.wikipedia.org/wiki/Berkeley_sockets

Neb answered 23/12, 2019 at 22:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.