国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【TCP/IP】利用I/O復(fù)用技術(shù)實現(xiàn)并發(fā)服務(wù)器 - select函數(shù)

這篇具有很好參考價值的文章主要介紹了【TCP/IP】利用I/O復(fù)用技術(shù)實現(xiàn)并發(fā)服務(wù)器 - select函數(shù)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

目錄

I/O復(fù)用技術(shù)

select函數(shù)

設(shè)置文件描述符

指定監(jiān)視范圍

設(shè)置超時

I/O復(fù)用服務(wù)器端的實現(xiàn)


??????由服務(wù)器創(chuàng)建多個進程來實現(xiàn)并發(fā)的做法有時會帶來一些問題,比如:內(nèi)存上的開銷、CPU的大量占用等,這些因素會消耗掉服務(wù)器端有限的計算資源、進而影響程序之間的執(zhí)行效率。那么,有沒有方法可以在不創(chuàng)建額外進程的條件下實現(xiàn)并發(fā)呢?當(dāng)然有,那就是I/O復(fù)用技術(shù)。

I/O復(fù)用技術(shù)

????????I/O復(fù)用指的是通過單個線程記錄一個或多個I/O流的狀態(tài),并對不同狀態(tài)下的I/O流進行協(xié)調(diào),使進程不阻塞于某個特定的I/O調(diào)用過程中,從而將有限資源最大化利用。

? ? ? ? 引用自一段情景材料,方便大家能更好地理解這個技術(shù)背后的思想:

假設(shè)你是一個機場的空管,你需要管理到你機場的所有的航線,包括進港,出港,有些航班需要放到停機坪等待,有些航班需要去登機口接乘客。

你會怎么做?

最簡單的做法,就是你去招一大批空管員,然后每人盯一架飛機,從進港,接客,排位,出港,航線監(jiān)控,直至交接給下一個空港,全程監(jiān)控。

那么問題就來了:

  • 很快你就發(fā)現(xiàn)空管塔里面聚集起來一大票的空管員,交通稍微繁忙一點,新的空管員就已經(jīng)擠不進來了。
  • 空管員之間需要協(xié)調(diào),屋子里面就1, 2個人的時候還好,幾十號人以后,基本上就成菜市場了。
  • 空管員經(jīng)常需要更新一些公用的東西,比如起飛顯示屏,比如下一個小時后的出港排期,最后你會很驚奇的發(fā)現(xiàn),每個人的時間最后都花在了搶這些資源上。

現(xiàn)實上我們的空管同時管幾十架飛機稀松平常的事情, 他們怎么做的呢?他們用這個東西:

【TCP/IP】利用I/O復(fù)用技術(shù)實現(xiàn)并發(fā)服務(wù)器 - select函數(shù)

這個東西叫 flight progress strip,每一個塊代表一個航班,不同的槽代表不同的狀態(tài),然后一個空管員可以管理一組這樣的塊(一組航班),而他的工作,就是在航班信息有新的更新的時候,把對應(yīng)的塊放到不同的槽子里面。這個東西現(xiàn)在還沒有淘汰哦,只是變成電子的了而已。是不是覺得一下子效率高了很多,一個空管塔里可以調(diào)度的航線可以是前一種方法的幾倍到幾十倍。?

如果你把每一個航線當(dāng)成一個 Sock(I/O 流),空管當(dāng)成你的服務(wù)端 Sock 管理代碼的話:

  • 第一種方法就是最傳統(tǒng)的多進程并發(fā)模型:每進來一個新的 I/O 流會分配一個新的進程管理。
  • 第二種方法就是 I/O 多路復(fù)用:單個線程,通過記錄跟蹤每個 I/O 流(sock)的狀態(tài),來同時管理多個 I/O 流 。?

????????????????????????????????????????????????????????????????????????參考資料:IO 多路復(fù)用是什么意思? - 羅志宇

select函數(shù)

