인공지능실험실 석사 2학기 김승겸 codekim@ai.hannam.ac.kr TCP/IP Socket Programming… 제 10장 멀티태스킹 기반의 서버구현 인공지능실험실 석사 2학기 김승겸 codekim@ai.hannam.ac.kr.

Slides:



Advertisements
Similar presentations
Signal Handling ( 금 ) 한 민 규
Advertisements

TCP 서버/클라이언트 동작 원리 - (1) TCP 서버/클라이언트 예 웹 서버 웹 클라이언트 웹 클라이언트
Linux System Programming
인공지능실험실 석사 2학기 이희재 TCP/IP Socket Programming… 제 11장 프로세스간 통신 인공지능실험실 석사 2학기 이희재
2014 ITA 8월 강의 C Programming -1주차- C언어 기초 정대진 ( )
Linux System Programming
Department of Computer Engineering
Signal & Inter-Process Communication
공유 메모리[1] 공유 메모리 공유 메모리 생성: shmget(2) 같은 메모리 공간을 두 개 이상의 프로세스가 공유하는 것
Department of Computer Engineering
제5장 제어명령
Multi-thread Programming
TCP Client/Server Program
Network Lab. Seoung Hyeon, Lee
얇지만 얇지 않은 TCP/IP 소켓 프로그래밍 C 2판
6 프로세스 생성과 실행.
6 프로세스 생성과 실행.
Linux System Programming
Global array – 1M의 integer, P0.dat, P1.dat, P2.dat, P3.dat
6장 비연결형 지향 프로토콜 Database Lab 강 우 석.
인터넷 주소 변환 School of Electronics and Information. Kyung Hee University.
제 12장 I/O멀티플렉싱(Multiplexing)
7. while 문의 흐름 제어.
Using Standard I/O on Sockets
Department of Computer Engineering
데이터베이스 실험실 석사 2학기 김기훈 TCP/IP Socket Programming… 제 17장 멀티쓰레드 기반의 서버구현 데이터베이스 실험실 석사 2학기 김기훈
Department of Computer Engineering
fork로 생성한 자식 프로세스에서 exec 함수군을 호출
멀티쓰레드 기반의 서버구현 School of Electronics and Information.
Department of Computer Engineering
고급 입출력 함수 School of Electronics and Information. Kyung Hee University.
Signal & Inter-Process Communication
Term Project Team Member
Homework 6… 12월 2일(금) 11:59pm까지 자신의 이름과 학번을 출력해 주는 유닉스/리눅스 네트워크 소켓 서버 프로그램 과 클라이언트 프로그램 을 작성해 보세요 참고 (실습1) Hello 프로그램 helloserver.c helloclient.c 컴파일.
Advanced Socket Programming
Department of Computer Engineering
13장 고급 입출력 함수 박사 4학기 최 성자.
10장 C 표준 파일 입출력 子曰 學而時習(실습?)之 不亦悅乎.
5 프로세스 정보.
13. 포인터와 배열! 함께 이해하기.
Signal & Inter-Process Communication
Memory & Data Management.
컴퓨터의 기초 제 2강 - 변수와 자료형 , 연산자 2006년 3월 27일.
멀티 쓰레드 기반의 채팅 프로그램 문성영 김현진 학번 이름 장용하 차희진 연구제안서.
TCP / IP 소켓 프로그래밍 3주차 ( Ch.10 ~ Ch.14 ).
11장 시그널.
네트워크 프로그래밍의 이해 School of Electronics and Information.
7 시그널.
제어문 & 반복문 C스터디 2주차.
Linux/UNIX Programming
School of Electronics and Information. Kyung Hee University.
3장. 변수와 연산자. 3장. 변수와 연산자 3-1 연산자, 덧셈 연산자 연산자란 무엇인가? 연산을 요구할 때 사용되는 기호 ex : +, -, *, / 3-1 연산자, 덧셈 연산자 연산자란 무엇인가? 연산을 요구할 때 사용되는 기호 ex : +, -, *, /
Department of Computer Engineering
Department of Computer Engineering
Signal & Inter-Process Communication
6장 반복제어문 for 문 while 문 do while 문 기타 제어문.
Department of Computer Engineering
-Part1- 제7장 반복문이란 무엇인가.
-Part1- 제8장 조건문이란 무엇인가 (교재 199페이지 ~ 224페이지)
쉽게 풀어쓴 C언어 Express 제6장 조건문 C Express.
1학기 정리 지난 학기에 배운 내용을 복습해 본다..
Department of Computer Engineering
어서와 C언어는 처음이지 제16장.
Signal & Inter-Process Communication
Linux/UNIX Programming
C.
printf("Global Korea\n");
Signal & Inter-Process Communication
배열, 포인터, 함수 Review & 과제 1, 2.
⊙ 입출력 처리란? data를 입력장치로부터 program 내부로 읽어 들이거나
Presentation transcript:

