日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Linux io模型及函数调用,Linux 网络编程的5种IO模型:信号驱动IO模型

發布時間:2023/11/27 生活经验 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux io模型及函数调用,Linux 网络编程的5种IO模型:信号驱动IO模型 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Linux 網絡編程的5種IO模型:信號驅動IO模型

背景

這一講我們來看 信號驅動IO 模型。

介紹

情景引入:

在信號驅動IO模型中,當用戶線程發起一個IO請求操作,會給對應的socket注冊一個信號函數,然后用戶線程會繼續執行,當內核數據就緒時會發送一個信號給用戶線程,用戶線程接收到信號之后,便在信號函數中調用IO讀寫操作來進行實際的IO請求操作。這個一般用于UDP中,對TCP套接口幾乎是沒用的,原因是該信號產生得過于頻繁,并且該信號的出現并沒有告訴我們發生了什么事情

%% 時序圖

sequenceDiagram

title : 信號驅動IO模型

participant application

participant kernel

Note right of application: 應用程序調用系統調用

application ->> kernel: signaction

kernel ->> application: 返回

kernel ->> application: 遞交SIGIO信號

application ->> application : 信號處理

application ->> kernel : recvfrom

kernel ->> kernel: 準備好數據,拷貝到用戶空間

kernel ->> application: 拷貝完成,返回成功

在UDP上,SIGIO信號會在下面兩個事件的時候產生:

1 數據報到達套接字

2 套接字上發生錯誤

因此我們很容易判斷SIGIO出現的時候,如果不是發生錯誤,那么就是有數據報到達了。

而在TCP上,由于TCP是雙工的,它的信號產生過于頻繁,并且信號的出現幾乎沒有告訴我們發生了什么事情。因此對于TCP套接字,SIGIO信號是沒有什么使用的。

有關函數

#include

int sigaction(int signum, const struct sigaction *act,

struct sigaction *oldact);

例程

這對例程是不太規范的,因為有BUG。但因為這種消息模型用的比較少所以我就不改了。

server.c

#include

#include

#include

#include

#include

#include

#include

#include

#include

int listenfd1;

volatile int read_flag = 0;

static char buf[256] = { 0 };

void do_sigio(int sig)

{

struct sockaddr_in cli_addr;

int clifd, clilen;

read_flag = 1;

memset(buf, 0, sizeof(buf));

recvfrom(listenfd1, buf, sizeof(buf), 0, (struct sockaddr *)&cli_addr, &clilen);

printf("Listenfd1 Message %s n", buf);

perror("recvfrom");

sendto(listenfd1, "Reply", sizeof("Reply"),0, (struct sockaddr *)&cli_addr, sizeof(cli_addr));

perror("sendto");

printf("sigio endn");

read_flag = 0;

}

int main(int argc, char *argv[])

{

//綁定監聽7779端口的fd

struct sockaddr_in serv_addr;

listenfd1 = socket(AF_INET, SOCK_DGRAM, 0);

bzero((char *) &serv_addr, sizeof(serv_addr));

serv_addr.sin_family = AF_INET;

serv_addr.sin_port = htons(7779);

serv_addr.sin_addr.s_addr = INADDR_ANY;

struct sigaction sigio_action;

memset(&sigio_action, 0, sizeof(sigio_action));

sigio_action.sa_flags = 0;

sigio_action.sa_handler = do_sigio;

sigaction(SIGIO, &sigio_action, NULL);

fcntl(listenfd1, F_SETOWN, getpid());

int flags;

flags = fcntl(listenfd1, F_GETFL, 0);

flags |= O_ASYNC ;//| O_NONBLOCK;

fcntl(listenfd1, F_SETFL, flags);

bind(listenfd1, (struct sockaddr *) &serv_addr, sizeof(serv_addr));

while(1)

{

sleep(2);

}

close(listenfd1);

return 0;

}

client.c

#include

#include

#include

#include

#include

#include

int main(int argc, char* argv[])

