中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

設(shè)計一個b2c網(wǎng)站b站不收費(fèi)網(wǎng)站

設(shè)計一個b2c網(wǎng)站,b站不收費(fèi)網(wǎng)站,如何做網(wǎng)站訪問量的統(tǒng)計,自己做的網(wǎng)站怎么樣合法socket 編程是一種用于網(wǎng)絡(luò)通信的編程方式,在 socket 的協(xié)議族中除了常用的 AF_INET、AF_RAW、AF_NETLINK等以外,還有一個專門用于 IPC 的協(xié)議族 AF_UNIX,IPC 是 Linux 編程中一個重要的概念,常用的 IPC 方式有管道、消息隊列、共…

socket 編程是一種用于網(wǎng)絡(luò)通信的編程方式,在 socket 的協(xié)議族中除了常用的 AF_INET、AF_RAW、AF_NETLINK等以外,還有一個專門用于 IPC 的協(xié)議族 AF_UNIX,IPC 是 Linux 編程中一個重要的概念,常用的 IPC 方式有管道、消息隊列、共享內(nèi)存等,本文主要介紹用于本地進(jìn)程間通信的 UNIX Domain Socket,本文給出了多個具體的實(shí)例,每個實(shí)例均附有完整的源代碼;本文所有實(shí)例在 Ubuntu 20.04 上編譯測試通過,gcc版本號為:9.4.0;本文的實(shí)例中涉及多進(jìn)程編程等,本文對 Linux 編程的初學(xué)者有一些難度。

1 UNIX Domain Socket 的基本概念

  • 本文不再回顧有關(guān) socket 編程的相關(guān)知識,但是閱讀本文需要掌握基本的 socket 編程方法,這方面的資料比較豐富,請自行解決;
  • 關(guān)于 UNIX Domain Socket 的在線文檔:man 7 unix
  • 在使用 socket() 創(chuàng)建一個 socket 時,如果使用 AF_UNIX 協(xié)議族,而不是我們常用的 AF_INET 時,創(chuàng)建的 sockst 被稱為 UNIX Domain Socket;
  • AF_UNIX 是一個用來進(jìn)行進(jìn)程間通信的協(xié)議族,AF_LOCAL 和 AF_UNIX 是完全一樣的;
  • AF_UNIX 協(xié)議族和 AF_INET 的主要區(qū)別:
    • 當(dāng)使用 AF_UNIX 時,一個進(jìn)程發(fā)送的數(shù)據(jù)無需再經(jīng)過協(xié)議棧,而是通過內(nèi)核緩沖區(qū)將數(shù)據(jù)直接拷貝到另一個進(jìn)程的緩沖區(qū)中;
    • 當(dāng)使用 AF_UNIX 時,無需再綁定 IP 地址,發(fā)送和接收過程也與 IP 地址無關(guān);
  • 作為 IPC 方法,socket 的 AF_UNIX 家族并沒有共享內(nèi)存的效率高,我認(rèn)為其存在的價值主要是它的使用方法幾乎和 socket 網(wǎng)絡(luò)編程方法無異,這無疑給那些熟悉 socket 編程的程序員帶來了極大的方便;
  • 使用 AF_UNIX 建立的 socket 被稱為 UNIX Domain Socket,又名 UDS 或者 IPC socket,常用于互聯(lián)網(wǎng)通信的,使用 AF_INET(AF_INET6) 建立的 socket 被稱為 Internet Socket;
  • 一個 Internet socket 需要綁定在一個 IP 地址和一個端口上,與 Internet Socket 不同,UNIX socket 必須綁定到一個文件路徑上,在后面會詳細(xì)說明;
  • UNIX socket 也可以是匿名的,也就是無需綁定到文件路徑上,沒有名稱,通常匿名的 UNIX socket 只能用于父子進(jìn)程或者有同一個父進(jìn)程的子進(jìn)程之間通信;
  • 以下如無特別說明,socket 特指 UNIX Domain Socket,而非 Internet Socket。

