인터넷프로토콜 6 장 중급소켓프로그래밍 (2)
목차 제 6 장중급소켓프로그래밍 6.1 소켓옵션 6.2 시그널 6.3 넌블로킹입 / 출력 6.4 멀티태스킹 6.5 멀티플렉싱 6.6 다수의수신자처리 2
시그널 (Signal) 시그널이란? 예상치않은이벤트발생에따른일종의소프트웨어인터럽트 Ex) ctrl + c, ctrl + z, 자식프로세스의종료 외부에서프로세스에게전달할수있는유일한통로 인터럽트와의차이점 인터럽트는 H/W 에의해 OS 로전달됨 시그널은 OS 에의해프로세스로전달됨 시그널값의확인 /usr/include/signal.h /usr/include/bits/signum.h 3
/usr/include/bits/signal.h #define SIGHUP 1 /* hangup */ #define SIGINT 2 /* interrupt, ctrl + c */ #define SIGQUIT 3 /* quit */ #define SIGILL 4 /* illegal instruction (not reset when caught) */ #define SIGTRAP 5 /* trace trap (not reset when caught) */ #define SIGIOT 6 /* IOT instruction */ #define SIGABRT 6 /* used by abort, replace SIGIOT in the future */ #define SIGEMT 7 /* EMT instruction */ #define SIGFPE 8 /* floating point exception */ #define SIGKILL 9 /* kill (cannot be caught or ignored) */ #define SIGBUS 10 /* bus error */ #define SIGSEGV 11 /* segmentation violation */ #define SIGSYS 12 /* bad argument to system call */ #define SIGPIPE 13 /* write on a pipe with no one to read it */ #define SIGALRM 14 /* alarm clock */ #define SIGTERM 15 /* software termination signal from kill */ #if defined( rtems ) #define SIGURG 16 /* urgent condition on IO channel */ #define SIGSTOP 17 /* sendable stop signal not from tty */ #define SIGTSTP 18 /* stop signal from tty */ #define SIGCONT 19 /* continue a stopped process */ #define SIGCHLD 20 /* to parent on child stop or exit */ #define SIGCLD 20 /* System V name for SIGCHLD */ #define SIGTTIN 21 /* to readers pgrp upon background tty read */ #define SIGTTOU 22 /* like TTIN for output if (tp->t_local<ostop) */ #define SIGIO 23 /* input/output possible signal */ #define SIGPOLL SIGIO /* System V name for SIGIO */ #define SIGWINCH 24 /* window changed */ #define SIGUSR1 25 /* user defined signal 1 */ #define SIGUSR2 26 /* user defined signal 2 */ 4
커널이시그널을처리하는방법 각시그널은시그널처리기 (signal handler) 를통해기본동작으로수행 가능한기본동작 커널이시그널을무시 사용자에게통지하지않고프로세스를종료 프로그램이인터럽트되며시그널처리루틴이실행 시그널이블로킹됨 Name Default action Description SIGINT Quit Interrupt SIGILL Dump Illegal instruction SIGKILL Quit Kill SIGSEGV Dump Out of range addr SIGALRM Quit Alarm clock SIGCHLD Ignore Child status change SIGTERM Quit Sw termination sent by kill 5
시그널처리과정 시그널처리과정 1. 시그널이프로세스로보내질때, OS 는해당프로세스를중지 2. 시그널처리기가실행되고내부루틴이실행됨 3. OS 는중지되었던해당프로세스를재실행 6
sigaction() 을이용한시그널처리 시그널과시그널핸들러를연결시켜주는함수 특정시그널에대한기본동작을바꾸어준다 #include <signal.h> int sigaction(int signo, const struct sigaction *act, int signo: 시그널번호 sigaction act: 새로운동작이정의된 sigaction sigaction old: 이전동작이저장된 sigaction struct sigaction { } struct sigaction *oldact ); void (*sa_handler)( int ); /* 시그널핸들러지정 */ sigset_t sa_mask; /* 블록될시그널마스킹 */ int sa_flags; /* 시그널의설정변경 */ 7
sigaction() 을이용한시그널처리 /* SIGINT 의기본동작은프로그램의종료이다. 기본핸들러를바꾸어서종료되지않고화면에문자열을출력되도록한다. */ void handler(int sig); int main(){ struct sigaction act; act.sa_handler = handler; /* 시그널핸들러연결 */ sigemptyset( &act.sa_mask ); /* 블록할시그널없음 */ act.sa_flags = 0; /* 기본동작으로설정 */ sigaction( SIGINT, &act, 0 ); /* SIGINT 과 handler 연결 */ } while(1) { printf("hello World!\n"); sleep(1); } void handler(int sig) { printf( type of signal is %d \n, sig); } 8
타임아웃 (SIGALM 시그널 ) 예제 SIGALM 시그널이란? alarm(int) 함수에의해발생하며 int 초이후발생 처리기의기본동작은프로세스종료 이를수정하여화면에문자열출력 void timer(int sig) { puts( alarm!! \n"); } exit(0); int main(int argc, char **argv) { struct sigaction act; act.sa_handler=timer; sigemptyset(&act.sa_mask); act.sa_flags=0; state=sigaction(sigalrm, &act, 0); alarm(5); } 9 while(1){ puts( wait"); sleep(2); } return 0;
SIGCHLD 시그널 SIGCHLD 시그널이란? fork() 로인해복제된프로세스중, 자식프로세스가종료되면부모프로세스에게전달되는시그널 10
wait() vs waitpid() wait() 자식프로세스가반환될때까지블럭됨 #include <sys/types.h> #include <sys/wait.h> pid_t wait(int * status) waitpid() WNOHANG 옵션을이용하면자식프로세스가반환될때까지블록되지않음 시그널의계류 (pending) 특성으로인해 SIGCHLD 시그널은한번도착했지만현재종료된자식프로세스는여러개일수있음 따라서넌블럭 waitpid 를반복호출하여남아있는좀비프로세스의제거가가능 #include <sys/types.h> #include <sys/wait.h> pid_t waitpid(pid_t pid, int * status, int options) 11
프로세스분기와 sigaction 을 이용한자식프로세스의자원수거 void handler(int sig){ int pid; int status; while(1) { pid = waitpid( WAIT_ANY, &status, WNOHANG ); if ( pid < 0 ) { perror("waitpid"); break; } if ( pid == 0 ) break; } } int main(int argc, char *argv[]){ struct sigaction act; act.sa_handler = handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; } sigaction(sigchld, &act, 0); pid = fork(); 12
넌블록 I/O 모델 다음과같은채팅프로그램의구현이가능한지토의하라 Hi.. Client Hi.. Server Hi.. Hi.. What s up? What s up? Not much!! Not much!! Anyway.. What are you doing? Anyway.. What are you doing? 13 I ve just finished network programming assignments I ve just finished network programming assignments
넌블록 I/O 모델 send() 를연이어두번하거나, 클라이언트혹은서버중어느한쪽이먼저채팅을시작하게할수있는가? Client Hi.. send() recv() Server Hi.. Hi.. recv() send() Hi.. What s up? send() recv() What s up? Not much!! recv() send() Not much!! Anyway.. What are you doing? send() send() recv() recv() Anyway.. What are you doing? 14 I ve just finished network programming assignments recv() send() I ve just finished network programming assignments
앞예제의문제점 사용자의입출력패턴과 recv(), send() 의동기화가필요함 send() 의경우, 사용자입력이있을때까지기다림 recv() 와같은함수의경우, 수신할데이터가있을때까지기다림 블록함수 동기화되지않을경우, block 되어진행불가 사용자의입력패턴을정확히예상하고 send(), recv() 를코딩 현실적으로불가능 한턴씩진행되는간단한경우에사용가능 15
해결방법 문제점 블록함수의사용으로인한고착상태 해결방안 Non Block 함수의사용 블록되지않고바로리턴 필요에따라폴링 (polling) 루틴작성필요 비동기 (Asynchronous I/O) 사용 소켓 ( 파일 ) 에서어떤 I/O 변화가발생하면그사실을응용프로그램이알수있도록하여그때원하는동작을할수있게하는모드 I/O 가발생시전달되는 SIGIO 처리를통해폴링이아닌인터럽트방식으로처리하는방식 16
블록모드 vs 넌블럭모드 blocking 모드 어떤시스템콜을호출하였을때네트워크시스템이동작을완료할때까지그시스템콜에서프로세스가멈춤 소켓생성시디폴트 blocking 모드 block 될수있는소켓시스템콜 listen(),connect(), accept(), recv(), send(), read(), write(), recvfrom(), sendto(), close() I/O 시처리가될때까지기다려야함 비동기적인작업수행불가능 일대일통신을하거나프로그램이한가지작업만하면되는경우는 blocking 모드로프로그램작성가능 17
블럭 vs 넌블럭 Non-blocking 모드 소켓관련시스템콜에대하여네트워크시스템이즉시처리할수없는경우라도시스템콜이바로리턴되어응용프로그램이 block 되지않게하는소켓모드 통신상대가여럿이거나여러가지작업을병행하려면 nonblocking 또는비동기모드를사용하여야함 non-blocking 모드를사용시동작방식 넌블럭모드를사용하는경우에는일반적으로어떤시스템콜이성공적으로실행될때까지계속루프를돌면서주기적으로확인하는방법 ( 폴링 ) 을사용 18
Blocking I/O Model Application recvfrom system call kernel no datagram ready process blocks datagram ready copy datagram process datagram return OK copy complete 19
Nonblocking I/O Model Application recvfrom system call EWOULDBLOCK kernel no datagram ready recvfrom recvfrom system call EWOULDBLOCK system call no datagram ready datagram ready copy datagram process datagram return OK copy complete 20
넌블럭 I/O 작업이완료되지않으면 EWOULDBLOCK(WSAEWOULDBLOC) 를리턴 작업이진행중이라는뜻으로에러가아님 non-blocking I/O 사용법 Linux fcntl(sock_fd, F_SETFL, O_NONBLOCK); // linux Windows unsigned long nb_flag = 1; ioctlsocket(sock, FIONBIO, &nb_flag); // nb_flag = 0 이면 off 모두 polling 을하여결과를확인해야함 while (read(..) == EWOULDBLOCK) {} 21
비동기 I/O( 시그널인터럽트방식 ) SIGIO 를이용한인터럽트방식 Polling 방식과대비됨 소켓에서 I/O 변화가발생하면커널이이를응용프로그램에게알려원하는동작을실행 동작과정 sigaction() 를이용인터럽트시그널의종류를시스템에알림 fcntl() 을이용하여자신을소켓의소유자로지정 fcntl() 을통해소켓에 FASYNC 플래그를설정하여소켓이비동기 I/O 를처리하도록수정 22
멀티플렉싱이란? select() 를이용한멀티 플렉싱 (Multiplexing) 다수의송수신자가하나의전송채널을공유하는방식 소켓프로그래밍에서의멀티플렉싱 하나의프로세스를이용다수의송수신채널을관리하는방식 주로 select() 를이용하여처리 멀티프로세싱 vs 멀티플렉싱 용도 다수의채널을관리하기위해멀티프로세싱이다수의프로세스를사용하는데비해멀티플렉싱은하나의프로세스내부에서다수의채널을관리 멀티프로세싱 : 동시에여러채널의 I/O 가일어날경우, 즉하나의프로세스의종료기간이일정시간지속될경우 멀티플렉싱 : 프로세스의 I/O 처리시간이짧아바로다음프로세스의처리가가능한경우 23
I/O Multiplexing Model(Select) Application select system call kernel no datagram ready process blocks recvfrom return readable system call datagram ready copy datagram process blocks process datagram return OK copy complete 24
select() 의활용 select() 를활용 단일프로세스에서여러 fd를모니터링하는방법을제공 #include <sys/time.h> #include <sys/types.h> #include <unistd.h> Read, write 검사할최대 fd+1 read(recv) 를감지할 fds write(send) 를감지할 fds int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); 0 : timeout -1 : error 1 이상 : IO가일어난 FD의수 struct timeval { int tv_sec; int tv_usec;}; Select 가 return 될시간 0=> 즉시리턴 Null => blocking 25
select() 관련매크로 // macro FD_ZERO(fd_set *set) - 파일기술자집합을소거한다 FD_SET(int fd, fd_set *set) - fd 를 set 에더해준다 FD_CLR(int fd, fd_set *set) - fd 를 set 에서빼준다 main(void) { fd_set rfds; struct timeval tv; int retval; 시간내에 IO 의변화가있을경우, 값을변경 FD_ZERO(&rfds); FD_SET(0, &rfds); tv.tv_sec=5; tv.tv_usec=0; retval = select(1, &rfds, NULL, NULL, &tv); if(retval) else printf( Data is available now.\n ); printf( No data within 5 seconed.\n ); } exit(0); 26
Select() 를이용한키보드입력과 데이터수신의비동기처리 Start loop select 키가눌렸는가? N Y 키보드를읽어처리 0 flag 1 Socket readable? Y 소켓을읽어처리 N 0 flag 27 Loop end 1
Select() 를이용한키보드입력과 데이터수신의비동기처리 FD_ISSET(int fd, fd_set *set) - fd 가 set 안에서 active 한지확인 int game_end; fd_set readok; flag=1; while(1) { FD_ZERO(&readOK); FD_SET(0,&readOK); /* 표준입력과소켓의디스크립터를세팅 */ FD_SET(sock,&readOK); select(maxfd+1, (fd_set*)&readok, NULL, NULL, NULL); if(fd_isset(0,&readok)) { send(); if(game_end) break; } Loop 안에있음을확인! 28 } if(fd_isset(sock, &readok) { recv(sock, buf, sizeof(buf), 0); if(game_end) break;
응용과제 2 장응용 2 번을확장하여 echo 클라이언트는키보드입력을받아서버에전달하는행위반복 echo 서버가일정시간동안서비스요청이없으면자동으로연결을종료하도록개선 29