最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語言詳解select函數(shù)的使用

 更新時間:2022年05月04日 10:28:00   作者:liufeng2023  
C語言中select函數(shù)的使用?一般用connect、accept、recv或recvfrom這類函數(shù),程序阻塞,直至該套接字上接受到數(shù)據(jù)后程序才能繼續(xù)運行。但是使用select函數(shù)可以實現(xiàn)非阻塞方式的程序

select

select API介紹

主旨思想:

  • 首先要構造一個關于文件描述符的列表,將要監(jiān)聽的文件描述符添加到該列表中。
  • 調(diào)用一個系統(tǒng)函數(shù),監(jiān)聽該列表中的文件描述符,直到這些描述符中的一個或者多個進行I/O操作時,該函數(shù)才返回。

a. 這個函數(shù)是阻塞

b. 函數(shù)對文件描述符的檢測的操作是由內(nèi)核完成的

  • 在返回時,它會告訴進程有多少(哪些)描述符要進行I/O操作。

// sizeof(fd_set) = 128字節(jié)     1024位, 每一個標志位對應一個文件描述符
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/select.h>
int select(int nfds, fd_set *readfds, fd_set *writefds,
            fd_set *exceptfds, struct timeval *timeout);
    - 參數(shù):
        - nfds : 委托內(nèi)核檢測的最大文件描述符的值 + 1
        - readfds : 要檢測的文件描述符的讀的集合(有數(shù)據(jù)發(fā)送過來),委托內(nèi)核檢測哪些文件描述符的讀的屬性
                - 一般檢測讀操作
                - 對應的是對方發(fā)送過來的數(shù)據(jù),因為讀是被動的接收數(shù)據(jù),檢測的就是讀緩沖區(qū)    
                - 是一個傳入傳出參數(shù)(內(nèi)核進行對文件描述符標志位檢測,檢測完后再返回回來;)
                 檢測過程: 文件描述符在用戶態(tài),1表示文件描述符需要檢測,0表示不需要檢測;在內(nèi)核中處理時:只檢測文件描述符為                        1的文件描述符,如果數(shù)據(jù)發(fā)生變化,置為1,不變化置為0,然后返回給用戶態(tài)。
        - writefds : 要檢測的文件描述符的寫的集合,委托內(nèi)核檢測哪些文件描述符的寫的屬性
                - 委托內(nèi)核檢測寫緩沖區(qū)是不是還可以寫數(shù)據(jù)(不滿的就可以寫)
                要檢測哪個文件描述符,就將那個標志位置為1;
                緩沖區(qū)滿了將對應文件描述符標志位置為0,有空余的數(shù)據(jù)可以寫, 置為1。
        - exceptfds : 檢測發(fā)生異常的文件描述符的集合
        - timeout : 設置的超時時間
            struct timeval {
                long tv_sec;     /* seconds */
                long tv_usec;     /* microseconds */
            };
            - NULL : 永久阻塞,直到檢測到了文件描述符有變化
            - tv_sec = 0 tv_usec = 0, 不阻塞
            - tv_sec > 0 tv_usec > 0, 阻塞對應的時間
        - 返回值
            - -1 : 失敗
            - 0 : select函數(shù)中設置了超時時間,超時時間到了,沒有檢測到,返回0
            - >0(n) : 檢測的集合中有n個文件描述符發(fā)生了變化
                
// 將參數(shù)文件描述符fd對應的標志位設置為0
void FD_CLR(int fd, fd_set *set);

// 判斷fd對應的標志位是0還是1, 返回值 : fd對應的標志位的值,0,返回0, 1,返回1
int FD_ISSET(int fd, fd_set *set);

// 將參數(shù)文件描述符fd 對應的標志位,設置為1
void FD_SET(int fd, fd_set *set);

// fd_set一共有1024 bit位, 全部初始化為0
void FD_ZERO(fd_set *set);

先創(chuàng)建檢測讀的文件描述符集合

fd_set reads;

將3,4,100,101四個文件描述符置為1,表示需要對這些文件描述符進行檢測;

接下來調(diào)用select函數(shù):

select(101+1, &reads, NULL, NULL, NULL);	//第一個參數(shù),需要檢測的文件描述符+1	--(+1才能遍歷到101,因為是從0開始的)

在這里插入圖片描述

將fd_set從內(nèi)核態(tài)拷貝到用戶態(tài)(由內(nèi)核幫我們檢測),同時假設A,B發(fā)送了數(shù)據(jù);

A,B對應的文件描述符為3和4;

在這里插入圖片描述

