TCP —— Linux網路程式設計 API(基礎準備)
基礎知識:
首先我們來了解Linux網路API:
①socket地址API: | socket最開始的含義:一個IP地址和埠對(ip,port)。他唯一的表示了TCP通訊的一端。 |
②socket基礎API: | socket主要的API包括建立socket,命名socket,監聽socket,接受連線,發起連線,讀寫資料,獲取地址資訊,檢測帶外標記,以及讀取和設定socket選項。 |
③網路資訊API: | 以實現主機名和IP地址之間的轉換;服務名稱和埠號之間的轉換。這些API都定義在netdb.h標頭檔案中。 |
主機位元組序和網路位元組序
1.位元組序
大端位元組序 | 一個整數的高位字儲存在記憶體的低地址處。 |
小端位元組序 | 是指整數的高位位元組儲存在記憶體的高地址。 |
主機位元組序 | 現代PC大多采用小端位元組序,因此成為主機位元組序。 |
網路位元組序 | 大端位元組序也稱為網路位元組序。 |
Linux提供了4個函式來完成主機位元組序列和網路位元組序列的轉換以保證接收端和傳送端的一致性:
#include<netinet/in.h> unsigned long int htonl(unsigned long int hostlong); unsigned short int htons(unsigned short int hostshort); unsigned long int ntohl(unsigned long int netlong); unsigned short int ntohs(unsigned short int netshort); //他們的含義很明確,比如htonl表示為:“host to nettwork long” //在這四個函式中,長整型函式通常用來轉換IP地址, //短整型函式用來轉換埠號。
函數了解:
系統呼叫函式1:建立socket(檔案描述符)
函式標頭檔案:
#include<sys/types.h>
#include<sys/socket.h>
函式原型:
int socket(int domain,int type,int protocol); |
函式引數解釋:
①domain: | 告訴系統使用哪個底層協議族。對於TCP協議族:PF_INET(Protocol Family of Internet,用於IPv4)或PF_INET6(IPv6); |
②type: |
指定服務型別---》流服務:SOCK_STREAM 和 資料報服務: SOCK_UGRAM。 對於TCP/IP協議族,採用流服務為其運輸層採用TCP協議,採用資料報服務表明其運輸層採用UDP協議。 |
③protocol: | 在前兩個引數構成的協議集合下,在選擇一個具體的協議。(前兩個引數已經決定了他的值),預設設定為0使用預設協議。 |
函式返回值:
socket系統呼叫成功時返回一個socket檔案描述符,失敗返回-1。 |
系統呼叫函式2:bind 命名socket
函式標頭檔案:
#include<sys/types.h>
#include<sys/socket.h>
函式原型:
int bind(int sockfd , const struct sockaddr* my_addr,socklen_t addrlen); |
函式解釋:
建立socket時,我們給它指定了地址族,但是並未指定使用該地址族中的那個具體的socket地址,將一個socket和socket地址繫結稱為給socket命名。在伺服器程式中,我們通常要命名socket,這樣客戶端才能知道該如何連線它。而客戶端通常不需要命名socket,而是採用匿名的socket地址。
函式引數:
①my_addr bind | my_addr bind將my_addr所指的socket地址分配給未命名的sockfd檔案描述符。 |
②addlen | 指出該socket地址的長度。 |
函式返回值:
成功 | 返回0 |
失敗 | 返回-1:失敗通常有兩種情況 EACCES:無許可權訪問該埠號 EADDRINUSE: 埠號被佔用。 |
系統呼叫函式3:listen //監聽socket
函式原型:
int listen(int sockfd,int backlog); |
函式解釋:
socket被命名之後還不能馬上接受客戶連線,我們需要使用系統呼叫來建立一個監聽佇列以存放待處理的客戶連線
函式引數:
①socket | 指定要被監聽的socket。 |
②backlog | 提示核心監聽佇列的最大長度。監聽佇列的長度如果超過了backlog,伺服器將不受理新的客戶連線,客戶端也受到ECONNREFUSED錯誤資訊2.2版本之後,其表示完全連線狀態的socket的上限。backlog引數的典型值為5。 |
系統呼叫函式4:accept //接受連線
函式原型:
int accept(int sockfd ,struct sockaddr * addr,socktlen_t *addrlen); |
函式引數:
①sockfd | 是執行過listen系統呼叫的監聽socket。 |
②addr | 用來獲取被接受連線的遠端 socket的地址。 |
③addrlen | 2中地址長度由addrlen引數指出。 |
函式解釋:
該函式只是從監聽佇列中取出連線,而不論連線處於何種狀態(ESTABLISHED狀態和CLOSE_WAIT狀態),更不關心任何網路狀況的變化。
系統呼叫函式5:connect //發起連線
函式原型:
int connect(int sockfd,const struct sockaddr *serv_add,socklen_t addrlen); |
函式引數:
①serv_addr | 是伺服器監聽的socket地址 |
②addrlen | 指定了這個地址的長度。 |
函式返回值:
成功 | 一旦連線成功,sockfd就唯一地標識了這個連線,客戶端就可以讀寫sockfd來和伺服器通訊。 |
失敗 | 兩種情況 ECONNREFUSED目標埠不在,連線被拒絕;ETIMEDOUT,連線超時。 |
函式6:TCP資料讀寫
函式原型:
ssize_t recv(int sockfd,void *buf ,size_t len,int flag);//讀取 ssize_t send(int sockfd,const void *buf,size_t len,int flags);//寫資料 |
函式解釋:
recv是讀取sockfd上的資料 | |
buf和len | 指定讀取緩衝區的位置和大小 |
flag | 為資料收發提供的額外控制,通常設定為0。 |
函式返回值:
成功 | 返回實際讀取到的資料的長度,可能小於我們期望的len,返回0,表明對方已經關閉連線了。 |
失敗 | 失敗返回-1. |
函式7:close //關閉連線
函式原型:
int close(int fd); |
函式引數:
fd | fd 待關閉的socket的sockfd。close系統呼叫並非總是立即關閉一個連線,而是將fd的引用計數減一,只有當fd為0時,才真正關閉連線。 |