select函数

select函数可以实现非阻塞方式的程序。它能够监视我们需要监视的文件描述符的变化情况——读写或是异常。

**int select(int maxfdp,fd_set readfds,fd_set writefds,fd_set errorfds,struct timevaltimeout);
头文件:#include <sys/select.h>

maxfdp是一个整数值,是指集合中所有文件描述符的范围,即所有文件描述符的最大值加1。
readfds是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的读变化的,即我们关心是否可以从这些文件中读取数据了,如果这个集合中有一个文件可读,select就会返回一个大于0的值,表示有文件可读,如果没有可读的文件,则根据timeout参数再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的读变化。
writefds是指向fd_set结构的指针,这个集合中应该包括文件描述符,我们是要监视这些文件描述符的写变化的,即我们关心是否可以向这些文件中写入数据了,如果这个集合中有一个文件可写,select就会返回一个大于0的值,表示有文件可写,如果没有可写的文件,则根据timeout再判断是否超时,若超出timeout的时间,select返回0,若发生错误返回负值。可以传入NULL值,表示不关心任何文件的写变化。
errorfds同上面两个参数的意图,用来监视文件错误异常。
timeout是select的超时时间,这个参数至关重要,它可以使select处于三种状态。
第一:若将NULL以形参传入,即不传入时间结构,就是将select置于阻塞状态,一定等到监视文件描述符集合中某个文件描述符发生变化为止;
第二:若将时间值设为0秒0毫秒,就变成一个纯粹的非阻塞函数,不管文件描述符是否有变化,都立刻返回继续执行,文件无变化返回0,有变化返回一个正值;
第三:timeout的值大于0,这就是等待的超时时间,即select在timeout时间内阻塞,超时时间之内有事件到来就返回了,否则在超时后不管怎样一定返回,返回值同上述。

返回值
负值:select错误;
正值:某些文件可读写或出错;
0:等待超时,没有可读写或错误的文件。

原文链接:https://blog.csdn.net/mayue_web/article/details/89021273

服务器

 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <string.h>
 #include <sys/select.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <unistd.h>
 
  #define SIZE   1024
  
 int main()
 {
      int ret;
      int fd[SIZE] = {0};
  
      //创建socket(文件)
      int sockfd = socket(PF_INET, SOCK_STREAM, 0);  
      //IPV4地址族     流式套接字(TCP)  具体的协议类型(默认0)
      if (-1 == sockfd)
      {
          perror("socket");
          exit(1);
      }
  
      int opt = 1;
      setsockopt(sockfd,SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));  
       //设置地址可以被复用(方便调试)

      struct sockaddr_in server_addr;   //保存服务器本身的信息
      struct sockaddr_in client_addr;   //保存客户端的信息
  
      memset(&server_addr, 0, sizeof(server_addr));   //清空结构体
      server_addr.sin_family = PF_INET;    //地址族  同socket第一个参数
      server_addr.sin_port = 7000;         
      //端口号(大于1024 小于65536) 客户地址可以被复用(方便调试)
      //查满手册,包含头文件 man inet_addr
      server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
      //ip地址 ifconfig>    获取  127.0.0.1回环ip(用于测试)
     
      //绑定信息
      ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr))    ;
      if (-1 == ret)
      {
          perror("bind");
          exit(1);
      }
  
      //设置监听队列
      ret = listen(sockfd, 10);
      if (-1 == ret)
      {
          perror("listen");
          exit(1);
      }
      
      fd_set readfd, tmpfd;   //集合
      FD_ZERO(&readfd);          //清空集合
      FD_SET(sockfd, &readfd);   //把sockfd添加到集合 
     int maxfd = sockfd;
  
      int length = sizeof(struct sockaddr_in);
      int i;
      char buf[128] = {0};
  
      while (1)
      {
          tmpfd = readfd;    //select每次会清空集合
          ret = select(maxfd + 1, &tmpfd, NULL, NULL, NULL); 
           //最后一个NULL表示阻塞
          if (-1 == ret)
          {
              perror("select");
              exit(1);
          }
  
         if (FD_ISSET(sockfd, &tmpfd))   //判断是否有客户端发起连接
         {
              printf("有客户端发起连接...\n");
              for (i = 0; i < SIZE; i++)
              { 
                  if (0 == fd[i])
                  {
                      break;
                  } 
              }
              fd[i] = accept(sockfd, (struct sockaddr *)&client_addr, &length)    ;   
              if (-1 == fd[i])
              { 
                  perror("accept");
                  exit(1);
              }
              printf("接受客户端%d的连接!\n", fd[i]);
  
              if (fd[i] > maxfd)
              {
                  maxfd = fd[i];
              }
              FD_SET(fd[i], &readfd);
          } 
         else     //有客户端发消息
         {
             for (i = 0; i < SIZE; i++)
             {
                 if (FD_ISSET(fd[i], &tmpfd))  //判断哪个文件描述符可读
                 {
                     ret = recv(fd[i], buf, sizeof(buf), 0);
                     if (-1 == ret)
                    {
                         perror("recv");
                         exit(1);
                     }
                     if (0 == ret)
                     {
                         printf("客户端%d异常下线\n", fd[i]);
                         close(fd[i]);   //关闭TCP连接
                         FD_CLR(fd[i], &readfd);       //从集合中清除
                         fd[i] = 0;
                         break;
                    }
                    if (!strcmp(buf, "bye"))
                     {
                         printf("客户端%d下线!\n", fd[i]);
                         close(fd[i]);                 //关闭TCP连接
                         FD_CLR(fd[i], &readfd);       //从集合中清除
                         fd[i] = 0;
                         break;
                     }
                     printf("收到%d客户端消息%s\n", fd[i], buf);
                     memset(buf, 0, sizeof(buf));
                     break;
                 }
             }
          }
     }
 
    return 0;
}

客户端

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
      
 int main() 
 {   
     int sockfd = socket(PF_INET, SOCK_STREAM, 0)
     if (-1 == sockfd)
     {
          perror("socket");
          exit(1);
      }
      
      //客户端向服务器发起连接
      struct sockaddr_in server_addr;
      memset(&server_addr, 0, sizeof(server_addr));
      //跟服务器保持一致
      server_addr.sin_family = PF_INET;
      server_addr.sin_port = 7000;
      server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
 
      int ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
      if (-1 == ret)
      {
          perror("connect");
          exit(1);
      }
 
      char buf[128] = {0};
      while (1)
      {
          scanf("%s", buf);
          ret = send(sockfd, buf, strlen(buf), 0); //write
          if (-1 == ret)
         {
              perror("send");
              exit(1);
         }
         if (!strcmp(buf, "bye"))
         {
              break;
          }
      }
      close(sockfd);   //关闭TCP连接
 
      return 0;
 }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值