欧美性猛交xxxx免费看_牛牛在线视频国产免费_天堂草原电视剧在线观看免费_国产粉嫩高清在线观看_国产欧美日本亚洲精品一5区

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

什么是Netlink通信機(jī)制

科技綠洲 ? 來(lái)源:Linux開(kāi)發(fā)架構(gòu)之路 ? 作者:Linux開(kāi)發(fā)架構(gòu)之路 ? 2023-11-09 09:20 ? 次閱讀

一:什么是Netlink通信機(jī)制

Netlink是linux提供的用于內(nèi)核和用戶態(tài)進(jìn)程之間的通信方式。

但是注意雖然Netlink主要用于用戶空間和內(nèi)核空間的通信,但是也能用于用戶空間的兩個(gè)進(jìn)程通信。只是進(jìn)程間通信有其他很多方式,一般不用Netlink。除非需要用到Netlink的廣播特性時(shí)。

那么Netlink有什么優(yōu)勢(shì)呢?

一般來(lái)說(shuō)用戶空間和內(nèi)核空間的通信方式有三種:/proc、ioctl、Netlink。而前兩種都是單向的,但是Netlink可以實(shí)現(xiàn)雙工通信。

Netlink協(xié)議基于BSD socket和AF_NETLINK地址簇(address family),使用32位的端口號(hào)尋址(以前稱作PID),每個(gè)Netlink協(xié)議(或稱作總線,man手冊(cè)中則稱之為netlink family),通常與一個(gè)或一組內(nèi)核服務(wù)/組件相關(guān)聯(lián),如NETLINK_ROUTE用于獲取和設(shè)置路由與鏈路信息、NETLINK_KOBJECT_UEVENT用于內(nèi)核向用戶空間的udev進(jìn)程發(fā)送通知等。

netlink具有以下特點(diǎn):

① 支持全雙工、異步通信(當(dāng)然同步也支持)

② 用戶空間可使用標(biāo)準(zhǔn)的BSD socket接口(但netlink并沒(méi)有屏蔽掉協(xié)議包的構(gòu)造與解析過(guò)程,推薦使用libnl等第三方庫(kù))

③ 在內(nèi)核空間使用專用的內(nèi)核API接口

④ 支持多播(因此支持“總線”式通信,可實(shí)現(xiàn)消息訂閱)

⑤ 在內(nèi)核端可用于進(jìn)程上下文與中斷上下文

二:用戶態(tài)數(shù)據(jù)結(jié)構(gòu)

首先看一下幾個(gè)重要的數(shù)據(jù)結(jié)構(gòu)的關(guān)系:

圖片

1.struct msghdr

msghdr這個(gè)結(jié)構(gòu)在socket變成中就會(huì)用到,并不算Netlink專有的,這里不在過(guò)多說(shuō)明。只說(shuō)明一下如何更好理解這個(gè)結(jié)構(gòu)的功能。我們知道socket消息的發(fā)送和接收函數(shù)一般有這幾對(duì):recv/send、readv/writev、recvfrom/sendto。當(dāng)然還有recvmsg/sendmsg,前面三對(duì)函數(shù)各有各的特點(diǎn)功能,而recvmsg/sendmsg就是要囊括前面三對(duì)的所有功能,當(dāng)然還有自己特殊的用途。msghdr的前兩個(gè)成員就是為了滿足recvfrom/sendto的功能,中間兩個(gè)成員msg_iov和msg_iovlen則是為了滿足readv/writev的功能,而最后的msg_flags則是為了滿足recv/send中flag的功能,剩下的msg_control和msg_controllen則是滿足recvmsg/sendmsg特有的功能。

2.struct sockaddr_ln

struct sockaddr_ln為Netlink的地址,和我們通常socket編程中的sockaddr_in作用一樣,他們的結(jié)構(gòu)對(duì)比如下:

圖片

struct sockaddr_nl的詳細(xì)定義和描述如下:

struct sockaddr_nl
{
sa_family_t nl_family; /*該字段總是為AF_NETLINK */
unsigned short nl_pad; /* 目前未用到,填充為0*/
__u32 nl_pid; /* process pid */
__u32 nl_groups; /* multicast groups mask */
};

(1) nl_pid:在Netlink規(guī)范里,PID全稱是Port-ID(32bits),其主要作用是用于唯一的標(biāo)識(shí)一個(gè)基于netlink的socket通道。通常情況下nl_pid都設(shè)置為當(dāng)前進(jìn)程的進(jìn)程號(hào)。前面我們也說(shuō)過(guò),Netlink不僅可以實(shí)現(xiàn)用戶-內(nèi)核空間的通信還可使現(xiàn)實(shí)用戶空間兩個(gè)進(jìn)程之間,或內(nèi)核空間兩個(gè)進(jìn)程之間的通信。該屬性為0時(shí)一般指內(nèi)核。

