日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

基于select模型的TCP服务器

發布時間:2025/3/21 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于select模型的TCP服务器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
之前的一篇博文是基于TCP的服務器和客戶機程序,今天在這我要實現一個基于select模型的TCP服務器(僅實現了服務器)。

socket套接字編程提供了很多模型來使服務器高效的接受客戶端的請求,select就是其中之一。

了解select模型我們先來看一下的代碼:

int iResult = recv(s, buffer,1024);
這 是用來接收數據的,在默認的阻塞模式下的套接字里,recv會阻塞在那里,直到套接字連接上有數據可讀,把數據讀到buffer里后recv函數才會返 回,不然就會一直阻塞在那里。在單線程的程序里出現這種情況會導致主線程(單線程程序里只有一個默認的主線程)被阻塞,這樣整個程序被鎖死在這里,如果永 遠沒數據發送過來,那么程序就會被永遠鎖死。這個問題可以用多線程解決,但是在有多個套接字連接的情況下,這不是一個好的選擇,擴展性很差。Select 模型就是為了解決這個問題而出現的。


select函數:

[cpp] view plain copy
  • <span?style="font-family:Microsoft?YaHei;font-size:14px;">int?select(int?nfds,?fd_set??*readfds,?fd_set??*writefds,?fd_set?*exceptfds,?const?struct?timeval?*timeout?);</span>??


  • 參數nfds是需要監視的最?的?件描述符值+1;
    rdset,wrset,exset分別對應于需要檢測的可讀?件描述符的集合,可寫?件描述符的集 合及異
    常?件描述符的集合。
    struct timeval結構?于描述?段時間長度,如果在這個時間內,需要監視的描述符沒有事件

    發?則函數返回,返回值為0。

    [cpp] view plain copy
  • <span?style="font-family:Microsoft?YaHei;font-size:14px;">timeval結構體:??
  • struct??timeval?{??
  • ????????long????tv_sec;????????//秒??
  • ????????long????tv_usec;?????//毫秒??
  • };</span>??


  • select返回fd_set中可用的套接字個數。


    下?的宏提供了處理這三種描述詞組的?式:
    FD_CLR(inr fd,fd_set* set);?來清除描述詞組set中相關fd 的位
    FD_ISSET(int fd,fd_set *set);?來測試描述詞組set中相關fd 的位是否為真
    FD_SET(int fd,fd_set*set);?來設置描述詞組set中相關fd的位
    FD_ZERO(fd_set *set);?來清除描述詞組set的全部位


    函數返回值:
    執?成功則返回?件描述詞狀態已改變的個數。
    如果返回0代表在描述詞狀態改變前已超過timeout時間,沒有返回;
    當有錯誤發?時則返回-1, 錯誤原因存于errno,此時參數readfds,writefds,exceptfds和timeout的值變成不可預測。錯誤值可能為:
    EBADF ?件描述詞為?效的或該?件已關閉。
    EINTR 此調?被信號所中斷。
    EINVAL 參數n 為負值。
    ENOMEM 核?內存不?。



    根據以上的只是前提,我們可以得到select的特點:

    select模型的特點

      (1)可監控的?件描述符個數取決與sizeof(fd_set)的值。我這邊服務 器上sizeof(fd_set)=

    512,每bit表??個?件描述符,則我服務器上?持的最??件描述符是512*8=4096。據說

    可調,另有說雖 然可調,但調整上限受于編譯內核時的變量值。本?對調整fd_set的??不

    http://www.cppblog.com /CppExplore/archive/2008/03/21/45061.html?太感興趣,參考中的模

    型2(1)可以有效突破select可監控的?件描述符上 限。

      (2)將fd加?select監控集的同時,還要再使??個數據結構array保存放到select監控集

    中的fd,?是?于再select 返回后,array作為源數據和fd_set進?FD_ISSET判斷。?是select

    返回后會把以前加?的但并?事件發?的fd清空,則每次開始 select前都要重新從array取得fd

    逐?加?(FD_ZERO最先),掃描array的同時取得fd最?值maxfd,?于select的第?個 參

    數。

      (3)可見select模型必須在select前循環array(加fd,取maxfd),select返回后循環array

    (FD_ISSET判斷是否有時間發?)。



    以下是select模型的工作過程

    1:用FD_ZERO宏來初始化我們感興趣的fd_set。

    也就是select函數的第二三四個參數。

    2:用FD_SET宏來將套接字句柄分配給相應的fd_set。

    如果想要檢查一個套接字是否有數據需要接收,可以用FD_SET宏把套接接字句柄加入可讀性檢查隊列中

    3:調用select函數。

    如果該套接字沒有數據需要接收,select函數會把該套接字從可讀性檢查隊列中刪除掉,

    4:用FD_ISSET對套接字句柄進行檢查。

    如果我們所關注的那個套接字句柄仍然在開始分配的那個fd_set里,那么說明馬上可以進行相應的IO操 作。比如一個分配給select第一個參數的套接字句柄在select返回后仍然在select第一個參數的fd_set里,那么說明當前數據已經來了, 馬上可以讀取成功而不會被阻塞。



    基于select模型的TCP服務器的實現:

    [cpp] view plain copy
  • <span?style="font-family:Microsoft?YaHei;font-size:14px;">#include<stdio.h>??
  • #include<string.h>??
  • #include<stdlib.h>??
  • #include<sys/socket.h>??
  • #include<sys/types.h>??
  • #include<sys/select.h>??
  • #include<netinet/in.h>??
  • ??
  • #define?_MAX_SIZE_?10??
  • int?fd_arr[_MAX_SIZE_];??
  • int?max_fd=0;??
  • static?void?Useage(const?char*?proc)??
  • {??
  • ????printf("Useage:%s,[ip][port]");??
  • ????exit(1);??
  • }??
  • static?int?add_fd_arr(int?fd)??
  • {??
  • ????//fd?add?to?fd_arr??
  • ????int?i=0;??
  • ????for(;i<_MAX_SIZE_;++i)??
  • ????{??
  • ????????if(fd_arr[i]==-1)??
  • ????????{??
  • ????????????fd_arr[i]=fd;??
  • ????????????return?0;??
  • ????????}??
  • ????}??
  • ????return?1;??
  • }??
  • int?select_server(char*?ip,char*?port)??
  • {??
  • ????struct?sockaddr_in?ser;??
  • ????struct?sockaddr_in?cli;??
  • ????fd_set?fds;??
  • ????int?fd=socket(AF_INET,SOCK_STREAM,0);??
  • ????if(fd<0)??
  • ????{??
  • ????????perror("socket()");??
  • ????????exit(2);??
  • ????}??
  • ????int?yes=1;??
  • ????setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int));??
  • ??
  • ????memset(&ser,'\0',sizeof(ser));??
  • ????ser.sin_family=AF_INET;??
  • ????ser.sin_port=htons(port);??
  • ????ser.sin_addr.s_addr=ip;??
  • ??
  • ??
  • ????if(bind(fd,(struct?sockaddr*)&ser,sizeof(ser))<0)??
  • ????{??
  • ????????perror("bind()");??
  • ????????exit(3);??
  • ????}??
  • ??
  • ????//init?fd_arr??
  • ????int?i=0;??
  • ????for(;i<_MAX_SIZE_;++i)??
  • ????{??
  • ????????fd_arr[i]=-1;??
  • ????}??
  • ??
  • ????add_fd_arr(fd);??
  • ??
  • ??
  • ????FD_ZERO(&fds);??
  • ????if(listen(fd,5)<0)??
  • ????{??
  • ????????perror("listen");??
  • ????????exit(4);??
  • ????}??
  • ??
  • ??
  • ????while(1)??
  • ????{??
  • ????????//reset?fd_arr??
  • ????????for(i=0;i<_MAX_SIZE_;++i)??
  • ????????{??
  • ????????????if(fd_arr[i]!=-1)??
  • ????????????{??
  • ????????????????FD_SET(fd_arr[i],&fds);??
  • ????????????????if(fd_arr[i]>max_fd)??
  • ????????????????{??
  • ????????????????????max_fd=fd_arr[i];??
  • ????????????????}??
  • ????????????}??
  • ????????}??
  • ????????struct?timeval?timeout={3,0};??
  • ????????switch(select(max_fd+1,&fds,NULL,NULL,&timeout))??
  • ????????{??
  • ????????????case?-1:??
  • ????????????????{??
  • ????????????????????perror("select");??
  • ????????????????????exit(5);??
  • ????????????????????break;??
  • ????????????????}??
  • ????????????case?0:??
  • ????????????????{??
  • ????????????????????printf("select?timeout......");??
  • ????????????????????break;??
  • ????????????????}??
  • ????????????default:??
  • ????????????????{??
  • ????????????????????for(i=0;i<_MAX_SIZE_;++i)??
  • ????????????????????{??
  • ????????????????????????if(i==0&&fd_arr[i]!=-1&&FD_ISSET(fd_arr[i],&fds))??
  • ????????????????????????{??
  • ????????????????????????????socklen_t?len=sizeof(cli);??
  • ????????????????????????????int?new_fd=accept(fd,(struct?sockaddr*)&cli,&len);??
  • ????????????????????????????if(-1!=new_fd)??
  • ????????????????????????????{??
  • ????????????????????????????????printf("get?a?new?link");??
  • ????????????????????????????????if(1==add_fd_arr(new_fd))??
  • ????????????????????????????????{??
  • ????????????????????????????????????perror("fd_arr?is?full,close?new_fd\n");??
  • ????????????????????????????????????close(new_fd);??
  • ????????????????????????????????}??
  • ??????????????????????????????????
  • ????????????????????????????}??
  • ????????????????????????????continue;??
  • ????????????????????????}??
  • ????????????????????????if(fd_arr[i]!=-1&&FD_ISSET(fd_arr[i],&fds))??
  • ????????????????????????{??
  • ????????????????????????????char?buf[1024];??
  • ????????????????????????????memset(buf,'\0',sizeof(buf));??
  • ????????????????????????????ssize_t?size=recv(fd_arr[i],buf,sizeof(buf)-1,0);??
  • ????????????????????????????if(size==0||size==-1)??
  • ????????????????????????????{??
  • ????????????????????????????????printf("remote?client?close,size?is%d\n",size);??
  • ????????????????????????????????int?j=0;??
  • ????????????????????????????????for(;j<_MAX_SIZE_;++j)??
  • ????????????????????????????????{??
  • ????????????????????????????????????if(fd_arr[j]==fd_arr[i])??
  • ????????????????????????????????????{??
  • ????????????????????????????????????????fd_arr[j]=-1;??
  • ????????????????????????????????????????break;??
  • ????????????????????????????????????}??
  • ????????????????????????????????}??
  • ????????????????????????????????close(fd_arr[i]);??
  • ????????????????????????????????FD_CLR(fd_arr[i],&fds);??
  • ????????????????????????????}else??
  • ????????????????????????????{??
  • ????????????????????????????????printf("fd:%d,msg:%s",fd_arr[i],buf);??
  • ????????????????????????????}??
  • ????????????????????????}??
  • ????????????????????}??
  • ????????????????}??
  • ????????????????break;??
  • ????????}??
  • ??
  • ????}??
  • }??
  • int?main(int?argc,char*?argv[])??
  • {??
  • ????if(argc!=3)??
  • ????{??
  • ????????Useage(argv[0]);??
  • ????}??
  • ????select_server(argv[1],argv[2]);??
  • ????return?0;??
  • }??
  • </span>?
  • 總結

    以上是生活随笔為你收集整理的基于select模型的TCP服务器的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。