結果: 3和4有數(shù)據(jù),置為1,;100和101沒有數(shù)據(jù),將其1置為0。

修改完之后,再將fd_set從內(nèi)核態(tài)拷到用戶態(tài);

在這里插入圖片描述

用戶可以遍歷這個集合,找到哪個文件描述符為1,即3和4,就說明有數(shù)據(jù)了。

select 代碼

//客戶端
#include <stdio.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main() {
    // 創(chuàng)建socket
    int fd = socket(PF_INET, SOCK_STREAM, 0);
    if(fd == -1) {
        perror("socket");
        return -1;
    }
    struct sockaddr_in seraddr;
    inet_pton(AF_INET, "127.0.0.1", &seraddr.sin_addr.s_addr);
    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(9999);
    // 連接服務器
    int ret = connect(fd, (struct sockaddr *)&seraddr, sizeof(seraddr));
    if(ret == -1){
        perror("connect");
        return -1;
    }
    int num = 0;
    while(1) {
        char sendBuf[1024] = {0};
        sprintf(sendBuf, "send data %d", num++);
        write(fd, sendBuf, strlen(sendBuf) + 1);
        // 接收
        int len = read(fd, sendBuf, sizeof(sendBuf));
        if(len == -1) {
            perror("read");
            return -1;
        }else if(len > 0) {
            printf("read buf = %s\n", sendBuf);
        } else {
            printf("服務器已經(jīng)斷開連接...\n");
            break;
        }
        // sleep(1);
        usleep(1000);
    }
    close(fd);
    return 0;
}
//服務端
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
int main() {
    // 創(chuàng)建socket
    int lfd = socket(PF_INET, SOCK_STREAM, 0);
    struct sockaddr_in saddr;
    saddr.sin_port = htons(9999);
    saddr.sin_family = AF_INET;
    saddr.sin_addr.s_addr = INADDR_ANY;
    // 綁定
    bind(lfd, (struct sockaddr *)&saddr, sizeof(saddr));
    // 監(jiān)聽
    listen(lfd, 8);
    // 創(chuàng)建一個fd_set的集合,存放的是需要檢測的文件描述符
    fd_set rdset, tmp;	//fd_set底層可以表示1024個文件描述符
    FD_ZERO(&rdset);	//初始化
    FD_SET(lfd, &rdset);	//添加需要監(jiān)聽的文件描述符
    int maxfd = lfd;	//定義最大文件描述符,作為參數(shù)傳入select函數(shù)中
    while(1) {
        tmp = rdset;	//rdset這個不能變,因為內(nèi)核再檢測時,如果沒有數(shù)據(jù),就會將其變?yōu)?,因此,我們需要復制一份。
        // 調(diào)用select系統(tǒng)函數(shù),讓內(nèi)核幫檢測哪些文件描述符有數(shù)據(jù)
        int ret = select(maxfd + 1, &tmp, NULL, NULL, NULL);
        if(ret == -1) {
            perror("select");
            exit(-1);
        } else if(ret == 0) {	//這里不可能為0,因為設置了永久阻塞NULL,直到檢測到文件描述符有數(shù)據(jù)變化
            continue;	
        } else if(ret > 0) {	//ret只會返回文件描述符發(fā)生變化的個數(shù),不知道具體哪個發(fā)生了變化,需要遍歷查找
            // 說明檢測到了有文件描述符的對應的緩沖區(qū)的數(shù)據(jù)發(fā)生了改變
            if(FD_ISSET(lfd, &tmp)) {	//lfd為監(jiān)聽文件描述符
                // 表示有新的客戶端連接進來了
                struct sockaddr_in cliaddr;
                int len = sizeof(cliaddr);
                int cfd = accept(lfd, (struct sockaddr *)&cliaddr, &len);
                // 將新的文件描述符加入到集合中,下一次select檢測時,需要檢測這些通信的文件描述符有沒有數(shù)據(jù)
                FD_SET(cfd, &rdset);
                // 更新最大的文件描述符
                maxfd = maxfd > cfd ? maxfd : cfd;
            }
            //檢測剩余文件描述符有沒有數(shù)據(jù)變化,從lfd+1開始即可
            for(int i = lfd + 1; i <= maxfd; i++) {
                if(FD_ISSET(i, &tmp)) {
                    // 說明這個文件描述符對應的客戶端發(fā)來了數(shù)據(jù)
                    char buf[1024] = {0};
                    int len = read(i, buf, sizeof(buf));
                    if(len == -1) {
                        perror("read");
                        exit(-1);
                    } else if(len == 0) {	//說明客戶端斷開連接
                        printf("client closed...\n");
                        close(i);	//關閉文件描述符
                        FD_CLR(i, &rdset);	//fd_set中不在監(jiān)測這個文件描述符
                    } else if(len > 0) {
                        printf("read buf = %s\n", buf);
                        write(i, buf, strlen(buf) + 1);
                    }
                }
            }
        }
    }
    close(lfd);
    return 0;
}