(2) nl_groups:如果用戶空間的進(jìn)程希望加入某個(gè)多播組,則必須執(zhí)行bind()系統(tǒng)調(diào)用。該字段指明了調(diào)用者希望加入的多播組號(hào)的掩碼(注意不是組號(hào),后面我們會(huì)詳細(xì)講解這個(gè)字段)。如果該字段為0則表示調(diào)用者不希望加入任何多播組。對(duì)于每個(gè)隸屬于Netlink協(xié)議域的協(xié)議,最多可支持32個(gè)多播組(因?yàn)閚l_groups的長(zhǎng)度為32比特),每個(gè)多播組用一個(gè)比特來(lái)表示。

3.struct nlmsghdr

Netlink的報(bào)文由消息頭和消息體構(gòu)成,struct nlmsghdr即為消息頭。消息頭定義在文件里,由結(jié)構(gòu)體nlmsghdr表示:

struct nlmsghdr
{
__u32 nlmsg_len; /* Length of message including header */
__u16 nlmsg_type; /* Message content */
__u16 nlmsg_flags; /* Additional flags */
__u32 nlmsg_seq; /* Sequence number */
__u32 nlmsg_pid; /* Sending process PID */
};

消息頭中各成員屬性的解釋及說(shuō)明:

(1) nlmsg_len:整個(gè)消息的長(zhǎng)度,按字節(jié)計(jì)算。包括了Netlink消息頭本身。

(2) nlmsg_type:消息的類型,即是數(shù)據(jù)還是控制消息。目前(內(nèi)核版本2.6.21)Netlink僅支持四種類型的控制消息,如下:

a) NLMSG_NOOP-空消息,什么也不做;

b) NLMSG_ERROR-指明該消息中包含一個(gè)錯(cuò)誤;

c) NLMSG_DONE-如果內(nèi)核通過(guò)Netlink隊(duì)列返回了多個(gè)消息,那么隊(duì)列的最后一條消息的類型為NLMSG_DONE,其余所有消息的nlmsg_flags屬性都被設(shè)置NLM_F_MULTI位有效。

d) NLMSG_OVERRUN-暫時(shí)沒(méi)用到。

(3) nlmsg_flags:附加在消息上的額外說(shuō)明信息,如上面提到的NLM_F_MULTI。

三:用戶空間Netlink socket API

1.創(chuàng)建socket

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

domain指代地址族,即AF_NETLINK;

套接字類型為SOCK_RAW或SOCK_DGRAM,因?yàn)閚etlink是一個(gè)面向數(shù)據(jù)報(bào)的服務(wù);

protocol選擇該套接字使用哪種netlink特征。

以下是幾種預(yù)定義的協(xié)議類型:

NETLINK_ROUTE,

NETLINK_FIREWALL,

NETLINK_APRD,

NETLINK_ROUTE6_FW。

可以非常容易的添加自己的netlink協(xié)議。

為每一個(gè)協(xié)議類型最多可以定義32個(gè)多播組。

每一個(gè)多播組用一個(gè)bitmask來(lái)表示,1<

2.地址綁定bind()

bind(fd, (struct sockaddr*)&, nladdr, sizeof(nladdr));

3.發(fā)送netlink消息

為了發(fā)送一條netlink消息到內(nèi)核或者其他的用戶空間進(jìn)程,另外一個(gè)struct sockaddr_nl nladdr需要作為目的地址,這和使用sendmsg()發(fā)送一個(gè)UDP包是一樣的。

如果該消息是發(fā)送至內(nèi)核的,那么nl_pid和nl_groups都置為0.

如果消息是發(fā)送給另一個(gè)進(jìn)程的單播消息,nl_pid是另外一個(gè)進(jìn)程的pid值而nl_groups為零。

如果消息是發(fā)送給一個(gè)或多個(gè)多播組的多播消息,所有的目的多播組必須bitmask必須or起來(lái)從而形成nl_groups域。

sendmsg(fd, &, msg, 0);

4.接收netlink消息

一個(gè)接收程序必須分配一個(gè)足夠大的內(nèi)存用于保存netlink消息頭和消息負(fù)載。然后其填充struct msghdr msg,再使用標(biāo)準(zhǔn)的recvmsg()函數(shù)來(lái)接收netlink消息。

