博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
socket 请求接收完整的一个http响应(设置recv 接收超时选项SO_RCVTIMEO)
阅读量:6877 次
发布时间:2019-06-26

本文共 2978 字,大约阅读时间需要 9 分钟。

在前面的系列网络编程文章中,我们都是使用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 = {
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 ...\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;
}

 

输出如下:

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

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

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

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

转载于:https://www.cnblogs.com/alantu2018/p/8477074.html

你可能感兴趣的文章
Android SurfaceView概述
查看>>
at android.view.Surface.unlockCanvasAndPost(Native Method)
查看>>
[LeetCode] Convert Sorted List to Binary Search Tree DFS,深度搜索
查看>>
VS2010下开发WebApi 基本步骤
查看>>
WPF 外发光效果
查看>>
Less主要用法
查看>>
定时器
查看>>
js 字符串拼接 html 累加 html 叠加
查看>>
Android启动页面实现版本检查更新
查看>>
如何在ASP.NET MVC 中获取当前URL、controller、action
查看>>
Freemarket语法
查看>>
Windows7系统中怎么Ping端口?利用telnet命令Ping 端口的方法
查看>>
摩客、墨刀、axure,原型设计工具哪个好用?
查看>>
Flask
查看>>
正确使用lock 关键字
查看>>
虚拟内存管理
查看>>
iOS 10 之后权限设置
查看>>
c++ 函数指针
查看>>
三种vsftp安装方式
查看>>
angular validation 使用总结
查看>>