天天看點

linux網絡程式設計(一)

============================================================== 第一天:基本概念、TCP、FTP: ==============================================================

linux網絡程式設計(一)

========================================= *****************基本概念************ 【1】計算機與網絡發展的7個階段 1 - 6略 7. 從“單純建立連接配接”到“安全建立連接配接”(2010年) 【2】 1. 協定 一組控制資料通信的規則。 2. 标準 一緻同意的規則。 分類: 事實上的标準:實際情況或者習慣 合法标準:法律或者規章制度 3. 标準化組織 緩慢發展: ISO:國際标準化組織 ITU-T:國際電聯-電信标準部 ANSI:美國國家标準化局 IEEE:電氣電子工程師協會(主要是以太網、區域網路方面的) EIA:電子工業協會(實體傳輸标準、光釺傳輸) 快速發展: 論壇:幀中繼論壇、ATM論壇 管理機構:FCC 聯邦通信委員會 Internet标準:RFC 【3】 網絡體系結構即指網絡的層次結構和每層所使用協定的集合 【4】OSI開放系統互聯模型 應用層 應用程式:FTP、E-mail、Telnet 表示層 資料格式定義、資料轉換/加密 會話層 建立通信程序的邏輯名字與實體名字之間的聯系 傳輸層 差錯處理/恢複,流量控制,提供可靠的資料傳輸 網絡層 資料分組、路由選擇 資料鍊路層 資料組成可發送、接收的幀 實體層 傳輸實體信号、接口、信号形式、速率

linux網絡程式設計(一)

OSI參考模型 1. ISO(國際标準化組織)制定了一個國際标準OSI(開放式通信系統互聯參考模型),對通信系統進行了标準化。 2. OSI模型将通信協定中必要的功能分成了7層,每個分層都接收有它下一層所提供的特定服務,并且負責為自己的上一層提供特定的服務。 上下層之間進行互動時所遵循的約定叫做 “接口” 。 同一層之間的互動所遵循的約定叫做“協定”。 3. 7層通信 (1)應用層:指定特定應用的協定(比如發送和接受檔案的軟體按鈕,發送者輸入“早上好”并附上收件人,按下發送按鈕,接受者收到資訊會将其存儲在硬碟或者非易失存儲器(資料不會因為斷電而丢失的一種儲存設備)上,這些都是在應用層上的) (2)表示層: 裝置固有資料格式和網絡标準資料格式的轉換 (接受者和發送者如果使用的郵件用戶端不一樣,那麼就會出現問題,如何實作使用者之間的通信,那麼就需要在表示層來起作用, 使得在不同的用戶端上擁有相同的網絡格式 ) (3)會話層:通信管理,負責建立或者斷開通信連接配接(發送者一次性發送5份郵件,那麼接受者如何接受,是一次性接受所有的檔案然後斷開連接配接還是沒接受一次就斷開,然後再次進行,發送者同理) (4)傳輸層:管理兩個節點(互聯的網絡中斷)之間的資料傳輸。負責可靠傳輸(確定資料被可靠地傳送到目标位址)(確定發送者和接受者之間的通信,會話層負責決定建立連接配接和斷開連接配接的時機,而傳輸層進行實際的建立和斷開處理) (5)網絡層: 位址管理與路由選擇 ,作用:在網絡互相連接配接的環境中,将資料從發送端主機發送到接受端主機 (6)資料鍊路層:互連裝置之間傳送和識别 資料幀 (7)實體層:以“0”、“1”代表的電壓的高低、燈光的閃滅< 比特流 >。界定連接配接器和網絡的規格。

linux網絡程式設計(一)

【5】 TCP/IP協定族 : 傳輸控制/網際協定(Transfer Control Protocol/Internet Protocol) 又稱作網絡通訊協定