當(dāng)消息被正確的接收之后,nlh應(yīng)該指向剛剛接收到的netlink消息的頭。nladdr應(yīng)該包含接收消息的目的地址,其中包括了消息發(fā)送者的pid和多播組。同時(shí),宏NLMSG_DATA(nlh),定義在netlink.h中,返回一個(gè)指向netlink消息負(fù)載的指針。調(diào)用close(fd)關(guān)閉fd描述符所標(biāo)識(shí)的socket

recvmsg(fd, &, msg, 0);

四:內(nèi)核空間Netlink socket API

1.創(chuàng)建 netlink socket

struct sock *netlink_kernel_create(struct net *net,
int unit,unsigned int groups,
void (*input)(struct sk_buff *skb),
struct mutex *cb_mutex,struct module *module);

參數(shù)說(shuō)明:

(1) net:是一個(gè)網(wǎng)絡(luò)名字空間namespace,在不同的名字空間里面可以有自己的轉(zhuǎn)發(fā)信息庫(kù),有自己的一套net_device等等。默認(rèn)情況下都是使用 init_net這個(gè)全局變量。

(2) unit:表示netlink協(xié)議類型,如NETLINK_TEST、NETLINK_SELINUX。

(3) groups:多播地址。

(4) input:為內(nèi)核模塊定義的netlink消息處理函數(shù),當(dāng)有消 息到達(dá)這個(gè)netlink socket時(shí),該input函數(shù)指針就會(huì)被引用,且只有此函數(shù)返回時(shí),調(diào)用者的sendmsg才能返回。

(5) cb_mutex:為訪問(wèn)數(shù)據(jù)時(shí)的互斥信號(hào)量。

(6) module:一般為THIS_MODULE。

2.發(fā)送單播消息 netlink_unicast

int netlink_unicast(struct sock *ssk, struct sk_buff *skb, u32 pid, int nonblock)

參數(shù)說(shuō)明:

(1) ssk:為函數(shù) netlink_kernel_create()返回的socket。

(2) skb:存放消息,它的data字段指向要發(fā)送的netlink消息結(jié)構(gòu),而 skb的控制塊保存了消息的地址信息,宏NETLINK_CB(skb)就用于方便設(shè)置該控制塊。

(3) pid:為接收此消息進(jìn)程的pid,即目標(biāo)地址,如果目標(biāo)為組或內(nèi)核,它設(shè)置為 0。

(4) nonblock:表示該函數(shù)是否為非阻塞,如果為1,該函數(shù)將在沒(méi)有接收緩存可利用時(shí)立即返回;而如果為0,該函數(shù)在沒(méi)有接收緩存可利用定時(shí)睡眠。

3.發(fā)送廣播消息 netlink_broadcast

int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, u32 group, gfp_t allocation)

前面的三個(gè)參數(shù)與 netlink_unicast相同,參數(shù)group為接收消息的多播組,該參數(shù)的每一個(gè)位代表一個(gè)多播組,因此如果發(fā)送給多個(gè)多播組,就把該參數(shù)設(shè)置為多個(gè)多播組組ID的位或。參數(shù)allocation為內(nèi)核內(nèi)存分配類型,一般地為GFP_ATOMIC或GFP_KERNEL,GFP_ATOMIC用于原子的上下文(即不可以睡眠),而GFP_KERNEL用于非原子上下文。

4.釋放 netlink socket

int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, u32 group, gfp_t allocation)

