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\n");

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

     struct timeval timeout = { 30};
    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 ...\n");
                 break;
            }
             else  if (errno == EINTR)
            {
                printf( "interrupt by signal...\n");
                 continue;
            }
             else  if (errno == ENOENT)
            {
                printf( "recv RST segement...\n");
                 break;
            }
             else
            {
                printf( "unknown error!\n");
                exit( 1);
            }
        }
         else  if (size_recv ==  0)
        {
            printf( "peer closed ...\n");
             break;
        }
         else
        {
            total_size += size_recv;
            printf( "%s" , chunk);
        }
    }

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

     return  0;
}

输出如下:

socket 请求接收完整的一个http响应(设置recv 接收超时选项SO_RCVTIMEO)_第1张图片

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

socket 请求接收完整的一个http响应(设置recv 接收超时选项SO_RCVTIMEO)_第2张图片


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

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,在阻塞模式下不等到指定数目的数据是不会返回的,除非超时时间到。但在这里我们并不知道对方会发来具体多少数据,所以不能使用这种方法来读取数据,否则可能出现一直阻塞的情况。

你可能感兴趣的:(socket 请求接收完整的一个http响应(设置recv 接收超时选项SO_RCVTIMEO))