應用層 TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet 傳輸層 TCP,UDP 網絡層 IP,ICMP,RIP,OSPF,BGP,IGMP 網絡接口與實體層 SLIP,CSLIP,PPP,ARP,RARP,MTU ,ISO2110,IEEE802.1,EEE802.2 TCP (Transport Control Protocol)傳輸控制協定 UDP (User Datagram Protocol)使用者資料報協定 IP (Internetworking Protocol)網間協定 SMTP (Simple Mail Transfer Protocol)簡單郵件傳輸協定 HTTP (Hypertext Transfer Protocol) 超文本傳輸協定 FTP (File Transfer Protocol)檔案傳輸協定 ARP (Address Resolution Protocol)位址解析協定 【6】 UDP和TCP

linux網絡程式設計(一)

共同點:同為傳輸層協定 不同點: TCP:有連接配接,可靠 UDP:無連接配接,不保證可靠 TCP(即傳輸控制協定) 是一種面向連接配接的傳輸層協定, 它能提供高可靠性通信(即資料無誤、資料無丢失、資料無失序、資料無重複到達的通信) 适用情況: 适合于對 傳輸品質要求較高 ,以及 傳輸大量資料的通信 。 在需要可 靠資料傳輸 的場合,通常使用TCP協定 MSN/QQ等即時通訊軟體的使用者登入、賬戶管理相關的功能通常采用TCP協定 UDP(User Datagram Protocol)使用者資料報協定 是不可靠的面向無連接配接的協定。在資料發送前,因為不需要進行連接配接,是以可以進行高效率的資料傳輸。

适用情況: 發送小尺寸資料(如對DNS伺服器進行IP位址查詢時) 在接收到資料,給出應答較困難的網絡中使用UDP。(如:無線網絡) 适合于廣播/多點傳播式通信中。 MSN/QQ/Skype等即時通訊軟體的點對點文本通訊以及音視訊通訊通常采用UDP協定 流媒體、VOD、VoIP、IPTV等網絡多媒體服務中通常采用UDP方式進行實時資料傳輸 【7】 Socket 是一個程式設計接口 是一種特殊的檔案描述符 (everything in Unix is a file) 并不僅限于TCP/IP協定 面向連接配接 (Transmission Control Protocol - TCP/IP) 無連接配接 (User Datagram Protocol -UDP 和 Inter-network Packet Exchange - IPX) 套接字類型: 流式套接字(SOCK_STREAM) 提供了一個面向連接配接、可靠的資料傳輸服務,資料無差錯、無重複的發送且按發送順序接收。内設定流量控制,避免資料流淹沒慢的接收方。資料被看作是位元組流,無長度限制。 -->TCP 資料報套接字(SOCK_DGRAM) 提供無連接配接服務。資料包以獨立資料包的形式被發送,不提供無差錯保證,資料可能丢失或重複,順序發送,可能亂序接收。 -->UDP 原始套接字(SOCK_RAW) 可以對較低層次協定如IP、ICMP直接通路。 【8】IP位址 IP位址是Internet中主機的唯一辨別 IP位址為32位(IPv4)或者128位(IPv6) 檢視IP位址: linux:ifconfig dos:ipconfig 每個資料包都必須攜帶目的IP位址和源IP位址,路由器依靠此資訊為資料包選擇路由 IPv4表示形式: 點分十進制形式 ,如192.168.2.222,最後都會轉換為一個32位的無符号整數。

IP位址分類(相對于ipv4的第一部分類區分(前八位)) A類 0000 0000 - 0111 1111 0.x.x.x - 127.x.x.x B類 1000 0000 - 1011 1111 128.x.x.x - 191.x.x.x C類 1100 0000 - 1101 1111 192.x.x.x - 223.x.x.x D類 1110 0000 - 1110 1111 224.x.x.x - 239.x.x.x 表示多點傳播位址 E類 1111 0000 - 1111 1111 240.x.x.x - 255.x.x.x 屬于保留測試

linux網絡程式設計(一)

192.168.x.x 屬于區域網路IP位址 127.x.x.x 屬于自己的主機位址,一般用于自己主機通信使用 192.168.2.x 192.168.2.0 表示網段 192.168.2.255 表示廣播位址 子網路遮罩:表示能夠連接配接的主機的最大數 A類 255.0.0.0 2^24 B類 255.255.0.0 2^16 C類 255.255.255.0 2^8 實際:2^8 - 2 = 254

