Reputation: 7550
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
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
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:
Declare a buffer of a sufficient size, perhaps 4096 bytes or more.
Read data into this buffer using read
and your connfd
until:
You have received 4095 bytes (in which case your server should respond with error 413)
You have encountered the characters "\r\n\r\n"
(this indicates a blank line)
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()
.
Once you have received the HTTP request into your buffer, parse it:
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.
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.
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
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