2 命名 UNIX Socket 的使用

  • 創(chuàng)建 UNIX Socket

    #include <sys/socket.h>
    #include <sys/un.h>unix_socket = socket(AF_UNIX, type, 0);
    
    • type 可以是:
      • SOCK_STREAM:面向連接的數(shù)據(jù)流傳輸;
      • SOCK_DGRAM:面向無連接的數(shù)據(jù)報傳輸;
      • SOCK_SEQPACKET:面向連接的順序數(shù)據(jù)包傳輸,可以按照發(fā)送的順序傳遞消息;
  • 綁定一個文件路徑

    • 一個命名的 UNIX domain socket 必須綁定到一個路徑下;

    • 在 IPv4 下,Internet Socket 綁定 IP 地址和端口時,使用 struct sockaddr_in,在 Unix Socket 上綁定文件路徑時需要使用結(jié)構(gòu) struct sockaddr_un

      struct sockaddr_un {sa_family_t sun_family;               /* AF_UNIX */char        sun_path[108];            /* Pathname */
      };
      
      • sun_family 一定是 AF_UNIX
      • sun_path 指向一個文件路徑,比如 /tmp/unix_socket
    • bind()

      #include <sys/types.h>          /* See NOTES */
      #include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
      
      • sockfd 是使用 socket() 建立的 UNIX Socket;
      • addr 指向 struct sockaddr_un 的指針
  • 下面代碼片段創(chuàng)建了一個 socket 并綁定到了一個文件路徑上

    ......
    int unix_sock;
    struct sockaddr_un serveraddr;unix_sock = socket(AF_UNIX, SOCK_STREAM, 0);memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sun_family = AF_UNIX;
    strcpy(serveraddr.sun_path, "/tmp/unix_socket");bind(unix_sock, (struct sockaddr *)&serveraddr, SUN_LEN(&serveraddr));
    ......
    
  • 建議使用宏 SUN_LEN(addr) 來計算填好文件路徑的 struct sockaddr_un 的長度,因?yàn)槠渲械?sun_path 字段是不定長的,這個宏可以幫助我們計算出正確的結(jié)果,宏 SUN_LEN(addr) 定義在頭文件 sys/un.h 中;

  • 當(dāng)把一個 socket 綁定到一個文件上時,在文件系統(tǒng)上,這個文件會真實(shí)存在,但是這個文件不能使用 open() 打開,而只能使用 socket() 打開;

  • 建議在使用完一個命名 UNIX domain socket 后,顯式地使用 unlink() 或者 remove() 將其刪除,避免其殘留在文件系統(tǒng)中;

  • 盡管我們的例子中使用的文件名在 /tmp/ 目錄下,但在實(shí)際應(yīng)用中我們并不建議這樣做,因?yàn)?/tmp/ 目錄是任何人都可以讀寫的,這可能會帶來一些安全隱患,通常可以把這個文件建立在項(xiàng)目所在的目錄下,相對比較安全;

  • 當(dāng)我們用 bind() 將一個文件綁定到 socket 上時,相應(yīng)的文件將被建立,該文件的默認(rèn)權(quán)限為所綁定的 socket 的權(quán)限,通常情況下使用 socket() 建立的 socket 的權(quán)限是 0777,可以使用 fstat 獲得,但這時建立的 socket 文件的默認(rèn)屬性是 0775;

  • 如果我們在 bind() 之前先使用 fchmod() 修改 socket 的權(quán)限,那么再使用 bind() 綁定一個文件時,其建立的文件的權(quán)限也會產(chǎn)生變化,下面這段代碼可以演示這種權(quán)限的變化;

    ......
    #define SOCK_NAME       "./unix_socket.sock"
    ......
    int sockfd;
    struct sockaddr_un addr;
    struct stat sock_stat;sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
    fchmod(sockfd, 0660);memset(&addr, 0, sizeof(struct sockaddr_un));
    addr.sun_family = AF_UNIX;
    strcpy(addr.sun_path, SOCK_NAME);
    bind(sockfd, (struct sockaddr *)&addr, SUN_LEN(&addr));system("ls -l unix_socket.sock");
    ......
    
  • 這段代碼在當(dāng)前目錄下生成的 socket 文件的權(quán)限為 0660,最后一行的 system("ls -l") 顯示的文件清單將清楚地顯示出來,你可以嘗試一下,如果沒有 fchmod() 這行代碼,生成的文件的權(quán)限為 0775;

  • 使用 ls -l 顯示文件清單時,該文件的前面有一個 s 標(biāo)志,表示這是一個 socket 文件;

  • socket 以及 socket 文件是可以使用 stat()、fstat() 獲取屬性,同時可以使用 chmod()、fchmod() 來改變權(quán)限的;

  • 改變一個 socket 文件權(quán)限的意義在于安全性,因?yàn)槠渌M(jìn)程是需要通過 socket 文件來使用這個 UNIX domain socket 的,那么這個進(jìn)程必須要有相應(yīng)的權(quán)限才行;

  • 可以使用 read()/write()、send()/recv()、sendto()/recvfrom()、sendmsg()/recvmsg() 來發(fā)送和接收數(shù)據(jù),與 Internet Socket 下的使用方法無大的差異;

  • read()/write()

    #include <unistd.h>ssize_t read(int fd, void *buf, size_t count);
    ssize_t write(int fd, const void *buf, size_t count);
    
    • 這對函數(shù)是文件的讀/寫函數(shù),因?yàn)?socket 返回的是標(biāo)準(zhǔn)的文件描述符,所以可以使用這兩個函數(shù)進(jìn)行接收和發(fā)送數(shù)據(jù);
    • 這對函數(shù)通常僅用于面向連接的 socket,也就是通常不用于 SOCK_DGRAM 類型的 socket;
    • 這對函數(shù)是比較簡單的,write() 基本不會出錯;
    • 使用 read() 接收數(shù)據(jù)時可能會有阻塞問題,當(dāng)使用 SOCK_STREAM 時,可能還有粘包問題,不過這些問題在 Internet Socket 的 TCP 編程中也是一樣存在的,并不是 UNIX Socket 所特有的,如果有這方面的問題,請參考有關(guān)資料;
  • recv()/send()

    #include <sys/types.h>
    #include <sys/socket.h>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);
    
    • 這對函數(shù)理論上既可以用于有連接的 socket(AF_STREAM),也可以用于無連接的 socket(AF_DGRAM),但通常僅用于面向連接的 socket,也就是通常不用于 SOCK_DGRAM 類型的 socket;
    • 與 read()/write() 相比,這對函數(shù)多了一個參數(shù) flags
    • 在使用 send() 發(fā)送數(shù)據(jù)時,絕大多數(shù)情況下,flags 都可以設(shè)置為 0,最常用的 falgs 設(shè)置是 MSG_DONTWAIT,但對于向 UNIX Socket 發(fā)送數(shù)據(jù)而言,如果發(fā)送的數(shù)據(jù)不是很大,是不可能產(chǎn)生阻塞的,所以不需要設(shè)置 MSG_DONTWAIT;
    • 在使用 recv() 接收數(shù)據(jù)時,當(dāng) socket 上沒有數(shù)據(jù)時,會產(chǎn)生阻塞,如果不希望阻塞,可以設(shè)置 flags 為 MSG_DONTWAIT,這樣可以讓程序有更好的適應(yīng)性;
    • 在使用 recv() 接收數(shù)據(jù)時,與 Internet Socket 的 TCP 編程一樣,可能出現(xiàn)"粘包"問題,請參考相關(guān)資料;
  • recvfrom()/sendto()

    #include <sys/types.h>
    #include <sys/socket.h>ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
    ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
    
    • 這對函數(shù)通常多用于面向無連接的 socket,也就是通常僅用于 SOCK_DGRAM 類型的 socket;

    • Internet Socket 的 UDP 編程中,需要使用 struct sockaddr_in 設(shè)置對端的 IP 地址和端口,而 UNIX Socket 要使用 struct sockaddr_un 來設(shè)置對端的文件路徑;

    • 源程序:sendto-recvfrom.c(點(diǎn)擊文件名下載源程序)演示了如何使用 sendto() 和 recvfrom() 進(jìn)行面向報文的進(jìn)程間通信;

    • 編譯:gcc -Wall -g sendto-recvfrom.c -o sendto-recvfrom

    • 運(yùn)行:./sendto-recvfrom

    • 運(yùn)行截圖:

      screenshot of running sendto-recvfrom


  • recvmsg()/sendmsg()
    #include <sys/types.h>
    #include <sys/socket.h>ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
    ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
    
    • 這對函數(shù)在 socket 上接收/發(fā)送數(shù)據(jù)相對較為復(fù)雜,主要是 struct msghdr 結(jié)構(gòu)比較復(fù)雜,這對函數(shù)既可以用于有連接的 socket(AF_STREAM),也可以用于無連接的 socket(AF_DGRAM),在實(shí)踐中也確實(shí)如此;
    struct msghdr {void         *msg_name;       /* Optional address */socklen_t     msg_namelen;    /* Size of address */struct iovec *msg_iov;        /* Scatter/gather array */size_t        msg_iovlen;     /* # elements in msg_iov */void         *msg_control;    /* Ancillary data, see below */size_t        msg_controllen; /* Ancillary data buffer len */int           msg_flags;      /* Flags (unused) */
    };struct iovec {void  *iov_base;    /* Starting address */size_t iov_len;     /* Number of bytes to transfer */
    };
    • 在多數(shù)的編程實(shí)踐中,我們并不需要使用這對函數(shù),使用 recv()/send()、read()/write() 或者 sendto()/recvfrom() 已經(jīng)足夠;

    • struct msghdr 看似有很多字段,其實(shí)也并不是很復(fù)雜;

      • 最后一個字段 msg_flags 在 sendmsg() 中沒有使用,在 recvmsg() 調(diào)用返回時將被設(shè)置為某個標(biāo)志,可以不用管它;
      • msg_controlmsg_controllen 是用來傳輸控制信息的,如果我們不傳輸控制信息,這兩個字段填 NULL 和 0 即可;
      • 最前面的兩個字段 msg_namemag_namelen,在無連接的 socket(SOCK_DGRAM) 中有意義,在 sendmsg() 中用于指定目的地址,在 recvmsg() 中用于填充發(fā)送方的源地址,如果我們使用有連接的 socket(SOCK_STREAM),則這兩個字段只需填 NULL 和 0;
      • msg_iov 是一個結(jié)構(gòu)數(shù)組,而 msg_iovlen 為這個數(shù)組的元素個數(shù),這是這個結(jié)構(gòu)中的靈魂所在;
    • 關(guān)于這對函數(shù)的使用可以參考在線文檔 man sendmsg、man recvmsgman writev,本文并不打算詳細(xì)描述這對函數(shù)的使用方法,但會給出一個具體實(shí)例;

    • 源程序:sendmsg-recvmsg.c(點(diǎn)擊文件名下載源程序)演示了如何使用 sendmsg() 和 recvmsg() 進(jìn)行面向報文的進(jìn)程間通信;

    • 編譯:gcc -Wall -g sendmsg-recvmsg.c -o sendmsg-recvmsg

    • 運(yùn)行:./sendmsg-recvmsg

    • 運(yùn)行截圖:

      screenshot of running sendmsg-recvmsg


  • 實(shí)際上,這些在 socket 上發(fā)送/接收數(shù)據(jù)的函數(shù)并不需要成對使用,這個意思是說,我們可以使用 send() 發(fā)送數(shù)據(jù),然后使用 recvmsg() 去接收 send() 發(fā)送的數(shù)據(jù),沒有任何問題。

  • 關(guān)閉 socket 和刪除 socket 所關(guān)聯(lián)的文件

    #include <unistd.h>close(unix_sock)
    unlink(UNIX_SOCK_FILE_NAME);
    

