sadaf2605
sadaf2605

Reputation: 7550

Get requested address in socket programming with C

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);

Upvotes: 8

Views: 5183

Answers (3)

Clay
Clay

Reputation: 697

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

Upvotes: 0

dreamlax
dreamlax

Reputation: 95365

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.

Upvotes: 6

Ishmeet
Ishmeet

Reputation: 1620

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.

Upvotes: 1

Related Questions