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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

UNP Chapter 22 - 信号驱动I/O

發布時間:2023/12/10 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 UNP Chapter 22 - 信号驱动I/O 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

22.1. 概述

信號驅動是指當某個描述字上發生了某個事件時,讓內核通知進程。

這里描述的信號驅動不是真正的異步I/O。

第15章描述的非阻塞I/O同樣不是異步I/O。在非阻塞I/O中,啟動I/O操作后內核并不像真正的異步I/O那樣立即返回,它只有在進程非得睡眠才能完成操作時才立即返回。

?

22.2. 套接口上的信號驅動I/O

使用套接口上的信號驅動I/O(SIGIO)需要進程執行以下三個步驟:

1. 給SIGIO信號建立信號處理程序

2. 設置套接口屬主,通常使用fcntl的F_SETOWN命令

3. 激活套接口的信號驅動I/O,通常使用fcntl的F_SETFL命令打開O_ASYNC標志

?

UDP套接口上的SIGIO信號

? UDP上使用信號驅動I/O是簡單的。當下述事件發生時產生SIGIO信號:

? 1. 數據報到達套接口

? 2. 套接口上發生異步錯誤

因此,當我們捕獲到SIGIO信號時,我們調用recvfrom讀取到達的數據報或者獲取異步錯誤。

?

TCP套接口上的SIGIO信號

? 不幸的是,信號驅動I/O對TCP套接口幾乎是沒用的,原因是該信號產生得過于頻繁,并且該信號的出現并沒有告訴我們發生了什么事情。

? 下列條件均可在TCP套接口上產生SIGIO信號(假設信號驅動I/O是使能的):

??? 1. 在監聽套接口上有一個連接請求已經完成

??? 2. 發起了一個連接拆除請求

??? 3. 一個連接拆除請求已經完成

??? 4. 一個連接的一半已經關閉

??? 5. 數據到達了套接口

??? 6. 數據已從套接口上發出(即輸出緩沖區有空閑時間)

??? 7. 發生了一個異步錯誤

例如,如果一個進程既從一個TCP套接口讀數據,又向其上寫數據,當新數據到達或者以前所寫數據得到確認后均會產生SIGIO信號,進程無法在信號處理程序中區分這兩種情況。如果在這種情況下使用SIGIO,TCP套接口應該被設置為非阻塞方式以防止read或write發生阻塞。我們應該考慮只在監聽TCP套接口上使用SIGIO,因為在監聽套接口上產生SIGIO的唯一條件是一個新連接的完成。

?

這里找到的實際使用信號驅動I/O的程序是基于UDP的NTP(網絡時間協議)服務器程序。NTP服務器的主循環從客戶接收數據報并送回相應,但是每個客戶請求都要進行相當數量的處理(比我們簡單的回射服務器多得多)。對于服務器來講,很重要的一點是給每個收到的數據報記錄精確的時間戳,因為這個值要返回給客戶,客戶要用它來計算到達該服務器的來回時間。圖22.1展示了構建這樣一個UDP服務器的兩種方法。

大多數UDP服務器都被設計成圖中左邊的方式。但是NTP服務器采用了圖中右邊的技術: 當一個新數據報到達時,SIGIO處理程序讀得該數據報,同時記錄數據報到達的時刻,然后把它放入進程的另一個隊列中,由主服務器循環移走和處理。雖然這種技巧使服務器代碼變得復雜,但是它為到達的數據報提供了精確的時間戳。

?

22.3. 使用SIGIO的UDP回射服務器程序

現在舉一個類似圖22.1.右邊的例子:一個使用SIGIO信號接收到達的數據報的UDP服務器程序。

我們使用圖8.7和8.8中同樣的客戶程序以及圖8.3中同樣的服務器程序main函數。我們做的唯一修改是dg_echo函數,下邊四張圖給出這些修改,圖22.2給出了全局變量聲明。

