《網路編程》先進 I/O

來源:互聯網
上載者:User

標籤:

這部分是進階插座 I/O 。

設定通訊端逾時警示,使用更方便的資料轉送功能。

通訊端 I/O 設定作業逾時有三種方法:

  1. 轉讓 alarm 效能,製作時,它指定逾時 SIGALRM 訊號;
  2. 在 select 函數中設定逾時堵塞等待 I/O,以替代直接堵塞在 read 或write 調用上;
  3. 使用 SO_RCVTIMEO 和 SO_SNDTIMEO 通訊端選項(這兩個選項僅僅是一部分實現支援)。

      以下使用 alarm 產生的 SIGALRM 訊號為 connect 函數設定逾時,當然系統會為 connect 函數設定逾時限制,這裡我們僅僅是表示 SIGALRM 訊號在設定逾時的作用。

#include <signal.h>#include <errno.h>#include <stdio.h>#include <unistd.h>#include <sys/socket.h>typedef void Sigfunc(int);extern void err_sys(const char *,...);static Sigfunc *M_signal(int signo, Sigfunc *func);static Sigfunc *MySignal(int signo, Sigfunc *func);static void connect_alarm(int);int Myconnect_timo(int sockfd, const struct sockaddr *saptr, socklen_t salen, int nsec){    Sigfunc *sigfunc;    int n;    /* SIGALRM 訊號處理函數。並儲存現有訊號處理函數 */    sigfunc = MySignal(SIGALRM, connect_alarm);    /* 設定alarm逾時 */    if(alarm(nsec) != 0)/* 若已經設定了逾時,則alarm返回的是當前剩餘秒數。否則返回0 */        printf("alarm was already set\n");/* 提示:已經設定過alarm逾時 */    if( (n = connect(sockfd, saptr, salen)) < 0)    {/* 由逾時處理函數調用中斷導致串連失敗,則關閉通訊端,並設定是由逾時導致的失敗 */        close(sockfd);        if(errno == EINTR)            errno = ETIMEDOUT;    }    /* 關閉 alarm */    alarm(0);    /* 恢複原來的處理函數 */    MySignal(SIGALRM, sigfunc);    return(n);}static void connect_alarm(int signo){    printf("flag: %d\n", signo);    return;/* just interrupt the connect */}static Sigfunc *MySignal(int signo, Sigfunc *func){    Sigfunc *sigfunc;    if( (sigfunc = M_signal(signo, func)) == SIG_ERR)        err_sys("signal error");    return (sigfunc);}static Sigfunc *M_signal(int signo, Sigfunc *func){    struct sigaction act, oact;    /* 設定訊號處理函數 */    act.sa_handler = func;    /* 初始化訊號集 */    sigemptyset(&act.sa_mask);    act.sa_flags = 0;    if(signo == SIGALRM)    {/* 若是SIGALRM訊號,則系統不會自己主動重新啟動 */#ifdef SA_INTERRUPT        act.sa_flags |= SA_INTERRUPT;#endif    }    else    {/* 其餘訊號設定為系統會自己主動重新啟動 */#ifdef SA_RESTART        act.sa_flags |= SA_RESTART;#endif    }    /* 調用 sigaction 函數 */    if(sigaction(signo, &act, &oact) < 0)        return(SIG_ERR);    return(oact.sa_handler);}

使用 select 函數為 recvfrom 設定逾時。有關select 函數的解說能夠參考文章《I/O 多工》。

#include <sys/select.h>#include <stdlib.h>extern void err_sys(const char *,...);/* 在指定的時間內等待描寫敘述符變為可讀 */int readable_timeo(int fd, int sec){fd_setrset;struct timevaltv;    /* 初始化fd_set 結構,並加入描寫敘述符 */FD_ZERO(&rset);FD_SET(fd, &rset);    /* 設定逾時的時間 */tv.tv_sec = sec;/* 秒數 */tv.tv_usec = 0;/* 微秒 */    /* 調用select函數,使進程堵塞於select的逾時等待描寫敘述符變為可讀 */return(select(fd+1, &rset, NULL, NULL, &tv));/* 4> 0 if descriptor is readable */}/* end readable_timeo */intRead_timeo(int fd, int sec){intn;if ( (n = readable_timeo(fd, sec)) < 0)err_sys("readable_timeo error");return(n);}

        使用 使用 SO_RCVTIMEO 和 SO_SNDTIMEO 通訊端選項,使用這兩個通訊端選項設定描寫敘述符時,其逾時設定將應用於該描寫敘述符的全部讀或寫操作上。SO_RCVTIMEO 通訊端選項僅僅能應用於讀操作,而 SO_SNDTIMEO 通訊端選項僅僅能應用於寫操作。

