본문 바로가기
CS/컴퓨터네트워크

[열혈] 멀티플렉싱 기반 서버구현

by sun__ 2020. 11. 24.

목적 : 멀티플렉싱 기반 서버 구현에 대한 이해, 멀티플렉싱 특징

 

프로그램 : 

1. 멀티플렉싱을 이용해서 다수의 클라이언트에 서비스. 단, 한번에 하나의 클라이언트만 처리함.

2. select함수 사용

 


 

멀티프로세스 기반 서버는 프로세스 생성에 상당한 오버헤드가 든다. IPC가 필요한 상황에서 코딩하기도 매우 힘들다.

 

멀티플렉싱 : 하나의 통신채널을 통해 둘 이상의 데이터(시그널)를 전송하는데 사용되는 기술.

 

->멀티플렉싱을 이용하면 하나의 프로세스로 다수의 client를 상대하는 서버를 구현할 수 있다.

 

멀티프로세스 / 멀티플렉싱

 


select함수와 사용되는 구조체

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

int select(int maxfd, fd_set *readset, fd_set *writeset, 
			fd_set *exceptset, const struct timeval * timeout);
            
/*
오류시 -1, 타임아웃 시 0 반환
readset, writeset, exceptset에 등록된 fd에 변화가 발생하면 변화가 발생한 fd의 개수 반환

maxfd : 검사 대상이 되는 파일 디스크립터 개수
readset : 수신 데이터 존재여부 검사
writeset : 데이터 전송(non-blocking)의 가능여부 검사
excetpset : 예외상황 발생여부 검사
timeout : 무한정 블로킹되지 않도록 timeout 설정
*/

/* 자료형 설명
timeval : 시간 설정
fd_set : 최대 1024개의 비트를 설정할 수 있는 구조체. 
-> FD_ZERO, FD_SET, FD_CLR, FD_ISSET사용해서 설정
*/

 

 

<echo_selectserv.c> 여태 사용했던 아무 echo_client 처리가능

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/select.h>

#define BUF_SIZE 100
void error_handling(char * buf);

int main(int argc, char ** argv){
    int serv_sock, clnt_sock;
    struct sockaddr_in serv_adr, clnt_adr;
    struct timeval timeout;
    fd_set reads, cpy_reads;

    socklen_t adr_sz;
    int fd_max, str_len, fd_num, i;
    char buf[BUF_SIZE];
    if(argc!=2){
	printf("Usage: %s <port>\n", argv[0]);
	exit(1);
    }
    
    serv_sock = socket(PF_INET, SOCK_STREAM, 0);
    memset(&serv_adr, 0, sizeof(serv_adr));
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_adr.sin_port = htons(atoi(argv[1]));

    if(bind(serv_sock, (struct sockaddr*) &serv_adr, sizeof(serv_adr))==-1)
	error_handling("bind() error");
    if(listen(serv_sock, 5)==-1)
	error_handling("listen() error");
    
    //~~서버소켓을 만들고 bind, listen하는것 똑같음
    
    FD_ZERO(&reads);
    FD_SET(serv_sock, &reads);	//데이터 수신여부를 관찰하는 대상에 서버소켓 포함시키기.
    fd_max = serv_sock;		//index = fd_max 까지 확인할 것. (개수는 fd_max+1)

    while(1){
	cpy_reads = reads;
        //timeout = 6
	timeout.tv_sec = 5;
	timeout.tv_usec = 5000;	

	if((fd_num = select(fd_max+1, &cpy_reads, 0 , 0, &timeout))==-1)//error
	    break;
	if(fd_num==0)							//timeout
	    continue;	

        //serv_sock에 변화가 있었다면 새로운 연결 요청 받았다는 것
        //그 외(당연히 3이상)에 변화가 있었다면 메세지를 수신한 것
	for(i=0; i<fd_max+1; i++){
	    if(FD_ISSET(i, &cpy_reads)){	//수신된 데이터가 있는 소켓 감지
		if(i==serv_sock){	    //connection request!
		    adr_sz = sizeof(clnt_adr);
		    clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, &adr_sz);
		    FD_SET(clnt_sock, &reads);

		    if(fd_max < clnt_sock)
			fd_max=clnt_sock;
		    printf("connected client: %d\n", clnt_sock);
		}
    		else{			    //read message!
		    str_len = read(i, buf, BUF_SIZE);
		    if(str_len==0){  //close request
			FD_CLR(i, &reads);
			close(i);
			printf("closed client: %d\n", i);
		    }
		    else{	    //echo
			write(i, buf, str_len);
		    }
		}
	    }
	}
    }
    close(serv_sock);
    return 0;
}

void error_handling(char * buf){
    fputs(buf, stderr);
    fputc('\n', stderr);
    exit(1);
}

'CS > 컴퓨터네트워크' 카테고리의 다른 글

TCP/IP (1)  (0) 2020.12.22
[열혈] 멀티쓰레드 기반 서버구현  (0) 2020.12.22
[열혈] 멀티 프로세스 기반 서버구현  (2) 2020.10.25
[열혈] dns  (0) 2020.10.24
[열혈] half close  (0) 2020.10.24