一、訊號驅動。
1、訊號驅動原理是什麼?
就是使用了系統程式設計中訊號的機制,首先讓程式安裝sigio的訊號處理函式,通過監聽檔案描述符是否產生了sigio訊號,我們就知道檔案描述符有沒有資料到達。如果有資料到達(小明這個客人來了),則系統就會產生了sigio訊號(門鈴響了),我們只需要在訊號處理函式讀取資料即可。
模型:void fun(int sig)
signal(sigio,fun); -> 只要將來收到sigio這個訊號,就執行fun這個函式
sockfd -> 只要有資料到達sockfd,就會產生乙個sigio的訊號
2、 訊號驅動特點以及步驟。
特點: 適用於udp協議,不適用於tcp協議。
步驟一: 由於不知道資料什麼時候會到達,所以需要提前捕捉sigio訊號。 -> signal()
步驟二: 設定套接字的屬主,其實就是告訴這個套接字對應的程序id是誰。 -> fcntl()
步驟三: 給套接字新增訊號觸發模式。 -> fcntl()
1)如何設定屬主? -> fcntl() -> man 2 fcntl
#include
#include
int fcntl(int fd, int cmd, ... /* arg */ );
fd: 檔案描述符
cmd: f_getfl (void) -> 獲取檔案屬性
f_setfl (int) -> 設定檔案屬性
f_setown (int) -> 設定屬性 -> 最後乙個引數要填,填程序id號,一般都是getpid()。
返回值:
成功:檔案描述符所有者
失敗:-1
例如: fcntl(sockfd,f_setown,getpid()); -> 讓sockfd與程序id繫結在一起。
2)如何新增訊號觸發模式? -> fcntl() -> man 2 fcntl
int state;
state = fcntl(sockfd,f_getfl);
state |= o_async;
fcntl(sockfd,f_setfl,state);
例題1: 使用訊號驅動io模型寫乙個udp協議伺服器,實現監聽多個客戶端給我傳送過來的訊息。
#include "head.h"
int sockfd;
struct sockaddr_in cliaddr;
socklen_t len = sizeof(cliaddr);
void func(int sig)
int main(int argc,char *ar**) // ./server 50001
二、超時接收。
1、為什麼會有超時接收?
一般地,我們都習慣使用阻塞io,就是有資料就讀取,沒有資料就會一直阻塞等待。
因為有可能會出現一種情況,就是一直等待,都等不到結果,所以超時接收就是為了解決這個問題。
2、如何實現超時控制? --- 方法一:使用多路復用。
select(xx,***,xx,xx,null); -> 無限等待集合中的資料。
-> 如果集合中的檔案描述符有資料到達,則函式就會返回。
-> 如果集合中的檔案描述符沒有資料到達在,則函式就會一直阻塞。
每次select之前,都需要重置好時間。
select(xx,***,xx,xx,5s); -> 只會在5s內阻塞等待,5s後就會返回。
-> 5s內有資料到達,則函式返回就緒的檔案描述符個數。
-> 5s內沒有資料到達,則5s內會阻塞。
-> 5s後,這個函式就會返回0,不會繼續監聽這個集合。
3、如何設定時間?
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
時間結構體:
struct timeval ;
例如:設定5s
struct timeval v;
v.tv_sec = 5;
v.tv_usec = 0;
select(xx,xx,xx,xx,&v);
例題2: 寫乙個tcp協議伺服器,使用select函式去監聽客戶端的訊息,如果客戶端在5s內沒有資料到達,則列印一句"timeout",如果有資料,就列印客戶端所說的話。
#include "head.h"
void *func(void *arg)
}int main(int argc,char *ar**) // ./rose 50000
//5. 使用多路復用讀取套接字上資料
fd_set set;
struct timeval v;
int ret;
char buf[100];
while(1)
if(ret == 0)
if(ret > 0)}}
//5. 阻塞讀取套接字上的資料
/*char buf[100];
while(1)}*/
//6. **tcp套接字的資源
close(sockfd);
close(connfd);
return 0;
}練習3:修改test2/,如果在10s內,沒有資料到,則列印timeout。
4、 如何實現超時接收? -- 方法二: 設定套接字的屬性為超時接收。
1)機制如何?
如果不給套接字設定屬性,那麼讀取套接字上的資料時就會無限等待 -> 一直阻塞。
如果設定超時接收屬性給套接字,那麼讀取套接字資料時,就會有時間的限制。 -> 前一段時間阻塞,時間過了就會返回。
2)操作步驟?
阻塞情況:
connfd = accept(sockfd); -> 一直阻塞。
recv(connfd); -> 一直阻塞等待資料的到達。
connfd = accept(sockfd); -> 一直阻塞。
設定超時接收屬性給connfd
recv(connfd); -> 在規定時間內,就會阻塞讀取,超過了時間,這個recv函式就會返回失敗。
3)如何設定超時接收屬性給套接字? -> setsockopt() -> man 2 setsockopt
#include /* see notes */
#include
int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
sockfd:套接字
level: 優先順序
sol_socket:套接字
ipproto_ip:ip優先順序
ippro_tcp:tcp優先順序
optname:選項名字
optval: 值,使能為1,不使能為0
optlen: 值型別大小
返回值:
成功:0
失敗:-1
例子:struct timeval v;
v.tv_sec = 5;
v.tv_usec = 0;
setsockopt(connfd,sol_socket,so_rcvtimeo,&v,sizeof(v));
接下來,再去讀取connfd的資料,前5s就會阻塞,過了5s就會返回失敗了。
練習4: 寫乙個tcp伺服器,使用recv函式接收客戶端的訊息,如果伺服器在5s內,沒有資料到達,就列印timeout。
#include "head.h"
void *func(void *arg)
}int main(int argc,char *ar**) // ./rose 50000
//5. 設定超時屬性給connfd。
struct timeval v;
v.tv_sec = 5;
v.tv_usec = 0;
setsockopt(connfd,sol_socket,so_rcvtimeo,&v,sizeof(v));
//6. 不斷讀取connfd的內容。
char buf[100] = ;
while(1)
else
if(strncmp(buf,"quit",4) == 0)
}close(connfd);
close(sockfd);
return 0;
}
關於recvfrom接收超時
標籤 socket 2014 08 18 11 07 671人閱讀收藏 舉報 網路程式設計學習心得 recvfrom,這方法如果不特意設定,預設為阻塞模式,如果一直收不到訊息,那麼會一直阻塞在那裡。如何設定阻塞時間,或者說如何設定recvfrom接收超時時間。可以使用setsockopt。setso...
python 控制接收超時
python 測試接收超時 node2 root test cat connect2.py coding utf 8 import socket import time s socket.socket socket.af inet,socket.sock stream s.settimeout 10...
使用訊號實現超時
訊號是軟體中斷,能夠提供一種處理非同步事件的方法。這些訊號被定義在signal.h中,列表如下 define sighup 1 hangup posix define sigint 2 interrupt ansi define sigquit 3 quit posix define sigill ...