亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Linux Socket學習(三)

系統 1865 0
無名套接口
套接口并不總是需要有一個地址。例如, socketpair函數創建了兩個彼此相連的兩個套接口,但是卻沒有地址。實際上,他們是無名套接口。想像一下冷戰期間美國總統與蘇聯之間的紅色電話。 他們任何一端并不需要電話號碼,因為他們是直接相連的。同樣,socketpair函數也是直接相連的,也并不需要地址。
匿名調用
有時在實際上,連接中的兩個套接口中的一個也沒有地址。對于要連接的遠程套接口,他必須要有一個地址來標識。然而,本地套接口是匿名的。建立起來的連接具有一個有地址的遠程套接口和另一個無地址的套接口。

生成地址
有 時我們并不會介意我們的本地址是什么,但是我們需要一個來進行通信。這對于需要連接到一個服務器(例如一個RDBMS數據服務)的程序來說通常是正確的。 他們的本地地址僅為持續的連接所需要。分配確定的地址也可以完成,但是這增加了網絡管理的工作。相應的,當地址可用時才會生成地址。
理解域
當Berkeley開發組正在構思BSD套接口接口時,TCP/IP仍在開發之中。與此同時,有一些其他的即將完成的協議正在為不同的組織所使用,例如X.25協議。其他的協議也正在研究之中。
我 們在上一章所見的socketpair函數,以及我們將會看到的socket函數,很明智的允許了其他協議需不是TCP/IP也許會用到的可能性。 socketpair函數的domain參數允許這種約束。為了討論的方便,讓我們先來回顧一下socketpair函數的概要:
#include <sys/types.h>
#include <sys/socket.h>
int socketpair(int domain, int type, int protocol, int sv[2]);
通常,protocol參數指定為0。0允許操作系統選擇我們所選擇的domain的所用的默認協議。對于這些規則有一些例外,但是這超出了我們討論的范圍。
現在我們要來解釋一下domain參數。對于socketpair函數,這個值必須為AF_LOCAL或者AF_UNIX。在上一章,我們已經指出AF_UNIX宏與舊版的AF_LOCAL等同。然而AF_LOCAL意味著什么?他選擇了什么呢?
常量的AF_前緣指明了地址族。domain參數選擇要使用的地址族。

格式化套接口地址
每 一個通信協議指明了他自己的網絡地址的格式。相應的,地址族用來指明要使用哪種類型的地址。常量AF_LOCAL(AF_UNIX)指明了地址將會按照本 地(UNIX)地址規則來格式化。常量AF_INET指明了地址將會符合IP地址規則。在一個地址族中,可以有多種類型。
在下面的部分中,我們將會檢測各種地址族的格式以及物理布局。這是需要掌握的重要的一部分。人們使用BSD套接口接口時所遇到的困難,很多與地址初始化相關。

檢測通常的套接口地址
因為BSD套接口地址的開發早于ANSI C標準,所以沒有(void *)數據指針來接受任何結構地址。相應的BSD的解決選擇是定義一個通用的地址結構。通用的地址結構是用下面的C語言語句來定義的:
#include <sys/socket.h>
struct sockaddr {
sa_family_t sa_family; /* Address Family */
char sa_data[14]; /* Address data. */
};
這里的sa_family_t數據類型是一個無符號短整數,在Linux下為兩個字節。整個結構為16個字節。結構元素的sa_data[14]代表了地址信息的其余14個字節。
下圖顯示了通用地址結構的物理布局:
Linux Socket學習(三)
通用套接口地址結構對于程序而言并不是那樣有用。然而,他確實提供了其他地址結構必須適合的引用模型。例如,我們將會了解到所有地址必須在結構中的同樣的位置定義一個sa_family成員,因為這個元素決定了地址結構的剩余字節數。

格式化本地地址
這個地址結構用在我們的本地套接口中(我們的運行Linux的PC)。例如,當我們使用lpr命令排除要打印的文件時,他使用一個本地套接口與我們的PC上假脫機服務器進行通信。雖然也可以用TCP/IP協議來進行本地通信,但是事實證明這是低效的。
傳統上,本地地址族已經被稱這為AF_UNIX域。這是因為這些地址使用本地UNIX文件來作為套接口名字。
AF_LOCAL或者AF_UNIX的地址結構名為sockaddr_un。這個結構是通過在我們的C程序中包含下面的語句來定義的:
#include <sys/un.h>
sockaddr_un的地址結構:
struct sockaddr_un {
sa_family_t sun_family;/* Address Family */
char sun_path[108]; /* Pathname */
};
結構成員sun_family的值必須為AF_LOCAL或者AF_UNIX。這個值表明這個結構是通過sockaddr_un結構規則來進行格式化的。
結構成員sun_path[108]包含一個可用的UNIX路徑名。這個字符數組并不需要結尾的null字節。
在下面的部分中,我們將會了解到如何來初始化一個AF_LOCAL地址與定義他的長度。