五:用戶態(tài)范例一

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAX_PAYLOAD 1024 // maximum payload size
#define NETLINK_TEST 25 //自定義的協(xié)議
int main(int argc, char* argv[])
{
int state;
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL; //Netlink數(shù)據(jù)包頭
struct iovec iov;
struct msghdr msg;
int sock_fd, retval;
int state_smg = 0;
// Create a socket
sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);
if(sock_fd == -1){
printf("error getting socket: %s", strerror(errno));
return -1;
}
// To prepare binding
memset(&src_addr, 0, sizeof(src_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = 100; //A:設(shè)置源端端口號(hào)
src_addr.nl_groups = 0;
//Bind
retval = bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
if(retval < 0){
printf("bind failed: %s", strerror(errno));
close(sock_fd);
return -1;
}
// To orepare create mssage
nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
if(!nlh){
printf("malloc nlmsghdr error!n");
close(sock_fd);
return -1;
}
memset(&dest_addr,0,sizeof(dest_addr));
dest_addr.nl_family = AF_NETLINK;
dest_addr.nl_pid = 0; //B:設(shè)置目的端口號(hào)
dest_addr.nl_groups = 0;
nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
nlh->nlmsg_pid = 100; //C:設(shè)置源端口
nlh->nlmsg_flags = 0;
strcpy(NLMSG_DATA(nlh),"Hello you!"); //設(shè)置消息體
iov.iov_base = (void *)nlh;
iov.iov_len = NLMSG_SPACE(MAX_PAYLOAD);
//Create mssage
memset(&msg, 0, sizeof(msg));
msg.msg_name = (void *)&dest_addr;
msg.msg_namelen = sizeof(dest_addr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
//send message
printf("state_smgn");
state_smg = sendmsg(sock_fd,&msg,0);
if(state_smg == -1)
{
printf("get error sendmsg = %sn",strerror(errno));
}
memset(nlh,0,NLMSG_SPACE(MAX_PAYLOAD));
//receive message
printf("waiting received!n");
while(1){
printf("In while recvmsgn");
state = recvmsg(sock_fd, &msg, 0);
if(state<0)
{
printf("state<1");
}
printf("Received message: %sn",(char *) NLMSG_DATA(nlh));
}
close(sock_fd);
return 0;
}

上面程序首先向內(nèi)核發(fā)送一條消息;“Hello you”,然后進(jìn)入循環(huán)一直等待讀取內(nèi)核的回復(fù),并將收到的回復(fù)打印出來(lái)。如果看上面程序感覺(jué)很吃力,那么應(yīng)該首先復(fù)習(xí)一下UDP中使用sendmsg的用法,特別時(shí)struct msghdr的結(jié)構(gòu)要清楚,這里再贅述。下面主要分析與UDP發(fā)送數(shù)據(jù)包的不同點(diǎn):

  1. socket地址結(jié)構(gòu)不同,UDP為sockaddr_in,Netlink為struct sockaddr_nl;
  2. 與UDP發(fā)送數(shù)據(jù)相比,Netlink多了一個(gè)消息頭結(jié)構(gòu)struct nlmsghdr需要我們構(gòu)造。

注意代碼注釋中的A、B、C三處分別設(shè)置了pid。首先解釋一下什么是pid,網(wǎng)上很多文章把這個(gè)字段說(shuō)成是進(jìn)程的pid,其實(shí)這完全是望文生義。這里的pid和進(jìn)程pid沒(méi)有什么關(guān)系,僅僅相當(dāng)于UDP的port。對(duì)于UDP來(lái)說(shuō)port和ip標(biāo)示一個(gè)地址,那對(duì)我們的NETLINK_TEST協(xié)議(注意Netlink本身不是一個(gè)協(xié)議)來(lái)說(shuō),pid就唯一標(biāo)示了一個(gè)地址。所以你如果用進(jìn)程pid做為標(biāo)示當(dāng)然也是可以的。當(dāng)然同樣的pid對(duì)于NETLINK_TEST協(xié)議和內(nèi)核定義的其他使用Netlink的協(xié)議是不沖突的(就像TCP的80端口和UDP的80端口)。

下面分析這三處設(shè)置pid分別有什么作用,首先A和B位置的比較好理解,這是在地址(sockaddr_nl)上進(jìn)行的設(shè)置,就是相當(dāng)于設(shè)置源地址和目的地址(其實(shí)是端口),只是注意B處設(shè)置pid為0,0就代表是內(nèi)核,可以理解為內(nèi)核專用的pid,那么用戶進(jìn)程就不能用0做為自己的pid嗎?這個(gè)只能說(shuō)如果你非要用也是可以的,只是會(huì)產(chǎn)生一些問(wèn)題,后面在分析。

接下來(lái)看為什么C處的消息頭仍然需要設(shè)置pid呢?這里首先要知道一個(gè)前提:內(nèi)核不會(huì)像UDP一樣根據(jù)我們?cè)O(shè)置的原、目的地址為我們構(gòu)造消息頭,所以我們不在包頭寫入我們自己的地址(pid),那內(nèi)核怎么知道是誰(shuí)發(fā)來(lái)的報(bào)文呢?當(dāng)然如果內(nèi)核只是處理消息不需要回復(fù)進(jìn)程的話舍不設(shè)置這個(gè)消息頭pid都可以。

所以每個(gè)pid的設(shè)置功能不同:A處的設(shè)置是要設(shè)置發(fā)送者的源地址,有人會(huì)說(shuō)既然源地址又不會(huì)自動(dòng)填充到報(bào)文中,我們?yōu)槭裁催€要設(shè)置這個(gè),因?yàn)槟氵€可能要接收回復(fù)啊。就像寄信,你連“門牌號(hào)”都沒(méi)有,即使你在寫信時(shí)候?qū)懮夏愕牡刂肥?00號(hào),對(duì)方回信目的地址也是100號(hào),但是郵局發(fā)現(xiàn)根本沒(méi)有這個(gè)地址怎么可能把信送到你手里呢?所以A的主要作用是注冊(cè)源地址,保證可以收到回復(fù),如果不需要回復(fù)當(dāng)然可以簡(jiǎn)單將pid設(shè)置為0;B處自然就是收信人的地址,pid為0代表內(nèi)核的地址,假如有一個(gè)進(jìn)程在101號(hào)上注冊(cè)了地址,并調(diào)用了recvmsg,如果你將B處的pid設(shè)置為101,那數(shù)據(jù)包就發(fā)給了另一個(gè)進(jìn)程,這就實(shí)現(xiàn)了使用Netlink進(jìn)行進(jìn)程間通信;C相當(dāng)于你在信封上寫的源地址,通常情況下這個(gè)應(yīng)該和你的真實(shí)地址(A)處注冊(cè)的源地址相同,當(dāng)然你要是不想收到回信,又想惡搞一下或者有特殊需求,你可以寫成其他進(jìn)程注冊(cè)的pid(比如101)。這和我們現(xiàn)實(shí)中寄信是一樣的,你給你朋友寫封情書,把寫信人寫成你的另一個(gè)好基友,然后后果你懂得……

