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;
}


//!> client端代码
//!>client.c


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

#define MAXLINE 1024
#define SERV_PORT 6000

//!> 注意输入是由stdin,接受是由server发送过来
//!> 所以在client端也是需要select进行处理的
void send_and_recv( int connfd )
{
      FILE * fp =stdin;
      int    lens;
      charsend[MAXLINE];
      charrecv[MAXLINE];
      fd_setrset;
      FD_ZERO(&rset );
      int maxfd =( fileno( fp ) > connfd ? fileno( fp ) :connfd  + 1);     
                                                                        //!> 输入和输出的最大值
      int n;
     
      while( 1)
      {
            FD_SET(fileno( fp ), &rset );
            FD_SET(connfd, &rset);                  //!> 注意不要把rset看作是简单的一个变量
                                                                        //!> 注意它其实是可以包含一组套接字的哦,
                                                                        //!> 相当于是封装的数组!每次都要是新的哦!
           
            if( select(maxfd, &rset, NULL, NULL, NULL ) == -1 )
            {
                  printf("Client Select Error..\n");
                  exit(EXIT_FAILURE  );
            }
           
            //!> if 连接口有信息
            if(FD_ISSET( connfd, &rset ))      //!> if 连接端口有信息
            {
                  printf("client get from server ...\n" );
                  memset(recv, 0, sizeof( recv ) );
                  n = read(connfd, recv, MAXLINE );
                  if( n == 0)
                  {
                        printf("Recvok...\n");
                        break;
                  }
                  else if( n== -1 )
                  {
                        printf("Recverror...\n");
                        break;
                  }
                  else
                  {
                        lens =strlen( recv );
                        recv[lens] ='\0';
                        //!> 写到stdout
                        write(STDOUT_FILENO, recv, MAXLINE );
                        printf("\n");
                  }

            }
           
            //!> if 有stdin输入
            if(FD_ISSET( fileno( fp ), &rset ))      //!> if 有输入
            {
                  //!> printf("client stdin ...\n");
                 
                  memset(send, 0, sizeof( send ) );
                  if( fgets(send, MAXLINE, fp ) == NULL )
                  {
                        printf("End...\n");
                        exit(EXIT_FAILURE );
                  }
                  else
                  {
                        //!>if( str )
                        lens =strlen( send );
                        send[lens-1]= '\0';            //!> 减一的原因是不要回车字符
                                                                  //!> 经验值:这一步非常重要的哦!!!!!!!!
                        if( strcmp(send, "q" ) == 0 )
                        {
                              printf("Bye..\n" );
                              return;
                        }
                       
                        printf("Client send : %s\n", send);
                        write(connfd, send, strlen( send ) );
                  }
            }
           
      }
     
}

int main( int argc, char ** argv )
{
      //!> char * SERV_IP = "10.30.97.188";
      char      buf[MAXLINE];
      int          connfd;
      structsockaddr_in servaddr;
     
      if( argc !=2 )
      {
            printf("Input server ip !\n");
            exit(EXIT_FAILURE );
      }
     
      //!> 建立套接字
      if( ( connfd= socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 )
      {
            printf("Socket Error...\n" , errno );
            exit(EXIT_FAILURE );
      }

      //!> 套接字信息
      bzero(&servaddr, sizeof(servaddr));
      servaddr.sin_family = AF_INET;
      servaddr.sin_port = htons(SERV_PORT);
      inet_pton(AF_INET, argv[1],&servaddr.sin_addr);
     
      //!> 链接server
      if( connect(connfd, ( struct sockaddr *  )&servaddr, sizeof( servaddr ) ) < 0)
      {
            printf("Connect error..\n");
            exit(EXIT_FAILURE);
         
     

      //!>
      //!> send and recv
      send_and_recv( connfd );
     
      //!>

      close(connfd );
      printf("Exit\n");
     
      return0;
}


编译+运行:

gcc -o server server.c
gcc -o client    client.c

./server
./client10.80.1.251      (注意参数你指定的server的IP哦  )


如果要多个一起运行,给个脚本:
#!/bin/sh
index=10

while [ $index -gt 0 ]
do
        ./client  10.80.1.251&                  # 注意在后台哦,所以只能看到在server下的现象,可以自己改进
          $index = `expr $index - 1`
done

exit 0

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值