格式化傳統本地地址
傳統本地地址的地址名空間為文件系統路徑名。一個進程也許會用任何可用的路徑名來命名他的本地套接口。然則為了可用,命名套接口的進程必須可以訪問路徑名的所有目錄組件,并且有權限來在指定的目錄中創建最終的套接口對象。
一些程序員喜歡在填充地址結構之前將其全部初始化為0。這通常是通過memset函數來做到的,并且這是一個不錯的主意。
struct sockaddr_un uaddr;
memset(&uaddr,0,sizeof uaddr);
這個函數會為我們將這個地址結構的所有字節設置為0。
下面的例子演示了一個簡單的初始化sockaddr_un結構的C程序,然后調用netstat命令來證明他起到了作用。在這里我們要先記住在socket與bind上的程序調用,這是兩個我們還沒有涉及到的函數。
/*****************************************
*
* af_unix.c
*
* AF_UNIX Socket Example:
*
* ******************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>

/*
* This function reports the error and
* exits back to the shell:
*/
static void bail(const char *on_what)
{
perror(on_what);
exit(1);
}

int main(int argc,char **argv,char **envp)
{
int z; /* Status return code */
int sck_unix; /* Socket */
struct sockaddr_un adr_unix; /* AF_UNIX */
int len_unix; /* length */
const char pth_unix[] = "/tmp/my_sock"; /* pathname */

/*
* Create a AF_UNIX (aka AF_LOCAL) socket:
*/
sck_unix = socket(AF_UNIX,SOCK_STREAM,0);

if(sck_unix == -1)
bail("socket()");

/*
* Here we remove the pathname for the
* socket,in case it existed from a
* prior run.Ignore errors (it maight
* not exist).
*/
unlink(pth_unix);

/*
* Form an AF_UNIX Address:
*/
memset(&adr_unix,0,sizeof adr_unix);

adr_unix.sun_family = AF_LOCAL;
strncpy(adr_unix.sun_path,pth_unix,
sizeof adr_unix.sun_path-1)
[sizeof adr_unix.sun_path-1] = 0;
len_unix = SUN_LEN(&adr_unix);

/*
* Now bind the address to the socket:
*/
z = bind(sck_unix,
(struct sockaddr *)&adr_unix,
len_unix);
if(z == -1)
bail("bind()");
/*
* Display all of our bound sockets
*/
system("netstat -pa --unix 2>/dev/null |"
"sed -n '/^Active UNIX/,/^Proto/P;"
"/af_unix/P'");
/*
* Close and unlink our socket path:
*/
close(sck_unix);
unlink(pth_unix);

return 0;
}
上面的這個例子的步驟如下:
1 在第28行定義了sck_unix來存放創建的套接口文件描述符。
2 在第29行定義了本地地址結構并且命名為adr_unix。這個程序將會用一個AF_LOCAL套接口地址來處理這個結構。
3 通過調用socket函數來在第37行創建了一個套接口。在第39行檢測錯誤并報告。
4 在第48行調用unlink函數。因為AF_UNIX地址將會創建一個文件系統對象,如果不再需要必須進行刪除。如果這個程序最后一次運行時沒有刪除,這條語句會試著進行刪除。
5 在第53行adr_unix的地址結構被清0。
6 在第55行將地址族初始化為AF_UNIX。
7 第57行到第59行向地址結構中拷貝路徑名"/tmp/my_sock"。在這里使用代碼在結構中添加了一個null字節,因為在第61行Linux提供了宏SUN_LEN()需要他。
8 在第61行計算地址的長度。這里的程序使用了Linux提供的宏。然而這個宏依賴于adr_unix.sun_path[]結構成員的一個結束字符。
9 在第66行到68行調用bind函數,將格式化的地址賦值給第37行創建的套接口。
10 在第76行調用netstat命令來證明我們的地址已綁定到了套接口。
11 在第83 行關閉套接口。
12 當調用bind函數時為套接口所創建的UNIX路徑名在第66行被刪除。
在 第61行將長度賦值給len_unix,在這里使用了SUN_LEN()宏,但是并不會計算拷貝到adr_unix.sun_path[]字符數組中的空 字節。然而放置一個空字節是必要的,因為SUN_LEN()宏會調用strlen函數來計算UNIX路徑名的字符串長度。
程序的執行結果如下:
$ ./af_unix
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags Type State I-Node PID/Program name Path
unix 0 [] STREAM 104129 800/af_unix /tmp/my_sock
$

格式化抽象本地地址
傳統AF_UNIX套接口名字的麻煩之一就在于總是調用文件系統對象。這不是必須的,而且也不方便。如果原始的文件系統對象并沒有刪除,而在bind調用時使用相同的文件名,名字賦值就會失敗。
Linux 2.2內核使得為本地套接口創建一個抽象名了成為可能。他的方法就是使得路徑名的第一個字節為一個空字節。在路徑名中空字節之后的字節才會成為抽象名字的一部分。下面的這個程序是上一個例子程序的修改版本。這個程序采用了一些不同的方法來創建一個抽象的名字。
/*****************************************
* af_unix2.c
*
* AF_UNIX Socket Example
* Create Abstract Named AF_UNIX/AF_LOCAL
* ******************************************/
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>