編譯運行

再打開一個客戶端:

服務端可以看出有新客戶端進來了:

又連進來了新的客戶端:

select和poll缺點

到此這篇關于C語言詳解select函數(shù)的使用的文章就介紹到這了,更多相關C語言select函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • C++ Boost Parameter超詳細講解

    C++ Boost Parameter超詳細講解

    Boost是為C++語言標準庫提供擴展的一些C++程序庫的總稱。Boost庫是一個可移植、提供源代碼的C++庫,作為標準庫的后備,是C++標準化進程的開發(fā)引擎之一,是為C++語言標準庫提供擴展的一些C++程序庫的總稱
    2022-11-11
  • C語言各種操作符透徹理解下篇

    C語言各種操作符透徹理解下篇

    C?語言提供了豐富的操作符,除了上篇中的算術操作符,移位操作符,位操作符,賦值操作符外,還有單目操作符、關系操作符、邏輯操作符、條件操作符等等,讓我們通讀本篇來詳細了解吧
    2022-02-02
  • C++實現(xiàn)推箱子小游戲源碼

    C++實現(xiàn)推箱子小游戲源碼

    這篇文章主要為大家詳細介紹了C++實現(xiàn)推箱子小游戲源碼,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • C指針原理教程之AT&T匯編

    C指針原理教程之AT&T匯編

    AT&T 匯編是一種和intel匯編在語法上完全不同的匯編語言,為避免混淆intel語法,本文只介紹AT&T匯編,AT&T的第一個特點就是每個寄存器名前必須加‘%’,立即數(shù)前必須加‘$’
    2019-02-02
  • C語言實現(xiàn)刪除某一個數(shù)組值的方法

    C語言實現(xiàn)刪除某一個數(shù)組值的方法

    這篇文章主要給大家分享C語言數(shù)組中刪除數(shù)組中某個值的方法,既然要學習刪除數(shù)組中的元素,我們就必須得先知道數(shù)組中有哪些元素。同時還要定義一個變量,并將需要刪除的元素賦值給那個變量。下面來看看文章的詳細內(nèi)容吧
    2021-11-11
  • Vscode配置C/C++環(huán)境使用minGW(保姆級配置過程)

    Vscode配置C/C++環(huán)境使用minGW(保姆級配置過程)

    本文主要介紹了Vscode配置C/C++環(huán)境使用minGW(保姆級配置過程),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • linux下c語言中隱藏進程命令行參數(shù)(例如輸入密碼等高危操作)

    linux下c語言中隱藏進程命令行參數(shù)(例如輸入密碼等高危操作)

    啟動程序很多時候用命令行參數(shù)可以很方便,做到簡化一些配置,但是輸入用戶名密碼等操作,如果通過進程查看工具直接看到密碼就太不安全了,這里就為大家分享一下方法
    2021-01-01
  • C語言算法積累圖的遍歷鄰接表簡單路徑

    C語言算法積累圖的遍歷鄰接表簡單路徑

    這篇文章主要為大家介紹了C語言算法積累圖的遍歷鄰接表簡單路徑實現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • C語言實現(xiàn)圖書管理系統(tǒng)課程設計

    C語言實現(xiàn)圖書管理系統(tǒng)課程設計

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)圖書管理系統(tǒng)課程設計,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • C語言實現(xiàn)簡易的掃雷小游戲

    C語言實現(xiàn)簡易的掃雷小游戲

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)簡易的掃雷小游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05

最新評論

嵊州市| 和田市| 湖州市| 图们市| 丰顺县| 邵阳市| 林甸县| 天津市| 宝坻区| 长垣县| 枣庄市| 友谊县| 遂川县| 女性| 安义县| 新郑市| 鄂尔多斯市| 蚌埠市| 汝州市| 淳安县| 绿春县| 忻城县| 蓝山县| 浪卡子县| 沙湾县| 叙永县| 翼城县| 洞头县| 静海县| 云浮市| 炎陵县| 安仁县| 岫岩| 刚察县| 武城县| 保定市| 白朗县| 汝州市| 贵阳市| 永胜县| 永嘉县|