好了,有了這個(gè)例子我們就大概知道用戶態(tài)怎么使用Netlink了。

六:內(nèi)核態(tài)程序范例一

#include
#include
#include
#include
#include
#include
#include
#define NETLINK_TEST 25
#define MAX_MSGSIZE 1024
int stringlength(char *s);
int err;
struct sock *nl_sk = NULL;
int flag = 0;
//向用戶態(tài)進(jìn)程回發(fā)消息
void sendnlmsg(char *message, int pid)
{
struct sk_buff *skb_1;
struct nlmsghdr *nlh;
int len = NLMSG_SPACE(MAX_MSGSIZE);
int slen = 0;
if(!message || !nl_sk)
{
return ;
}
printk(KERN_ERR "pid:%dn",pid);
skb_1 = alloc_skb(len,GFP_KERNEL);
if(!skb_1)
{
printk(KERN_ERR "my_net_link:alloc_skb errorn");
}
slen = stringlength(message);
nlh = nlmsg_put(skb_1,0,0,0,MAX_MSGSIZE,0);
NETLINK_CB(skb_1).pid = 0;
NETLINK_CB(skb_1).dst_group = 0;
message[slen]= '?';
memcpy(NLMSG_DATA(nlh),message,slen+1);
printk("my_net_link:send message '%s'.n",(char *)NLMSG_DATA(nlh));
netlink_unicast(nl_sk,skb_1,pid,MSG_DONTWAIT);
}
int stringlength(char *s)
{
int slen = 0;
for(; *s; s++)
{
slen++;
}
return slen;
}
//接收用戶態(tài)發(fā)來(lái)的消息
void nl_data_ready(struct sk_buff *__skb)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
char str[100];
struct completion cmpl;
printk("begin data_readyn");
int i=10;
int pid;
skb = skb_get (__skb);
if(skb->len >= NLMSG_SPACE(0))
{
nlh = nlmsg_hdr(skb);
memcpy(str, NLMSG_DATA(nlh), sizeof(str));
printk("Message received:%sn",str) ;
pid = nlh->nlmsg_pid;
while(i--)
{//我們使用completion做延時(shí),每3秒鐘向用戶態(tài)回發(fā)一個(gè)消息
init_completion(&cmpl);
wait_for_completion_timeout(&cmpl,3 * HZ);
sendnlmsg("I am from kernel!",pid);
}
flag = 1;
kfree_skb(skb);
}
}
// Initialize netlink
int netlink_init(void)
{
nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, 1,
nl_data_ready, NULL, THIS_MODULE);
if(!nl_sk){
printk(KERN_ERR "my_net_link: create netlink socket error.n");
return 1;
}
printk("my_net_link_4: create netlink socket ok.n");
return 0;
}
static void netlink_exit(void)
{
if(nl_sk != NULL){
sock_release(nl_sk->sk_socket);
}
printk("my_net_link: self module exitedn");
}
module_init(netlink_init);
module_exit(netlink_exit);
MODULE_AUTHOR("zhao_h");
MODULE_LICENSE("GPL");

附上內(nèi)核代碼的Makefile文件:

ifneq ($(KERNELRELEASE),)
obj-m :=netl.o
else
KERNELDIR ?=/lib/modules/$(shell uname -r)/build
PWD :=$(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif

我們將內(nèi)核模塊insmod后,運(yùn)行用戶態(tài)程序,結(jié)果如下:

圖片

這個(gè)結(jié)果復(fù)合我們的預(yù)期,但是運(yùn)行過(guò)程中打印出“state_smg”卡了好久才輸出了后面的結(jié)果。這時(shí)候查看客戶進(jìn)程是處于D狀態(tài)的(不了解D狀態(tài)的同學(xué)可以google一下)。這是為什么呢?因?yàn)檫M(jìn)程使用Netlink向內(nèi)核發(fā)數(shù)據(jù)是同步,內(nèi)核向進(jìn)程發(fā)數(shù)據(jù)是異步。什么意思呢?也就是用戶進(jìn)程調(diào)用sendmsg發(fā)送消息后,內(nèi)核會(huì)調(diào)用相應(yīng)的接收函數(shù),但是一定到這個(gè)接收函數(shù)執(zhí)行完用戶態(tài)的sendmsg才能夠返回。我們?cè)趦?nèi)核態(tài)的接收函數(shù)中調(diào)用了10次回發(fā)函數(shù),每次都等待3秒鐘,所以內(nèi)核接收函數(shù)30秒后才返回,所以我們用戶態(tài)程序的sendmsg也要等30秒后才返回。相反,內(nèi)核回發(fā)的數(shù)據(jù)不用等待用戶程序接收,這是因?yàn)閮?nèi)核所發(fā)的數(shù)據(jù)會(huì)暫時(shí)存放在一個(gè)隊(duì)列中。

再來(lái)回到之前的一個(gè)問(wèn)題,用戶態(tài)程序的源地址(pid)可以用0嗎?我把上面的用戶程序的A和C處pid都改為了0,結(jié)果一運(yùn)行就死機(jī)了。為什么呢?我們看一下內(nèi)核代碼的邏輯,收到用戶消息后,根據(jù)消息中的pid發(fā)送回去,而pid為0,內(nèi)核并不認(rèn)為這是用戶程序,認(rèn)為是自身,所有又將回發(fā)的10個(gè)消息發(fā)給了自己(內(nèi)核),這樣就陷入了一個(gè)死循環(huán),而用戶態(tài)這時(shí)候進(jìn)程一直處于D。

另外一個(gè)問(wèn)題,如果同時(shí)啟動(dòng)兩個(gè)用戶進(jìn)程會(huì)是什么情況?答案是再調(diào)用bind時(shí)出錯(cuò):“Address already in use”,這個(gè)同UDP一樣,同一個(gè)地址同一個(gè)port如果沒(méi)有設(shè)置SO_REUSEADDR兩次bind就會(huì)出錯(cuò),之后我用同樣的方式再Netlink的socket上設(shè)置了SO_REUSEADDR,但是并沒(méi)有什么效果。

七:用戶態(tài)范例二

之前我們說(shuō)過(guò)UDP可以使用sendmsg/recvmsg也可以使用sendto/recvfrom,那么Netlink同樣也可以使用sendto/recvfrom。具體實(shí)現(xiàn)如下:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAX_PAYLOAD 1024 // maximum payload size
#define NETLINK_TEST 25
int main(int argc, char* argv[])
{
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
int sock_fd, retval;
int state,state_smg = 0;
// Create a socket
sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);
if(sock_fd == -1){
printf("error getting socket: %s", strerror(errno));
return -1;
}
// To prepare binding
memset(&src_addr, 0, sizeof(src_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = 100;
src_addr.nl_groups = 0;
//Bind
retval = bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
if(retval < 0){
printf("bind failed: %s", strerror(errno));
close(sock_fd);
return -1;
}
// To orepare create mssage head
nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
if(!nlh){
printf("malloc nlmsghdr error!n");
close(sock_fd);
return -1;
}
memset(&dest_addr,0,sizeof(dest_addr));
dest_addr.nl_family = AF_NETLINK;
dest_addr.nl_pid = 0;
dest_addr.nl_groups = 0;
nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
nlh->nlmsg_pid = 100;
nlh->nlmsg_flags = 0;
strcpy(NLMSG_DATA(nlh),"Hello you!");
//send message
printf("state_smgn");
sendto(sock_fd,nlh,NLMSG_LENGTH(MAX_PAYLOAD),0,(struct sockaddr*)(&dest_addr),sizeof(dest_addr));
if(state_smg == -1)
{
printf("get error sendmsg = %sn",strerror(errno));
}
memset(nlh,0,NLMSG_SPACE(MAX_PAYLOAD));
//receive message
printf("waiting received!n");
while(1){
printf("In while recvmsgn");
state=recvfrom(sock_fd,nlh,NLMSG_LENGTH(MAX_PAYLOAD),0,NULL,NULL);
if(state<0)
{
printf("state<1");
}
printf("Received message: %sn",(char *) NLMSG_DATA(nlh));
memset(nlh,0,NLMSG_SPACE(MAX_PAYLOAD));
}
close(sock_fd);
return 0;
}

熟悉UDP編程的同學(xué)看到這個(gè)程序一定很熟悉,除了多了一個(gè)Netlink消息頭的設(shè)置。但是我們發(fā)現(xiàn)程序中調(diào)用了bind函數(shù),這個(gè)函數(shù)再UDP編程中的客戶端不是必須的,因?yàn)槲覀儾恍枰裊DP socket與某個(gè)地址關(guān)聯(lián),同時(shí)再發(fā)送UDP數(shù)據(jù)包時(shí)內(nèi)核會(huì)為我們分配一個(gè)隨即的端口。但是對(duì)于Netlink必須要有這一步bind,因?yàn)镹etlink內(nèi)核可不會(huì)為我們分配一個(gè)pid。再?gòu)?qiáng)調(diào)一遍消息頭(nlmsghdr)中的pid是告訴內(nèi)核接收端要回復(fù)的地址,但是這個(gè)地址存不存在內(nèi)核并不關(guān)心,這個(gè)地址只有用戶端調(diào)用了bind后才存在。

