Linux網路編程詳解

一、套接字(Socket)

套接字是進行網路編程時非常重要的概念,它是一種通信的機制,可以在不同主機之間進行通信。套接字在網路編程中扮演著重要的角色,下面我們來一步步地了解它。

1.創建套接字


#include <sys/types.h>
#include <sys/socket.h>

int socket(int domain, int type, int protocol);

socket()函數可以創建一個新的套接字。其中,domain參數指定了通信協議的領域,如AF_INET表示IPv4協議族,AF_INET6表示IPv6協議族。type參數指定了套接字的類型,如SOCK_STREAM表示TCP類型。protocol參數指定使用的協議,一般為0。

2.綁定套接字


#include <sys/types.h>
#include <sys/socket.h>

int bind(int sockfd, const struct sockaddr \*addr, socklen_t addrlen);

bind()函數將本地的Socket地址和創建的Socket進行綁定。其中,sockfd參數即為socket()函數返回的文件描述符。addr參數是一個指向本地Socket地址結構體的指針。addrlen參數是該結構體的長度。

3.監聽套接字


#include <sys/types.h>
#include <sys/socket.h>

int listen(int sockfd, int backlog);

listen()函數將sockfd指定的Socket轉換成被動式的Socket,backlog指定了連接請求隊列的最大長度。

4.接收連接請求


#include <sys/types.h>
#include <sys/socket.h>

int accept(int sockfd, struct sockaddr \*addr, socklen_t \*addrlen);

accept()函數從連接請求隊列中取得一個連接請求,生成一個全新的Socket進行通信。其中,sockfd為listen()函數創建的Socket。addr和addrlen參數表示請求連接的客戶端的地址信息。

二、進程和線程

進程和線程是操作系統中非常基礎的概念,本篇文章著重介紹在網路編程中如何使用它們。

1.進程

進程是操作系統中進行資源分配和調度的基本單位。在網路編程中,我們可以使用fork()函數創建一個新進程,讓進程分別運行不同的代碼。


#include <unistd.h>

pid_t fork(void);

fork()函數會創建一個新的進程,並將父進程的數據複製到子進程中。父子進程是並發的,但是它們運行的是同一個代碼。我們可以通過進程間的通信(IPC),使它們在運行過程中進行信息的交互。

2.線程

線程是進程中的更小單位,它可以輕鬆的與其他線程共享進程數據,便於實現並發。在Linux系統中,線程的實現依賴於POSIX的線程庫。


#include <pthread.h>

int pthread_create(pthread_t \*thread, const pthread_attr_t \*attr, void *(*start_routine) (void *), void \*arg);

pthread_create()函數可以創建一個新的線程,其中參數thread是線程的標識符,attr指向線程屬性的結構,start_routine是線程的入口地址,arg參數將傳遞給入口函數。

三、並發編程

在網路編程中,進程和線程是實現並發編程的基本手段。當多個客戶端同時連接伺服器時,我們需要一種方法來同時處理這些連接請求,這時候並發編程便派上了用場。

1.多進程實現並發


#include <sys/wait.h>

pid_t pid;

switch (pid = fork()) {
    case -1:
        perror("fork");
        break;
    case 0:
        /* child */
        exit(0);
        break;
    default:
        /* parent */
        waitpid(pid, NULL, 0);
        break;

上述代碼中,我們可以在主進程中調用fork()函數創建一個子進程來處理一個請求。這樣,就可以同時處理多個請求。通過使用進程的基於文件描述符的機制可以實現進程之間的通信。

2.多線程實現並發


#include <pthread.h>

int threads_num;
pthread_t threads[THREAD_NUM];

/* create threads */
for (int i = 0; i < threads_num; i++) {
    if (pthread_create(&threads[i], NULL, worker, NULL)) {
        perror("pthread_create failed");
        exit(1);
    }
}

/* join threads */
for (int i = 0; i < threads_num; i++) {
    if (pthread_join(threads[i], NULL)) {
        perror("pthread_join failed");
        exit(1);
    }
}

上述代碼中,我們使用pthread_create()函數創建若干個線程,並通過pthread_join()函數等待線程結束。線程可以共享數據,且線程和線程之間的切換速度比進程之間的切換速度要快得多。

四、網路編程實踐

下面我們通過一個簡單的例子來演示Linux網路編程的過程。

1.創建Socket


#include <sys/types.h>
#include <sys/socket.h>

int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
    perror("socket error");
    exit(1);
}

上述代碼中,我們使用socket()函數創建一個新的Socket。其中,參數AF_INET表示使用IPv4協議族,SOCK_STREAM表示使用TCP協議。

2.綁定Socket


#include <sys/types.h>
#include <sys/socket.h>