3 UNIX socket 的抽象命名空間

當(dāng)我們使用 socket(AF_UNIX, ......) 建立一個 socket,并將其綁定到一個文件路徑上(比如:/tmp/unix_sock.sock)時,系統(tǒng)會在文件系統(tǒng)上建立一個真實(shí)的文件,當(dāng)所有打開這個 socket 的進(jìn)程均關(guān)閉 socket 后,這個真實(shí)的文件并不會因此而消失,必須顯式地使用 unlink() 或者 remove() 刪除這個文件,才能將這個文件刪除,如果一個打開 socket 的進(jìn)程異常退出,沒有顯式刪除 socket 相關(guān)聯(lián)的文件,將導(dǎo)致在文件系統(tǒng)上留下一些沒有用處的文件,我們把這種現(xiàn)象稱為“文件系統(tǒng)污染”,顯然,UNIX domain socket 會造成文件系統(tǒng)污染;

  • Linux 為 Unix Domain Socket 提供一種特殊的尋址方案,即所謂的"抽象命名空間(Abstract Namespace)",它可以避免使用 UNIX domain socket 時造成文件系統(tǒng)污染;

  • 使用抽象命名空間的 socket,在建立連接時可以不用在文件系統(tǒng)上建立一個真實(shí)文件,當(dāng)所有打開這個 socket 的進(jìn)程終止后,這個在抽象命名空間的 socket 也會隨之消失;

  • 使用抽象命名空間建立 socket,不必再顯式地刪除其綁定的文件路徑,即使打開該 socket 的進(jìn)程是異常退出,這個 socket 也會隨著所有進(jìn)程的終止而消失;

  • 顯式地刪除一個 socket 關(guān)聯(lián)的文件路徑還會帶來一些其它不可預(yù)知的問題,比如有可能刪除一個其它進(jìn)程正在使用的文件等等;

  • 抽象命名空間最大的問題是其代碼的可移植性并不好,所以在實(shí)際應(yīng)用中很少見到相應(yīng)的代碼;

  • 抽象命名空間的另一個問題是其安全性,在文件系統(tǒng)上建立的 socket 文件可以使用文件權(quán)限來控制其讀寫權(quán)限,相對較為安全,抽象命名空間沒有權(quán)限,任何知道其名稱的進(jìn)程均可以使用該 socket,其安全性不好;

  • 實(shí)際上,在抽象命名空間中建立一個 socket 與在普通用戶空間上建立一個 socket 的區(qū)別并不大,在設(shè)定地址時,都是使用 struct sockaddr_un,但使用抽象命名空間時 sun_path 字段的第一個字符必須是 '\0',下面代碼片段演示了如何將一個 socket 綁定到抽象命名空間上:

    ......int sock_server = -1;
    int rc;
    socklen_t length;
    struct sockaddr_un server_addr;sock_server = socket(AF_UNIX, SOCK_STREAM, 0);
    memset(&server_addr, 0, sizeof(struct sockaddr_un));
    server_addr.sun_family = AF_UNIX;
    strcpy(server_addr.sun_path, "#unix_sock.sock");
    length = SUN_LEN(&server_addr);
    server_addr.sun_path[0] = '\0';bind(sock_server, (struct sockaddr *)&server_addr, length);......
    
  • 這段代碼將字符串 #unix_sock.sock 拷貝到 sun_path 字段,其中的 '#' 是一個占位字符,在后面的代碼中,'#' 被替換為 '\0'

  • 要注意的是,一定要在替換 '#' 前使用 SUN_LEN() 宏去計算 server_addr 的長度,否則因?yàn)?'\0' 的替換將導(dǎo)致長度計算錯誤;

  • 源程序:abstract-socket.c(點(diǎn)擊文件名下載源程序)演示了如何使用抽象命名空間 socket 進(jìn)行進(jìn)程間通信;

    • 該程序建立了兩個進(jìn)程,一個是服務(wù)端進(jìn)程,另一個是客戶端進(jìn)程;
    • 服務(wù)端進(jìn)程在抽象命名空間上建立了一個 socket 并偵聽在該 socket 上;
    • 客戶端進(jìn)程連接到該 socket 上并發(fā)送消息,服務(wù)端進(jìn)程收到消息并給客戶端一個回應(yīng)消息,然后兩個進(jìn)程分別退出;
    • 為了簡化程序,突出抽象命名空間的使用,該程序的 server 進(jìn)程沒有處理多個客戶端進(jìn)程連接的情況;
    • 在 server 進(jìn)程中,socket 綁定完抽象命名空間的 socket 名稱并開始偵聽該 socket 后,執(zhí)行了 lsof 命令,可以很清楚第看到一個名為 @unix_socket.sock,類型為 STREAM 的對象被打開;
  • 編譯:gcc -Wall -g abstract-socket.c -o abstract-socket

  • 運(yùn)行:./abstract-socket

  • 運(yùn)行截圖:

    screenshot of running abstract-socket


