• socket之非阻塞


    非阻塞之多路复用

    fcntl()

    NAME
    fcntl - manipulate file descriptor

    SYNOPSIS

       #include <unistd.h>
       #include <fcntl.h>
    
       int fcntl(int fd, int cmd, ... /* arg */ );
    

    fcntl可以修改文件状态标志:

    File status flags
    Each open file description has certain associated status flags, initialized by open(2) and possibly modified by fcntl().

       The file status flags and their semantics are described in open(2).
    
       F_GETFL (void)
              Get the file access mode and the file status flags; arg is ignored.
    
       F_SETFL (int)
              Set the file status flags to the value specified by arg. On Linux this command can change only the O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK flags.
    

    实例:

    用fcntl给socket设置 O_NONBLOCK,所以在accept时资源不可用时,就以及返回。

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/wait.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/un.h>
    #include <sys/time.h>
    #include <sys/ioctl.h>
    #include <unistd.h>
    #include <netinet/in.h>
    #include <fcntl.h>
    
    #define SERVPORT 3333
    #define BACKLOG 10
    #define MAXDATASIZE 100
    
    int main()
    {
    	struct sockaddr_in server_sockaddr,client_sockaddr;
    	int sin_size = 0,recvbytes = 0,flags = 0;
    	int sockfd,client_fd;
    	char buf[MAXDATASIZE];
    
    	if((sockfd = socket(AF_INET,SOCK_STREAM,0))== -1){
    		perror("socket");
    		exit(1);
    	}
    	printf("socket success!,sockfd=%d
    ",sockfd);
    
    	server_sockaddr.sin_family=AF_INET;
    	server_sockaddr.sin_port=htons(SERVPORT);
    	server_sockaddr.sin_addr.s_addr=INADDR_ANY;
    	bzero(&(server_sockaddr.sin_zero),8);
    
    	if(bind(sockfd,(struct sockaddr *)&server_sockaddr,sizeof(struct sockaddr))== -1){
    		perror("bind");
    		exit(1);
    	}	
    	printf("bind success!
    ");
    
    	if(listen(sockfd,BACKLOG)== -1){
    		perror("listen");
    		exit(1);
    	}
    	printf("listening....
    ");
    
    	/* 调用 fcntl 函数设置非阻塞参数 */
    	if((flags=fcntl( sockfd, F_GETFL, 0)) < 0)
    		perror("fcntl F_SETFL");
    	flags |= O_NONBLOCK;
    	if(fcntl(sockfd,F_SETFL,flags)<0)
    		perror("fcntl");
    
    	while(1){
    		sin_size = sizeof(struct sockaddr_in);
    		if((client_fd=accept(sockfd,(struct sockaddr*)&client_sockaddr,&sin_size))== -1){
    			perror("accept");
    			exit(1);
    		}
    
    		if((recvbytes=recv(client_fd,buf,MAXDATASIZE,0))== -1){
    			perror("recv");
    			exit(1);
    		}
    
    		if(read(client_fd,buf,MAXDATASIZE)<0){
    			perror("read");
    			exit(1);
    		}	
    		printf("received a connection :%s",buf);
    	
    		close(client_fd);
    		exit(1);
    	}/*while*/
    }
    

    结果如下:

    xxx@xxx-pc:~/Documents$ ./a.out 
    socket success!,sockfd=3
    bind success!
    listening....
    accept: Resource temporarily unavailable
    

    select()

    SYNOPSIS

       /* According to POSIX.1-2001 */
       #include <sys/select.h>
    
       /* According to earlier standards */
       #include <sys/time.h>
       #include <sys/types.h>
       #include <unistd.h>
    
       int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);
    
       void FD_CLR(int fd, fd_set *set);    
       int  FD_ISSET(int fd, fd_set *set);  
       void FD_SET(int fd, fd_set *set);    
       void FD_ZERO(fd_set *set);
    
           struct timeval {
               long    tv_sec;         /* seconds */
               long    tv_usec;        /* microseconds */
           };
    

    Four macros are provided to manipulate the sets. FD_ZERO() clears a set. FD_SET() and FD_CLR() respectively add and remove a given file descriptor from a set. FD_ISSET() tests to see if a file descriptor is part of the set; this is useful after select() returns.

    readfds: 读文件描述符的集合,select检测该集合读变化,若该集合有文件可读,select返回大于0的数。如果没有可读,则等待timeout返回0,若发生错误返回负数。
    writefds:写文件描述符的集合。
    exceptfds:要检测是否异常的文件描述符集合。

    timeout的值大于0,若文件描述符的集合没有变化,则等待timeout时间返回。
    特例:timeout的结构体时间值都为0,则立马timeout,立即就返回了。
    如果timeout的参数设为0(NULL),则会一直阻塞直到文件描述符出现了变化。

    实例:

    server端:

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/wait.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/un.h>
    #include <sys/time.h>
    #include <sys/ioctl.h>
    #include <unistd.h>
    #include <netinet/in.h>
    
    #define SERVPORT 3333
    #define BACKLOG 10
    #define MAXDATASIZE 100
    
    int main()
    {
    	struct sockaddr_in server_sockaddr,client_sockaddr;
    	int sin_size,recvbytes;
    	fd_set readfd;
    	fd_set writefd;
    	int sockfd,client_fd;
    	char buf[MAXDATASIZE] = {0};
    	struct timeval time = {0,0};
    
    	if((sockfd = socket(AF_INET,SOCK_STREAM,0))== -1){
    		perror("socket");
    		exit(1);
    	}
    	printf("socket success!,sockfd=%d
    ",sockfd);
    
    	server_sockaddr.sin_family=AF_INET;
    	server_sockaddr.sin_port=htons(SERVPORT);
    	server_sockaddr.sin_addr.s_addr=INADDR_ANY;
    	bzero(&(server_sockaddr.sin_zero),8);
    
    	if(bind(sockfd,(struct sockaddr *)&server_sockaddr,sizeof(struct sockaddr))== -1){
    		perror("bind");
    		exit(1);
    	}	
    	printf("bind success!
    ");
    
    	if(listen(sockfd,BACKLOG)== -1){
    		perror("listen");
    		exit(1);
    	}
    	printf("listening....
    ");
    
    	/* 将调用 socket 函数的描述符作为文件描述符 */
    	FD_ZERO(&readfd);
    	FD_SET(sockfd,&readfd);
    
    	sin_size=sizeof(struct sockaddr_in);
    	while(1){
    		/* 调用 select 函数 */
    		if(select(sockfd+1,&readfd,NULL,NULL,0) > 0){
    			if(FD_ISSET(sockfd,&readfd) > 0){
    				if((client_fd = accept(sockfd,(struct sockaddr *)&client_sockaddr,&sin_size))== -1){
    					perror("accept");
    					exit(1);
    				}
    	
    				if((recvbytes = recv(client_fd,buf,MAXDATASIZE,0))== -1){
    					perror("recv");
    					exit(1);
    				}
    
    				printf("received a connection - %s
    ", buf);
    			}/*if*/
    			close(client_fd);
    		}/*select*/
    	}/*while*/
    }
    

    结果如下:

    xxx@xxx-pc:~/Documents$ ./server 
    socket success!,sockfd=3
    bind success!
    listening....
    received a connection - hello
    received a connection - hello
    received a connection - hello
  • 相关阅读:
    2.2 与球体相交-几何解
    2.1 与球体的交点 -代数解
    2 必要的光线追踪算法=>光线球体的相交和映射
    3.1 Matrix Properties
    chapter 3:Matriices
    4.8 渲染方程
    webstorm 皮肤(Sublime text)设置
    数字键盘(纯js)
    ios中设置readonly还会有光标?
    JS重要的坑
  • 原文地址:https://www.cnblogs.com/fuluwwa/p/6789996.html
Copyright © 2020-2023  润新知