#include <arpa/inet.h> 将點分十進制IP位址轉化為網絡位元組序的整型資料 in_addr_t inet_addr(const char *cp); 将網絡位元組序的整型資料轉化為點分十進制IP位址 char *inet_ntoa(struct in_addr in); 一般是将accept填充的有關client的資訊的結構體中提取IP并顯示。 例子: inet_addr("192.168.2.189"); 【9】端口号 ( vi /etc/services 查詢占用的端口号) 為了區分一台主機接收到的資料包應該轉交給哪個程序來進行處理,使用端口号來差別 TCP端口号與UDP端口号獨立 端口号一般由IANA (Internet Assigned Numbers Authority) 管理 衆所周知端口:1~1023(1~255之間為衆所周知端口,256~1023端口通常由UNIX系統占用) 已登記端口:1024~49151 動态或私有端口:49152~65535 一般使用 6666 7777 8888 9999 10000 10001 10002 【10】位元組序 不同類型CPU的主機中,記憶體存儲多位元組整數序列有兩種方法,稱為主機位元組序(HBO): 小端序(little-endian) - 低序位元組存儲在低位址 将低位元組存儲在起始位址,稱為“Little-Endian”位元組序,Intel、AMD等采用的是這種方式; 大端序(big-endian)- 高序位元組存儲在低位址 将高位元組存儲在起始位址,稱為“Big-Endian”位元組序,由ARM、Motorola等所采用

如何測試主機位元組序:

linux網絡程式設計(一)

方法1:使用指針 int a = 0x12345678; char *p; p = (char *)&a; printf("a = %#x\n", a); printf("*p = %#x\n", *p);

方法2:使用file指令 file a.out 其中LSB 的L代表小端存儲 方法3:共用體

linux網絡程式設計(一)

union un{ int a; char b; }; myun.a = 0x12345678; printf("a = %#x\n", myun.a); printf("b = %#x\n", myun.b);

網絡中傳輸的資料必須按網絡位元組序,即大端位元組序 #include <arpa/inet.h> 将主機位元組序轉化為網絡位元組序 uint32_t htonl(uint32_t hostlong); uint16_t htons(uint16_t hostshort); 将網絡位元組序轉化為主機位元組序 uint32_t ntohl(uint32_t netlong); uint16_t ntohs(uint16_t netshort);

例子: htons(9999); 【11】 ctags工具測建立和使用 第一步:添加索引檔案 在/usr/include裡面 執行sudo ctags -R, 生成一個tags檔案 第二步:設定為全局 在家目錄下的配置檔案.vimrc中,添加 set tags+=/usr/include/tags 使用: vim -t xxx 在系統核心當中查找xxx ctrl + ] 追代碼(Ctrl+滑鼠左鍵) ctrl + t 傳回上一層(Ctrl+滑鼠右鍵)

ctags: sudo ctags -R vim -t uint32_t :可以檢視uint32_t 說明 ================================================= *****************TCP網絡程式設計************** 【1】 流程 伺服器:server.c 建立套接字 socket( ) 填充伺服器網絡資訊結構體 sockaddr_in 将套接字與伺服器網絡資訊結構體綁定 bind( ) 将套接字設定為監聽模式 listen( ) 阻塞等待用戶端的連接配接請求 accept( ) 進行通信 recv( )/send( ) 用戶端:client.c 建立套接字 socket( ) 填充伺服器網絡資訊結構體 sockaddr_in 發送用戶端的連接配接請求 connect( ) 進行通信 send( )/recv( ) 【2】socket( ) #include <sys/types.h> #include <sys/socket.h>

