a亚洲精品_精品国产91乱码一区二区三区_亚洲精品在线免费观看视频_欧美日韩亚洲国产综合_久久久久久久久久久成人_在线区

首頁 > 系統 > Unix > 正文

UNIX網絡編程讀書筆記:UNIX域協議

2024-06-28 13:27:25
字體:
來源:轉載
供稿:網友
UNIX網絡編程讀書筆記:UNIX域協議紅心概述

UNIX域協議并不是一個實際的協議族,而是在單個主機上執行客戶/服務器通信的一種方法,所用API與在不同主機上執行客戶/服務器通信所用的API(套接口API)相同。UNIX域協議可視為進程間通信(ipC)方法之一。

UNIX域提供兩類套接口:字節流套接口(類似TCP)和數據報套接口(類似UDP)。

使用UNIX域套接口的理由有3個:

燈泡在源自Berkeley的實現中,UNIX域套接口往往比通信兩端位于同一主機的TCP套接口快出一倍。

燈泡UNIX域套接口可用于在同一個主機上的不同進程間傳遞描述字。

燈泡UNIX域套接口較新的實現把客戶的憑證(用戶ID和組ID)提供給服務器,從而能夠提供額外的安全檢查措施。

UNIX域中用于標識客戶和服務器的協議地址是普通文件系統中的路徑名。這些路徑名不是普通的UNIX文件:除非把它們和UNIX域套接口關聯起來,否則無法讀寫這些文件。

紅心UNIX域套接口地址結構

在頭文件<sys/un.h>中定義了UNIX域套接口地址結構:

struct sockaddr_un {    sa_family_t    sun_family;       /* AF_LOCAL */    char           sun_path[104];    /* null-terminated pathname */};

存放在sun_path數組中的路徑名必須以空格字符結尾。

實現提供的SUN_LEN宏以一個指向sockaddr_un結構的指針為參數并返回該結構的長度,其中包括路徑名中非空字節數。

未指定地址(通配地址),通過以空字符串作為路徑名指示,也就是一個sun_path[0]值為0的地址結構。這是UNIX域中與IPv4的INADDR_ANY常值以及IPv6的IN6ADDR_ANY_INIT常值等價的一個地址。

POSIX把UNIX域協議重新命名為“本地IPC”,以消除它對于UNIX操作系統的依賴。歷史性的AF_UNIX常值變為AF_LOCAL。盡管POSIX努力使它獨立于操作系統,它的套接口地址結構仍然保留_un后綴。

熱烈的笑臉實例:UNIX域套接口的bind調用

創建一個UNIX域套接口,往其上bind一個路徑名,再調用getsockname輸出這個綁定的路徑名。

#include <sys/un.h>#include <sys/socket.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>intmain(int argc, char **argv){    int                   sockfd;    socklen_t             len;    struct sockaddr_un    addr1, addr2;    if(argc != 2)    {        PRintf("usage: unixbind <pathname> ");        exit(0);    }    sockfd = socket(AF_LOCAL, SOCK_STREAM, 0);    unlink(argv[1]);    /* 如果文件系統中已存在該路徑名,bind將會失敗。為此我們先調用unlink刪除這個路徑名,以防止它已經存在。 */    bzero(&addr1, sizeof(addr1));    addr1.sun_family = AF_LOCAL;    strncpy(addr1.sun_path, argv[1], sizeof(addr1.sun_path) - 1);    bind(sockfd, (struct sockaddr *)&addr1, SUN_LEN(&addr1));    len = sizeof(addr2);    getsockname(sockfd, (struct sockaddr *)&addr2, &len);    printf("bound name = %s, returned len = %d/n", addr2.sun_path, len);        exit(0);}

運行結果如下:

image

紅心socketpair函數

socketpair函數創建兩個隨后連接起來的套接口。本函數僅適用于UNIX域套接口。

#include <sys/socket.h>int socketpair(int family, int type, int protocol, int sockfd[2]);返回:0——成功,-1——出錯

family參數必須為AF_LOCAL;

protocol參數必須為0;

type參數可以是SOCK_STREAM,也可以是SOCK_DGRAM。

新創建的兩個套接口描述字作為sockfd[0]和sockfd[1]返回。

本函數類似于UNIX的pipe函數:返回兩個彼此連接的描述字。事實上,源自berkeley的實現通過執行與socketpair一樣的內部操作給出pipe接口。

這樣創建的兩個套接口不曾命名;也就是說其中沒有涉及隱式的bind調用。它與調用pipe創建的普通UNIX管道類似,差別在于流管道(socketpair創建的)是全雙工的,即兩個描述字都是既可讀又可寫。

POSIX不要求全雙工管道。

紅心套接口函數

當用于UNIX域套接口時,套接口函數中存在一些差異和限制:

燈泡由bind創建的路徑名缺省訪問權限應為0777(屬主用戶、組用戶和其他用戶都可讀、可寫并可執行),并按照當前umask值進行修正。

燈泡與UNIX域套接口關聯的路徑名應該是一個絕對路徑名,而不是一個相對路徑名。

