zoukankan      html  css  js  c++  java
  • socket 请求接收完整的一个http响应(设置recv 接收超时选项SO_RCVTIMEO)

    在前面的系列网络编程文章中,我们都是使用socket 自己实现客户端和服务器端来互相发数据测试,现在尝试使用socket 客户端发

    送http 请求给某个网站,然后接收网站的响应数据。http 协议参考 这里

    代码如下:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
     
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>    //strlen
    #include<sys/socket.h>
    #include<arpa/inet.h> //inet_addr
    #include<netdb.h>
    #include<errno.h>

    int main(int argc , char *argv[])
    {
        int socket_desc;
        struct sockaddr_in server;
        char *message;

        //Create socket
        socket_desc = socket(AF_INET , SOCK_STREAM , 0);
        if (socket_desc == -1)
        {
            printf("Could not create socket");
        }

        char ip[20] = {0};
        char *hostname = "www.google.com.hk";
        struct hostent *hp;
        if ((hp = gethostbyname(hostname)) == NULL)
            return 1;
        //  #define h_addr h_addr_list[0]
        strcpy(ip, inet_ntoa(*(struct in_addr *)hp->h_addr_list[0]));

        server.sin_addr.s_addr = inet_addr(ip);
        server.sin_family = AF_INET;
        server.sin_port = htons( 80 );


        //Connect to remote server
        if (connect(socket_desc , (struct sockaddr *)&server , sizeof(server)) < 0)
        {
            puts("connect error");
            return 1;
        }

        puts("Connected ");

        //Send some data
        message = "GET /?st=1 HTTP/1.1 Host: www.google.com.hk ";
        if( send(socket_desc , message , strlen(message) , 0) < 0)
        {
            puts("Send failed");
            return 1;
        }
        puts("Data Send ");

        struct timeval timeout = {3, 0};
        setsockopt(socket_desc, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval));

        //Receive a reply from the server
        //loop
        int size_recv , total_size = 0;
        char chunk[512];
        while(1)
        {
            memset(chunk , 0 , 512); //clear the variable
            if((size_recv =  recv(socket_desc , chunk , 512 , 0) ) == -1)
            {
                if (errno == EWOULDBLOCK || errno == EAGAIN)
                {
                    printf("recv timeout ... ");
                    break;
                }
                else if (errno == EINTR)
                {
                    printf("interrupt by signal... ");
                    continue;
                }
                else if (errno == ENOENT)
                {
                    printf("recv RST segement... ");
                    break;
                }
                else
                {
                    printf("unknown error! ");
                    exit(1);
                }
            }
            else if (size_recv == 0)
            {
                printf("peer closed ... ");
                break;
            }
            else
            {
                total_size += size_recv;
                printf("%s" , chunk);
            }
        }

        printf("Reply received, total_size = %d bytes ", total_size);

        return 0;
    }

    输出如下:


    .............................省略................................



    从上面的输出可以看到有完整的<html> </html> ,即已经完整接收,但有一点不解的是为什么最后会接收到一个0? 

    Chunked transfer encoding uses a chunk size of 0 to mark the end of the content.


    程序中  struct timeval timeout = {3,0}; 

    setsockopt(socket_desc, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval));

    设置超时时间为3s,现在recv 为阻塞接收,如果超时时间内接收缓冲区没有一点数据,则返回-1 且errno = EWOULDBLOCK 。

    退出循环,程序结束。


    在这里顺便提一下,recv的第四个参数如果设置为MSG_WAITALL,在阻塞模式下不等到指定数目的数据是不会返回的,除非超时时间到或者被信号打断。但在这里我们并不知道对方会发来具体多少数据,所以不能使用这种方法来读取数据,否则可能出现一直阻塞的情况。


    注:在阻塞发送时,也有人喜欢设置发送超时,超时判断返回值,如果没有发送完整则继续发送。但实际上本身阻塞发送会一直阻

    塞到发送完整才返回,好像二者并无大的区别。

  • 相关阅读:
    网络协议栈(6)RFC793TCP连接时部分异常流程及实现
    网络协议栈(5)sendto/send返回成功意味着什么
    LeetCode——Detect Capital
    LeetCode——Find All Numbers Disappeared in an Array
    LeetCode——Single Number
    LeetCode——Max Consecutive Ones
    LeetCode——Nim Game
    LeetCode——Reverse String
    LeetCode——Next Greater Element I
    LeetCode——Fizz Buzz
  • 原文地址:https://www.cnblogs.com/alantu2018/p/8477074.html
Copyright © 2011-2022 走看看