int socket(int domain, int type, int protocol); 功能:建立一個套接字,傳回一個檔案描述符 參數: domain:通信域、協定族 AF_UNIX 本地通信 AF_INET 網絡通信 AF_PACKET 底層通信 type: SOCK_STREAM 流式套接字 TCP SOCK_DGRAM 資料報套接字 UDP SOCK_RAW 底層 protocol:協定,通常為0 傳回值: 成功:檔案描述符 失敗:-1 例子: int sockfd; if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("fail to socket"); //return -1; exit(1); } 【3】bind( ) #include <sys/types.h> #include <sys/socket.h>

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 功能:将套接字與IP位址、端口号綁定 參數: sockfd: 檔案描述符,socket的傳回值 addr:網絡資訊結構體 通用的:一般不用 struct sockaddr { sa_family_t sa_family; 2個位元組 char sa_data[14]; 14個位元組 } 一般使用:sockaddr_in #include <netinet/in.h> struct sockaddr_in { __SOCKADDR_COMMON (sin_); ==> #define __SOCKADDR_COMMON(sa_prefix) \ sa_family_t sa_prefix##family ==> 在函數宏裡面,##代表字元串的拼接 sa_family_t sin_family; //位址族 AF_INET 2個位元組 in_port_t sin_port ; 端口号 2個位元組 struct in_addr sin_addr; ==> struct in_addr { in_addr_t s_addr ; ip位址 4個位元組 };

這個沒有用,為了使得sockaddr_in與sockaddr長度一緻 unsigned char sin_zero[sizeof (struct sockaddr) - __SOCKADDR_COMMON_SIZE - sizeof (in_port_t) - sizeof (struct in_addr)]; }; addrlen:addr的長度 傳回值: 成功:0 失敗:-1 例子: struct sockaddr_in serveraddr; serveraddr.sin_family = AF_INET; serveraddr.sin_port = htons(9999); serveraddr.sin_addr.s_addr = inet_addr("192.168.2.189"); if(bind(sockfd, (struct sockaddr *)&serveraddr , sizeof(struct sockaddr)) < 0) { perror("fail to bind"); exit(1); } 【4】listen( ) #include <sys/types.h> #include <sys/socket.h>

int listen(int sockfd, int backlog); 功能:将套接字設定為被動監聽狀态 參數: sockfd:檔案描述符,socket的傳回值 backlog:允許同時響應用戶端請求的個數,一般設定為5,10 傳回值: 成功:0 失敗:-1 例子: if(listen(sockfd, 5) < 0) { perror("fail to listen"); exit(1); } 【5】accept( ) #include <sys/types.h> #include <sys/socket.h>

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 功能:阻塞等待用戶端的連接配接請求 參數: sockfd:檔案描述符,socket的傳回值 addr: 網絡資訊結構體(自動填充的用戶端的網絡資訊結構體) addrlen:addr的長度 傳回值: 成功:新的檔案描述符(用于與用戶端通信) 失敗:-1 例子: struct sockaddr_in clientaddr; socklen_t addrlen = sizeof(clientaddr); if(accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen) < 0) { perror("fail to accept"); exit(1); } 【6】connect( ) #include <sys/types.h> #include <sys/socket.h>

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 參數: sockfd:檔案描述符,socket的傳回值 addr: 伺服器的網絡資訊結構體(需要自己填充) addrlen:addr的長度 傳回值: 成功:0 失敗:-1 例子: if(connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) { perror("fail to connect"); exit(1); } 【7】send( ) #include <sys/types.h> #include <sys/socket.h>

ssize_t send(int sockfd, const void *buf, size_t len, int flags); 功能:發送資料 參數: sockfd:檔案描述符 伺服器:accept的傳回值(用于向用戶端發送) 用戶端:socket的傳回值(用于向伺服器器發送 ) buf:發送的資料 len:資料的長度 flags:标志位 0 阻塞 MSG_DONTWAIT 非阻塞 傳回值: 成功:發送的資料的長度 失敗:-1 【8】recv( ) #include <sys/types.h> #include <sys/socket.h>

ssize_t recv(int sockfd, void *buf, size_t len, int flags); 功能:接收資料 參數: sockfd:檔案描述符 伺服器:accept的傳回值 用戶端:socket的傳回值 buf:接收的資料 len:資料的長度 flags:标志位

0 阻塞 MSG_DONTWAIT 非阻塞 傳回值: 成功:接收的資料的長度 0 : 發送端異常退出或者關閉檔案描述符 失敗:-1

繼續閱讀