select模型代码2

前言:关于select原理,只有弄懂 了内核的工作原理之后,才能真正明白。在CSDN上找了很多文章,要么是列出实践代码写一个服务器,要么是分析源码,都是一头雾水看不懂,所以推荐这篇讲原理的文章,先看明白

讲epoll原理的但是先讲了select

B站对应视频课时

上篇代码的缺点:总是感觉for循环,从监听描述符+1 开始遍历,到maxfd结束遍历的代码有点点奇怪,我反正是看不明白。这是第54课中,老师第二次优化的代码,但是我又删掉了maxi这个变量 ( - -就算遍历到1024,总比代码看不明白要好)

这里只有服务器代码!客户端代码网上任意搜一个

//select模型  第二次代码,将所有文件描述符放金一个数组中,减少便利此书 
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <sys/select.h>
#include <errno.h>

int main() {
    int sfd = socket(AF_INET, SOCK_STREAM, 0); 
    //设置端口复用
    int opt =1;
    setsockopt ( sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));
   
    //定义一个地址结gou体
    struct sockaddr_in servad;
    bzero(&servad, sizeof( servad));
    servad.sin_family =AF_INET;
    servad.sin_port =htons(8888);
    servad.sin_addr.s_addr = htonl (INADDR_ANY);
 
    int ret = bind(sfd, (struct sockaddr*)&servad, sizeof( servad));
 
    //将socket从主动变为被动(服务器必备),这样可以监听来自客户的请求
    listen(sfd,128);  
     //select 模型的相关参数 设置  
     //定义fd_set 类型的变量, 并且清空它们
    fd_set readfds, tmpfds;
    FD_ZERO ( &readfds);
    FD_ZERO ( &tmpfds);
    //把sfd加入到readfds中,让内核监视sfd的变化
    FD_SET (sfd, &readfds);

    int maxfd = sfd;
    int newfd ;
    int i ;
    int nready =0;
    int sockfd;
    char buf[FD_SETSIZE];
    int connfd[FD_SETSIZE];
    //保存所有有效的 文件描述符
    for (i =0;i<FD_SETSIZE; i++){
	connfd[i] =-1;
    }
    while (1) {
        tmpfds = readfds;
        //因为超时时间设置为NULL ,所以进程会无限阻塞在这一步,除非有了变化才往下走
    	nready = select (maxfd+1, &tmpfds, NULL, NULL, NULL);
        if (nready >0) { 
             //两种情况,第一种,有新的连接请求。注意,tmpfds  已经变化了,但是readfds没有变化
             if ( FD_ISSET (sfd, &tmpfds)) {
                 newfd = accept (sfd,NULL, NULL);
	         if (newfd<0) {
		      if(errno ==ECONNABORTED ||errno == EINTR){
			    continue;
	              }
		    break;
	         }
	         //在数组里找一个最靠前的,还是-1的地方,替换成newfd
	         for (i =0; i<FD_SETSIZE; i++){
	            if( connfd[i] ==-1) {
			connfd [i] =newfd;
			break;
		    }
		 }
		    //如果整个数组都不是-1了说明存满了文件描述符
		    if (i ==FD_SETSIZE){
		        printf("connfd array is full \n");
   			close(newfd);
		   	continue;
		    }
                    //将newfd纳入内核的监控范围
                    FD_SET ( newfd ,&readfds );  
                    if (maxfd <  newfd) {
                        maxfd = newfd;
                    } 
            }    	
            //第二种情况,目前的文件描述符,有新的内容到了缓冲区了 ..主要是for循环里的东西不懂
            //因为后面i 有变化,所以先定义sockfd = i
           for ( i= 0; i <FD_SETSIZE; i++) {
               sockfd = i;    
               if (FD_ISSET (sockfd, &tmpfds) ){
		           char buf[1024];
                   //读数据
                   memset(buf,0x00,sizeof(buf));
                   int n =read (sockfd, buf, sizeof(buf));
                   if (n <=0){ 
                      printf(" read error or client close ,n==[%d]\n", n); 
                      close (sockfd);
                      FD_CLR (sockfd, &readfds);
                      //把这个位置让出来,又可以填充-1了
                      connfd[i] = -1;
                   }
                   else {
                       printf ("这里是服务器端n =%d ,读到的是%s \n", n,buf);
                       //将小写字母都转化wie大写
                       for (int j =0; j<n; j++) { 
                           buf[j] =toupper (buf[j]); 
                       }    // ctype.h头文件
                       //发送数据
                      write (sockfd, buf, n);
                  }
              }
           }
      }
    }

  • 12
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
select模型和epoll模型都属于多路转接模型,用于处理大量客户端并发需求中的socket模型问题。 select模型的操作流程是通过调用select函数,将需要进行I/O操作的文件描述符集合传递给内核,内核会监视这些文件描述符是否有可读或可写事件发生,然后返回就绪的文件描述符集合给应用程序进行处理。select模型代码操作包括设置文件描述符集合、调用select函数以及处理返回的就绪文件描述符集合。select模型的优缺点分析:优点是跨平台支持良好,适用于小规模的并发连接;缺点是效率低下,当并发连接数量增多时,每次都需要遍历整个文件描述符集合。 epoll模型的操作流程是通过调用epoll_ctl函数注册要监视的文件描述符以及关注的事件类型,然后通过调用epoll_wait函数等待事件的发生,一旦有就绪事件发生,内核会将就绪的事件信息返回给应用程序进行处理。epoll模型代码操作包括注册文件描述符和事件、调用epoll_wait函数等待事件的发生以及处理返回的就绪事件。epoll模型的监控流程是由内核负责监视文件描述符的状态变化,并在有就绪事件时通知应用程序。epoll模型具有高效的事件通知机制,能够支持大规模的并发连接。它使用了事件驱动的方式,只需要关注就绪的事件,避免了无效的遍历,因此效率更高。 select模型和epoll模型的主要区别在于效率和可扩展性方面。select模型适用于小规模的并发连接,而epoll模型适用于大规模的并发连接。epoll模型通过使用内核事件通知机制,只关注就绪的事件,避免了无效的遍历,因此在处理大量并发连接时具有更高的效率。但是,epoll模型的使用需要更多的代码和复杂的管理逻辑。 总结起来,select模型适用于小规模的并发连接,而epoll模型适用于大规模的并发连接,并且具有更高的效率和可扩展性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [【Linux】多路转接之select、poll、epoll模型](https://blog.csdn.net/weixin_43939593/article/details/106651301)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [socket网络通信模型select与epoll](https://blog.csdn.net/chenlycly/article/details/123717804)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值