4 順序數(shù)據(jù)包(SOCK_SEQPACKET)

  • 通常情況下,基于連接的 socket(SOCK_STREAM) 被認(rèn)為可以可靠地傳輸數(shù)據(jù),而基于無連接的 socket(SOCK_DGRAM) 被認(rèn)為是不可靠的,在傳輸數(shù)據(jù)中,有可能丟失數(shù)據(jù);

  • 但是,使用 SOCK_STREAM 創(chuàng)建的 socket 是基于數(shù)據(jù)流的,數(shù)據(jù)報之間的邊界是不清晰的,接收方收到的數(shù)據(jù)包可能被拆分或者合并,導(dǎo)致收到的數(shù)據(jù)包可能并不是一個完整的數(shù)據(jù)報或者其中還包含著下一個數(shù)據(jù)報的一部分,這就是常說的“粘包(Sticky Packet)”;

  • 使用 SOCK_DGRAM 創(chuàng)建的 socket 也是有明顯優(yōu)點(diǎn)的,它是基于數(shù)據(jù)報的,所以可以保證每次收到的數(shù)據(jù)是一個數(shù)據(jù)報,不會有類似“粘包”的問題;

  • 當(dāng)然,我們希望有一種 socket,它是基于連接的,數(shù)據(jù)傳輸可靠,同時,數(shù)據(jù)報之間的邊界清晰,不會產(chǎn)生“粘包”;

  • 順序數(shù)據(jù)包(SOCK_SEQPACKET)正是這樣一種 socket,它是基于連接的的可靠傳輸,同時保證有明確的報文邊界,通常認(rèn)為它是介于 SOCK_STREAM 和 SOCK_DGRAM 之間的一種連接形式;

  • 目前這種 socket 僅能在 UNIX domain socket(AF_UNIX) 上使用,在 Internet socket(AF_INET) 上不能使用,所以我們在通常的應(yīng)用中看不到使用 SOCK_SEQPACKET 的例子;

  • 使用 SOCK_SEQPACKET 建立 socket 的編程方法與 SOCK_STREAM 非常類似,除了在建立 socket 時使用 SOCK_SEQPACKET 以外基本沒有任何區(qū)別;

  • 以下是 ChatGPT 3.5 給出的 SOCK_SEQPACKET 的特性:

    1. 有界數(shù)據(jù)包傳輸SOCK_SEQPACKET 提供有界數(shù)據(jù)包傳輸,這意味著它可以保留數(shù)據(jù)包的邊界。發(fā)送方在發(fā)送數(shù)據(jù)時定義了數(shù)據(jù)包的邊界,接收方可以按照這個邊界來接收和處理數(shù)據(jù)包。這對于需要確保消息邊界的應(yīng)用程序非常有用。
    2. 可靠性:與 SOCK_DGRAM 套接字類型不同,SOCK_SEQPACKET 提供可靠的數(shù)據(jù)傳輸。它使用面向連接的傳輸協(xié)議來確保數(shù)據(jù)的可靠性,即數(shù)據(jù)在發(fā)送和接收之間保持順序,并且不會丟失或重復(fù)。
    3. 面向連接SOCK_SEQPACKET 是面向連接的套接字類型。在進(jìn)行數(shù)據(jù)傳輸之前,需要先建立連接。連接的建立過程確保了通信雙方之間的可靠通信,并提供了數(shù)據(jù)包傳輸?shù)捻樞虮WC。
    4. 雙向通信SOCK_SEQPACKET 套接字類型支持雙向通信,即可以在連接上進(jìn)行雙向的數(shù)據(jù)傳輸。發(fā)送方可以發(fā)送數(shù)據(jù)給接收方,接收方可以發(fā)送響應(yīng)數(shù)據(jù)給發(fā)送方。
    5. 適用于可靠的流式服務(wù):由于 SOCK_SEQPACKET 提供可靠的、有界的數(shù)據(jù)包傳輸,它適用于需要確保消息邊界和可靠性的應(yīng)用程序。它通常用于基于TCP的應(yīng)用程序,如文件傳輸、視頻流傳輸和實(shí)時通信應(yīng)用。

    需要注意的是,與其他套接字類型相比,SOCK_SEQPACKET 套接字可能會引入一些性能開銷,因?yàn)樗枰S護(hù)消息邊界和數(shù)據(jù)包的順序。因此,在選擇套接字類型時,應(yīng)權(quán)衡應(yīng)用程序的需求和性能要求。

  • 源程序:seqpacket.c(點(diǎn)擊文件名下載源程序)演示了如何使用順序數(shù)據(jù)包進(jìn)行進(jìn)程間通信,同時演示了 SOCK_STREAM 的“粘包”現(xiàn)象以及 SOCK_SEQPACKET 有清晰報文邊界的特性;

    • 建立了三個進(jìn)程,第一個是 SOCK_STREAM 類型 socket 的服務(wù)端進(jìn)程,第二個是 SOCK_SEQPACKET 類型 socket 的服務(wù)端進(jìn)程,第三個是客戶端進(jìn)程;
    • 客戶端進(jìn)程使用同樣的程序分別向兩個服務(wù)端進(jìn)程發(fā)送了三條連續(xù)的報文;
    • 兩個服務(wù)端進(jìn)程除了 socket 類型不同外,其它程序完全一樣;
    • SOCK_STREAM 服務(wù)端進(jìn)程會一次性地收到客戶端發(fā)來的三條報文,三條報文“粘”在一起;
    • SOCK_SEQPACKET 服務(wù)端每次只會收到一條完整報文,三條報文需要接收三次,報文邊界清晰;
    • 為簡單起見,服務(wù)端程序連續(xù)收到 5 個 EAGAIN(EWOULDBLOCK) 錯誤時認(rèn)為客戶端進(jìn)程已經(jīng)完成發(fā)送;
  • 編譯:gcc -Wall -g seqpacket.c -o seqpacket

  • 運(yùn)行:./seqpacket

  • 運(yùn)行截圖:

    screenshot of running seqpacket