{

int socketfd;

socklen_t n;

socketfd = socket(AF_INET, SOCK_DGRAM, 0);

struct sockaddr_in serv_addr;

struct sockaddr_in addr;

bzero((char *)&serv_addr, sizeof(serv_addr));

serv_addr.sin_family = AF_INET;

serv_addr.sin_port = htons(7779);

char buf[64] = {0};

//write(socketfd, "client message", sizeof("client message"));

sendto(socketfd, "client message", sizeof("client message"),0, (struct sockaddr *)&serv_addr, sizeof(serv_addr));

memset(buf, 0, sizeof(buf));

//read(socketfd, buf, sizeof(buf));

recvfrom(socketfd, buf, sizeof(buf), 0, (struct sockaddr *)&serv_addr, &n);

printf("%u %sn",n ,buf);

return 0;

}

附錄:異步通知

ref :異步通知

注意:異步通知只有SIGIO信號,沒有別的信號可用,其他各種信號在app空間可以任意使用.

通過使用異步通知,應用程序可以在數據可用時收到一個信號,而無需不停地輪詢。

啟用步驟:

(1)它們指定一個進程作為文件的擁有者:使用 fcntl 系統調用發出 F_SETOWN 命令,這個擁有者進程的 ID 被保存在 filp->f_owner。目的:讓內核知道信號到達時該通知哪個進程。

(2)使用 fcntl 系統調用,通過 F_SETFL 命令設置 FASYNC 標志。

內核操作過程

1.F_SETOWN被調用時filp->f_owner被賦值。

當 F_SETFL 被執行來打開 FASYNC, 驅動的 fasync 方法被調用.這個標志在文件被打開時缺省地被清除。

當數據到達時,所有的注冊異步通知的進程都會被發送一個 SIGIO 信號。

Linux 提供的通用方法是基于一個數據結構和兩個函數,定義在。

數據結構:

struct fasync_struct{

int magic;

int fa_fd;

struct fasync_struct *fa_next;/* singly linked list */

struct file *fa_file;

};

驅動調用的兩個函數的原型:

int fasync_helper(int fd,structfile*filp,int mode, struct fasync_struct**fa);

void kill_fasync(struct fasync_struct**fa,int sig, int band);

當一個打開的文件的FASYNC標志被修改時,調用 fasync_helper 來從相關的進程列表中添加或去除文件。除了最后一個參數, 其他所有參數都時被提供給 fasync 方法的相同參數并被直接傳遞。 當數據到達時,kill_fasync 被用來通知相關的進程,它的參數是被傳遞的信號(常常是 SIGIO)和 band(幾乎都是 POLL_IN)。

這是 scullpipe 實現 fasync 方法的:

staticint scull_p_fasync(int fd,struct file*filp,int mode)

{

struct scull_pipe *dev = filp->private_data;

return fasync_helper(fd, filp, mode,&dev->async_queue);

}

當數據到達, 下面的語句必須被執行來通知異步讀者. 因為對 sucllpipe 讀者的新數據通過一個發出 write 的進程被產生, 這個語句出現在 scullpipe 的 write 方法中:

if (dev->async_queue) kill_fasync(&dev->async_queue, SIGIO, POLL_IN); /* 注意, 一些設備也針對設備可寫而實現了異步通知,在這個情況,kill_fasnyc 必須以 POLL_OUT 模式調用.*/

當文件被關閉時必須 調用fasync 方法,來從活動的異步讀取進程列表中刪除該文件。盡管這個調用僅當 filp->f_flags 被設置為 FASYNC 時才需要,但不管什么情況,調用這個函數不會有問題,并且是普遍的實現方法。 以下是 scullpipe 的 release 方法的一部分:

/* remove this filp from the asynchronously notified filp's */ scull_p_fasync(-1, filp, 0);

異步通知使用的數據結構和 struct wait_queue 幾乎相同,因為他們都涉及等待事件。區別異步通知用 struct file 替代 struct task_struct. 隊列中的 file 用獲取 f_owner, 一邊給進程發送信號。

內容來源于網絡如有侵權請私信刪除

總結

以上是生活随笔為你收集整理的Linux io模型及函数调用,Linux 网络编程的5种IO模型:信号驱动IO模型的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。