第13章學習筆記
一、概述
本章論述了TCP/IP和網路程式設計,分為兩個部分。第一部分論述了TCP/IP協議及其應用,具體包括TCP/IP棧、IP地址、主機名、DNS、IP資料包和路由器;介紹了TCP/P網路中的UDP和TCP協議、埠號和資料流;闡述了伺服器-客戶機計算模型和套接字程式設計介面;通過使用UDP和TCP套接字的示例演示了網路程式設計。第一個程式設計專案可實現一對通過網際網路執行檔案操作的TCP伺服器–客戶機,可讓使用者定義其他通訊協議來可靠地傳輸檔案內容。
本章的第二部分介紹了Web和CGI程式設計,解釋了HTTP程式設計模型、Web頁面和Web瀏覽器;展示瞭如何配置Linux HTTPD伺服器來支援使用者Web頁面、PHP和CGI程式設計;闡釋了客戶機和伺服器端動態Web頁面;演示瞭如何使用PHP和CGI建立伺服器端動態Web頁面。
二、學到了什麼
1.TCP/IP協議
TCP/IP(Comer 1988,2001;RFC1180 1991)是網際網路的基礎。TCP代表傳輸控制協議。IP 代表網際網路協議。目前有兩個版本的IP,即IPv4和IPv6。IPv4使用32位地址,IPv6則使用128位地址。本節圍繞IPv4 進行討論,它仍然是目前使用最多的IP版本。TCP/IP 的組織結構分為幾個層級,通常稱為TCP/IP堆疊。如圖所示為 TCP/IP 的各個層級以及每一層級的代表性元件及其功能。
2.IP協議:
用於在IP主機之間傳送/接收資料包。IP盡最大努力執行。IP主機只向接收主機發送資料包,但它不能保證資料包會被髮送到它們的目的地,也不能保證按順序傳送。
3.IP資料包:
由IP頭、傳送方地址和接收方I地址以及資料組成。每個資料包的大小最大為64KB。IP頭包含有關資料包的更多資訊,例如資料包的總長度、資料包使用TCP還是UDP、生存時間(TTL)計數、錯誤檢測的校驗和等。
4.UDP/TCP
UDP(使用者資料報協議)
在IP上執行,用於傳送/接收資料報。與IP類似,UDP不能保證可靠性,但是快速高效。它可用於可靠性不重要的情況。
TCP(傳輸控制協議)
是一種面向連線的協議,用於傳送/接收資料流。TCP也可在IP 上執行,但它保證了可靠的資料傳輸。通常,UDP類似於傳送郵件的USPS,而TCP類似於電話連線。
5.埠編號:
埠號是分配給應用程式的唯一無符號短整數。要想使用UDP或TCP,應用程式(程序)必須先選擇或獲取一個埠號。前1024個埠號已被預留。其他埠號可供一般使用。應用程式可以選擇一個可用埠號,也可以讓作業系統核心分配埠號。
6.網路和主機位元組序:
計算機可以使用大端位元組序,也可以使用小端位元組序。在網際網路上,資料始終按網路序排列,這是大端。在小端機器上,例如基於Intel x86的PC,htons()、htonl()、ntohs()、ntohl()等庫函式,可在主機序和網路序之間轉換資料。例如,PC中的埠號1234按主機位元組序(小端)是無符號短整數。必須先通過htons(1234)把它轉換成網路序,才能使用。相反,從網際網路收到的埠號必須先通過ntohs(port)轉換為主機序。
7.TCP/Ip網路中的資料流
8.網路程式設計
伺服器 — 客戶機計算模型
在伺服器 — 客戶機計算模型中,我們首先在伺服器主機上執行伺服器程序。然後,我們從客戶主機執行客戶及。在UDP中,伺服器等待來自客戶機的戶籍包,處理資料包並生成對客戶及的相應。在TCP中,伺服器等待客戶機連線。客戶機首先連線到伺服器,在客戶機和伺服器之間建立一個虛擬電路。
9. 套接字地址
建立套接字的函式 socket 的三個引數的含義:
domain:使用的協議族。一般只會用到 PF_INET,即 IPv4 協議族。
type:套接字型別,即套接字的資料傳輸方式。主要是兩種:SOCK_STREAM(即 TCP)和 SOCK_(即 UDP)。
protocol:選擇的協議。一般情況前兩個引數確定後,protocol 也就確定了,所以設為 0 即可。
10.套接字型別
同一個協議族可能有多種資料傳輸方式,因此在指定了 socket 的第一個引數後,還要指定第二個引數 type。
SOCK_STREAM 代表的是 TCP 協議,會建立面向連線的套接字,有如下特點:
1.可靠傳輸,傳輸的資料不會消失。
2.按序傳輸。
3.傳輸的資料沒有邊界:從面向連線的位元組流角度理解。接收方收到資料後放到接收快取中,使用者使用 read 函式像讀取位元組流一樣從中讀取資料,因此傳送方 write 的次數和接收方 read 的次數可以不一樣
11.主機名和IP地址
如果打算在不同的主機上執行伺服器和客戶機,伺服器埠號由作業系統核心分配,則需要 知道伺服器的主機名或IP地址及其埠號。如果某臺計算機執行TCP/IP,他的主機名通常記錄在/etc/hosts/檔案中。庫函式
gethostname(char *name,sizeof(name))
在name陣列中返回計算機的主機名字串。但是他可能不是用點記法表示的完整正式名稱,也不是其IP地址。庫函式
struct hostent *gethostbyname(void addr,socklen_t len,int typo) //用來獲取計算機全名及其IP地址。
三、實踐
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#define MAXLINE 256
#define PORT 7777
void sys_err(char *msg){
perror(msg);
exit(-1);
}
int main(int argc , char **argv){
int sockFd,n;
char recvLine[MAXLINE];
struct sockaddr_in servAddr;
if (argc != 2) {
sys_err("usage: a.out <IPaddress>");
}
sockFd=socket(AF_INET,SOCK_STREAM,0);
memset(&servAddr,0,sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(PORT);
if (inet_pton(AF_INET,argv[1],&servAddr.sin_addr) <= 0) {
sys_err("inet_pton error");
}
connect(sockFd,(struct sockaddr *)&servAddr,sizeof(servAddr));
while((n=read(sockFd,recvLine,MAXLINE)) >0 ){
recvLine[n] = '\0';
if(fputs(recvLine,stdout) == EOF){
sys_err("fputs error");
}
}
if(n <0){
sys_err("read error");
}
return 0;
}