인공지능실험실 석사 2학기 김승겸 codekim@ai.hannam.ac.kr TCP/IP Socket Programming… 제 10장 멀티태스킹 기반의 서버구현 인공지능실험실 석사 2학기 김승겸 codekim@ai.hannam.ac.kr

목차 다중 접속 서버의 구현 방법들 프로세스의 생성 프로세스 & 좀비 프로세스 시그널 핸들링 & 좀비 프로세스 Fork 함수를 이용한 다중 접속 서버의 구현 TCP 입출력 루틴 분할하기

다중 접속 서버의 구현 방법들 다중 접속 서버의 구현 방법 프로세스 생성을 통한 멀티태스킹 서버의 구현 select 함수에 의한 멀티플렉싱 서버의 구현 쓰레드를 기반으로 하는 멀티 쓰레팅 서버의 구현

프로세스의 생성 프로세스 ID 프로세스 식별자 프로세스마다 할당되는 유일한 숫자(2 ~ 32786) 프로세스 확인을 위한 ps 명령 실행

프로세스의 생성 fork 함수 호출을 통한 프로세스 생성 fork 함수 이용 fork를 호출한 프로세스의 복사본 생성 모든 메모리 공간을 그대로 복사 똑같은 프로그램을 완전히 독립된 프로세스가 실행 fork함수에 의한 리턴값은 다르다. 부모 프로세스 리턴값 : 자식 프로세스 ID 자식 프로세스 리턴값 : 0 #include <sys/types.h> #include <unistd.h> pid_t fork (void); 성공 시 프로세스 ID, 실패 시 -1을 리턴

프로세스의 생성 fork.c #include<stdio.h> #include<unitd.h> #include<sys/types.h> int main( ) { pid_t pid; int data = 10; pid = fork(); if(pid == -1) printf(“fork실패, 프로세스 id : %d\n”, pid); printf(“fork성공, 프로세스 id : %d\n”, pid); if(pid == 0) // 자식 프로세스 data += 10; else // 부모 프로세스 data -= 10; printf(“data : %d\n”, data); return 0; } 실행결과

프로세스 & 좀비 프로세스 좀비 프로세스 실행이 종료 되었지만 아직 삭제되지 않은 프로세스 프로세스가 종료하고 난 후 부모 프로세스가 종료 상태를 가져 올때가지의 프로세스 프로세스 테이블 요소를 제외하고 어떤 자원도 없는 죽은 존재이지만 계속 시스템 안에 상주한다.

프로세스 & 좀비 프로세스 좀비 프로세스가 생성되는 이유 자식 프로세스 부모 프로세스 커널 좀비 소멸 자식 프로세스 소멸 과정

프로세스 & 좀비 프로세스 zombie.c #include<stdio.h> #include<unitd.h> #include<sys/types.h> int main( ) { pid_t pid; int data = 10; pid = fork(); if(pid == -1) printf(“fork실패, 프로세스 id : %d\n”, pid); printf(“fork성공, 프로세스 id : %d\n”, pid); if(pid == 0) // 자식 프로세스 data += 10; else { // 부모 프로세스 data -= 10; sleep(20); // 20초동안 정지 상태 printf(“data : %d\n”, data); return 0; } ■ 부모 프로세스 루틴 부분에 sleep(20)함수를 주어서 20초동안 정지상태로 만든다. ■ 자식 프로세스가 먼저 종료한 후에 부모 프로세스는 20초 후에 종료한다. ■ 20초간의 시간 동안 자식 프로세스가 좀비가 된것을 확인 할 수 있다.

