在前面的系列網絡編程文章中,咱們都是使用socket 本身實現客戶端和服務器端來互相發數據測試,如今嘗試使用socket 客戶端發html
送http 請求給某個網站,而後接收網站的響應數據。http 協議參考 這裏。編程
代碼以下:服務器
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; } |
輸出以下:網絡
.............................省略................................socket
從上面的輸出能夠看到有完整的<html> </html> ,即已經完整接收,但有一點不解的是爲何最後會接收到一個0? oop
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));
google
設置超時時間爲3s,如今recv 爲阻塞接收,若是超時時間內接收緩衝區沒有一點數據,則返回-1 且errno = EWOULDBLOCK 。spa
退出循環,程序結束。
在這裏順便提一下,recv的第四個參數若是設置爲MSG_WAITALL,在阻塞模式下不等到指定數目的數據是不會返回的,除非超時時間到或者被信號打斷。但在這裏咱們並不知道對方會發來具體多少數據,因此不能使用這種方法來讀取數據,不然可能出現一直阻塞的狀況。
注:在阻塞發送時,也有人喜歡設置發送超時,超時判斷返回值,若是沒有發送完整則繼續發送。但實際上自己阻塞發送會一直阻
塞到發送完整才返回,好像兩者並沒有大的區別。