????????select是I/O復(fù)用技術(shù)中比較經(jīng)典且常用到的一個函數(shù)(還有poll、epoll),在使用上,需要引入<sys/select.h>和<sys/time.h>兩個頭文件。

#include <sys/select.h>
#include <sys/time.h>

int select(int maxfd , fd_set * readset , fd_set * writeset , fd_set * exceptset , const struct timeval * timeout);

//成功時返回大于0的值,失敗時返回-1。其余情況為返回發(fā)生事件(監(jiān)視項)的文件描述符數(shù)量

/* 監(jiān)視項 */
// 1.接收數(shù)據(jù)的套接字
// 2.傳輸數(shù)據(jù)(無阻塞)的套接字
// 3.發(fā)生異常的套接字

/* 參數(shù)含義 */
// maxfd: 監(jiān)視對象文件描述符數(shù)量
// readset: 將所有關(guān)注"是否存在待讀取數(shù)據(jù)"的文件描述符注冊到fd_set型變量,并傳遞其地址值。
// writeset: 將所有關(guān)注"是否可傳輸無阻塞數(shù)據(jù)"的文件描述符注冊到fd_set型變量,并傳遞其地址值。
// exceptset: 將所有關(guān)注"是否發(fā)生異常"的文件描述符注冊至fd_set型變量,并傳遞其地址值。
// timeout: 調(diào)用 select 函數(shù)后,為防止陷入無限阻塞的狀態(tài),傳遞超時(time-out)消息。


????????使用select函數(shù)時,一般遵循以下流程步驟:

【TCP/IP】利用I/O復(fù)用技術(shù)實現(xiàn)并發(fā)服務(wù)器 - select函數(shù)

設(shè)置文件描述符

????????在調(diào)用select函數(shù)之前,我們需要聲明監(jiān)視事件,并用數(shù)據(jù)類型為fd_set的變量來記錄監(jiān)視事件下的每個文件描述符的狀態(tài)。如圖所示,fd_set以數(shù)組的形式記錄每個文件描述符的狀態(tài):

【TCP/IP】利用I/O復(fù)用技術(shù)實現(xiàn)并發(fā)服務(wù)器 - select函數(shù)

????????以圖中fd0、fd2為例,值為0,代表著所指向的文件描述符不是被監(jiān)視對象;反之,fd1和fd3值為1,則是被監(jiān)視對象。

????????在對fd_set數(shù)組操作時,有些宏可以幫助我們簡化代碼的編寫工作,下列所示為與對fd_set操作相關(guān)的宏:

  • FD_ZERO(fd_set * fdset): 將fd_set變量的所有位初始化為0 。
  • FD_SET(int fd , fd_set * fdset): 在參數(shù)fdset指向的變量中注冊文件描述符fd的信息。
  • FD_CLR(int fd , fd_set * fdset): 從參數(shù)fdset指向的變量中清除文件描述符fd的信息。
  • FD_ISSET(int fd , fd_set * fdset): 若參數(shù)fdset指向的變量中包含文件描述符fd的信息,則返回"真",用于對select調(diào)用結(jié)果的驗證。

????????宏對應(yīng)的操作含義如圖所示:

【TCP/IP】利用I/O復(fù)用技術(shù)實現(xiàn)并發(fā)服務(wù)器 - select函數(shù)

指定監(jiān)視范圍

????????即設(shè)置select函數(shù)中的第一個參數(shù) maxfd,其值用來標(biāo)記限制對監(jiān)視事件中的文件描述符最大監(jiān)視數(shù)。

設(shè)置超時

????????當(dāng)監(jiān)視的文件描述符未發(fā)生變化時,select函數(shù)會導(dǎo)致進程發(fā)生阻塞。為了避免這種情況發(fā)生,我們可以通過設(shè)置超時(select函數(shù)中的最后一個參數(shù)timeout)來防止這種情況的發(fā)生。

