網路程式設計-Socket通訊

sleeeeeping發表於2024-08-26

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檔案。

相關文章