프로세스 & 좀비 프로세스 실행결과

성공 시 종료된 자식 프로세스 ID, 실패 시 -1을 리턴 프로세스 & 좀비 프로세스 wait 함수의 사용 wait 함수 이용 이미 종료된 자식 프로세스가 있다면, 리턴값을 읽어들인다. 종료된 자식 프로세스가 없다면, 임의의 자식 프로세스가 종료될때까지 부모 프로세스는 블로킹 상태가 된다. wait함수의 인자인 포인터가 가리키는 변수에 여러가지 정보 저장 #include <sys/types.h> #include <sys/wait.h> pid_t wait (int * status); 성공 시 종료된 자식 프로세스 ID, 실패 시 -1을 리턴 매크로 함수 리턴 값 WIFEXITED(status) 정상 종료를 했을 경우 0을 반환한다. WEXITSTATUS(status) 종료시에 return 하거나 exit함수의 인자로 넘겨진 값을 반환한다.

프로세스 & 좀비 프로세스 wait.c #include<stdio.h> #include<unitd.h> #include<sys/types.h> int main( ) { pid_t pid, child; int data = 10; int state; pid = fork(); if(pid == -1) printf(“fork실패, 프로세스 id : %d\n”, pid); printf(“fork성공, 프로세스 id : %d\n”, pid); if(pid == 0) // 자식 프로세스 data += 10; else { // 부모 프로세스 data -= 10; child = wait(&state); // 자식 프로세스 종료대기 printf(“자식프로세스 ID=%d\n”, child); printf(“리턴값=%d\n”, WEXITSTATUS(state)); sleep(20); // 20초동안 정지 상태 printf(“data : %d\n”, data); return 0; } ■ wait함수를 이용하여 종료된 자식프로세스의 종료상태를 읽어온다. ■ WEXITSTATUS 매크로 함수를 이용하여 자식프로세스가 종료시 리턴값을 얻는다. ■ wait함수를 이용하여 좀비가 되는것을 막을 수 있다.

프로세스 & 좀비 프로세스 실행결과

성공 시 종료된 자식 프로세스 ID, 실패 시 -1을 리턴 프로세스 & 좀비 프로세스 waitpid 함수의 사용 waitpid 함수 이용 pid : 종료 확인을 원하는 자식 프로세스의 ID이다. status : 리턴된 값을 비롯해서 여러가지 정보저장 options : ‘WNOHANG’ 상수를 인자로 전달하게 되면 이미 종료된 자식프로세스가 없어도 대기 상태로 들어가지 않고 바로 리턴하게 된다. #include <sys/types.h> #include <sys/wait.h> pid_t waitpid (pid_t pid, int *status, int options); 성공 시 종료된 자식 프로세스 ID, 실패 시 -1을 리턴

프로세스 & 좀비 프로세스 waitpid.c #include<stdio.h> #include<unitd.h> #include<sys/types.h> int main( ) { pid_t pid, child; int data = 10; int state; pid = fork(); if(pid == -1) printf(“fork실패, 프로세스 id : %d\n”, pid); printf(“fork성공, 프로세스 id : %d\n”, pid); if(pid == 0) // 자식 프로세스 data += 10; sleep(10) // 종료를 10초 지연 else { // 부모 프로세스 data -= 10; do{ sleep(3); puts(“3초 대기”); child = waitpid(-1, &state, WNOHANG); }while(child == 0); printf(“Chid process id=%d, return value = %d \n”,child,WEXITSTATUS(state)); printf(“data : %d\n”, data); return 0; } ■ waitpid함수를 이용하여 종료된 자식프로세스의 종료상태를 읽어온다. ■ WNOHANG인자를 주어서 이미 종료된 자식이 없어도 대기 상태로 들어가지 않고 바로 리턴한다.

