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 = {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,在阻塞模式下不等到指定數目的資料是不會返回的,除非超時時間到或者被訊號打斷。但在這裡我們並不知道對方會發來具體多少資料,所以不能使用這種方法來讀取資料,否則可能出現一直阻塞的情況。
注:在阻塞傳送時,也有人喜歡設定傳送超時,超時判斷返回值,如果沒有傳送完整則繼續傳送。但實際上本身阻塞傳送會一直阻
塞到傳送完整才返回,好像二者並無大的區別。
相關文章
- 完整的一次 HTTP 請求響應過程(一)HTTP
- 完整的一次 HTTP 請求響應過程(二)HTTP
- 設定讓ASP.NET管道接收所有型別的請求ASP.NET型別
- HTTP的請求與響應HTTP
- HTTP 請求與響應HTTP
- Http請求與響應HTTP
- 【Python】python透過get方式,post方式傳送http請求和接收http響應PythonHTTP
- okhttp 原始碼解析 - 網路協議的實現 - 請求流程: 請求的傳送與響應的接收HTTP原始碼協議
- 一次完整的HTTP請求HTTP
- PHP 是怎麼接收到請求的?PHP
- Go如何響應http請求?GoHTTP
- 理解Http請求與響應HTTP
- 解決 Laravel 接收非簡單請求時,只有收到 OPTIONS 請求的問題Laravel
- HTTP請求格式和HTTP響應格式HTTP
- 如何理解Cookie的接收與響應?Cookie
- System.ServiceModel.CommunicationException: 接收HTTP 響應時發生錯誤ExceptionHTTP
- HTTP協議---HTTP請求中的常用請求欄位和HTTP的響應狀態碼及響應頭HTTP協議
- SOCKET模擬HTTP請求HTTP
- HTTP請求與響應簡析HTTP
- HTTP請求頭與響應頭HTTP
- 分析HTTP請求以降低HTTP走私攻擊HTTP資料接收不同步攻擊的風險HTTP
- http請求頭與響應頭的應用HTTP
- angular學習筆記(二十六)-$http(4)-設定請求超時Angular筆記HTTP
- axios請求超時,設定重新請求的完美解決方法iOS
- 一次完整的 HTTP 請求過程HTTP
- 一次完整的HTTP請求過程HTTP
- RESTFUL風格的URL請求及引數接收REST
- 精講響應式WebClient第5篇-請求超時設定與異常處理Webclient
- 【踩坑】spring mvc在接收請求引數時由於大小寫問題導致的接收失敗SpringMVC
- 使用Spring Integration接收TCP與UDP請求SpringTCPUDP
- JAVA設定http請求代理JavaHTTP
- Angular 記錄 - Rxjs 完整處理一個 Http 請求AngularJSHTTP
- Socket程式設計注意接收緩衝區大小程式設計
- Spring MVC能響應HTTP請求的原因?SpringMVCHTTP
- 為什麼使用Socket接收時丟失資料?
- Java後端請求想接收多個物件入參的資料方法Java後端物件
- 指令碼化HTTP 取得響應 指定請求指令碼HTTP
- HTTP請求頭和響應頭詳解HTTP