燈泡在connect調用中指定的路徑名必須是一個當前捆綁在某個打開的UNIX域套接口上的路徑名,而且它們的套接口類型(字節流或數據報)也必須一致。

燈泡調用connect連接一個UNIX域套接口涉及的權限測試等同于調用open以只讀方式訪問相應的路徑名。

燈泡UNIX域字節流套接口類似于TCP套接口:它們都為進程提供一個無記錄邊界的字節流接口。

燈泡如果對于某個UNIX域字節流套接口的connect調用發現這個監聽套接口的隊列已滿,調用就立即返回一個ECONNREFUSED錯誤。這一點不同于TCP:如果TCP監聽套接口的隊列已滿,TCP監聽端就忽略新到達的SYN,而TCP連接發起端將數次發送SYN進行重試。

燈泡UNIX域數據報套接口類似UDP套接口:它們都提供一個保留記錄邊界的不可靠的數據報服務。

燈泡在一個未綁定的UNIX域套接口上發送數據報不會自動給這個套接口捆綁一個路徑名,這一點不同于UDP套接口:在一個未綁定的UDP套接口上發送UDP數據報導致給這個套接口捆綁一個臨時端口。這一點意味著除非數據報發送端已經捆綁一個路徑名到它的套接口,否則數據報接收端無法發回應答數據報。類似地,對于某個UNIX域數據報套接口的connect調用不會給本套接口綁定一個路徑名,這一點不同于TCP和UDP。

紅心UNIX域字節流客戶/服務器程序
/* unixstrserv01.c */#include <sys/un.h>#include <errno.h>#include <sys/wait.h>#include <signal.h>#include <sys/socket.h>#include <sys/types.h>#include <stdio.h>#include <stdlib.h>#include <strings.h>#include <string.h>#define UNIXSTR_PATH    "/tmp/unix.str"intmain(int argc, char **argv){    int                   listenfd, connfd;    pid_t                 childpid;    socklen_t             clilen;    struct sockaddr_un    cliaddr, servaddr;    void                  sig_chld(int);    daemonize("unixstrserver");    listenfd = socket(AF_LOCAL, SOCK_STREAM, 0);    unlink(UNIXSTR_PATH);    bzero(&servaddr, sizeof(servaddr));    servaddr.sun_family = AF_LOCAL;    strcpy(servaddr.sun_path, UNIXSTR_PATH);        bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));    listen(listenfd, 5);    signal(SIGCHLD, sig_chld);    for(;;)    {        clilen = sizeof(cliaddr);            if((connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen)) < 0)        {            if(errno == EINTR)                continue;    /* back to for() */            else            {                perror("accept");                exit(1);            }        }                if((childpid = fork()) == 0)        {            close(listenfd);            str_echo(connfd);            exit(0);        }        close(connfd);    }}voidsig_chld(int signo){    pid_t    pid;    int      stat;        while((pid = waitpid(-1, &stat, WNOHANG)) > 0)    {        printf("child %d terminated/n", pid);    }        return;}
/* unixstrcli01.c */#include <sys/un.h>#include <strings.h>#include <sys/un.h>#include <sys/socket.h>#include <sys/types.h>#include <stdio.h>#include <stdlib.h>#define UNIXSTR_PATH    "/tmp/unix.str"intmain(int argc, char **argv){    int    sockfd;    struct sockaddr_un    servaddr;        sockfd = socket(AF_LOCAL, SOCK_STREAM, 0);        bzero(&servaddr, sizeof(servaddr));    servaddr.sun_family = AF_LOCAL;    strcpy(servaddr.sun_path, UNIXSTR_PATH);        connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));    str_cli(stdin, sockfd);    exit(0);}

其他相關使用到的函數參見:http://www.CUOXin.com/nufangrensheng/p/3587962.html 以及http://www.CUOXin.com/nufangrensheng/p/3544104.html。

紅心UNIX域數據報客戶/服務器程序
/* unixdgserv01.c */#include <sys/un.h>#include <sys/socket.h>#define UNIXDG_PATH    "/tmp/unix.dg"int main(int argc, char **argv){    int                   sockfd;    struct sockaddr_un    servaddr, cliaddr;        sockfd = socket(AF_LOCAL, SOCK_DGRAM, 0);    unlink(UNIXDG_PATH);    bzero(&servaddr, sizeof(servaddr));    servaddr.sun_family = AF_LOCAL;    strcpy(servaddr.sun_path, UNIXDG_PATH);    bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));        dg_echo(sockfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr));}
/* unixdgcli01.c */#include <sys/un.h>#include <stdio.h>#include <stdlib.h>#include <sys/socket.h>#include <sys/types.h>#define UNIXDG_PATH    "/tmp/unix.dg"intmain(int argc, char **argv){    int                   sockfd;    struct sockaddr_un    cliaddr, servaddr;    sockfd = socket(AF_LOCAL, SOCK_DGRAM, 0);        bzero(&cliaddr, sizeof(cliaddr));    cliaddr.sun_family = AF_LOCAL;    strcpy(cliaddr.sun_path, tmpnam(NULL));        bind(sockfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr));        bzero(&servaddr, sizeof(servaddr));    servaddr.sun_family = AF_LOCAL;    strcpy(servaddr.sun_path, UNIXDG_PATH);        dg_cli(stdin, sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));    exit(0);}