#include "unp.h"
static int sockfd;
#define QSIZE 8 /* size of input queue */
#define MAXDG 4096 /* maximum datagram size */ /* SIGIO信號處理程序將到達的數據報放入一個隊列中。該隊列是一個DG結構數組,我們將它處理成環形緩沖區。 */ /* 每個DG結構包括一個指向收到的數據報的指針,數據報的長度,一個指向包含客戶協議地址的套接口地址結構的指針以及協議地址的大小。 */ /* 靜態分配我們QSIZE個DG結構,從圖22.4我們將看到dg_echo函數調用malloc給所有的數據報和套接口地址結構分配內存。 */ /* 我們還分配一個診斷用計數器cntread,不久將會解釋到。圖22.3展示了當第一項指向一個150字節數據報,與其關聯的套接口地址結構長度為16時,DG結構數組的內容 */
typedef struct {
void * dg_data; /* ptr to actual datagram */
size_t dg_len; /* length of datagram */
struct sockaddr * dg_sa; /* ptr to sockaddr{} w/client's address */
socklen_t dg_salen; /* lenght of sockaddr{} */
} DG;
static DG dg[QSIZE]; /* the queue of datagrams to process */
static long cntread[QSIZE+1]; /* diagnostic counter */ /* iget是主循環將處理的下一個數組元素的下標 */ /* iput是信號處理程序將要存放的下一個數組元素的下標 */ /* nqueue是主循環將要處理的隊列中數據報的總數目 */ static int iget; /* next one for main loop to process */
static int iput; /* next one for signal handler to read into */
static int nqueue; /* #on queue for main loop to process */
static socklen_t clilen; /* max length of sockaddr{} */
static void sig_io(int);
static void sig_hup(int);

?

dg_echo函數:服務器主處理循環

void dg_echo(int sockfd_arg, SA * pcliaddr, socklen_t clilen_arg)
{
int on = 1;
sigset_t zeromask, newmask, oldmask;
sockfd = sockfd_arg;
clilen = clilen_arg; /* 套接口描述字保存在一個全局變量中,因為信號處理程序要用到它。已收到數據報隊列被初始化 */
for ( i = 0; i < QSIZE; i++) { /* init queue of buffers */
dg[i].dg_data = Malloc(MAXDG);
dg[i].dg_sa = Malloc(clilen);
dg[i].dg_salen = clilen;
}
iget = iput = nqueue = 0; /* 給SIGHUP和SIGIO建立信號處理程序 */
Signal(SIGHUP, sig_hup);
Signal(SIGIO, sig_io); /* 用fcntl設置套接口屬主 */
Fcntl(sockfd, F_SETOWN, getpid()); /* 用ioctl設置信號驅動和非阻塞I/O標志 */
ioctl(sockfd, FIOASYNC, &on);
ioctl(sockfd, FIONBIO, &on); /* 初始化三個信號集:zeromask(從不改變)、oldmask(記錄我們阻塞SIGIO時的老信號掩碼)和newmask */
Sigemptyset(&zeromask); /* init three signal sets */
Sigemptyset(&oldmask);
Sigemptyset(&newmask); /* sigaddset打開newmask中與SIGIO對應的位 */
Sigaddset(&newmask, SIGIO); /* the signal we want to block */
/* sigprocmask將進程當前信號掩碼存入oldmask中,然后將newmask與當前的信號掩碼進行邏輯或。這將阻塞SIGIO并返回當前的信號掩碼 */ Sigprocmask(SIG_BLOCK, &newmask, &oldmask); /* 進入for循環并測試nqueue計數器。只要這個計數器為0,進程就無事可做。這時我們調用sigsuspend。 */ /* 因為zeromask是一個空信號集,所有的信號將被解阻塞。sigsuspend在捕獲一個信號并在其信號處理程序返回后返回 */
/* 但在返回前,sigsuspend總是將信號掩碼恢復為調用它時的信號掩碼值,在這里這個掩碼值為newmask,所以我們能夠保證sigsuspend返回后,SIGIO仍被阻塞 */ /* 這就是為什么我們能夠測試nqueue標志,因為當我們測試時,SIGIO信號不可能被遞交。 */ for( ; ; ) {
while (nqueue == 0)
sigsuspend(&zeromask); /* wait for a datagram to process */
/* unblock SIGIO */
Sigprocmask(SIG_SETMASK, &oldmask, NULL); /* 調用sigprocmask將進程的信號掩碼設置為先前保存的oldmask的舊值,從而解除了SIGIO阻塞 */
Sendto(sockfd, dg[iget].dg_data, dg[iget].dg_len, 0, dg[iget].dg_sa, dg[iget].dg_salen);/* 然后調用sendto發送應答 */
if( ++iget >= QSIZE) /* 下標iget加1,如果其值等于數據元素個數,則置iget為0,因為我們把數組當作環形緩沖區對待 */
iget = 0; /* 當修改iget時,我們不需要阻塞SIGIO,因為iget只被主循環使用,信號處理程序永遠不會修改它 */
/* block SIGIO */
Sigprocmask(SIG_BLOCK, &newmask, &oldmask); /* 阻塞SIGIO,nqueue減1,我們在修改nqueue是必須阻塞SIGIO,因為主循環和信號處理程序在共享這個變量 */
nqueue--;
}
}

SIGIO處理程序