struct sockaddr_in server_addr;
bzero(\&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htons(INADDR_ANY);
server_addr.sin_port = htons(port);

int ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret == -1) {
    perror("bind error");
    exit(1);
}

上述代碼中,我們使用bind()函數將Socket與本地的IP地址和埠進行綁定。

3.監聽Socket


#include <sys/types.h>
#include <sys/socket.h>

int ret = listen(sockfd, backlog);
if (ret == -1) {
    perror("listen error");
    exit(1);
}

上述代碼中,我們使用listen()函數將Socket轉化為可接受的請求,backlog參數指定了連接請求隊列的長度。

4.接受連接請求


#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

struct sockaddr_in client_addr;
socklen_t len = sizeof(client_addr);
int connfd = accept(sockfd, (struct sockaddr *)&client_addr, &len);
if (connfd == -1) {
    perror("accept error");
    exit(1);
}
printf("accept from %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

上述代碼中,我們使用accept()函數從連接請求隊列中取出一個連接請求生成一個全新的Socket,客戶端的地址信息保存在client_addr結構體中,我們可以通過inet_ntoa()和ntohs()函數將網路位元組順序的IP地址和埠轉換為可讀形式。

5.接收和發送消息


ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);

上述代碼中,我們使用recv()和send()函數進行接收和發送消息,分別對應於TCP中的read()和write()函數。

結論

以上便是Linux網路編程的詳解,我們介紹了套接字、進程和線程、並發編程、以及通過一個簡單例子演示了網路編程的基本流程。在進一步的使用和探索中,相信本篇文章為讀者提供了很好的指引。

原創文章,作者:LWXLV,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/370615.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
LWXLV的頭像LWXLV
上一篇 2025-04-22 01:14
下一篇 2025-04-22 01:14

相關推薦

  • 如何在Linux中添加用戶並修改配置文件

    本文將從多個方面詳細介紹在Linux系統下如何添加新用戶並修改配置文件 一、添加新用戶 在Linux系統下創建新用戶非常簡單,只需使用adduser命令即可。使用以下命令添加新用戶…

    編程 2025-04-27
  • 如何解決linux jar包 invalid or corrupt jarfile問題

    對於許多開發人員和系統管理員在Linux環境下使用Java開發過程中遇到的一個常見的問題是 invalid or corrupt jarfile(無效或損壞的jar文件)錯誤。當您…

    編程 2025-04-27
  • 在Linux上安裝JRE並配置環境變數

    本文將從以下幾個方面為您詳細闡述如何在Linux系統上,通過自己賬戶安裝JRE,並且配置環境變數。 一、安裝JRE 在進行安裝前,我們需要下載JRE的安裝包並解壓,可以從官方網站下…

    編程 2025-04-27
  • GTKAM:Linux下的照片管理器

    GTKAM是用於Linux操作系統的一款照片管理器,它支持多種相機及存儲設備,並提供了一系列強大的工具,讓用戶可以方便地瀏覽、管理、編輯和導出照片。本文將從多個方面對GTKAM進行…

    編程 2025-04-27
  • Linux sync詳解

    一、sync概述 sync是Linux中一個非常重要的命令,它可以將文件系統緩存中的內容,強制寫入磁碟中。在執行sync之前,所有的文件系統更新將不會立即寫入磁碟,而是先緩存在內存…

    編程 2025-04-25
  • 神經網路代碼詳解

    神經網路作為一種人工智慧技術,被廣泛應用於語音識別、圖像識別、自然語言處理等領域。而神經網路的模型編寫,離不開代碼。本文將從多個方面詳細闡述神經網路模型編寫的代碼技術。 一、神經網…

    編程 2025-04-25
  • Linux修改文件名命令詳解

    在Linux系統中,修改文件名是一個很常見的操作。Linux提供了多種方式來修改文件名,這篇文章將介紹Linux修改文件名的詳細操作。 一、mv命令 mv命令是Linux下的常用命…

    編程 2025-04-25
  • git config user.name的詳解

    一、為什麼要使用git config user.name? git是一個非常流行的分散式版本控制系統,很多程序員都會用到它。在使用git commit提交代碼時,需要記錄commi…

    編程 2025-04-25
  • MPU6050工作原理詳解

    一、什麼是MPU6050 MPU6050是一種六軸慣性感測器,能夠同時測量加速度和角速度。它由三個感測器組成:一個三軸加速度計和一個三軸陀螺儀。這個組合提供了非常精細的姿態解算,其…

    編程 2025-04-25
  • Java BigDecimal 精度詳解

    一、基礎概念 Java BigDecimal 是一個用於高精度計算的類。普通的 double 或 float 類型只能精確表示有限的數字,而對於需要高精度計算的場景,BigDeci…

    編程 2025-04-25

發表回復

登錄後才能評論