麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁(yè) > 系統(tǒng) > Unix > 正文

UNIX網(wǎng)絡(luò)編程讀書(shū)筆記:UNIX域協(xié)議

2024-06-28 13:27:25
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友
UNIX網(wǎng)絡(luò)編程讀書(shū)筆記:UNIX域協(xié)議紅心概述

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

UNIX域提供兩類(lèi)套接口:字節(jié)流套接口(類(lèi)似TCP)和數(shù)據(jù)報(bào)套接口(類(lèi)似UDP)。

使用UNIX域套接口的理由有3個(gè):

燈泡在源自Berkeley的實(shí)現(xiàn)中,UNIX域套接口往往比通信兩端位于同一主機(jī)的TCP套接口快出一倍。

燈泡UNIX域套接口可用于在同一個(gè)主機(jī)上的不同進(jìn)程間傳遞描述字。

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

UNIX域中用于標(biāo)識(shí)客戶和服務(wù)器的協(xié)議地址是普通文件系統(tǒng)中的路徑名。這些路徑名不是普通的UNIX文件:除非把它們和UNIX域套接口關(guān)聯(lián)起來(lái),否則無(wú)法讀寫(xiě)這些文件。

紅心UNIX域套接口地址結(jié)構(gòu)

在頭文件<sys/un.h>中定義了UNIX域套接口地址結(jié)構(gòu):

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

存放在sun_path數(shù)組中的路徑名必須以空格字符結(jié)尾。

實(shí)現(xiàn)提供的SUN_LEN宏以一個(gè)指向sockaddr_un結(jié)構(gòu)的指針為參數(shù)并返回該結(jié)構(gòu)的長(zhǎng)度,其中包括路徑名中非空字節(jié)數(shù)。

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

POSIX把UNIX域協(xié)議重新命名為“本地IPC”,以消除它對(duì)于UNIX操作系統(tǒng)的依賴(lài)。歷史性的AF_UNIX常值變?yōu)锳F_LOCAL。盡管POSIX努力使它獨(dú)立于操作系統(tǒng),它的套接口地址結(jié)構(gòu)仍然保留_un后綴。

熱烈的笑臉實(shí)例:UNIX域套接口的bind調(diào)用

創(chuàng)建一個(gè)UNIX域套接口,往其上bind一個(gè)路徑名,再調(diào)用getsockname輸出這個(gè)綁定的路徑名。

#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]);    /* 如果文件系統(tǒng)中已存在該路徑名,bind將會(huì)失敗。為此我們先調(diào)用unlink刪除這個(gè)路徑名,以防止它已經(jīng)存在。 */    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);}

運(yùn)行結(jié)果如下:

image

紅心socketpair函數(shù)

socketpair函數(shù)創(chuàng)建兩個(gè)隨后連接起來(lái)的套接口。本函數(shù)僅適用于UNIX域套接口。

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

family參數(shù)必須為AF_LOCAL;

protocol參數(shù)必須為0;

type參數(shù)可以是SOCK_STREAM,也可以是SOCK_DGRAM。

新創(chuàng)建的兩個(gè)套接口描述字作為sockfd[0]和sockfd[1]返回。

本函數(shù)類(lèi)似于UNIX的pipe函數(shù):返回兩個(gè)彼此連接的描述字。事實(shí)上,源自berkeley的實(shí)現(xiàn)通過(guò)執(zhí)行與socketpair一樣的內(nèi)部操作給出pipe接口。

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

POSIX不要求全雙工管道。

紅心套接口函數(shù)

當(dāng)用于UNIX域套接口時(shí),套接口函數(shù)中存在一些差異和限制:

燈泡由bind創(chuàng)建的路徑名缺省訪問(wèn)權(quán)限應(yīng)為0777(屬主用戶、組用戶和其他用戶都可讀、可寫(xiě)并可執(zhí)行),并按照當(dāng)前umask值進(jìn)行修正。

燈泡與UNIX域套接口關(guān)聯(lián)的路徑名應(yīng)該是一個(gè)絕對(duì)路徑名,而不是一個(gè)相對(duì)路徑名。

燈泡在connect調(diào)用中指定的路徑名必須是一個(gè)當(dāng)前捆綁在某個(gè)打開(kāi)的UNIX域套接口上的路徑名,而且它們的套接口類(lèi)型(字節(jié)流或數(shù)據(jù)報(bào))也必須一致。

燈泡調(diào)用connect連接一個(gè)UNIX域套接口涉及的權(quán)限測(cè)試等同于調(diào)用open以只讀方式訪問(wèn)相應(yīng)的路徑名。

