博客專欄

        EEPW首頁 > 博客 > 使用 C 語言實現一個 HTTP GET 連接

        使用 C 語言實現一個 HTTP GET 連接

        發布人:電子禪石 時間:2024-05-16 來源:工程師 發布文章

         

        如果您比較有耐心,建議從頭至尾讀完這篇文章。如果您只想快速應用 C 語言的 HTTP GET 連接功能,可以直接跳到文末拷貝源代碼去使用

         

        1、HTTP 連接的流程

         

        HTTP 連接都是建立在 TCP 連接之上的。這里我們不討論 TCP 的三次握手四次揮手過程。我們只單純地來分析下一個 HTTP 連接的過程應該是怎樣的。

         

        首先,我們需要創建一個 TCP 的 Socket 。后面我們的網絡連接操作都是基于這個 Socket 來構建的。

         

        其次,我們需要來組裝一下 HTTP 請求。就是封裝一個 GET 請求,表明一下我們想要連接哪個服務器的哪些資源。當然,其實第 1 步和第 2 步的順序并不重要。

         

        第三步,我們需要發送 HTTP GET 請求了,將前面封裝好的請求信息通過前面創建好的 TCP 通道發送出去。

         

        第四步,讀取服務端的返回結果。

         

        2、代碼實操

         

        1、創建 Socket
        復制代碼
            int sockfd;     
             //創建套接字
            if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
                printf("socket failed!!!\n");
                exit(0);
            }
        復制代碼

        沒什么好說的,照著做就好了。

         

        2、封裝 HTTP 請求
        復制代碼
            char request[512] = {0};
            memset(request, 0, 512);
            strcat(request, "GET ");
            strcat(request, "/index.html");
            strcat(request, " HTTP/1.1\n");
            strcat(request, "Host: ");
            strcat(request, "192.168.221.30");
            strcat(request, "\nContent-Type: text/html\n");
            strcat(request, "Content-Length: 0\n");
            strcat(request, "\r\n");
        復制代碼

        上面加粗標灰底的部分分別是要訪問的資源路徑以及服務器地址。其中服務器地址并不是很重要,但是上面的資源路徑一定不能錯!

         

        3、發起 HTTP 請求
        復制代碼
            struct sockaddr_in servaddr;    int writeRet;
            
            bzero(&servaddr, sizeof(servaddr));
            servaddr.sin_family = AF_INET;
            servaddr.sin_port = htons(80);    
            if (inet_pton(AF_INET, "192.168.221.30", &servaddr.sin_addr) <= 0 ){
                printf("inet_pton error!\n");
                exit(0);
            }    if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0){
                printf("connect error!\n");
                exit(0);
            }
        
            writeRet = write(sockfd, request, strlen(request));    if (writeRet < 0) {
                printf("make http error:%d,%s\n", errno, strerror(errno));
                exit(0);
            }
        復制代碼

        上面加粗標灰底的地址就很重要了,一定不能填錯,而且只能填 IP 地址。那個部分的 inet_pton 函數的作用是將字符串形式的 IPV4 地址轉換成二進制形式的。如果是 IPV6 地址,則要用 inet_ntop 函數。

         

        4、讀取返回結果
        復制代碼
            struct timeval tv;    int selectRet = 0;
            fd_set t_set1;
            
            sleep(2);
            
            tv.tv_sec= 0;
            tv.tv_usec= 0;
        
            FD_ZERO(&t_set1);
            FD_SET(sockfd, &t_set1);
            
            selectRet = select(sockfd + 1, &t_set1, NULL, NULL, &tv);    if (selectRet < 0) {
                close(sockfd);
                printf("select failed!\n");        return;
            }    if (selectRet > 0){        char buf[4096] = {0};        int readLen = 0;
        
                memset(buf, 0, 4096);
                readLen = read(sockfd, buf, 4095); // read once only!
                printf("readLen:%d\n", readLen);
                printf("\n\n%s\n\n", buf);
            }
        復制代碼

        上示代碼最后會將讀取的結果保存到 buf 數組中并打印出來。

         

        5、關閉 Socket
            close(sockfd);
            
            printf("Bye!\n");

        最后,用完 HTTP 通信以后,一定不要忘記關閉剛才打開的資源。

         

        筆者這邊通過 nginx 搭建了一個模擬服務器,與這份代碼調試,一切正常。可以在控制臺上得到如下回復

        復制代碼
        hello world-------------GET /index.html HTTP/1.1Host: 192.168.221.30Content-Type: text/html
        Content-Length: 0>>>>>>> success with 90 byte(s) <<<<<<<readLen:850HTTP/1.1 200 OK
        Server: nginx/1.16.0Date: Wed, 08 May 2019 06:13:27 GMT
        Content-Type: text/html
        Content-Length: 612Last-Modified: Tue, 23 Apr 2019 13:09:07 GMT
        Connection: keep-alive
        ETag: "5cbf0e73-264"Accept-Ranges: bytes<!DOCTYPE html>
        <html>
        <head>
        <title>Welcome to nginx!</title>
        <style>
            body {
                width: 35em;
                margin: 0 auto;
                font-family: Tahoma, Verdana, Arial, sans-serif;
            }</style>
        </head>
        <body>
        <h1>Welcome to nginx!</h1>
        <p>If you see this page, the nginx web server is successfully installed and
        working. Further configuration is required.</p>
        
        <p>For online documentation and support please refer to<a href="http://nginx.org/">nginx.org</a>.<br/>Commercial support is available at<a href="http://nginx.com/">nginx.com</a>.</p>
        
        <p><em>Thank you for using nginx.</em></p>
        </body>
        </html>Bye!
        復制代碼

         

        再接下來,就是根據自己的實際需要,去做業務層的處理了。

         

        3、完整代碼

         

        復制代碼
        #include <stdio.h>#include <stdlib.h>#include <sys/socket.h>#include <string.h>#include <netinet/in.h>#include <errno.h>#include "http.h"void main()
        {
            
            printf("hello world\n");    
            // step 1 , create socket
            int sockfd;     
             //創建套接字
            if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
                printf("socket failed!!!\n");
                exit(0);
            }    
            // step 2, package the http request
            char request[512] = {0};
            memset(request, 0, 512);
            strcat(request, "GET ");
            strcat(request, "/index.htm");
            strcat(request, " HTTP/1.1\n");
            strcat(request, "Host: ");
            strcat(request, "www.baidu.com");
            strcat(request, "\nContent-Type: text/html\n");
            strcat(request, "Content-Length: 0\n");
            strcat(request, "\r\n");
            printf("-------------\n%s\n",request);    
            
            // step 3, connect and send http request.
            struct sockaddr_in servaddr;    int writeRet;
            
            bzero(&servaddr, sizeof(servaddr));
            servaddr.sin_family = AF_INET;
            servaddr.sin_port = htons(80);    
            if (inet_pton(AF_INET, "192.168.221.30", &servaddr.sin_addr) <= 0 ){
                printf("inet_pton error!\n");
                exit(0);
            }    if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0){
                printf("connect error!\n");
                exit(0);
            }
        
            writeRet = write(sockfd, request, strlen(request));    if (writeRet < 0) {
                printf("make http error:%d,%s\n", errno, strerror(errno));
                exit(0);
            }
        
            printf(">>>>>>> success with %d byte(s) <<<<<<<\n", writeRet);    
            
            // step 4, read response
            
            struct timeval tv;    int selectRet = 0;
            fd_set t_set1;
            
            sleep(2);
            
            tv.tv_sec= 0;
            tv.tv_usec= 0;
        
            FD_ZERO(&t_set1);
            FD_SET(sockfd, &t_set1);
            
            selectRet = select(sockfd + 1, &t_set1, NULL, NULL, &tv);    if (selectRet < 0) {
                close(sockfd);
                printf("select failed!\n");        return;
            }    if (selectRet > 0){        char buf[4096] = {0};        int readLen = 0;
        
                memset(buf, 0, 4096);
                readLen = read(sockfd, buf, 4095); // read once only!
                printf("readLen:%d\n", readLen);
                printf("\n\n%s\n\n", buf);
            }
        
            close(sockfd);
            
            printf("Bye!\n");
        }
        復制代碼

         


         




        *博客內容為網友個人發布,僅代表博主個人觀點,如有侵權請聯系工作人員刪除。



        關鍵詞: http

        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 广平县| 汽车| 泗阳县| 灵石县| 铅山县| 湖南省| 贵州省| 应城市| 商南县| 进贤县| 巴林右旗| 孟津县| 黄陵县| 扶风县| 康保县| 寿宁县| 乐清市| 太原市| 延吉市| 石城县| 通城县| 青田县| 锡林浩特市| 西林县| 桐梓县| 慈溪市| 津南区| 姚安县| 德庆县| 延庆县| 永宁县| 枣阳市| 繁峙县| 弋阳县| 宝鸡市| 锡林浩特市| 广灵县| 阿城市| 虞城县| 勐海县| 靖州|