1 #include "stdafx.h" //控制台應用自帶頭文件,能夠加快編譯的速度
2 #include<winsock2.h> //通過該頭文件調用winsock的函數,如下文的WSAStartup、bind()、connect()、inet_addr()等
3 #include<windows.h> //調用windows內核及接口函數
4 #include<stdio.h>
5 #include<stdlib.h>
6 #include<assert.h>
7 #pragma comment(lib,"ws2_32") //說明需要使用win32的庫
8
9 int main(int argc, char* argv[]) { 10 int i; 11 SOCKET fd; //套接字初始化 12 SOCKADDR_IN addr; //該結構體初始化可以讓我們對 “協議簇類型、網絡地址、端口號”進行操作 13 WSADATA wsadata; 14
15 i = WSAStartup(0x0202, &wsadata); //說明Win32庫的版本及對象 16 fd = socket(PF_INET, SOCK_STREAM, 0); //協議類型、地址、端口號的初始化 17 addr.sin_addr.S_un.S_addr = 0; 18 addr.sin_family = AF_INET; 19 addr.sin_port = 0; 20
21 i = bind(fd, (sockaddr*)&addr, sizeof(SOCKADDR_IN)); //將上文的套接字進行綁定 22
23 addr.sin_addr.S_un.S_addr = inet_addr("202.119.224.201"); //確定IP地址和端口號 24 addr.sin_port = ntohs(80); 25
26 i = connect(fd, (sockaddr*)&addr, sizeof(SOCKADDR_IN)); //嘗試進行TCP三次握手 27 if (i == NOERROR) { 28 char *Buffer = new char[8193]; 29 i = sprintf(Buffer, "GET / HTTP/1.1\r\n" //HTTP協議的語法格式
30 "Host:www.njupt.edu.cn\r\n"
31 "User-Agent:whatever\r\n"
32 "Accept-Type:*/*\r\n"
33 "Connection:close\r\n"
34 "X-Power:XXX\r\n\r\n"); //注意這里要空一行,因為HTTP頭與體之間需要空一行進行區分
//否則對方服務器無法識別,請求無法通過
35 int n = send(fd, Buffer, i, 0); //發送請求數據 36 if (n == i) { 37 do { 38 i = recv(fd, Buffer, 8192, 0); //接收服務器響應 39 if (i <= 0) { 40 printf("closed by peer:%d\r\n", i); 41 break; 42 } 43 Buffer[i] = '\0'; 44 printf("%s\r\n", Buffer); //循環輸出網頁數據 45 } while ("Go!"); 46
47 } 48 else //兩個else是錯誤情況的反饋
49 { 50 printf("we can't send to...\r\n"); 51 } 52 delete[]Buffer; //數組使用完成,釋放掉數組空間 53 } 54 else
55 { 56 printf("we can't connect to..\r\n"); 57 } 58 i = closesocket(fd); //請求完成,關閉套接字,清除WSA 59 i = WSACleanup(); 60 system("pause"); 61 return 0; 62 }
需要明確兩個概念:
網絡字節:指的是網絡字節順序,它是TCP/IP協議中規定的字節順序,通常采用大端排序
主機字節:主機中內存地址順序。排序方式與CPU 操作系統有關。
結構體說明:
SOCK_STREAM,流套接字用於提供可靠有連接的數據傳輸服務,能夠保證無差錯、有順序、無重復接收,使用TCP協議。
SOCKET,套接字結構體
SOCKADDR_IN, 看一看它的結構相信就能夠有所理解了
struct SOCKADDR_IN{
short int sin_family; //通信協議類型族
unsigned short int sin_port; //端口號
struct in_addr sin_addr; //IP地址
unsigned char si_zero[8]; //填充0以保持與sockaddr結構的長度相同,這個暫時用不着
}
代碼中所說的HTTP結構需要空一行的原因用兩個個圖說明:
爭取下周把服務器的代碼也放出來