燈泡UNIX域字節(jié)流套接口類(lèi)似于TCP套接口:它們都為進(jìn)程提供一個(gè)無(wú)記錄邊界的字節(jié)流接口。

燈泡如果對(duì)于某個(gè)UNIX域字節(jié)流套接口的connect調(diào)用發(fā)現(xiàn)這個(gè)監(jiān)聽(tīng)套接口的隊(duì)列已滿,調(diào)用就立即返回一個(gè)ECONNREFUSED錯(cuò)誤。這一點(diǎn)不同于TCP:如果TCP監(jiān)聽(tīng)套接口的隊(duì)列已滿,TCP監(jiān)聽(tīng)端就忽略新到達(dá)的SYN,而TCP連接發(fā)起端將數(shù)次發(fā)送SYN進(jìn)行重試。

燈泡UNIX域數(shù)據(jù)報(bào)套接口類(lèi)似UDP套接口:它們都提供一個(gè)保留記錄邊界的不可靠的數(shù)據(jù)報(bào)服務(wù)。

燈泡在一個(gè)未綁定的UNIX域套接口上發(fā)送數(shù)據(jù)報(bào)不會(huì)自動(dòng)給這個(gè)套接口捆綁一個(gè)路徑名,這一點(diǎn)不同于UDP套接口:在一個(gè)未綁定的UDP套接口上發(fā)送UDP數(shù)據(jù)報(bào)導(dǎo)致給這個(gè)套接口捆綁一個(gè)臨時(shí)端口。這一點(diǎn)意味著除非數(shù)據(jù)報(bào)發(fā)送端已經(jīng)捆綁一個(gè)路徑名到它的套接口,否則數(shù)據(jù)報(bào)接收端無(wú)法發(fā)回應(yīng)答數(shù)據(jù)報(bào)。類(lèi)似地,對(duì)于某個(gè)UNIX域數(shù)據(jù)報(bào)套接口的connect調(diào)用不會(huì)給本套接口綁定一個(gè)路徑名,這一點(diǎn)不同于TCP和UDP。

