Linux網路程式設計 訊號驅動I O

2021-07-05 14:14:08 字數 4972 閱讀 9590

實現乙個基本的流式套接字客戶端/伺服器通訊程式,客戶端和伺服器按如下步驟互動:

(1)客戶端向伺服器發出日期時間請求字串,如:%d %y %a %t等。

(2)伺服器從網路接收到日期時間請求字串後,根據字串格式生成對應的日期時間值返回給客戶端。

為了在乙個套接字上使用訊號驅動 i/o 操作,下面這三步是所必須的。

(1)乙個和 sigio訊號的處理函式必須設定。

(2)套接字的擁有者必須被設定。一般來說是使用 fcntl 函式的 f_setown 引數來

進行設定擁有者。

(3)套接字必須被允許使用非同步 i/o。一般是通過呼叫 fcntl 函式的 f_setfl 命令,o_async為引數來實現。

雖然設定套接字為非同步 i/o 非常簡單,但是使用起來困難的部分是怎樣在程式中斷定產生 sigio訊號傳送給套接字屬主的時候,程式處在什麼狀態。 在

udp 協議上使用非同步 i/o 非常簡單.這個訊號將會在這個時候產生:

(1)套接字收到了乙個資料報的資料報。

(2)套接字發生了非同步錯誤。

當我們在使用 udp 套接字非同步 i/o 的時候,我們使用 recvfrom()函式來讀取資料報資料或是非同步 i/o 錯誤資訊。

2.tcp 套接字的 sigio 訊號 

不幸的是,非同步 i/o 幾乎對 tcp 套接字而言沒有什麼作用。因為對於乙個 tcp 套接字來說,sigio 訊號發生的機率太高了,所以 sigio 訊號並不能告訴我們究竟發生了什麼事情。

(1)在 tcp 連線中, sigio 訊號將會在這個時候產生:

(2)在乙個監聽某個埠的套接字上成功的建立了乙個新連線。

(3)乙個斷線的請求被成功的初始化。

(4)乙個斷線的請求成功的結束。

(5)套接字的某乙個通道(傳送通道或是接收通道)被關閉。

(6)套接字接收到新資料。

(7)套接字將資料傳送出去。

(8)發生了乙個非同步 i/o 的錯誤。

二、設定套接字工作於訊號驅動i/o模式

為了讓套接字描述符可以工作於訊號驅動i/o模式,應用程序必須完成如下三步設定:

(1)註冊sigio訊號處理程式

(2)使用fcntl的f_setown命令,設定套接字所有者為當前程序

(3)使用fcntld的f_setfl命令,置o_async標誌,允許套接字使用訊號驅動i/o。

注意:必須保證在設定套接字所有者之前,向系統註冊訊號處理程式,否則就有可能在fcntl呼叫後,訊號處理程式註冊前核心向應用交付sigio訊號,導致應用丟失此訊號,下面的程式片段描述了怎麼樣為套接字設定訊號驅動i/o。

void do_sigio(int sig)

...int sockfd;//套接字

struct sigaction sigio_action;

...sigio_action.sa_handler=do_sigio;//訊號處理程式

if(sigaction(sigio,&sigio_action,null)==-1)

//設定套接字所有者為當前程序

if((flags=fcntl(sockfd,f_setown,getpid()))<0)

//獲取當前套接字的flags

if((flags=fcntl(sockfd,f_getfl,0))<0)

//設定訊號驅動和非阻塞模式

//注意:在設定套接字工作於非驅動模式時,要先取得原有狀態標誌,然後通過邏輯或來增加新的標誌,\

不能直接設定套接字為訊號驅動和非阻塞模式,這樣會清除套接字的原有其它工作模式

flags|=o_async|o_nonblock;

if (fcntl(s, f_setfl,flags)<0)

使用訊號驅動模式重寫了前面的時間伺服器程式,在訊號處理程式中讀取套接字接收到的udp資料報,然後將資料存入乙個訊息佇列,再由應用的主迴圈從佇列中取出資料報進行處理。

/*udp伺服器

說明:用於在sigio訊號處理程式中接收來自資料報客戶端發來的資料報,接到的資料報存放

在乙個佇列中,隨後程式主迴圈將從此佇列中讀取資料並進行處理。

用法:./server ip portnumber

*/#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define quesize 16

