實現乙個基本的流式套接字客戶端/伺服器通訊程式,客戶端和伺服器按如下步驟互動:
(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模型
同步是指乙個任務的完成需要依賴另外乙個任務時,只有等待被依賴的任務完成後,依賴的任務才能算完成。非同步是指不需要等待被依賴的任務完成,只是通知被依賴的任務要完成什麼工作,依賴的任務也立即執行,只要自己完成了整個任務就算完成了,非同步一般使用狀態 通知和 阻塞是指呼叫結果返回之前,當前執行緒會被掛起,...