5 匿名 UNIX Socket 的使用

  • 前面介紹的 UNIX domain socket 均是需要命名的,或者引用一個文件路徑,或者在抽象命名空間中引用一個名稱;

  • Linux 同樣支持匿名的 UNIX domain socket,就像在文章《IPC之一:使用匿名管道進(jìn)行父子進(jìn)程間通信的例子》介紹的匿名管道一樣,匿名 UNIX domain socket 也是僅能用于父子進(jìn)程或擁有同一個父進(jìn)程的子進(jìn)程間進(jìn)行通信;

  • 在使用匿名管道進(jìn)行全雙工通信時,需要建立兩個管道,一個用于讀,另一個用于寫,匿名 UNIX domain socket 與之類似,也是需要建立一對 socket,一個用于讀,另一個用于寫,使用 socketpair() 建立一對 socket;

    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>int socketpair(int domain, int type, int protocol, int sv[2]);
    
    • 調(diào)用成功,該函數(shù)返回 0,sv 數(shù)組中存放這一對 socket,調(diào)用失敗返回 -1,errno 中為錯誤代碼;
    • 返回的一對 socket 是已經(jīng)連接好的,這意味著無需再調(diào)用其它函數(shù),可以直接在 sv 返回的 socket 上進(jìn)行讀/寫操作;
    • socketpair() 目前只能用在 AF_UNIX 上,所以參數(shù) domain 只能是 AF_UNIX;
    • type 可以是 SOCK_STREAM、SOCK_DGRAM 或者 SOCK_SEQPACKET;
    • protocol 通常填 0 即可;
    • sv 是一個整數(shù)數(shù)組的指針,用于在調(diào)用成功時返回一對 socket,調(diào)用失敗時,sv 數(shù)組的內(nèi)容不會被改動;
  • 使用 socketpair() 建立的 socket 對,與使用 socket() 建立的 socket,在編程上沒有區(qū)別;

  • 因?yàn)槭悄涿?#xff0c;所以只能通過繼承的方式將 socket 對傳遞給子進(jìn)程,所以只能用于父子進(jìn)程間或擁有同一父進(jìn)程的子進(jìn)程之間進(jìn)行通信;

  • 源程序:socketpair.c(點(diǎn)擊文件名下載源程序)演示了如何 socketpair() 建立的 socket 對進(jìn)行進(jìn)程間通信;

    • 在父進(jìn)程中建立一個 socket 對;
    • 建立了兩個子進(jìn)程,第一個是服務(wù)端進(jìn)程,第二個是客戶端進(jìn)程,socket 對通過繼承傳到子進(jìn)程;
    • 服務(wù)端進(jìn)程接收客戶端進(jìn)程發(fā)送的消息
  • 編譯:gcc -Wall -g socketpair.c -o socketpair

  • 運(yùn)行:./socketpair

  • 運(yùn)行截圖:

    screenshot of running socketpair