我們看到這兩個(gè)例子都是用戶態(tài)首先發(fā)起的,那Netlink是否支持內(nèi)核態(tài)主動(dòng)發(fā)起的情況呢?

當(dāng)然是可以的,只是內(nèi)核一般需要事件觸發(fā),這里,只要和用戶態(tài)約定號(hào)一個(gè)地址(pid),內(nèi)核直接調(diào)用netlink_unicast就可以了。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 通信
    +關(guān)注

    關(guān)注

    18

    文章

    6077

    瀏覽量

    136482
  • 總線
    +關(guān)注

    關(guān)注

    10

    文章

    2905

    瀏覽量

    88444
  • netlink
    +關(guān)注

    關(guān)注

    0

    文章

    5

    瀏覽量

    7220
  • udev
    +關(guān)注

    關(guān)注

    0

    文章

    13

    瀏覽量

    8245
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    CC2530無(wú)線通信機(jī)制問(wèn)題

    ? ?? 如果有的話,協(xié)調(diào)器和路由器是多久有一次通信? ?路由器和終端是多久一次通信?? 應(yīng)該有這樣的機(jī)制,各個(gè)設(shè)備才能知道是否有連接還是斷線,不用用戶再去定義通信協(xié)議來(lái)檢測(cè)設(shè)備是否斷
    發(fā)表于 06-01 01:31

    基于幀數(shù)據(jù)的串口通信機(jī)制

    藍(lán)橋杯(14)——串口通信機(jī)制(基于幀數(shù)據(jù))
    發(fā)表于 05-29 16:11

    基于Linux的Netlink熱插拔監(jiān)控

    Linux中Netlink實(shí)現(xiàn)熱插拔監(jiān)控——內(nèi)核與用戶空間通信
    發(fā)表于 03-19 11:42

    netlink 套接字在系統(tǒng)通信中的應(yīng)用研究

    分析了當(dāng)前普遍應(yīng)用的幾種內(nèi)核和用戶進(jìn)程的通信方式的不足,詳細(xì)討論了linux2.4 以上版本所提供的netlink套接字在內(nèi)核和用戶進(jìn)程通信中的應(yīng)用。Linux 作為一種全新的、功能齊備
    發(fā)表于 08-18 08:47 ?17次下載

    無(wú)線mesh網(wǎng)絡(luò)匿名通信機(jī)制研究

    無(wú)線mesh網(wǎng)絡(luò)匿名通信機(jī)制研究.....
    發(fā)表于 01-04 15:26 ?11次下載

    基于WSNs的語(yǔ)音通信機(jī)制設(shè)計(jì)與實(shí)現(xiàn)_劉源

    基于WSNs的語(yǔ)音通信機(jī)制設(shè)計(jì)與實(shí)現(xiàn)_劉源
    發(fā)表于 03-19 19:11 ?0次下載

    基于netlink的linux服務(wù)器集群統(tǒng)一外設(shè)事件監(jiān)聽(tīng)機(jī)制

    事件接收模塊和服務(wù)進(jìn)程,然后由外設(shè)事件處理進(jìn)程監(jiān)聽(tīng)netlink多播組,最終由外設(shè)事件處理進(jìn)程將外設(shè)事件通過(guò)網(wǎng)絡(luò)發(fā)送給服務(wù)器端監(jiān)控進(jìn)程.通過(guò)本監(jiān)聽(tīng)機(jī)制的設(shè)計(jì),提高了服務(wù)器集群系統(tǒng)的整體安全性。
    發(fā)表于 11-15 09:55 ?6次下載
    基于<b class='flag-5'>netlink</b>的linux服務(wù)器集群統(tǒng)一外設(shè)事件監(jiān)聽(tīng)<b class='flag-5'>機(jī)制</b>

    用戶空間和內(nèi)核空間通訊- Netlink

    如果我們?cè)?b class='flag-5'>Netlink協(xié)議簇里開(kāi)發(fā)一個(gè)新的協(xié)議,只要在該文件中定義協(xié)議號(hào)即可,例如我們定義一種基于Netlink協(xié)議簇的、協(xié)議號(hào)是20的自定義協(xié)議,如上所示。
    發(fā)表于 04-26 13:44 ?811次閱讀
    用戶空間和內(nèi)核空間通訊- <b class='flag-5'>Netlink</b>

    用戶空間和內(nèi)核空間通訊-Netlink

    當(dāng)內(nèi)核態(tài)的Netlink發(fā)送數(shù)據(jù)到用戶空間時(shí)一般需要填充skbuff的控制塊,填充的方式是通過(guò)強(qiáng)制類型轉(zhuǎn)換,將其轉(zhuǎn)換成struct netlink_skb_parms{}之后進(jìn)行填充賦值的。
    發(fā)表于 04-26 13:49 ?740次閱讀
    用戶空間和內(nèi)核空間通訊-<b class='flag-5'>Netlink</b>

    用戶空間和內(nèi)核空間通訊-Netlink

    Alan Cox在內(nèi)核1.3版本的開(kāi)發(fā)階段最先引入了Netlink,剛開(kāi)始時(shí)Netlink是以字符驅(qū)動(dòng)接口的方式提供內(nèi)核與用戶空間的雙向數(shù)據(jù)通信;
    發(fā)表于 04-29 15:32 ?609次閱讀

    linux 內(nèi)核與用戶空間通信netlink使用方法

    Linux中的進(jìn)程間通信機(jī)制源自于Unix平臺(tái)上的進(jìn)程通信機(jī)制。Unix的兩大分支AT&T Unix和BSD Unix在進(jìn)程通信實(shí)現(xiàn)
    發(fā)表于 05-10 14:29 ?634次閱讀

    Linux Netlink 基本使用方法

    什么是Netlink?Netlink是linux提供的用于內(nèi)核和用戶態(tài)進(jìn)程之間的通信方式。但是注意雖然Netlink主要用于用戶空間和內(nèi)核空間的通信
    發(fā)表于 05-13 11:48 ?1483次閱讀
    Linux <b class='flag-5'>Netlink</b> 基本使用方法

    用戶與內(nèi)核空間數(shù)據(jù)交換的方式之一:netlink

    Netlink 是一種在內(nèi)核與用戶應(yīng)用間進(jìn)行雙向數(shù)據(jù)傳輸?shù)姆浅:玫姆绞?,用戶態(tài)應(yīng)用使用標(biāo)準(zhǔn)的 socket API 就可以使用 netlink 提供的強(qiáng)大功能,內(nèi)核態(tài)需要使用專門的內(nèi)核 API 來(lái)使用 netlink。
    發(fā)表于 05-14 16:59 ?850次閱讀
    用戶與內(nèi)核空間數(shù)據(jù)交換的方式之一:<b class='flag-5'>netlink</b>

    Linux用戶態(tài)與內(nèi)核態(tài)的交互——netlink

    ://www-128.ibm.com/developerworks/cn/linux/l-netlink/imp2.tar.gz 在?Linux?2.4?版以后版本的內(nèi)核中,幾乎全部的中斷過(guò)程與用戶態(tài)進(jìn)程的通信都是使用?netlink
    發(fā)表于 04-02 14:43 ?800次閱讀

    詳解linux內(nèi)核的uevent機(jī)制

    在linux內(nèi)核中,uevent機(jī)制是一種內(nèi)核和用戶空間通信機(jī)制,用于通知用戶空間應(yīng)用程序各種硬件更改或其他事件,比如插入或移除硬件設(shè)備(如USB驅(qū)動(dòng)器或網(wǎng)絡(luò)接口)。uevent表示“用戶空間
    的頭像 發(fā)表于 09-29 17:01 ?1006次閱讀