歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Linux 網絡編程---->多路復用:select實例!

好吧,我承認找了好久,網上都沒有像樣的完整的實例,然後自己參照書自己寫一個吧!

//!> server端代碼
//!>server.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>

#define BUF_LEN 1024
#define SERV_PORT 6000
#define FD_SIZE 100
#define MAX_BACK 100

int main( int argc, char ** argv )
{
     int          listenfd,connfd, sockfd, maxfd, maxi, i;
    int          nready,client[FD_SIZE];      //!> 接收select返回值、保存客戶端套接字
    int          lens;
    ssize_t   n;            //!> read字節數
   fd_set       rset,allset;   //!> 不要理解成就只能保存一個,其實fd_set有點像封裝的數組
    char      buf[BUF_LEN];            
   socklen_t   clilen;
    structsockaddr_in servaddr, chiaddr;
   
    if( (listenfd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 )
    {
       printf("Create socket Error : %d\n", errno );
       exit(EXIT_FAILURE );
    }
   
   //!>
   //!> 下面是接口信息
    bzero(&servaddr, sizeof( servaddr ) );
   servaddr.sin_family = AF_INET;
   servaddr.sin_addr.s_addr  =htonl( INADDR_ANY);
   servaddr.sin_port = htons( SERV_PORT );
   
   //!>
   //!> 綁定
    if( bind(listenfd, ( struct sockaddr * )&servaddr, sizeof(servaddr ) ) == -1 )
     
       printf("BindError : %d\n", errno);
      exit(EXIT_FAILURE  );
    }
   
   //!>
   //!> 監聽
    if( listen(listenfd, MAX_BACK ) == -1 )
    {
      printf("Listen Error : %d\n", errno );
       exit(EXIT_FAILURE );
    }
   
   //!> 當前最大的感興趣的套接字fd
    maxfd =listenfd;   //!> 當前可通知的最大的fd
    maxi =-1;         //!> 僅僅是為了client數組的好處理
   
    for( i = 0;i < FD_SIZE; i++)   //!> 首先置為全-1
    {
       client[i] =-1;      //!> 首先client的等待隊列中是沒有的,所以全部置為-1
    }
   
    FD_ZERO(&allset);      //!> 先將其置為0
    FD_SET(listenfd, &allset );
               //!> 說明當前我對此套接字有興趣,下次select的時候通知我!
   
    while( 1)
    {
       rset =allset;//!> 由於allset可能每次一個循環之後都有變化,所以每次都賦值一次
       if( (nready= select( maxfd + 1, &rset, NULL, NULL, NULL )) ==-1)
                    //!> if 存在關注
         printf("Select Erorr : %d\n", errno );
          exit(EXIT_FAILURE );
       }
      
       if( nready<= 0)         //!> if 所有的感興趣的沒有就接著回去select
       {
         continue;
       }
      
      
      
       if(FD_ISSET( listenfd, &rset ))         //!> if 是監聽接口上的“來電”
                                      //!>
         //!> printf("server listen ...\n");
          clilen =sizeof( chiaddr );
         
         printf("Start doing... \n");
         
            if( (connfd  = accept( listenfd, (struct sockaddr*)&chiaddr, &clilen ) ) == -1)
                                        //!> accept 返回的還是套接字
               printf("Accept Error : %d\n", errno );
              continue;
            }
           
           
            for( i = 0;i < FD_SIZE; i++)   //!> 注意此處必須是循環,剛開始我認
                                      //!> 為可以直接設置一個end_i來直接處
                                      //!> 理,實質是不可以的!因為每個套接
                                     //!> 字的退出時間是不一樣的,後面的
               if(client[i] < 0)            //!> 可能先退出,那麼就亂了,所以只
                                     //!> 有這樣了!
                  client[i] =connfd;         //!> 將client的請求連接保存
                  break;
               }
            }
           
            if( i ==FD_SIZE )            //!> The last one
            {
               printf( "Tomany ... " );
               close(connfd );         //!> if 滿了那麼就不連接你了,關閉吧
            continue;               //!> 返回
            }
                                 //!> listen的作用就是向數組中加入套接字!
          FD_SET(connfd, &allset);   //!> 說明現在對於這個連接也是感興趣的!
                                 //!> 所以加入allset的陣容
          if( connfd> maxfd)         //!> 這個還是為了解決亂七八糟的數組模型
                                 //!> 的處理
          {
             maxfd =connfd;
          }
         
          if( i> maxi)               //!> 同上
          {
             maxi =i;
          }
       }

      //!> 下面就是處理數據函數( 其實說本質的select還是串行 )
       for( i = 0;i <= maxi; i++)      //!> 對所有的連接請求的處理
       {
          if( ( sockfd= client[i] ) > 0)   //!> 還是為了不規整的數組
                 //!> 也就說client數組不是連續的全正數或者-1,可能是鋸齒狀的
             if(FD_ISSET( sockfd, &rset ))   //!> if 當前這個數據套接字有要讀的
              {
                 memset( buf,0, sizeof( buf ));   //!> 此步重要,不要有時候出錯
             
                 n = read(sockfd, buf, BUF_LEN);
                 if( n< 0 )
                 {
                   printf("Error!\n");
                    close(sockfd );         //!> 說明在這個請求端口上出錯了!
                   FD_CLR(sockfd, &allset );
                   client[i] =-1;
                  continue;
                 }
                if( n == 0)
                {
                   printf("nodata\n");
                   close(sockfd );         //!> 說明在這個請求端口上讀完了!
                   FD_CLR(sockfd, &allset );
                   client[i] =-1;
                  continue;
                }
               
               printf("Server Recv: %s\n", buf);
               
                if( strcmp(buf, "q" ) == 0)            //!> 客戶端輸入“q”退出標志
                {
                   close(sockfd );
                   FD_CLR(sockfd, &allset );
                   client[i] =-1;
                  continue;
                }
               
               printf("Server send : %s\n", buf);
                write(sockfd, buf, n);      //!> 讀出來的寫進去
             }
          }
       }
      
    }
   
    return0;
}
Copyright © Linux教程網 All Rights Reserved