//佇列大小

#define bufsize 1024

struct request

;staticvoidbail(constchar*on_what)

static

struct

request req_queue[quesize]; //

使用者空間的快取佇列

static

int idx_in;

static

int idx_out;

static

int nqueue;

int s;

struct

sockaddr_in peer_addr;//

伺服器套接字

static

socklen_t socklen=sizeof(peer_addr);

//sigio訊號處理函式

void do_sigio(int signum)

z=recvfrom(s, p_req->reqstr, bufsize, 0, (struct

sockaddr*)p_req->peer, &socklen);

if (z<0)

}p_req->reqstr[z]=0;

p_req->reqlen=z;

nqueue++;

if (++idx_in>=quesize)

idx_in=0;}}

//初始化佇列

void init_queue()

idx_in=idx_out=nqueue=0;

}//註冊sigio訊號處理程式

static

void install_sigio()

//設定套接字為訊號驅動i/o和非阻塞模式

void set_sockopt(int s,int flags)

int main(int argc,char **argv)

}else

//建立資料報套接字s=

socket

(af_inet, sock_dgram, 0);

if (s==-1)

bail("socket()");

init_queue

();

//初始化應用資料報接收佇列

install_sigio

();//

註冊sigio

訊號處理程式

set_sockopt(s

, flags);

//設定非阻塞和

sigio

驅動i/o模式

//初始化套接字位址

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

srvaddr.sin_family=pf_inet;

srvaddr.sin_port=htons(portnumber);

if (!inet_aton(srvr_addr, &srvaddr.sin_addr))

bail

("bad address.");

len_inet=sizeof(srvaddr);

//繫結套接字到指定位址和埠,於是客戶端可以連線到該伺服器

z=bind(s, (struct

sockaddr*)&srvaddr, len_inet);

if (z==-1)

bail("bind()");

sigemptyset(&zeromask);

sigemptyset(&newmask);

sigemptyset(&oldmask);

sigaddset(&newmask, sigio);

//  sigprocmask(sig_block, &newmask, &oldmask);

for (; ; )

return0;}

/*udp客戶端

用法:./client ip port

*/#include

#include

#include

#include

#include

#include

#include

#include

#include

#define bufsize 1024

staticvoidbail(constchar*on_what)

int main(int argc,char **argv)

//建立伺服器位址

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

server_addr.sin_family=af_inet;

server_addr.sin_port=htons(portnumber);

if (!inet_aton(srv_addr, &server_addr.sin_addr))

bail("bad address");

//建立udp套接字

sockfd=socket(af_inet,sock_dgram, 0);

if (sockfd==-1)

bail("socket()");

for (; ; )

printf

("\n exits from loop.\n");

close(sockfd);

return0;}

訊號驅動式I O

訊號驅動式i o是一種 拉模式 當資料報到達時觸發sigio訊號,該訊號通知資料已經到來,並沒有將資料都入到應用程式的buffer中。因此,還需要我們在sigio訊號處理函式中,手動的讀取到來的資料,將其存放在buffer中。針對乙個套接字使用訊號驅動式io sigio 要求程序執行以下3個步驟 1...

訊號驅動 SIGIO 的非同步I O

結合阻塞與非阻塞訪問 poll函式可以較好地解決裝置的讀寫,但是如果有了非同步通知就更方便了。非同步通知的意思是 一旦裝置就緒,則主動通知應用程式,這樣應用程式根本就不需要查詢裝置狀態,這一點非常類似於硬體上 中斷 地概念,比較準確的稱謂是 訊號驅動 sigio 的非同步i o 我們先來看乙個使用訊...

Linux網路程式設計之IO模型

同步是指乙個任務的完成需要依賴另外乙個任務時,只有等待被依賴的任務完成後,依賴的任務才能算完成。非同步是指不需要等待被依賴的任務完成,只是通知被依賴的任務要完成什麼工作,依賴的任務也立即執行,只要自己完成了整個任務就算完成了,非同步一般使用狀態 通知和 阻塞是指呼叫結果返回之前,當前執行緒會被掛起,...