Socket通訊
1、什麼是套接字
Socket是封裝了TCP/IP協議簇的系統API介面,這使得程式設計師無需關注協議本身,直接使用socket提供的介面與不同主機間的程序互聯通訊。
目前市面上主流的作業系統都採用這套機制進位制網路通訊,所以不同種類的作業系統,使用不同的程式語言,只要呼叫作業系統提供的Socket介面,都能進行網路通訊。
2、基於TCP協議的Socket程式設計模型
被連線者需要完成的任務(服務端):
1、建立socket核心物件,核心建立完成後會返回它的描述符(該描述只是為了完成連線,三次握手)
2、準備本機地址(ip地址+埠號)
3、繫結(把本機地址與socket物件進行繫結)
4、開啟監聽,並設定排隊的佇列長度
5、等待連線,連線成功後,核心會再返回一個連線成功的Socket描述符,專門用來通訊
for (;;) {
6、接收請求
7、返回結果
}
8、關閉通訊的Socket物件
9、關閉連線的Socket物件
連線者需要完成的任務(客戶端):
1、建立socket核心物件,核心建立完成後會返回它的描述符
2、準備被連線者的地址(ip地址+埠號)
3、發起連線,使用Socket+地址(ip地址+埠號)發起連線請求
for (;;) {
4、傳送請求
5、接收結果
}
6、關閉Socket物件
3、TCP通訊需要使用Socket介面
/**
* 功能: 建立Socket物件
* @domain:
* AF_UNIX, AF_LOCAL 採用本地socket檔案進行通訊,如果用它則只能本機上的兩個程序進行通訊
* AF_INET IPv4地址
* AF_INET6 IPv6地址
* @type:
* SOCK_STREAM 資料流 TCP
* SOCK_DGRAM 報文 UDP
* @protocol:
* 特殊通訊協議,寫0即可
* 返回值:
* 成功則返回Socket物件描述符,失敗返回-1。
*/
int socket(int domain, int type, int protocol);
// 基本地址型別,它是socket系列介面的表面引數,而實際使用的是sockaddr_un或sockaddr_in,我們需要把sockaddr_in強制轉換成sockaddr型別。
struct sockaddr_in {
sa_family_t sin_family; // 地址型別,與domain保持一致即可
in_port_t sin_port; // 埠號,網路位元組序的2位元組整數
struct in_addr sin_addr.s_addr; // IP地址,網路位元組序的4位元組整數
};
/**
* 功能: 繫結Socket物件與通訊地址
* @sockfd: Socket物件描述符
* @addr: 通訊地址,實際提供可能是sockaddr_un或sockaddr_in,需要對它們進行強制轉換
* @addrlen: addr結構體的位元組數
* 返回值: 成功返回0,失敗返回-1
*/
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
/**
* 功能: 開啟Socket物件的監聽
* sockfd: Socket地址描述符
* backlog: 備胎的數量
*/
int listen(int sockfd, int backlog);
/**
* 功能: 等待連線,沒有成功連線之前,會進入阻塞狀態
* @sockfd: Socket物件描述符
* @addr: 用於儲存連線者的通訊地址
* @addrlen: 既是輸入(告訴accetp介面,addr結構體的位元組數),也是輸出(實際接收到的addr結構的位元組數)
* 返回值: 建立連線的,能夠通訊的Socket物件描述符,失敗返回-1
*/
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
/**
* 功能: 讓sockfd物件向addr地址發起連線
* @sockfd: Socket物件描述符
* @addr: 連線目標的地址
* @addrlen: addr結構體的位元組數
* 返回值: 成功返回0,失敗返回-1
*/
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
/**
* 功能: 從Socket物件讀接收幹位元組
* @sockfd: Socket物件描述符
* @buf: 接收資料的記憶體塊首地址
* @len: buf的位元組數
* @flags: 是否阻塞,寫0即可
* 返回值: 成功接收到了多少個位元組,失敗返回-1
*/
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
/**
* 功能: 透過Socket物件傳送若干位元組
* @sockfd: Socket物件描述符
* @buf: 要傳送的記憶體塊首地址
* @len: 要傳送的位元組數
* @flags: 是否阻塞,寫0即可
* 返回值: 成功傳送了多少個位元組,失敗返回-1
*/
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
/**
* 功能: 關閉fd描述所代表的核心物件
*/
int close(int fd);
/**
* 功能: 把本地位元組序的 unsigned short 型別的資料轉換網路位元組序
*/
uint16_t htons(uint16_t hostshort);
/**
* 功能: 把字串格式 點分十進位制的ip地址 轉換成網路位元組序的4位元組ip地址
*/
in_addr_t inet_addr(const char *cp);
4、基於UDP協議的Socket程式設計模型
被接收者需要完成的任務(服務端):
1、建立socket核心物件,核心建立完成後會返回它的描述符
type:SOCK_DGRAM
2、準備本機地址(ip地址+埠號)
3、繫結(把本機地址與socket物件進行繫結)
for (;;) {
4、接收請求,同時接收傳送者的地址
5、返回結果,按傳送者的地址進行返回
}
6、關閉Socket物件
傳送者需要完成的任務:
1、建立socket核心物件,核心建立完成後會返回它的描述符
type:SOCK_DGRAM
2、準備接收者的地址(ip地址+埠號)
for (;;) {
3、傳送請求,根據接收者的地址傳送資料
4、接收結果,並接收返回者的地址
}
5、關閉Socket物件
5、UDP通訊需要使用Socket介面
/**
* 功能: UDP專用的資料傳送函式。
* @dest_addr: 收件人的地址。
* @addrlen: 地址長度。
*/
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
/**
* 功能: UDP專用的資料接收函式。
* @src_addr: 發件人的地址,也是資料返回時的地址
* @addrlen: 地址長度,既是輸入也是輸出
*/
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
6、UDP的連線操作
UPD協議底層是否需要連線操作,客戶端但可以在Socket層面進行連線,連線後的Socket物件在後續的通訊過程中就不再需要通訊地址了。
7、本地Socket通訊
網路Socket通訊是把網路卡抽象成Socket檔案配合TCP/IP協議簇,能夠使當前程序與其它計算機的程序進行網路通訊。
本地Socket通訊是在檔案系統中建立Socket
檔案,能夠使當前程序與本機的其它程序進行通訊(IPC程序間通訊)。
使用sockaddr_un
型別的通訊地址,當呼叫socket物件與通訊地址繫結時,會自動建立socket
檔案。