/*
* This function reports the error and
* exits back to the shell:
*/
static void bail(const char *on_what)
{
perror(on_what);
exit(1);
}

int main(int argc,char **argv,char **envp)
{
int z; /* Status return code */
int sck_unix; /* Socket */
struct sockaddr_un adr_unix; /* AF_UNIX */
int len_unix; /* length */
const char pth_unix[] /* Abs .Name */
= "Z*MY-SOCKET*";

/*
* Create an AF_UNIX (aka AF_UNIX) socket:
*/
sck_unix = socket(AF_UNIX,SOCK_STREAM,0);
if(sck_unix == -1)
bail("socket()");

/*
* Form an AF_UNIX Address
*/
memset(&adr_unix,0,sizeof adr_unix);
adr_unix.sun_family = AF_UNIX;
strncpy(adr_unix.sun_path,pth_unix,
sizeof adr_unix.sun_path-1)
[sizeof adr_unix.sun_path-1] = 0;
len_unix = SUN_LEN(&adr_unix);

/*
* Now make first byte null
*/
adr_unix.sun_path[0] = 0;

z = bind(sck_unix,(struct sockaddr *)&adr_unix,len_unix);
if(z == -1)
bail("bind()");
/*
* Display all of our bound sockets:
*/
system("netstat -pa --unix 2>/dev/null |"
"sed -n '/^Active UNIX/,/^Proto/P;"
"/af_unix/P'");
/*
* Close and unlink our socket path:
*/
close(sck_unix);
return 0;
/*
* Now bind the address to the socket:
*/
}
這個程序的運行結果如下:
$ ./af_unix2
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags Type State I-Node PID/Program name Path
unix 0 [] STREAM 104143 5186/af_unix2 @*MY- SOCKET*
$
從這個輸出結果中我們可以看到,套接口地址是以 @*MYSOCKET*的名字出現的。開頭的@標志是為netstat命令用來標識抽象UNIX套接口名字。其余的字符是拷貝到字符數組剩余位置的字符。注意@字符出現在我們的Z字符應出現的地方。
整個程序的步驟與前一個程序的相同。然而,地址的初始化步驟有一些不同。這些步驟描述如下:
1 在第31行和第32行定義了套接口抽象名字的字符串。注意字符串的第一個字符為Z。在這個字符串這個多余的字符只是起到占位的作用,因為實際上他會在第6步被一個空字節代替。
2 在第45行通過調用memset函數將整個結構初始經為0。
3 在第47行將地址族設置為AF_UNIX。
4 在第49行使用strncpy函數將抽象名字拷貝到adr_unix.sun_path中。在這里要注意,為了SUN_LEN()宏的使用在目的字符數組的放置了一個結束的空字節。否則就不需要這個結束的空字節。
5 在第53通過Linux所提供的SUN_LEN() C 宏來計算地址的長度。這個宏會在sun_path[]上調用strlen函數,所以需要提供了一個結束字符。
6 這一步是新的:sun_path[]數組的第一個字節被設置為空字節。如果使用SUN_LEN()宏,必須最后執行這一步。
在這一部分,我們了解了如何來創建AF_LOCAL和AF_UNIX的套接口地址。為了計算套接口地址的長度,我們使用SUN_LEN()宏。然而,當計算抽象套接口名字時,我們要十分注意。

Linux Socket學習(三)


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 亚洲人成网站999久久久综合 | 久久厕所精品国产精品亚洲 | 天天干人人 | 99爱精品视频 | 爱爱小视频在线观看网站 | 青青青青啪视频在线观看 | 国产麻豆之光e奶女教师 | 四虎影片 | 日韩视频中文字幕 | 日本一区二区高清 | 久久久四虎成人永久免费网站 | 久久国产精品夜色 | 国产99欧美精品久久精品久久 | 欧美不卡影院 | 97在线观看免费版 | 骚婷婷| 9999在线视频| 久久久久国产成人精品亚洲午夜 | 日本九九视频 | 欧美真人视频一级毛片 | 日本免费小视频 | 亚洲日韩精品欧美一区二区 | 日本强日本不卡一 | 毛片网页 | 中文字幕不卡一区2021 | 91精品全国免费观看青青 | 四虎影视国产精品 | 亚洲一区二区在线视频 | 老扒夜夜春宵粗大好爽aa毛片 | 精品成人在线观看 | 99999久久久久久亚洲 | 97看吧| 久草视频在线观 | 在线亚洲成人 | 天天操天天射天天色 | 天天弄天天操 | 国产女人18一级毛片视频 | 中国一级特黄真人毛片免 | 狼人香蕉香蕉在线视频播放 | 91精品国产91久久久久福利 | 老子影院午夜精品欧美视频 |