????????timeout的結(jié)構(gòu)體定義如下:

struct timeval
{
    long tv_sec; // 秒
    long tv_usec; // 毫秒
}

//timeval.tv_sec=5,timeval.tv_usec=500; 代表設(shè)置超時等待周期為5秒500毫秒

I/O復(fù)用服務(wù)器端的實現(xiàn)

io_echoserver.cpp

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/select.h>

#define BUF_SIZE 1024

void Sender_error(char *message);

int main(int argc, char *argv[])
{
    int port, serv_sock, clnt_sock;
    struct sockaddr_in serv_adr, clnt_adr;
    struct timeval timeout;
    fd_set reads, cpy_reads;
    socklen_t adr_sz;
    int fd_max, str_len, fd_num, i;
    char buf[BUF_SIZE];
    //可以改為直接傳參(即使用argv數(shù)組),這里主要方便驗證和展示
    printf("Please input the port of socket that you want to create:\n");
    scanf("%d", &port);

    serv_sock = socket(PF_INET, SOCK_STREAM, 0);
    if (serv_sock == -1)
    {
        Sender_error((char *)"Sock creation error");
    }
    else
    {
        // 注意:serv_sock初始化成功后值為0
        fd_max = serv_sock;
    }

    memset(&serv_adr, 0, sizeof(serv_adr));
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_adr.sin_port = htons(port);

    if (bind(serv_sock, (struct sockaddr *)&serv_adr, sizeof(serv_adr)) == -1)
    {
        Sender_error((char *)"Bind() error");
    }
    if (listen(serv_sock, 5) == -1)
    {
        Sender_error((char *)"Listen error");
    }
    // 對監(jiān)測項的文件描述符作初始化賦0操作
    FD_ZERO(&reads);
    // 注冊serv_sock套接字信息至reads變量中
    FD_SET(serv_sock, &reads);

    while (1)
    {
        // cpy_reads用來記錄文件描述符變化
        cpy_reads = reads;
        // 設(shè)置超時等待周期為5s
        timeout.tv_sec = 5;
        timeout.tv_usec = 0;

        // 只關(guān)注接收數(shù)據(jù)的套接字,不對傳輸數(shù)據(jù)、出現(xiàn)異常的套接字進行監(jiān)視
        // fd_num用來記錄發(fā)生監(jiān)視事件的文件描述符數(shù)量
        if ((fd_num = select(fd_max + 1, &cpy_reads, 0, 0, &timeout)) == -1)
        {
            break;
        }

        if (fd_num == 0)
        {
            continue;
        }

        for (i = 0; i < fd_max + 1; i++)
        {
            // 判斷cpy_reads中是否含有文件描述符i的信息
            if (FD_ISSET(i, &cpy_reads))
            {
                // 若當(dāng)前只有服務(wù)器端套接字,則嘗試接收客戶端請求
                if (i == serv_sock)
                {
                    adr_sz = sizeof(clnt_adr);
                    clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_adr, &adr_sz);
                    // 將客戶端的套接字文件描述符信息注冊至reads中
                    FD_SET(clnt_sock, &reads);
                    if (fd_max < clnt_sock)
                    {
                        // 增加監(jiān)視數(shù)上限(因為有新的客戶端套接字加入)
                        fd_max = clnt_sock;
                    }
                    printf("Connected client: %d \n", clnt_sock);
                }
                else
                {
                    // 接收數(shù)據(jù)
                    str_len = read(i, buf, BUF_SIZE);
                    // 無數(shù)據(jù),則關(guān)閉對應(yīng)套接字
                    if (str_len == 0)
                    {
                        // 清除reads變量中文件描述符i的信息
                        FD_CLR(i, &reads);
                        close(i);
                        printf("Closed client: %d \n", i);
                    }
                    else
                    {
                        write(i, buf, str_len);
                    }
                }
            }
        }
    }
    close(serv_sock);
    return 0;
}