紅心UNIX域字節(jié)流客戶/服務(wù)器程序
/* 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);}

其他相關(guān)使用到的函數(shù)參見(jiàn):http://www.CUOXin.com/nufangrensheng/p/3587962.html 以及http://www.CUOXin.com/nufangrensheng/p/3544104.html。

紅心UNIX域數(shù)據(jù)報(bào)客戶/服務(wù)器程序
/* 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);}

使用到的相關(guān)函數(shù)可參考:http://www.CUOXin.com/nufangrensheng/p/3592158.html。

燈泡注意燈泡與UDP客戶不同的是,當(dāng)使用UNIX域數(shù)據(jù)報(bào)協(xié)議時(shí),我們必須顯式bind一個(gè)路徑名到我們的套接口,這樣服務(wù)器才會(huì)有回送應(yīng)答的路徑名

紅心描述字傳遞

當(dāng)考慮從一個(gè)進(jìn)程到另一個(gè)進(jìn)程傳遞打開(kāi)的描述字時(shí),我們通常會(huì)想到:

(1)fork調(diào)用返回后,子進(jìn)程共享父進(jìn)程的所有打開(kāi)的描述字。

(2)exec調(diào)用執(zhí)行之后,所有描述字通常保持打開(kāi)狀態(tài)不變。

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

當(dāng)前的UNIX系系統(tǒng)提供了用于從一個(gè)進(jìn)程到任一其他進(jìn)程傳遞任一打開(kāi)的描述字的方法。也就是說(shuō),這兩個(gè)進(jìn)程之間無(wú)需存在親緣關(guān)系。這種技術(shù)要求首先在這兩個(gè)進(jìn)程之間創(chuàng)建一個(gè)UNIX域套接口,然后使用sendmsg跨這個(gè)UNIX域套接口發(fā)送一個(gè)特殊消息。這個(gè)消息由內(nèi)核處理,從而把打開(kāi)的描述字從發(fā)送進(jìn)程傳遞到接收進(jìn)程。使用UNIX域套接口的描述字傳遞方法是最便于移植的編程技術(shù)。

在兩個(gè)進(jìn)程之間傳遞描述字涉及的步驟如下:

(1)創(chuàng)建一個(gè)字節(jié)流或數(shù)據(jù)報(bào)的UNIX域套接口。

如果目標(biāo)是fork一個(gè)子進(jìn)程,讓子進(jìn)程打開(kāi)待傳遞的描述字,再把它傳遞回父進(jìn)程,那么父進(jìn)程可以預(yù)先調(diào)用socketpair創(chuàng)建一個(gè)可用于在父子進(jìn)程之間交換描述字的流管道。

如果進(jìn)程之間沒(méi)有親緣關(guān)系,那么服務(wù)器進(jìn)程必須創(chuàng)建一個(gè)UNIX域字節(jié)流套接口,bind一個(gè)路徑到該套接口,以允許客戶進(jìn)程connect到該套接口??蛻羧缓罂梢韵蚍?wù)器發(fā)送一個(gè)打開(kāi)某個(gè)描述字的請(qǐng)求,服務(wù)器再把該描述字通過(guò)UNIX域套接口傳遞回客戶。客戶和服務(wù)器之間也可以使用UNIX域數(shù)據(jù)報(bào)套接口,不過(guò)這么做缺乏優(yōu)勢(shì),而且數(shù)據(jù)報(bào)存在被丟棄的可能性。

(2)發(fā)送進(jìn)程通過(guò)調(diào)用返回描述字的任一UNIX函數(shù)打開(kāi)一個(gè)描述字,這些函數(shù)的例子有:open、pipe、mkfifo、socket和accept。可以在進(jìn)程之間傳遞的描述字不限類(lèi)型,這就是我們稱(chēng)這種技術(shù)為“描述字傳遞”而不是“文件描述字傳遞”的原因。

(3)發(fā)送進(jìn)程創(chuàng)建一個(gè)msghdr結(jié)構(gòu)(http://www.CUOXin.com/nufangrensheng/p/3567376.html),其中含有待傳遞的描述字POSIX規(guī)定描述字作為輔助數(shù)據(jù)(msghdr結(jié)構(gòu)的msg_control成員)發(fā)送。發(fā)送進(jìn)程調(diào)用sendmsg跨來(lái)自步驟(1)的UNIX域套接口發(fā)送該描述字。至此我們說(shuō)這個(gè)描述字“在飛行中(in flight)”。即使發(fā)送進(jìn)程在調(diào)用sendmsg之后但在接收進(jìn)程調(diào)用recvmsg之前就關(guān)閉了該描述字,對(duì)于接收進(jìn)程它仍然保持打開(kāi)狀態(tài)。發(fā)送一個(gè)描述字導(dǎo)致該描述字的引用計(jì)數(shù)加1.

(4)接收進(jìn)程調(diào)用recvmsg在來(lái)自步驟(1)的UNIX域套接口上接收這個(gè)描述字。這個(gè)描述字在接收進(jìn)程中的描述字號(hào)不同于它在發(fā)送進(jìn)程中的描述子號(hào)是正常的。傳遞一個(gè)描述字并不是傳遞一個(gè)描述字號(hào),而是涉及在接收進(jìn)程中創(chuàng)建一個(gè)新的描述字,而這個(gè)描述字指引的內(nèi)核中文件表項(xiàng)和發(fā)送進(jìn)程中飛行前的那個(gè)描述字指引的相同。

客戶和服務(wù)器之間必須存在某種應(yīng)用協(xié)議,以便描述字的接收進(jìn)程預(yù)先知道何時(shí)期待接收。另外,在期待接收描述字的recvmsg調(diào)用中應(yīng)該避免使用MSG_PEEK標(biāo)志,否則后果不可預(yù)料。


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 亚洲成人中文字幕在线 | 精品中文一区 | 欧美精品久久久久久久久老牛影院 | 在线看免费观看日本 | 国产精品一区在线免费观看 | 免费观看黄色影片 | 亚洲精品一二三区 | 黄色99视频 | 97青青草视频 | 欧美一级黄色片在线观看 | 日本爽快片100色毛片视频 | 欧美一级性 | 欧美大胆xxxx肉体摄影 | 欧美三级日本三级少妇99 | 中国的免费的视频 | 一本色道久久综合狠狠躁篇适合什么人看 | 丁香天堂网 | 国产免费网站视频 | 国产精品99久久久久久董美香 | 高清视频一区二区 | 欧美黄色一级片视频 | 久久av免费 | 深夜毛片免费看 | 可以看逼的视频 | 动漫孕妇被羞羞视频 | 激情夜色| 久久不射电影网 | 欧洲精品视频在线观看 | 免费色片| 精品久久久久久久久久久下田 | av电影在线免费 | 色中色在线播放 | 免费观看国产精品视频 | 日韩黄在线观看 | 久久久久久99 | 久久2019中文字幕 | 污视频在线看 | 久久羞羞视频 | 成人福利视频在 | 一级做a爱片性色毛片高清 日本一区二区在线看 | 色污视频 |