Linux 如何使用套接字?


簡介

Linux 是一種開源作業系統,因其穩定性和安全性而廣受歡迎。它廣泛應用於各種領域,例如 Web 伺服器、嵌入式系統和超級計算機。

Linux 的關鍵方面之一是它有效地利用套接字進行程序間通訊。套接字提供了一種靈活的方式來建立不同程序之間的通訊通道,這些程序可以在同一臺機器上執行,也可以在網路上連線的不同機器上執行。

什麼是套接字?

套接字是 Linux 網路中的一個基本概念,允許在網路上不同計算機上的程序之間進行通訊。簡單來說,套接字是兩個程序之間建立的雙向通訊鏈路的端點。

套接字由 IP 地址和埠號組合構成。IP 地址標識遠端計算機,而埠號指定要連線到該計算機上的哪個程式或服務。

套接字的定義

在技術術語中,套接字被定義為“透過網路傳送或接收資料的端點”。它本質上是一個抽象層,允許程式在高級別上與網路協議互動,而無需擔心底層細節。

Linux 中使用的套接字型別:流式、資料報、原始和順序資料包

Linux 中主要使用四種類型的套接字:流式、資料報、原始和順序資料包。- 流式套接字 (SOCK_STREAM) 透過 TCP/IP 協議提供可靠的位元組流通訊,並確保資料包按順序到達。

  • 資料報套接字 (SOCK_DGRAM) 透過 UDP 協議提供不可靠的基於資料包的通訊。

  • 原始套接字 (SOCK_RAW) 提供對底層傳輸層協議(如 ICMP 和 IGMP)的訪問。

  • 順序資料包套接字 (SOCK_SEQPACKET) 提供可靠的資料包傳遞並支援排序,但使用 SCTP(流控制傳輸協議)。

每種型別都有其優點和缺點,具體取決於特定的用例。瞭解這些不同的型別對於使用 Linux 上的套接字進行高效的網路程式設計至關重要。

Linux 中套接字的工作原理?

套接字建立過程概述

套接字是網路程式設計的基本組成部分,它們允許 Linux 程序之間進行通訊。在 Linux 中,套接字的建立是透過對 socket() 系統呼叫進行函式呼叫來啟動的。

此函式接受三個引數:地址族、套接字型別和協議。地址族指定套接字是否將用於透過網際網路協議 (IP) 網路或其他型別的本地通訊通道進行通訊。

套接字檔案描述符的解釋以及它們如何在通訊中使用

為了在 Linux 中兩個套接字之間傳輸資料,每個套接字都必須與其自己的唯一檔案描述符相關聯。這些檔案描述符在使用 bind()、listen()、accept()、connect()、send() 和 recv() 等系統呼叫初始化套接字時建立。當兩個套接字透過此檔案描述符機制相互通訊時,它們使用一組標準函式(稱為“套接字 API”)來來回傳輸資料。

Linux 中的套接字通訊協議

TCP/IP 協議用於網路上的可靠通訊

傳輸控制協議/網際網路協議 (TCP/IP) 是網路上最常用的可靠通訊協議。此協議確保從一臺裝置傳送到另一臺裝置的資料按正確的順序到達目的地,並且沒有錯誤。

TCP/IP 使用三次握手來啟動兩個裝置之間的連線,然後使用滑動視窗演算法進行資料傳輸。此協議還包括錯誤檢測和糾正機制,以確保維護資料完整性。

UDP 協議用於網路上的快速但不可靠的通訊

使用者資料報協議 (UDP) 是 Linux 中另一種流行的協議,用於網路上的快速但不可靠的通訊。與 TCP/IP 不同,UDP 不包含任何錯誤檢測或糾正機制。

因此,無法保證在目的地接收到的資料與從源傳送的資料相同。但是,由於它沒有像 TCP 的滑動視窗演算法或三次握手這樣的機制,因此 UDP 可以比 TCP/IP 更快地傳輸較小的資料包,並且開銷更少。

Linux 中的套接字程式設計

使用 C 語言和系統呼叫的套接字程式設計概述

使用 C 語言和系統呼叫的套接字程式設計廣泛用於 Linux 開發環境。建立套接字是為了在網路上的兩臺機器之間提供通訊。套接字介面允許程式透過流或資料報相互通訊。