static void sig_io(int signo)
{
ssize_t len;
int nread;
DG *ptr;
for(nread = 0; ; ) {
if(nqueue >= QSIZE) /* 如果隊列滿,進程就終止 */
err_quit("receive overflow");
ptr = &dg[iput]; /* 在非阻塞的套接口上調用recvfrom,iput做下標的數組項是數據報存儲的地方,如果沒有可讀數據報,則跳出for循環 */
ptr->dg_salen = clilen;
len = recvfrom(sockfd, ptr->dg_data, MAXDG, 0, ptr->dg_sa, &ptr->dg_salen);
if(len<0) {
if(errno == EWOULDBLOCK)
break; /* all done; no more queued to read */
else
err_sys("recvfrom error");
}
ptr->dg_len = len;
nread++; /* nread是一個計數器,記錄每個信號讀的數據報數 */
nqueue++; /* nqueue是主循環將要處理的數據報數 */
if(++iput >= QSIZE)
iput = 0;
}
cntread[nread]++; /* histogram of #datagrams read per signal */
/* 信號處理程序在返回前,將與每個信號讀到的數據報數目對應的計數器加1,當SIGHUP遞交后,該數組的內容做為診斷信息輸出 */ }

SIGHUP信號處理程序

static void sig_hup(int signo)
{/* SIGHUP信號處理程序,它輸出cntread數組的內容,cntread數組統計每個信號讀到的數據報數目 */
int i;
for(i = 0; i <= QSIZE; i++)
printf("cntread[%d] = %d\n", i, cntread[i];
}


22.4. 小結

?

轉載于:https://www.cnblogs.com/s7vens/archive/2012/03/28/2421602.html

總結

以上是生活随笔為你收集整理的UNP Chapter 22 - 信号驱动I/O的全部內容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 毛片网站免费观看 | 国产超碰人人 | 骚婷婷 | 无码一区二区精品 | 日日骚一区二区 | 午夜精品一区二区三区在线视频 | 最新超碰在线 | 国产精品久久久久久久久久直播 | 99在线视频观看 | 精品国产xxx | 成人午夜天 | 亚洲欧洲免费视频 | 高清性爱视频 | 91中文字幕在线播放 | 波多野结衣中文字幕一区二区 | 女性生殖扒开酷刑vk | a√国产 | 高h视频在线免费观看 | 在线免费观看视频 | 射进来av影视 | 亚洲另类网站 | 国产成人亚洲综合a∨婷婷 台湾a级片 | 中文字幕天堂 | 色涩网站 | 久久新网址 | 午夜激情影院 | 久久888| 女女同性被吸乳羞羞 | 黄色大片在线播放 | 国产成人精品毛片 | 国产一二在线观看 | 久久99婷婷 | 中国黄色小视频 | 亚洲v欧美v另类v综合v日韩v | 涩涩片影院 | 福利视频不卡 | 日韩精品一区二区三区 | 欧美韩一区 | 99蜜桃臀久久久欧美精品网站 | 国产无遮挡aaa片爽爽 | av嫩草| 亚洲一级在线观看 | 久久久久久久久免费视频 | 天天摸夜夜操 | 老头糟蹋新婚少妇系列小说 | 国产一区二区三区免费播放 | 少妇色欲网 | 国产吞精囗交免费视频网站 | 精品久久久久久久免费人妻 | 亚洲天堂中文字幕在线 | 极品一区 | 国产精品69毛片高清亚洲 | 亚洲国产一区二区三区在线观看 | 天天操天天操天天操 | 久久动态图 | 国产成人在线视频网站 | 国产精品正在播放 | 69视频网| 亚洲精品国产乱伦 | av体验区 | 五月婷婷天堂 | 日韩成人短视频 | 中文字幕爱爱 | 色999日韩 | 亚洲美女黄色片 | 麻豆视频免费 | 天天干天天日夜夜操 | 天天草影院 | 光棍福利视频 | 夜色精品 | 日韩电影一区二区三区四区 | 日本精品视频一区二区 | 可以在线观看的黄色 | 日本网站在线 | 成人激情免费视频 | 亚洲欧洲av在线 | 中文字幕综合 | av鲁丝一区鲁丝二区鲁丝三区 | aaa国产精品 | 久色 | 午夜精品久久久久久 | 成人免费xxxxxx视频 | 潘金莲性xxxxhd | 最新在线视频 | 一本一道精品欧美中文字幕 | 欧美激情一区二区三区四区 | 黄色网页在线看 | 麻豆传媒在线观看视频 | 李华月全部毛片 | 中文字幕永久免费 | 美女福利一区 | 五月天中文字幕在线 | 日本在线网址 | 成人性生交大片免费 | 操干视频 | 91夜色 | 一级黄色大片免费 | 免费看av毛片 | 欧美性猛交xxxx黑人猛交 |