使用到的相關函數可參考:http://www.CUOXin.com/nufangrensheng/p/3592158.html。

燈泡注意燈泡與UDP客戶不同的是,當使用UNIX域數據報協議時,我們必須顯式bind一個路徑名到我們的套接口,這樣服務器才會有回送應答的路徑名

紅心描述字傳遞

當考慮從一個進程到另一個進程傳遞打開的描述字時,我們通常會想到:

(1)fork調用返回后,子進程共享父進程的所有打開的描述字。

(2)exec調用執行之后,所有描述字通常保持打開狀態不變。

在(1)中,進程先打開一個描述字,再調用fork,然后父進程關閉這個描述字,子進程則處理這個描述字。這樣一個打開的描述字就從父進程傳遞到子進程。然而我們也可能想讓子進程打開一個描述字并把它傳遞給父進程。

當前的UNIX系系統提供了用于從一個進程到任一其他進程傳遞任一打開的描述字的方法。也就是說,這兩個進程之間無需存在親緣關系。這種技術要求首先在這兩個進程之間創建一個UNIX域套接口,然后使用sendmsg跨這個UNIX域套接口發送一個特殊消息。這個消息由內核處理,從而把打開的描述字從發送進程傳遞到接收進程。使用UNIX域套接口的描述字傳遞方法是最便于移植的編程技術。

在兩個進程之間傳遞描述字涉及的步驟如下:

(1)創建一個字節流或數據報的UNIX域套接口。

如果目標是fork一個子進程,讓子進程打開待傳遞的描述字,再把它傳遞回父進程,那么父進程可以預先調用socketpair創建一個可用于在父子進程之間交換描述字的流管道。

如果進程之間沒有親緣關系,那么服務器進程必須創建一個UNIX域字節流套接口,bind一個路徑到該套接口,以允許客戶進程connect到該套接口。客戶然后可以向服務器發送一個打開某個描述字的請求,服務器再把該描述字通過UNIX域套接口傳遞回客戶。客戶和服務器之間也可以使用UNIX域數據報套接口,不過這么做缺乏優勢,而且數據報存在被丟棄的可能性。

(2)發送進程通過調用返回描述字的任一UNIX函數打開一個描述字,這些函數的例子有:open、pipe、mkfifo、socket和accept。可以在進程之間傳遞的描述字不限類型,這就是我們稱這種技術為“描述字傳遞”而不是“文件描述字傳遞”的原因。

(3)發送進程創建一個msghdr結構(http://www.CUOXin.com/nufangrensheng/p/3567376.html),其中含有待傳遞的描述字POSIX規定描述字作為輔助數據(msghdr結構的msg_control成員)發送。發送進程調用sendmsg跨來自步驟(1)的UNIX域套接口發送該描述字至此我們說這個描述字“在飛行中(in flight)”。即使發送進程在調用sendmsg之后但在接收進程調用recvmsg之前就關閉了該描述字,對于接收進程它仍然保持打開狀態。發送一個描述字導致該描述字的引用計數加1.

(4)接收進程調用recvmsg在來自步驟(1)的UNIX域套接口上接收這個描述字。這個描述字在接收進程中的描述字號不同于它在發送進程中的描述子號是正常的。傳遞一個描述字并不是傳遞一個描述字號,而是涉及在接收進程中創建一個新的描述字,而這個描述字指引的內核中文件表項和發送進程中飛行前的那個描述字指引的相同。

客戶和服務器之間必須存在某種應用協議,以便描述字的接收進程預先知道何時期待接收。另外,在期待接收描述字的recvmsg調用中應該避免使用MSG_PEEK標志,否則后果不可預料。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: www.视频在线观看 | 91精品久久久久久 | 欧美精品一区二区三区涩爱蜜 | 国产精品国产精品国产专区不卡 | 999热在线 | 先锋资源中文字幕 | 日韩在线一区二区 | 久久精品二区 | 手机在线成人免费视频 | 亚洲精品久久久久久一区二区 | 欧美视频亚洲视频 | 国产亚洲一区二区在线 | 精品久久香蕉国产线看观看亚洲 | 国产欧美日本 | 日本色网址 | 四虎影院最新网址 | 三级在线观看视频 | 日韩中文字幕一区二区 | 日日操夜夜添 | 日韩国产在线 | 一区二区欧美在线 | 日韩欧美国产网站 | 六月丁香av| 国产亚洲综合一区二区 | 国产精品久久久久久久久久99 | 成人精品视频 | 狠狠爱天天干 | 国产视频一视频二 | 蜜桃comaaa| 日本一区二区三区视频在线 | 一区二区日韩精品 | 国产中文字幕在线 | 日本一区二区不卡 | 日韩视频在线观看视频 | 亚州黄色 | 成人免费视频国产免费麻豆 | 精品国产一区二区三区久久久蜜月 | 色综合成人 | 亚洲一区高清 | 亚洲国产精品久久久久 | 精品一区二区免费视频 |