• I/O multiplexing
    : synchronous, Blocking I/O 형태의 멀티 프로세스 서버, 멀티 스레드 서버 모두 고성능 서버로는 부적합하다.
    : 클라이언트마다 프로세스나 스레드를 할당하면 Context Switching 문제로 메모리적인 문제가 발생한다.
    -> 멀티플렉싱 개념 필요

    - poll
      ■ 1_poll
       : mkfifo fifo 파이프 만들기
       : IPC 전용 메커니즘
       : cat > myfifo로 리다이렉션

    #include <unistd.h>
    
    #include <stdio.h>
    #include <fcntl.h>
    
    int main()
    {
    	char buff[100];
    	int ret;
    
    	int fd = open("myfifo", O_RDWR);
    
    	while (1)
    	{
    		ret = read(0, buff, sizeof buff);
    		buff[ret] = '\0';
    		printf("Keyboard : %s\n", buff);
    
    		ret = read(fd, buff, sizeof buff);
    		buff[ret] = '\0';
    		printf("myfifo : %s\n", buff);
    	}
    }
    

      ■ 2_poll
    #include <unistd.h>
    
    #include <stdio.h>
    #include <fcntl.h>
    
    #include <poll.h>
    
    int main()
    {
    	char buff[100];
    	int ret;
    
    	int fd = open("myfifo", O_RDWR);
    
    
    	// 비동기적으로 이벤트를 처리할 디스크립터 배열
    	struct pollfd fds[2];
    
    	while (1)
    	{
    		fds[0].fd = 0;
    		fds[0].events = POLLIN;  // 관심 있는 이벤트의 종류
    														 // read  : POLLIN
    														 // write : POLLOUT
    
    		fds[1].fd = fd;
    		fds[1].events = POLLIN;
    
    
    		poll(fds, 2, -1);
    
    
    		// 주의할 점 : 이벤트가 동시에 발생할 수 있으므로
    		//             절대 else 로 묶으면 안된다.
    		if (fds[0].revents & POLLIN) 
    		{
    			ret = read(0, buff, sizeof buff);
    			buff[ret] = '\0';
    			printf("Keyboard : %s\n", buff);
    		}
    
    		if (fds[1].revents & POLLIN)
    		{
    			ret = read(fd, buff, sizeof buff);
    			buff[ret] = '\0';
    			printf("myfifo : %s\n", buff);
    		}
    	}
    }
    


    - select (참고: http://ozt88.tistory.com/21)
     : select는 싱글스레드로 다중 I/O를 처리하는 멀티플렉싱 통지모델의 가장 대표적인 방법이다.
     : 해당 파일 디스크립터가 I/O를 할 준비가 되었는지 알 수 있다면, 그 파일 디스크립터가 할당받은 커널 Buffer에 데이터를 복사해주기만 하면 된다. 이런 목적하에 통지모델은 파일디스크립터의 상황을 파악할 수 있게 하는 기능을 할 수 있어야한다. select는 많은 파일 디스크립터들을 한꺼번에 관찰하는 FD_SET 구조체를 사용하여 빠르고 간편하게 유저에게 파일 디스크립터의 상황을 알려준다.
     : select를 사용해서 I/O의 상황을 알기 위해서는 프로세스가 커널에게 직접 상황 체크를 요청해야한다. 프로세스가 커널의 상황을 지속적으로 확인하고 그에 맞는 대응을 하는 형태로 구성되기 때문에 프로세스와 커널이 서로 동기화된 상태에서 정보를 주고 받는 형태로 볼 수 있다. 따라서 select의 통지형태를 동기형 통지방식이라 부를 수 있다. 그리고 select 그 자체는 I/O를 담당하지 않지만, 통지하는 함수의 호출방식이 timeout에 따라 non-blocking 또는 blocking 형태가 된다. timeout을 설정하지 않으면, 관찰 대상이 변경되지 않는 이상 반환되지 않으므로 blocking 함수가 되고, timeout이 설정되면 주어진 시간이 지나면 시간이 다되었다는 정보를 반환하므로 non-blocking 함수가 된다. 

    #include  <stdio.h>
    
    #include  <unistd.h>
    #include  <sys/types.h>
    #include  <sys/select.h>
    #include  <sys/socket.h>
    
    #include  <arpa/inet.h>
    #include  <netinet/in.h>
    
    inline int max(int a, int b)
    {
    	return a > b ? a : b;
    }
    
    int main()
    {
    	int sock = socket(PF_INET, SOCK_STREAM, 0);
    
    	struct sockaddr_in saddr = {0, };
    	saddr.sin_family = AF_INET;
    	saddr.sin_port = htons(4000);
    	saddr.sin_addr.s_addr = INADDR_ANY; // 0.0.0.0
    
    	int option = true;
    	socklen_t optlen = sizeof(option);
    	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &option, optlen);
    
    	bind(sock, (struct sockaddr*)&saddr, sizeof saddr);
    	listen(sock, 5);
    
    	// fd_set : bit array
    	fd_set socks;					// source data
    	fd_set readsocks;
    
    	FD_ZERO(&socks);
    	FD_SET(sock, &socks);
    
    	int maxfds = sock;
    
    	while (1) 
    	{
    		readsocks = socks;
    
    		int ret = select(maxfds + 1, &readsocks, 0, 0, 0);
    		printf("ret : %d\n", ret);
    
    		for (int i = 0 ; i < maxfds + 1 ; ++i)
    		{
    			if (FD_ISSET(i, &readsocks))
    			{
    				if (i == sock)
    				{
    					struct sockaddr_in caddr = {0, };
    					socklen_t clen = sizeof(caddr);
    					int csock = accept(sock, (struct sockaddr*)&caddr, &clen);
    
    					char* cip = inet_ntoa(caddr.sin_addr);
    					printf("Connected from %s\n", cip);
    
    					// 새로운 연결을 등록해주어야 한다.
    					FD_SET(csock, &socks); 
    					maxfds = max(maxfds, csock);
    				}
    				else
    				{
    					int csock = i;
    					char buf[1024];
    					int n = read(csock, buf, sizeof buf);
    					
    					if (n <= 0)
    					{
    						printf("연결 종료!!\n");
    						close(csock);
    
    						// 종료된 디스크립터를 등록 해지해야 한다.
    						FD_CLR(csock, &socks);
    					} 
    					else
    						write(csock, buf, n);
    
    				}
    			} 
    		}
    
    #if 0
    		while (1)
    		{
    			char buf[1024];
    			int n = read(csock, buf, sizeof buf);
    			if (n == 0)
    				close(csock);
    			else if (n == -1)
    				close(csock);
    
    			write(csock, buf, n);
    		}
    #endif
    	}
    
    	close(sock);
    }
    


+ Recent posts