訊號驅動,超時接收

2021-10-24 17:15:23 字數 4265 閱讀 6398

一、訊號驅動。

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 ...