Multiplexing File Descriptor

EEEFFEE·2023년 11월 20일
0

네트워크

목록 보기
8/9

23.11.20 최초 작성

1. select

  • select() : I/O 멀티플렉싱 시스템 콜, 여러개의 파일 디스크립터 감시
  • 어떤 디스크립터가 읽기/쓰기 일어났는지 확인해 해당 디스크립터 선택
  • 이를 통해 단일 프로세스가 여러개의 I/O 처리

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/select.h>

int select(int nfds, fd_set *readfds, fd_set *writefds, 
			fd_set *exceptfds, struct timeval *timeout);
            
///
nfds : 확인할 파일 디스크립터의 범위를 지정. 확인할 파일 디스크립터의 값 중 가장 큰 값 + 1
readfds : 읽기 가능한 상태를 확인할 파일 디스크립터의 집합
writefds : 쓰기 가능한 상태를 확인할 파일 디스크립터의 집합
exceptfds : 예외 상태를 확인할 파일 디스크립터의 집합
timeout : select 함수가 블록되는 시간을 설정. NULL이면 무한 대기

Return
-1 : Fail
0 : timeout
else : 한개 이상의 파일 디스크립터가 준비됨

int n;
fd_set mask;
FD_SET(n, &mask)				//fd_set테이블에 검사할 파일 목록에 n 파일 디스크립터 추가
FD_CLR(n, &mask)				//fd_set테이블에 검사할 파일 목록 해제
result = FD_ISSET(n, &mask)		//fd_set테이블에 n번 파일 디스크립터가 설정되었는지 확인
FD_ZERO(&mask)					//mask의 비트 0으로 초기화

ex) 예제


#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>

int main(int argc, char *argv[]) {
	struct sockaddr_in server, remote;
	int request_sock, new_sock;
	int i, nfound, fd, maxfd, bytesread, addrlen;
	fd_set rmask, mask;
	static struct timeval timeout = { 5, 0 }; /* 5 seconds */

	char buf[BUFSIZ];
	if (argc != 2) {
		(void) fprintf(stderr,"usage: %s port\n",argv[0]);
		exit(1);
	}
	if ((request_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
		perror("socket");
		exit(1);
	}

	memset((void *) &server, 0, sizeof server);
	server.sin_family = AF_INET;
	server.sin_addr.s_addr = INADDR_ANY;
	server.sin_port = htons((u_short)atoi(argv[1]));
	if (bind(request_sock, (struct sockaddr *)&server, sizeof server) < 0) {
		perror("bind");
		exit(1);
	}
	if (listen(request_sock, SOMAXCONN) < 0) {
		perror("listen");
		exit(1);
	}

	FD_ZERO(&mask);
	FD_SET(request_sock, &mask);
	maxfd = request_sock;
	for (;;) {
		rmask = mask;
        
        //read의 경우만 가능한지 감시
		nfound = select(maxfd + 1, &rmask, (fd_set *)0, (fd_set *)0, &timeout);
		if (nfound < 0) {
			if (errno == EINTR) {
				printf("interrupted system call\n");
				continue;
			}
			/* something is very wrong! */
			perror("select");
			exit(1);
		}
		if (FD_ISSET(request_sock, &rmask)) {
			/* a new connection is available on the connetion socket */
			addrlen = sizeof(remote);
			new_sock = accept(request_sock,
				(struct sockaddr *)&remote, (socklen_t *)&addrlen);
			if (new_sock < 0) {
				perror("accept");
				exit(1);
			}
			printf("connection from host %s, port %d, socket %d\n",
				inet_ntoa(remote.sin_addr), ntohs(remote.sin_port),
				new_sock);
			FD_SET(new_sock, &mask);
			if (new_sock > maxfd)
				maxfd = new_sock;
			FD_CLR(request_sock, &rmask);
		}
		for (fd = 4; fd <= maxfd ; fd++) {
			/* look for other sockets that have data available */
			if (FD_ISSET(fd, &rmask)) {
				/* process the data */
				bytesread = read(fd, buf, sizeof (buf) - 1);
				if (bytesread < 0) {
					perror("read");
					/* fall through */
				}
				if (bytesread<=0) {
					printf("server: end of file on %d\n",fd);
					FD_CLR(fd, &mask);
					if (close(fd)) perror("close");
					continue;
				}
				buf[bytesread] = '\0';
				printf("%s: %d bytes from %d: %s\n",
					argv[0], bytesread, fd, buf);
				for(i = 0; i < bytesread; i++)
					buf[i] = toupper(buf[i]);

				/* echo it back */
				if (write(fd, buf, bytesread) != bytesread)
					perror("echo");
			}
		}
	}
}


0개의 댓글

관련 채용 정보