常用的系統呼叫包括:

  • bind() − 為套接字分配名稱

  • listen() − 告訴套接字偵聽傳入連線

  • accept() − 接受偵聽套接字上的傳入連線請求,並建立一個新的連線套接字以與客戶端程序通訊

  • connect() − 在指向另一個端點的未連線套接字上啟動連線請求。

  • send() − 在建立連線後,將資料從一個端點發送到另一個端點。

  • recv() − 從傳入訊息佇列中獲取訊息,並將它們放置到使用者空間提供的緩衝區中。

套接字程式設計概念的編碼示例

為了說明套接字在 Linux 中的工作原理,讓我們看一些程式碼片段,這些程式碼片段演示了基本操作,例如建立和關閉套接字、將它們繫結到特定地址/埠、建立連線以及傳送和接收資料:

#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
int main() { 
   int sockfd; sockfd=socket(AF_INET,SOCK_STREAM,0); 
   if(sockfd==-1) {
      printf("Failed to create TCP Socket"); 
      return -1; 
   } else { 
      printf("TCP Socket Created Successfully
"); } close(sockfd); return 0; }

在上面的程式碼中,我們使用 socket() 系統呼叫建立了一個 TCP 套接字。

它返回一個套接字描述符,該描述符將在其他操作中使用。如果描述符的值為負,則表示在建立套接字時發生錯誤。

#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
int main() {
   int sockfd; 
   struct sockaddr_in server; sockfd=socket(AF_INET,SOCK_STREAM,0); 
   if(sockfd==-1) {
      printf("Failed to create TCP Socket"); 
      return -1; 
   } else { 
      printf("TCP Socket Created Successfully
"); } bzero(&server,sizeof(server)); server.sin_family=AF_INET; server.sin_port=htons(8000); server.sin_addr.s_addr = INADDR_ANY; if(bind(sockfd,(struct sockaddr*)&server,sizeof(server)) == -1) { perror("Bind Failed:"); return -1; } else { printf("Bind Successfull
"); } close(sockfd); return 0; }

在此示例中,我們將之前建立的 TCP 套接字繫結到特定的地址和埠號。bind() 系統呼叫將建立的套接字檔案描述符和指向 sockaddr_in 型別結構的指標作為輸入,該結構包含有關地址族 (IPv4)、IP 地址 (INADDR_ANY) 和本地端點的埠號 (8000) 的資訊。

#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>

int main() { 
   int sockfd,newsockfd,portno,n,len; 
   char buffer[256]; struct sockaddr_in serv_addr,client_addr; 
   sockfd=socket(AF_INET,SOCK_STREAM,0); if(sockfd==-1) { 
      printf("Failed to create TCP Socket
"); return -1; } bzero(&serv_addr,sizeof(serv_addr)); portno=8000; serv_addr.sin_family=AF_INET; serv_addr.sin_port=htons(portno); serv_addr.sin_addr.s_addr = INADDR_ANY; if(bind(sockfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr))==-1) { perror("Bind Failed: "); return -1; } listen(sockfd,5); len=sizeof(client_addr); newsockfd=accept(sockfd,(struct sockaddr*)&client_addr,&len); if(newsockfd==-1) { printf("Error in Accepting Client Connection
"); return -1; } else { printf("Client Connected Successfully
"); bzero(buffer,256); n=read(newsockfd,buffer,255); if(n<0) perror("ERROR reading from socket"); printf("%s",buffer); n=write(newsockfd,"Server:
",40); if(n<0) perror("ERROR writing to socket"); close(newsockfd); } close(sockfd); return 0; }

在此程式碼片段中,我們正在接受先前繫結套接字上的傳入連線。

使用 accept() 函式呼叫接受連線後,我們可以使用 read() 從客戶端讀取資料,並使用 write() 系統呼叫將資料傳送到客戶端。這些示例展示瞭如何使用系統呼叫和 C 語言在 Linux 中對套接字進行程式設計。

結論

在本文中,我們探討了 Linux 如何使用套接字進行網路程式設計這一重要主題。我們首先定義了什麼是套接字,並探討了 Linux 中使用的不同型別的套接字。然後,我們研究了套接字在 Linux 中的工作原理以及可用的各種通訊協議。

接下來,我們深入研究了使用 C 語言和 bind()、listen()、accept()、connect()、send() 和 recv() 等系統呼叫的套接字程式設計。我們涵蓋了高階主題,例如多執行緒伺服器程式設計、非阻塞 I/O 和套接字的 IPv6 支援。

更新於: 2024年5月6日

1K+ 閱讀量

開啟你的 職業生涯

透過完成課程獲得認證

立即開始
廣告
© . All rights reserved.