歡迎訂閱 『進(jìn)程間通信專欄』


http://www.risenshineclean.com/news/65514.html

相關(guān)文章:

  • 學(xué)編程做網(wǎng)站網(wǎng)絡(luò)推廣員的前景
  • 搜索引擎的營銷方法搜索引擎優(yōu)化的主要特征
  • 如何幫助網(wǎng)站吸引流量營銷外包
  • 網(wǎng)站配色的方案最新新聞事件今天疫情
  • 百度網(wǎng)站架構(gòu)seo綜合查詢怎么用的
  • 做網(wǎng)站建設(shè)推廣好做嗎手機(jī)上怎么制作網(wǎng)頁
  • 凡科網(wǎng)站怎么樣櫻花bt引擎
  • 長安網(wǎng)站設(shè)計每日新聞
  • 網(wǎng)站被入侵后需做的檢測(1)網(wǎng)站建站推廣
  • 成都網(wǎng)站制作的公司高明搜索seo
  • 嶗山區(qū)建設(shè)管理局網(wǎng)站怎么了黑seo工作內(nèi)容
  • 網(wǎng)站開發(fā)建設(shè)總結(jié)seo技巧
  • wordpress企業(yè)站實(shí)操天津seo排名效果好
  • 做靜態(tài)網(wǎng)站的軟件電話營銷技巧和營銷方法
  • 諸城 建設(shè)外貿(mào)網(wǎng)站網(wǎng)站維護(hù)中
  • 自己做網(wǎng)站排名好嗎seo網(wǎng)站優(yōu)化技術(shù)
  • 云南企業(yè)網(wǎng)站代發(fā)qq群發(fā)廣告推廣
  • 成都網(wǎng)頁設(shè)計班百度seo系統(tǒng)
  • 做消費(fèi)信貸網(wǎng)站百度天眼查公司
  • 網(wǎng)站制作需求分析中國營銷網(wǎng)
  • 手機(jī)微網(wǎng)站怎么做的開封網(wǎng)絡(luò)推廣哪家好
  • 效果型網(wǎng)站建設(shè)seo查詢5118
  • 織夢如何做幾種語言的網(wǎng)站技術(shù)培訓(xùn)學(xué)校機(jī)構(gòu)
  • 自己做電臺直播的網(wǎng)站自己建網(wǎng)站流程
  • div css快速做網(wǎng)站西安seo外包行者seo06
  • 黑龍江省建設(shè)局網(wǎng)站太原做網(wǎng)站的
  • 如何做招聘網(wǎng)站分析google官方下載安裝
  • 品牌設(shè)計需要多少錢關(guān)鍵詞首頁優(yōu)化
  • 手機(jī)網(wǎng)站源代碼seo網(wǎng)站內(nèi)部優(yōu)化方案
  • 做網(wǎng)站的技術(shù)哪個簡單seo關(guān)鍵詞優(yōu)化怎么收費(fèi)