프로세스 & 좀비 프로세스 실행 결과

시그널 핸들링 & 좀비 프로세스 시그널 핸들링 Operatinn System signal Process 시그널 핸들링 과정 1. 특정상황발생 2. 시그널 전송 Operatinn System 3. 시그널 처리 함수 호출 signal Process 시그널 핸들링 과정 ■ 시그널 : 시스템에 특정 상황이 발생했을때 , 이를 알리기 위해 운영체제가 전달하는 메시지 ■ 시그널 핸들러 : 시그널을 처리하는 함수 모듈 ■ 시그널 핸들링 : 시그널 발생시, 해당 시그널 핸들러를 실행시키는 행위

시그널 핸들링 & 좀비 프로세스 시그널의 종류 시그널 발생 상황 SIGALRM 시간을 예약해 놓고 그 시간이 되었을 경우 발생한다. SIGINT 인터럽트 발생을 알린다. 여기서 인터럽트는 Ctrl+C 을 누른 경우 발생한다. SIGCHLD 자식 프로세스가 종료된 경우 발생한다.

리턴값은 이전 시그널 핸들러 함수의 주소값, 실패시 SIG_ERR 시그널 핸들링 & 좀비 프로세스 signal 함수를 이용한 시그널 핸들링 signal 함수 이용 시그널이 발생되었을때 시그널 핸들러 함수를 호출하여 시그널을 처리한다 int signum : 시그널 상수 func : 시그널 핸들러 함수 #include <signal.h> void (*signal(int signum, void(*func)(int)))(int); 리턴값은 이전 시그널 핸들러 함수의 주소값, 실패시 SIG_ERR

시그널 핸들링 & 좀비 프로세스 sigint.c #include<stdio.h> #include<unitd.h> #include<signal.h> void handler(int sig); int main( ) { int state; int num = 0; signal(SIGINT, handler); // 시그널 함수 while(1) { printf(“%d : 대기중\n”, num++); sleep(2); if(num>5) break; } return 0; } void handler(int sig) { // 시그널 핸들러 함수 signal(SIGINT, handler); printf(“전달된 시그널은 %d\n”, sig);

SIGINT(cltr + c) 발생시 시그널 핸들러 함수에 의해 처리되는 모습 시그널 핸들링 & 좀비 프로세스 실행 결과 SIGINT(cltr + c) 발생시 시그널 핸들러 함수에 의해 처리되는 모습

시그널 핸들링 & 좀비 프로세스 sigaction 함수를 이용한 시그널 핸들링 sigaction 함수 이용 signum : signal 함수와 마찬가지로 가로 채고자 하는 시그널의 종류를 인자로 전달하게된다. act : 새로 등록할 시그널 핸들러 정보로 초기화된 sigaction 구조체 변수의 포인터를 인자로 전달하게 된다. oldact : 이전에 등록되었던 시그널 핸들러의 포인터를 얻고자 할때 사용되게 하는 인자이다. #include <signal.h> int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); 리턴 값은 성공시 0을, 실패 시 -1을 리턴한다.

시그널 핸들링 & 좀비 프로세스 sigint2.c #include<stdio.h> #include<unitd.h> #include<signal.h> void handler(int sig); int main( ) { int state; int num = 0; struct sigaction act; act.sa_handler = handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; state = sigaction(SIGINT, &act, 0); if(state != 0) { puts(“sigaction() error”); exit(1); } while(1) { printf(“%d : 대기중\n”, num++); sleep(2); if(num>5) break; } return 0; void handler(int sig) { // 시그널 핸들러 함수 printf(“전달된 시그널은 %d\n”, sig);

SIGINT(cltr + c) 발생시 시그널 핸들러 함수에 의해 처리되는 모습 시그널 핸들링 & 좀비 프로세스 실행 결과 SIGINT(cltr + c) 발생시 시그널 핸들러 함수에 의해 처리되는 모습

