Thread: Socket Programming - Trouble Connecting to HTTP Server

  1. #1
    Registered User Mcdom34's Avatar
    Join Date
    Jun 2012
    Location
    North Royalton, Ohio, United States
    Posts
    22

    Socket Programming - Trouble Connecting to HTTP Server

    I've written a program that should establish a connection with a remote HTTP server, send it a request, and then print a response to the standard output.

    However, for some reason I cannot connect my socket. I have been around multiple sites and they each say that I'm doing everything right, so I'm not sure what's going on. I've posted my code below.

    I keep getting `Connection attempt failed. Program terminating...`

    Code:
    #include <netdb.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    
    
    int main(int argc, char *argv[])
    {
        FILE *fout;
    
    
        int c, sk;
        char *tk, host[64], path[64], fname[64], http_msg[256], buf[1024];
        
        struct sockaddr_in remote;
        struct hostent *hp;
        struct servent *se;
    
    
        if(argc != 2)
        {
            printf("Invalid number of arguments. Program terminating...\n");
            exit(1);
        }
    
    
        sk = socket(AF_INET, SOCK_STREAM, 0);
        if(sk == -1)
        {
            printf("Error opening socket. Program terminating...\n");
            exit(1);
        }
        
        c = 0;
        tk = strtok(argv[1], "/");
        while(tk != NULL)
        {
            if(c == 0)
                strcpy(host, tk);
            else if(c == 1)
                strcpy(path, tk);
            else
                strcpy(fname, tk);
            ++c;
            tk = strtok(NULL, "/");
        }
        
        snprintf(http_msg, 256, "GET /%s/%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", path, fname, host);
    
    
        hp = gethostbyname(host);
        if(hp == NULL)
        {
            printf("Can't find host %s. Program terminating...\n", host);
            exit(1);
        }
    
    
        remote.sin_family = AF_INET;
        bcopy((char *)hp->h_addr, (char *)&remote.sin_addr.s_addr, hp->h_length);
        se = getservbyname("http", "tcp");
        remote.sin_port = htons(se->s_port);    
        
        if(connect(sk, (struct sockaddr *)&remote, sizeof(remote)) == -1)
        {
            printf("Connection attempt failed. Program terminating...\n");
            exit(1);
        }
    
    
        send(sk, http_msg, sizeof(http_msg) + 1, 0);
        recv(sk, buf, sizeof(buf), 0);
        printf("%s\n", buf);
        
        fout = fopen(fname, "w");
        write(fout, buf, 1024);
    
    
        fclose(fout);
        close(sk);
    
    
        return 0;
    }

  2. #2
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    First, you forgot to #include <unistd.h> for the low-level I/O (close() in particular).

    Quote Originally Posted by Mcdom34 View Post
    Code:
    snprintf(http_msg, 256, "GET /%s/%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", path, fname, host);
    The result of that function is the number of bytes you should be send()ing. Because you use some other number -- in particular, adding any +1 for the end-of-string NUL byte is completely incorrect; the HTTP protocol does not include any NUL bytes -- you end up sending malformed requests, and even after other fixes you'll just get an "HTTP/1.0 400 Bad Request" response from any server you connect to.


    Quote Originally Posted by Mcdom34 View Post
    Code:
        se = getservbyname("http", "tcp");
        remote.sin_port = htons(se->s_port);
    No. getservbyname() returns a pointer to a struct servent yes, but its s_port field is in network byte order. In other words, no need to use htons() here; a simple assignment is needed.


    Quote Originally Posted by Mcdom34 View Post
    Code:
        send(sk, http_msg, sizeof(http_msg) + 1, 0);
        recv(sk, buf, sizeof(buf), 0);
    As mentioned above, sizeof http_msg + 1 is wrong. Not only is the idea wrong (sending the string and the tailing NUL byte '\0' -- you do not send the NUL bytes in HTTP messages), but you actually insist on doing a buffer overflow -- you're saying: "send the contents of this array, plus whatever byte might exist past the buffer".

    I also find it extremely disconcerting that you do not concern yourself with the function return values. Not only is it a bad habit, but with TCP/IP connections, it guarantees incorrect results. No, no hyperbole, I'm serious. You see, the transmission of data takes a long time in terms of program execution, and it tends to arrive in smallish chunks. The chunk size depends on the exact network path taken, and varies a lot -- although something around 1500 bytes is very common. In particular, the chunks never seem to end at nice boundaries, but might get split in the middle of a HTTP header.

    Instead just "throwing it out there" like an optimistic hippie, you should have much more of an engineering attitude, and keep your eyes on what is actually happening, taking firm control and responsibility of the logic, and not just hoping it works and nothing goes wrong.


    Quote Originally Posted by Mcdom34 View Post
    Code:
        fout = fopen(fname, "w");
        write(fout, buf, 1024);
        fclose(fout);
    I can tell you were hoping this would write the buffer to a file, but you're not only just writing 1024 bytes to it, you're also mixing low-level I/O and standard I/O, which will not work. Instead of write(), you should use fwrite(buf, 1, len, fout)..where len is the number of bytes you recv()ed.

    Quote Originally Posted by Mcdom34 View Post
    I have been around multiple sites and they each say that I'm doing everything right
    They're incompetent. Your code does not perform the way it is intended, and the intended behaviour is common and simple, so there is something wrong and fixable. The errors are not eye-pokingly obvious, but are there if you care to read through carefully enough.

    Note that I'd use getaddrinfo() interface instead of gethostbyname()/getservbyname(). That way your code would be trivial to enhance to work with both IPv4 and IPv6 connections.

  3. #3
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    27,070
    *Moved to Networking/Device Communication forum*
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. socket programming, simple echo server and client
    By blob84 in forum Linux Programming
    Replies: 5
    Last Post: 03-21-2014, 05:33 PM
  2. Replies: 1
    Last Post: 03-04-2013, 01:06 AM
  3. Replies: 2
    Last Post: 06-30-2010, 06:52 PM
  4. SOcket programming trouble
    By sodja in forum Networking/Device Communication
    Replies: 1
    Last Post: 01-11-2008, 10:20 AM
  5. Socket Programming: Retrieve file from HTTP
    By Tommo in forum Networking/Device Communication
    Replies: 9
    Last Post: 09-05-2007, 06:15 AM

Tags for this Thread