這兩者僅支援一部分實現。比如在 connect 函數不能使用這兩個通訊端選項。


recv 和 send 函數

/* 傳輸資料 *//* * 函數功能:發送資料; * 傳回值:若成功則返回傳送的位元組數。若出錯則返回-1; * 函數原型: */#include <sys/socket.h>ssize_t send(int sockfd, void *buff, size_t nbytes, int flags);/* * 說明 * 該函數的功能相似與write函數,除了有標識符flags之外。其它的同樣; * flags標識符的取值例如以下: * (1)MSG_DONTROUTE   勿將資料路由出本網 * (2)MSG_DONTWAIT    同意非堵塞操作 * (3)MSG_EOR         假設協議支援,此為記錄結束 * (4)MSG_OOB         假設協議支援。發送帶外資料 * * 若send成功返回,並不必定表示串連還有一端的進程接收資料,僅僅能說資料已經無錯誤地發送到網路。 * * 對於支援為報文設限的協議,若報文超過協議所支援的最大尺寸,send失敗並將errno設為EMSGSIZE; * 對於位元組流協議。send會堵塞直到整個資料被傳輸; *//* * 函數功能:接收資料; * 傳回值:以位元組計數的訊息長度,若無可用訊息或對方已經按序結束則返回0。若出錯則返回-1; * 函數原型: */#include <sys/socket.h>ssize_t recv(int sockfd, void *buff, size_t nbytes, int flags);/* * 說明 * 該函數的功能相似與read函數,除了有標識符flags之外,其它的同樣; * flags標識符的取值例如以下: * (1)MSG_PEEK        返回報文內容而不真正取走報文。即查看可讀取資料 * (2)MSG_TRUNC       即使報文被截斷,要求返回的是報文的實際長度 * (3)MSG_WAITALL     等待直到全部資料可用 * (4)MSG_OOB         假設協議支援,發送帶外資料 * (5)MSG_DONTWAIT    同意非堵塞操作 * */
以下是 flags 標誌的功能:

  1. MSG_DONTROUTE:本標誌告知核心。目的主機在某個直接連接的本網上,因而無需運行路由表尋找。
  2. MSG_DONTWAIT:本標誌在無需開啟對應通訊端的非堵塞標誌的前提下,把單個 I/O 操作暫時指定為非堵塞,接著運行 I/O 操作,然後關閉非堵塞標誌;
  3. MSG_OOB:若協議支援,則可發送帶外資料;
  4. MSG_PEEK :本標誌適用於 recv 和 recvfrom 函數,它同意查看已可讀取的資料,並且系統不在 recv 或 recvfrom 返回後丟棄這些資料。
  5. MSG_WAITALL:等待全部資料可用。

readv 和 writev 函數

這兩個函數類似於 read 和 write 函數,可是它們支援多個緩衝區操作。其定義例如以下:

/* 讀、寫多個非連續的緩衝區 *//* * 函數功能:讀取資料到多個非連續的緩衝區,或從多個非連續緩衝區寫資料到檔案。 * 傳回值:若成功則返回已讀、寫的位元組數,若出錯則返回-1。 * 函數原型: */#include <sys/uio.h>ssize_t readv(int filedes, const struct iovec *iov, int iovcnt);ssize_t writev(int filedes, const struct iovec *iov, int iovcnt);/* * 說明: * iovec的指標結構例如以下: */struct iovec{    void *iov_base;     /* starting address of buffer */    size_t iov_len;     /* size of buffer */};


recvmsg 和 sendmsg 函數

這兩個函數是通用的 I/O 函數,前面介紹的 I/O 函數都能夠使用這兩個函數替換。其定義例如以下:

ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);/* * 說明 * 該函數能夠使用不止一個的選擇來通過通訊端發送資料,能夠指定多重緩衝區資料轉送,相似與readv函數; * msghdr結構至少包括下面成員: */struct msghdr{    void        *msg_name;      /* optional address */    socklen_t   msg_namelen;    /* address size in bytes */    struct iovec *msg_iov;      /* array of IO buffers */    int         msg_iovlen;     /* number of elements in array */    void        *msg_control;   /* ancillary data */    socklen_t   msg_controllen; /* number of ancillary bytes */    int         msg_flags;      /* flags for recevied message */};


參考資料:

《Unix 網路編程》

著作權聲明:本文博主原創文章,部落格,未經同意不得轉載。

《網路編程》先進 I/O

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.