void Sender_error(char *message)
{
    puts(message);
    exit(1);
}

運行結(jié)果:

【TCP/IP】利用I/O復(fù)用技術(shù)實現(xiàn)并發(fā)服務(wù)器 - select函數(shù)文章來源地址http://www.zghlxwxcb.cn/news/detail-483139.html

到了這里,關(guān)于【TCP/IP】利用I/O復(fù)用技術(shù)實現(xiàn)并發(fā)服務(wù)器 - select函數(shù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • TCP服務(wù)器的演變過程:IO多路復(fù)用機制select實現(xiàn)TCP服務(wù)器

    TCP服務(wù)器的演變過程:IO多路復(fù)用機制select實現(xiàn)TCP服務(wù)器

    手把手教你從0開始編寫TCP服務(wù)器程序,體驗開局一塊磚,大廈全靠壘。 為了避免篇幅過長使讀者感到乏味,對【TCP服務(wù)器的開發(fā)】進行分階段實現(xiàn),一步步進行優(yōu)化升級。 本節(jié),在上一章節(jié)的基礎(chǔ)上,將并發(fā)的實現(xiàn)改為IO多路復(fù)用機制,使用select管理每個新接入的客戶端連

    2024年02月03日
    瀏覽(15)
  • 【TCP服務(wù)器的演變過程】使用IO多路復(fù)用器epoll實現(xiàn)TCP服務(wù)器

    【TCP服務(wù)器的演變過程】使用IO多路復(fù)用器epoll實現(xiàn)TCP服務(wù)器

    手把手教你從0開始編寫TCP服務(wù)器程序,體驗開局一塊磚,大廈全靠壘。 為了避免篇幅過長使讀者感到乏味,對【TCP服務(wù)器的開發(fā)】進行分階段實現(xiàn),一步步進行優(yōu)化升級。 本節(jié),在上一章節(jié)的基礎(chǔ)上,將IO多路復(fù)用機制select改為更高效的IO多路復(fù)用機制epoll,使用epoll管理每

    2024年01月17日
    瀏覽(16)
  • FPGA實現(xiàn) TCP/IP 協(xié)議棧 服務(wù)器 純VHDL代碼編寫 提供4套vivado工程源碼和技術(shù)支持

    FPGA實現(xiàn) TCP/IP 協(xié)議棧 服務(wù)器 純VHDL代碼編寫 提供4套vivado工程源碼和技術(shù)支持

    FPGA實現(xiàn) TCP/IP 協(xié)議棧 服務(wù)器 純VHDL代碼編寫 提供4套vivado工程源碼和技術(shù)支持 沒玩過TCP網(wǎng)絡(luò)通信都不好意思說自己玩兒過FPGA,這是CSDN某大佬說過的一句話,鄙人深信不疑。。。目前網(wǎng)上fpga實現(xiàn)udp協(xié)議的源碼滿天飛,我這里也有不少,但用FPGA純源碼實現(xiàn)TCP的項目卻很少,能上

    2024年02月04日
    瀏覽(26)
  • epoll多路復(fù)用_并發(fā)服務(wù)器

    應(yīng)用程序: 驅(qū)動程序:

    2024年02月15日
    瀏覽(20)
  • 使用select實現(xiàn)TCP并發(fā)服務(wù)器模型

    使用select實現(xiàn)TCP并發(fā)服務(wù)器模型

    本期主要分享的是對于select的使用,使用select實現(xiàn)TCP并發(fā)服務(wù)器模型,由于之前所用到的技術(shù)知識只能夠支撐我們進行單個訪問,但是有了select之后呢,我們就能夠?qū)崿F(xiàn)多用戶進行訪問;這也是非常符合客觀需求的; 這次呢我們重點來使用一下select; 用到的頭文件如下: 我

    2024年02月08日
    瀏覽(21)
  • FPGA實現(xiàn)10G萬兆網(wǎng)TCP/IP 協(xié)議棧,純VHDL代碼編寫,提供服務(wù)器和客戶端2套工程源碼和技術(shù)支持

    FPGA實現(xiàn)10G萬兆網(wǎng)TCP/IP 協(xié)議棧,純VHDL代碼編寫,提供服務(wù)器和客戶端2套工程源碼和技術(shù)支持

    目前網(wǎng)上fpga實現(xiàn)udp協(xié)議的源碼滿天飛,我這里也有不少,但用FPGA純源碼實現(xiàn)TCP的項目卻很少,能上板調(diào)試跑通的項目更是少之又少,甚至可以說是鳳毛菱角,但很不巧,本人這兒就有一個; 本設(shè)采用純VHDL實現(xiàn)了10G萬兆網(wǎng)TCP/IP協(xié)議棧,該協(xié)議棧分為TCP服務(wù)器核客戶端,沒有使

    2024年02月09日
    瀏覽(31)
  • Linux多路IO復(fù)用技術(shù)——epoll詳解與一對多服務(wù)器實現(xiàn)

    Linux多路IO復(fù)用技術(shù)——epoll詳解與一對多服務(wù)器實現(xiàn)

    本文詳細介紹了Linux中epoll模型的優(yōu)化原理和使用方法,以及如何利用epoll模型實現(xiàn)簡易的一對多服務(wù)器。通過對epoll模型的優(yōu)化和相關(guān)接口的解釋,幫助讀者理解epoll模型的工作原理和優(yōu)缺點,同時附帶代碼實現(xiàn)和圖解說明。

    2024年02月05日
    瀏覽(27)
  • linux并發(fā)服務(wù)器 —— IO多路復(fù)用(八)

    linux并發(fā)服務(wù)器 —— IO多路復(fù)用(八)

    半關(guān)閉只能實現(xiàn)數(shù)據(jù)單方向的傳輸;當(dāng)TCP 接中A向 B 發(fā)送 FIN 請求關(guān)閉,另一端 B 回應(yīng)ACK 之后 (A 端進入 FIN_WAIT_2 狀態(tài)),并沒有立即發(fā)送 FIN 給 A,A 方處于半連接狀態(tài) (半開關(guān)),此時 A 可以接收 B 發(fā)送的數(shù)據(jù),但是 A 已經(jīng)不能再向 B 發(fā)送數(shù)據(jù) close不會影響到其他進程,shutdown會

    2024年02月09日
    瀏覽(21)
  • 【高并發(fā)服務(wù)器 02】——線程池與IO多路復(fù)用

    線程池的好處 :所有的池都是為了事先把資源準(zhǔn)備好,在后續(xù)用的時候可以更加方便的拿到這個資源—— 不用去申請、釋放資源 什么時候用線程池 ? IO事務(wù)并發(fā)較高 :人在杭州,但是數(shù)據(jù)庫在北京,想要查詢數(shù)據(jù)庫,需要通過互聯(lián)網(wǎng)建立TCP三次握手,頻繁地創(chuàng)建和銷毀線

    2024年03月23日
    瀏覽(24)
  • C/S架構(gòu)學(xué)習(xí)之多線程實現(xiàn)TCP并發(fā)服務(wù)器

    并發(fā)概念: 并發(fā)是指兩個或多個事件在 同一時間間隔 發(fā)生; 多線程實現(xiàn)TCP并發(fā)服務(wù)器的實現(xiàn)流程: 一、創(chuàng)建套接字(socket函數(shù)): 通信域選擇IPV4網(wǎng)絡(luò)協(xié)議、套接字類型選擇流式; 二、填充服務(wù)器的網(wǎng)絡(luò)信息結(jié)構(gòu)體: 1.定義網(wǎng)絡(luò)信息結(jié)構(gòu)體變量; 2.求出結(jié)構(gòu)體變量的內(nèi)存

    2024年02月06日
    瀏覽(27)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包