当前位置:网站首页>Select for i/0 multiplexing

Select for i/0 multiplexing

2022-06-22 02:39:00 Think and act 66

I/0 Multiplexer select

1.select effect

The system provides select Function to implement multiplexing input / Output model :

  • select Call is used to let our program monitor the status changes of multiple file descriptors
  • The program will stop at select Wait here , Until one or more of the monitored file descriptors have changed state

2.select The function prototype

  • int select(int nfds,fd_set* readfds,fd_set* exceptfds,struct timeval* timeout);
  • nfds: The value is the value of the maximum file descriptor +1, The function is to control select Polling monitoring range for
  • resdfds: Read event collection
  • writefds: Write event set
  • exceptfds: Exception event collection
  • timeout: Block mode delivery NULL, Non blocking delivery 0, With timeout , Used to set select() The waiting time of

3. About fd_set Structure

Is an array of integers , More strictly speaking, it is a “ Bitmap ”, Use the corresponding bit in the bitmap to indicate the file descriptor to monitor :
 Insert picture description here
 Insert picture description here

4. operation fd_set The interface of

  • void FD_CLR(int fd, fd_set *set); // take fd From the event collection set Removed from , It's essentially fd The corresponding bit position is 0
  • int FD_ISSET(int fd, fd_set *set); // Judge fd Whether the file descriptor is in the collection set among , It's essentially judgment fd Whether the corresponding bit is 0, The return value is 0 Express fd be not in set among , by 1 It means that
  • void FD_SET(int fd, fd_set *set); // Set file descriptor to set In the event set , In essence, it's fd The corresponding bit position is 1
  • void FD_ZERO(fd_set *set); // Used to empty the event collection , In essence, it's set All bit positions in the are 0

5.select How to use

  • select There are three event sets : Read event collection , Write event set , Exception event collection
  • When you need to focus on an event of a file descriptor , Add a file descriptor to the corresponding event set
    for example : Focus on 0 Read event of file descriptor No , Will 0 No. file descriptor is added to the read event set readfds
  • If you don't pay attention to certain events , Is to select When passing parameters , Pass on NULL

6.select The return value of

  • The return value is the number of ready file descriptors
  • The ready file descriptor is stored in the event set and returned to the caller
    Be careful :select File descriptors that are not ready will be removed from the event set , Therefore, it is necessary to add again when monitoring again

7.select test

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

int main(){
    
	int listen_sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	if(listen_sockfd<0){
    
		perror("socket");
		return 0;
	}
	
	struct sockaddr_in addr;
	addr.sin_familt=AF_INET;
	addr.sin_port=htons(29090);
	addr.sin_addr.s_addr=inet_addr("0.0.0.0");
	int ret=bind(listem_sockfd,(struct sockaddr*)&addr,sizeof(addr));
	if(ret<0){
    
		perror("bind");
		return 0;
	}
	
	listen(listen_sockfd,5);
	
	fd_set readfds;
	FD_ZERO(&readfds);
  FD_SET(0, &readfds);
  FD_SET(listen_sockfd, &readfds);
	
	while(1){
    
		fd_set tmp=readfds;
		int ret=select(listen_sockfd+1,&tmp,NULL,NULL,NULL);
		printf("ret:%d\n",ret);
		
		if(FD_ISSET(0,&tmp)){
    
			char buf[1024]={
    0};
			read(0,buf,sizeof(buf)-1);
			printf("buf:%s",buf);	
		}else{
    
			printf("0 is not in readfds\n");
		}
		
		if(FD_ISSET(listen_sockfd,&tmp)){
    
			printf("listen_sockfd read\n");
			accept(listen_sockfd,NULL,NULL);
		}else{
    
			printf("listen_sockfd not in readfds\n");
		}
	}
	return 0;
}

8.select_tcp

The header file my_select.hpp:

#pragma once
#include <stdio.h>
#include <unistd.h>
#include <sys/select.h>
#include <vector>

class SelectSvr{
    
	public:
		SelectSvr(){
    
			//1. Empty event collection + initialization max_fd
			FD_ZERO(&readfds_);
			max_fd_=-1;	
		}
		~SelectSvr(){
    }
		void AddFd(int fd){
    
			// Add and update the maximum file descriptor 
			FD_SET(fd,&readfds_);
			if(fd>max_fd_){
    
				max_fd_=fd;	
			}
		}
		void DeleteFd(int fd){
    
			// Remove the file descriptor and update 
			FD_CLR(fd,&readfds_);
			for(int i=max_fd_;i>==0;i--){
    
				if(FD_ISSET(i,&readfds_)){
    
					max_fd_=i;
					break;	
				}	
			}	
		}
		int Select(std::vetcor<int>* vec){
    
			int ret=-1;
			while(1){
    
				fd_set tmp=readfds_;
				ret=select(max_fd_+1,&tmp,NULL,NULL,NULL);
				if(ret<0){
    
					return ret;
				}else if(ret==0){
    
					continue;
				}
				for(int i=0;i<max_fd_;i++){
    
					if(FD_ISSET(i,&tmp)){
    
						vec->push_back(i);
					}	
				}
				break;
			}
			return ret;
		}
		private:
			fd_set readfds_;
			int msx_fd_;
};

main.cpp:

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#include "my_select.hpp"

/* * 1.tcp Initialization work  * 2.select monitor  * 3. Handle according to the monitoring  * listen_sock * new_sockfd * */

int main(){
    
    int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
    if(listen_sock < 0){
    
        perror("socket");
        return 0;
    }

    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port  = htons(39090);
    addr.sin_addr.s_addr = inet_addr("0.0.0.0");
    int ret = bind(listen_sock, (struct sockaddr*)&addr, sizeof(addr));
    if(ret < 0){
    
        perror("bind");
        return 0;
    }

    listen(listen_sock, 5);

    SelectSvr ss;
    ss.AddFd(listen_sock);

    while(1){
    
        std::vector<int> vec;
        int ret = ss.Select(&vec);
        if(ret < 0){
    
            continue;
        }

        for(size_t i = 0; i < vec.size(); i++){
    
            if(listen_sock == vec[i]){
    
                // Listening socket 
                struct sockaddr_in peer_addr;
                socklen_t peer_addr_len = sizeof(peer_addr);
                int new_sockfd = accept(listen_sock, (struct sockaddr*)&peer_addr, &peer_addr_len);
                if(new_sockfd < 0){
    
                    continue;
                }

                ss.AddFd(new_sockfd);
                printf("recv new link, ip : %s, port : %d\n", inet_ntoa(peer_addr.sin_addr), ntohs(peer_addr.sin_port));
            }else{
    
               //  New connection socket has data coming 
               
               char buf[1024] = {
    0};
               ssize_t recv_size = recv(vec[i], buf, sizeof(buf) - 1,  0);
               if(recv_size < 0){
    
                   continue;
               }else if(recv_size == 0){
    
                   ss.DeleteFd(vec[i]);
                   close(vec[i]);
               }else{
    
                    printf("[%d sockfd] %s\n", vec[i], buf);
               }

            }
        }

    }



    return 0;
}

原网站

版权声明
本文为[Think and act 66]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/172/202206211709325039.html