시그널 핸들링 & 좀비 프로세스 시그널을 통한 좀비 프로세스의 소멸(zombie_handler.c) #include<stdio.h> #include<unitd.h> #include<signal.h> #include<sys/types.h> #include<sys/wait.h> void z_handler(int sig); int main( ) { pid_t pid; int state, i; struct sigaction act; act.sa_handler = z_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; state = sigaction(SIGCHLD, &act, 0); if(state != 0) { puts(“sigaction() error”); exit(1); } pid = fork(); if(pid == 0) { printf(“자식 프로세스 생성 : %d\n”, getpid()); exit(3); } else { sleep(3); } return 0; void z_handler(int sig) { // 시그널 핸들러 함수 pid_t pid; int rtn; while((pid=waitpid(-1, &rtn, WNOHANG)) > 0) { printf(“소멸된좀비프로세스ID : %d\n”, pid); printf(“리턴된데이터 : %d=n”,WEXITSTATUS(rtn));

SIGCHLD 신호를 받고 시그널 핸들러 함수에 waitpid함수를 써서 자식의 종료상태를 가져옴으로써 좀비를 제거한다. 시그널 핸들링 & 좀비 프로세스 실행 결과 SIGCHLD 신호를 받고 시그널 핸들러 함수에 waitpid함수를 써서 자식의 종료상태를 가져옴으로써 좀비를 제거한다.

fork함수를 이용한 다중접속 서버구현 다중 접속 서버 Echo Server Echo Client Process 1. 연결요청 Echo Server Echo Client 2. 프로세스 생성 3. 연결완료 Process Echo Client Process 다중 접속 서버 모델

fork함수를 이용한 다중접속 서버구현 echo_multiserv.c while(1) { addr_size = sizeof(clnt_addr); clnt_sock = accept(serv_sock, (struct sockaddr*) , &addr_size); if(clnt_sock == -1) continue; if((pid=fork()) == -1) { close(clnt_sock); }else if(pid > 0) { // 부모 프로세스 puts(“연결생성”); }else { // 자식 프로세스 close(serv_sock); while((str_len=read(clnt_sock, message, BUFSIZE)) != 0) { write(clnt_sock, message, str_len); write(1, message, str_len); } puts(“연결종료”); exit(0); } return 0; void z_handler(int sig) { pid_t pid; int rtn; pid=waitpid(-1, &rtn, WNOHANG); printf(“소멸된좀비프로세스ID : %d\n”, pid); printf(“리턴된데이터 : %d=n”,WEXITSTATUS(rtn));

fork함수를 이용한 다중접속 서버구현 실행 결과 SERVER Client 1 Client 2

TCP 입 출력 루틴 분할하기 입 출력 분리 Echo Client Echo Server 부모 프로세스 자식 프로세스 socket READ 부모 프로세스 fork WRITE 자식 프로세스 다중 접속 서버 모델

TCP 입 출력 루틴 분할하기 데이터 송수신 방법의 비교 데이터 송수신 방법의 비교 Client Server Client 에코 데이터 단일 프로세스 입출력 입출력 프로세스의 분리 데이터 송수신 방법의 비교

fork함수를 이용한 다중접속 서버구현 echo_multiclnt.c pid = fork(); If(pid == 0) { // 자식프로세스 (메시지 전송) while(1) { fputs(“전송할 메시지를 입력하세요: “, stdout); fgets(“message, BUFSIZE, stdin); if(!strcmp(message, “q\n”)) { shutdown(sock, SHUT_WR); close(sock); exit(0); } write(sock, message, strlne(message)); else { // 부모 프로세스 메시지 수신 while(1) { str_len = read(sock, message, BUFSIZE); if(str_len == 0) { exit(0); } message[str_len] = 0; printf(“서버로부터 전송된 메시지:%s\n”, message); close(sock); return 0;

참고문헌 “UNIX Network Programming”, W.Richard Stevens “TCP/IP 소켓 프로그래밍”, 윤성우 저

Q & A