I/O 재사용: 비동기식 채팅

8153 단어 I/O
하나.입출력 재사용
에서의 동기화 채팅 프로그램에서 TCP 고객이 표준 입력과 TCP 소켓 두 개의 입력을 동시에 처리하는 것을 보았습니다.고객이 표준 입력 fgets 호출에 막혔을 때 서버 프로세스가 죽는 것을 고려하여 서버 TCP는 고객 TCP에 FIN을 보내지만 고객 프로세스는 표준 입력 읽기 프로세스에 막힌다. 이 EOF는 플러그인에서 읽을 때까지 볼 수 없다.이러한 프로세스는 코어가 지정한 입출력 조건을 발견하면 프로세스에 알릴 수 있도록 코어에 미리 알려주는 기능을 필요로 합니다.이 능력은 I/O 복용이라고 하는데 select와poll 두 함수에 의해 지원됩니다.
입출력 재사용은 일반적으로 다음과 같은 경우에 적용됩니다.
  • 고객이 여러 응용 프로그램을 처리할 때(인터랙티브 입력과 네트워크 플러그인)
  • 한 고객이 여러 개의 플러그인을 동시에 처리한다
  • 하나의 TCP 서버는 감청 플러그인을 처리해야 할 뿐만 아니라 이미 연결된 플러그인도 처리해야 한다
  • 한 서버에서 TCP와 UDP를 모두 처리해야 합니다
  • 한 서버에서 여러 서비스나 여러 프로토콜을 처리해야 하는데..

  •  
    2.select 함수
    select 함수는 프로세스가 여러 이벤트 중 임의의 발생을 기다릴 수 있도록 합니다. 한 개 이상의 이벤트가 발생하거나 지정된 시간이 지나야만 깨울 수 있습니다.
    #include<sys/select.h>
    
    #include<sys/time.h>
    
    int select(int maxfdp1,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval *timeout);
    
    

    반환: 준비 설명자가 있으면 그 수를 반환하고, 시간을 초과하면 0을 반환하고, 오류가 발생하면 1을 반환합니다.
    헤더 파일 에 정의된 FD - SETSIZE 상수는 데이터 형식 fd_set의 설명자 총수, 그 값은 보통 1024입니다.
    maxfdp1 매개 변수는 테스트를 포함하는 설명자 개수를 지정합니다. 그 값은 테스트를 포함하는 최대 설명자 더하기 1, 설명자 0, 1, 2,...,maxfdp1-1 모두 테스트됩니다.
    중간 세 개의 매개 변수readset, writeset, exceptset은 내부 테스트를 읽기/쓰기, 이상 조건에 대한 설명자를 지정합니다.
    void FD_ZERO(fd_set *fdset);         //clear all bits in fdset
    
    void FD_SET(int fd,fd_set *fdset);   //turn on the bit for fd in fdset
    
    void FD_CLR(int fd,fd-set *fdset);    //turn off the bit for fd in fdset
    
    int FD_ISSET(int fd,fd_set *fdset);  //is the bit for fd on in fdset?
    
    

    그 중에서 묘사부호의 초기화는 매우 중요하다.
    파라미터timeout은 내부 핵이 지정한 설명자에 있는 모든 준비가 얼마나 걸릴지 알려줍니다. timeval 구조는 이 시간의 초수와 미묘수를 지정하는 데 사용됩니다.
    struct timeval
    
    {
    
         long tv_sec;    //second
    
         long tv_usec;   //microsecond
    
    };
    
    

    이 매개 변수는 세 가지 가능성이 있다.
  • 영원히 기다림: I/O가 준비되어 있을 때만 되돌아옵니다. 이 매개 변수를 비워 둡니다
  • 일정 시간 대기: I/O가 준비되었을 때 되돌아오지만timeval이 지정한 시간을 초과하지 않습니다
  • 전혀 기다리지 않습니다. 설명자를 검사한 후 바로 돌아갑니다. 이것을 폴링(polling)이라고 합니다. 이를 위해 초수와 미묘수는 0이어야 합니다

  •  
    셋.비동기식 채팅 프로그램
    TCP 비동기 채팅 프로그램을 작성하여 이해를 깊이 있게 하다.
    서버 코드:
    #include<stdio.h>
    
    #include<stdlib.h>
    
    #include<errno.h>
    
    #include<string.h>
    
    #include<sys/types.h>
    
    #include<arpa/inet.h>
    
    #include<netinet/in.h>
    
    #include<sys/socket.h>
    
    #include<sys/wait.h>
    
    #include <unistd.h>
    
    #include<time.h>
    
    
    
    #define MAXSIZE 1024
    
    #define PORT 8080
    
    #define BACKLOG 10
    
    
    
    int main(int argc,char **argv)
    
    {
    
    	int listenfd,connfd;
    
    	struct sockaddr_in servaddr,cliaddr;
    
    	socklen_t len;
    
    	char message[MAXSIZE];
    
    
    
    	fd_set rfds;
    
    //	struct timeval tv;
    
    	int retval,maxfd=-1;
    
    
    
    	if((listenfd=socket(AF_INET,SOCK_STREAM,0))==-1)
    
    	{
    
    		perror("socket");
    
    		exit(1);
    
    	}
    
    	else printf("socket create success!
    "); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=htonl(INADDR_ANY); servaddr.sin_port=htons(PORT); if((bind(listenfd,(struct sockaddr*)&servaddr,sizeof(struct sockaddr)))==-1) { perror("bind"); exit(1); } else printf("bind success!
    "); if(listen(listenfd,BACKLOG)==-1) { perror("listen"); exit(1); } else printf("sever is listening!
    "); for( ; ; ) { printf(" ...
    "); len=sizeof(struct sockaddr); if((connfd=accept(listenfd,(struct sockaddr*)&cliaddr,&len))==-1) { perror("accept"); exit(1); } else printf(" :%s: %d
    ",inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port)); printf(" !
    "); for( ; ; ) { FD_ZERO(&rfds); FD_SET(0,&rfds); maxfd=0; FD_SET(connfd,&rfds); if(connfd>maxfd) maxfd=connfd; retval=select(maxfd+1,&rfds,NULL,NULL,NULL); if(retval==-1) { printf("select !%s",strerror(errno)); break; } else if(retval==0) { printf(" ...
    "); continue; } else { if(FD_ISSET(0,&rfds)) { bzero(message,MAXSIZE); printf(" :"); fgets(message,MAXSIZE,stdin); if(!strncasecmp(message, "quit", 4)) { printf(" !
    "); break; } else len=send(connfd,message,strlen(message),0); if(len<0) { printf(" "); break; } } if(FD_ISSET(connfd,&rfds)) { bzero(message,MAXSIZE); len=recv(connfd,message,MAXSIZE,0); if(len>0) printf(" :%s",message); else { if(len<0) printf(" !
    "); else printf(" !
    "); break; } } } } close(connfd); printf(" [Y/N]:"); bzero(message,MAXSIZE); fgets(message,MAXSIZE,stdin); if(!strncasecmp(message, "Y", 1)) { printf(" !
    "); break; } } close(listenfd); return 0; }

    클라이언트 코드:
    #include <stdio.h>
    
    #include <stdlib.h>
    
    #include <string.h>
    
    #include <errno.h>
    
    #include <sys/socket.h>
    
    #include <arpa/inet.h>
    
    #include <netinet/in.h>
    
    #include <sys/types.h>
    
    #include <unistd.h>
    
    #include <time.h>
    
    
    
    #define MAXSIZE 1024
    
    #define PORT 8080
    
    
    
    int main(int argc, char **argv)
    
    {
    
        int sockfd;
    
        struct sockaddr_in servaddr;
    
        socklen_t len;
    
    	fd_set rfds;
    
    //	struct timeval tv;
    
    	int retval,maxfd=-1;
    
    
    
        char message[MAXSIZE];    
    
        
    
        if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
    
    	{
    
            perror("socket");
    
            exit(1);
    
        }
    
    	else printf("socket create success!
    "); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(PORT); inet_aton(argv[1],&servaddr.sin_addr); if(connect(sockfd,(struct sockaddr*)&servaddr,sizeof(struct sockaddr))==-1) { perror("connect"); exit(1); } else printf("conncet success!
    "); for( ; ; ) { FD_ZERO(&rfds); FD_SET(0,&rfds); maxfd=0; FD_SET(sockfd,&rfds); if(sockfd>maxfd) maxfd=sockfd; retval=select(maxfd+1,&rfds,NULL,NULL,NULL); if(retval==-1) { printf("select !%s",strerror(errno)); break; } else if(retval==0) { printf(" ...
    "); continue; } else { if(FD_ISSET(sockfd,&rfds)) { bzero(message,MAXSIZE); len=recv(sockfd,message,MAXSIZE,0); if(len>0) printf(" :%s",message); else { if(len<0) printf(" !
    "); else printf(" !
    "); break; } } if(FD_ISSET(0,&rfds)) { bzero(message,MAXSIZE); printf(" :"); fgets(message,MAXSIZE,stdin); if(!strncasecmp(message, "quit", 4)) { printf("client !
    "); break; } else len = send(sockfd,message,strlen(message),0); if(len<0) { printf(" !
    "); break; } } } } close(sockfd); return 0; }

    컴파일:
    gcc -Wall server.c -o server
    
    gcc -Wall client.c -o client
    
    

    서버 실행 결과:
    ./server 
    
    socket create success!
    
    bind success!
    
    sever is listening!
    
     ...
    
     :127.0.0.1: 50235
    
     !
    
     :
    
     : , !
    
     : 。
    
    
    
     : , !
    
     : :
    
     :Byebye!
    
     !
    
     [Y/N]:Y
    
     !
    
    

    클라이언트 실행 결과:
    ./client 127.0.0.1
    
    socket create success!
    
    conncet success!
    
    
    
     : , !
    
     : 。 
    
     : :
    
     : , !
    
    
    
     :Byebye!
    
     :quit
    
     :client  !
    
    

     

    좋은 웹페이지 즐겨찾기