SO. I'm trying to make a C application that retrieves the .html file from a server, for example www.example.com. For this I'm using Sockets and connect
send
and recv
methods. 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:
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?
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.
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.
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()
. So you are only sending 4 bytes ("GET "
) or 8 bytes ("GET /ind"
), depending on whether you are compiling a 32bit or 64bit executable. You need to use strlen()
instead of 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. But more importantly, the data being received is not null-terminated, but your call to printf()
after recv()
assumes that it is. 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With