1 / 34

Network Simulation

Network Simulation. Prof. Jae-Hwoon Lee Dept. of Information & Communication Engineering, Dongguk University e-mail: jaehwoon@dongguk.edu http://cnel.dongguk.ac.kr. 4 장 고급 소켓 프로그래밍. 다중 처리 기술 소켓의 동작 모드 비동기형 채팅 프로그램 폴링형 채팅 프로그램. 4.1 다중 처리 기술. 다중 처리 동시에 여러 작업을 처리하는 것

shauna
Download Presentation

Network Simulation

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Network Simulation Prof. Jae-Hwoon Lee Dept. of Information & Communication Engineering, Dongguk University e-mail: jaehwoon@dongguk.edu http://cnel.dongguk.ac.kr

  2. 4장 고급 소켓 프로그래밍 • 다중 처리 기술 • 소켓의 동작 모드 • 비동기형 채팅 프로그램 • 폴링형 채팅 프로그램

  3. 4.1 다중 처리 기술 • 다중 처리 • 동시에 여러 작업을 처리하는 것 • 멀티태스킹 (multitasking) • 여러 작업을 여러 프로세스(또는 스레드)들이 나누어 다중 처리하는 방법 • 다중화 (multiplexing) • 한 프로세스 내에서 여러 작업(다중 입출력 등)을 처리하는 다중 처리 기능

  4. 4.1.1 멀티태스킹 • 여러 작업(task)을 병행하여 처리하는 기법 • 유닉스에서는 멀티태스킹을 위해 프로세스를 여러 개 실행시키거나(멀티프로세스) 또는 스레드(thread)를 여러 개 실행시키는 방법(멀티스레드)를 사용

  5. 멀티프로세스 • 독립적으로 처리해야 할 작업의 수 만큼 프로세스를 만드는 방법 • 장점 : 각 프로세스들이 독립적으로 작업을 처리하므로 구현이 간편 • 단점 : • 병렬처리 해야 할 작업 수만큼 프로세스를 생성해야 함 • 프로세스가 많이 생성될수록 메모리 사용량이 증가하고 프로세스 스케줄링 횟수가 많아져 프로그램의 성능이 저하됨 • 동시에 개설할 수 있는 프로세스의 수가 제한됨 • 프로세스들 사이에 데이터를 공유하는 것이 불편함 • 프로세스간 데이터 공유를 위해서는 운영체제의 도움을 받아 프로세스간 통신(IPC: Inter-Process Communication)을 하여야 하며 이로 인한 프로그램 구현이 복잡

  6. 멀티스레드 • 스레드 – 프로세스 내에서 독립적으로 실행되는 작업 단위 • 프로세스에서 스레드를 생성하면 새로 만들어진 스레드는 원래 프로세스의 이미지를 같이 사용한다 • 단, 새로 생성된 스레드용 스택 영역은 스레드별로 별도로 배정된다. • 장점 - 한 프로세스 내에서 생성된 스레드들은 이미지를 공유하므로 전역 변수를 같이 사용하므로 서로 쉽게 데이터를 공유 • 단점 – 여러 스레드가 한 데이터에 동시에 접근하는 경우에 동기화 문제가 발생할 수 있음.

  7. 4.1.2 다중화 • 파일에서 데이터를 읽기 위해 read()를 호출하면 • 대부분 즉시 데이터를 읽어오거나 잠시 기다리면 결과를 얻게 됨 • 네트워크로부터 데이터를 읽기 위해 read()를 호출하면 • 수신 버퍼에 이미 수신된 데이터가 있었다면 read()가 바로 리턴 • 아직 수신한 데이터가 없으면 read()는 데이터가 도착할 때까지 계속 기다림(블록) • 한 프로세스에서 다수의 입출력을 처리해야 하는 경우에 블록될 수 있는 입출력 함수를 사용하면 안됨 • 한 곳에서 입출력이 블록되면 프로그램 전체가 블록되게 됨. • 동시에 처리해야 할 입출력의 수만큼 프로세스(또는 스레드)를 생성하고 각 프로세스가 입출력을 독립적으로 담당 • 생성할 수 있는 프로세스(또는 스레드) 수에 한계가 있어 사용에 제한 • 다중화란 한 프로세스(또는 스레드) 내에서 이루어지는 다중 처리 기법 • 폴링(polling) • 셀렉팅(selecting) • 인터럽트(interrupt)

  8. 다중화 (계속) • 폴링 • 처리해야 할 작업들을 순차적으로 돌아가면서 처리하는 방법 • 입출력 함수가 어느 한 곳에서 블록되지 않도록 파일이나 소켓을 non-block 모드로 설정해야 함 • 셀렉트 • 어떤 클라이언트로부터 데이터가 도착하면 서버는 데이터가 도착한 클라이언트의 입출력을 처리하는 방식 • 유닉스에서는 select() 함수를 이용하여 입출력을 처리할 파일이나 소켓들을 비동기 모드로 바꾸어야 함 • 인터럽트 • 프로세스가 어떤 작업을 처리하는 도중에 특정한 이벤트가 발생하면 해당 이벤트를 처리하는 방식 • 유닉스에서는 프로세스 사이에 이벤트 발생을 알려주기 위해서 시그널(signal)를 제공하는데 시그널을 사용하여 데이터 입출력을 인터럽트 방식으로 처리 • 시그널을 소프트웨어 인터럽트라고 함

  9. 4.1.3 다중처리 예 • 채팅 프로그램 • 채팅 클라이언트 • 채팅에 참가하는 절차가 필요하고 채팅 메시지 입력과 다른 클라이언트가 보낸 채팅 메시지를 (서버를 경유하여) 수신하고 화면에 출력하는 기능이 필요 • 채팅 서버 • 클라이언트가 채팅 참가 요청을 보내오면 이를 접수하여 채팅 참가 리스트에 추가 • 채팅에 참가한 클라이언트들이 보내오는 메시지를 수신하여 모든 채팅 참가자에게 메시지를 방송 • 서버에서는 여러 작업을 병행하여 처리하는 기능이 필요함 • 멀티프로세스형 서버 프로그램 • 새로운 클라이언트가 접속될 때마다 프로세스를 만들고 각 프로세스가 각 클라이언트와의 통신을 담당 • 폴링형 서버 프로그램 • 소켓을 넌블록 모드로 설정하고 돌아가면서 클라이언트의 입출력 상태를 확인 • 셀렉팅형 서버 프로그래밍 • 셀렉팅을 이용하여 서버가 다수의 클라이언트와의 통신을 처리 • 인터럽트형 서버 프로그램 • 시그널을 이용하여 클라이언트로부터 연결요청이 오거나 데이터가 도착하면 인터럽트 방식으로 처리

  10. 4.2 소켓의 동작 모드 • 블록(blocking) 모드 • 시스템 콜을 호출하였을 때 동작을 완료할 때까지 시스템 콜에서 프로세스가 멈추어 있는 모드 • 넌블록(non-blocking) 모드 • 소켓 관련 시스템 콜에 대하여 시스템이 즉시 처리할 수 있으면 바로 결과를 리턴하고, 즉시 처리할 수 없는 경우라도 시스템 콜이 바로 리턴되어 응용 프로그램이 블록되지 않도록 함 • 다중화를 위해 시스템 콜이 성공적으로 실행될 때까지 계속 확인(폴링)하는 방법을 주로 사용 • 비동기(asynchronous) 모드 • 소켓에서 어떤 I/O 변화가 발생하면 그 사실을 응용 프로그램이 알 수 있도록 하여 그 때 입출력 처리 등 원하는 동작을 하는 모드 • Select()를 이용하는 방법 • I/O 변화가 발생할 수 잇는 소켓들 전체를 대상으로 select()를 호출해두면 그 중 임의의 소켓에서 I/O 변화가 발생되었을 때 select() 문이 리턴되고 해당 소켓에 대해 원하는 작업을 하는 방법 • Fcntl()를 사용하여 소켓을 signal-driven I/O 모드로 변경하는 방법 • 특정 소켓에서 I/O 변화가 발생하였을 때 SIGIO 시그널을 발생시키고 응용 프로그램에서는 이 시그널을 받으면 필요한 작업을 하는 방법

  11. 4.3 비동기형 채팅 프로그램 • 셀렉팅을 이용하여 채팅 서버 프로그램 구현 • 채팅 서버의 기능 • 클라이언트의 채팅 참가 요청 수락 • 클라이언트들의 송신 메시지를 다른 클라이언트들에게 방송 • select()를 사용하여 소켓을 비 동기 모드로 설정

  12. 4.3.1 채팅 서버 프로그램 구조 Select()를 이용한 비동기형 채팅 서버 비동기형 채팅 서버 socket() bind() 모든 소켓의 I/O 변화 감지 select() (채팅 참가 신청) Y N (채팅 메시지 수신) 연결용 소켓? accept() 채팅 메시지 발송 client_s[]에 새로운 소켓번호 추가

  13. 4.3.1 채팅 서버 구조 채팅 서버와 클라이언트의 연결 관계 채팅 클라이언트 (chat_client.c) 채팅 서버 chat_server.c 채팅 참가자 1 select() 채팅 참가자 2 채팅 참가자 3 소켓 s client_s[] 채팅 참가자 4 TCP/IP 채팅 참가 신청중

  14. Select() 시스템 콜의 사용문법 4.3.2 select() 시스템 콜 the descriptors that we want the kernel to test for reading, writing, and exception conditions the number of descriptors to be tested (“max fd plus 1”) #include <sys/types.h> /* fd_set data type */ #include <sys/time.h> /* struct timeval */ #include <unistd.h> /* function prototype might be here */ int select(int maxfdp1, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *tvptr); Returns: count of ready descriptors, 0 on timeout, -1 if error

  15. tvptr의 구조체 select()가 기다리는 시간을 지정 • tvptr == NULL • wait forever • tvptr->tv_sec == 0 && tvptr->tv_usec == 0 • don’t wait at all • tvptr->tv_sec != 0 || tvptr->tv_usec != 0 • wait the specified number of seconds and microseconds struct timeval *tvptr struct timeval { long tv_sec; /* seconds */ long tv_usec; /* and microseconds */ };

  16. fd_set 타입의 구조체와 소켓번호와의 관계 fd0 fd1 fd2 fd3 • Four macros on a variable of the fd_set data type • FD_ZERO (fd_set *fdset); /* fdset의 모든 비트를 지운다 */ • FD_SET (int fd, fd_set *fdset); /* fdset 중 소켓 fd에 해당하는 비트를 1로 한다 */ • FD_CLR (int fd, fd_set *fdset); /* fdset 중 소켓 fd에 해당하는 비트를 0으로 한다 */ • FD_ISSET (int fd, fd_set *fdset); /* fdset 중 소켓 fd에 해당하는 비트가 세트되어 있으면 양수 값을 리턴한다 */ readfd 1 0 0 1 … | | one bit per possible descriptor writefd 0 1 0 1 … | | fd_set data type exceptfd 0 0 0 0 … maxfdp1 - 1

  17. select() 호출 • fd_set 구조체 구성의 예 • read_fds를 select()의 두 번째 인자(읽기 변화 감지용 fd_set)로 지정하고 쓰기 및 예외발생에 해당하는 fd_set은 NULL로 지정하여 select()를 호출한 예 fd_set read_fds; FD_ZERO(&read_fds); // read_fds의 모든 소켓을 0으로 초기화 FD_SET(s, &read_fds); // 연결용 소켓을 선택 for(i=1; i< num_chat; i++) // 모든 통신용 소켓을 선택 FD_SET(clisock_list[i], &read_fds); select(maxfdp1, &read_fds, NULL, NULL, NULL);

  18. select() 호출 (cont.) • FD_ISSET 매크로를 이용하여 어떤 소켓에서 I/O 변화가 발생했는지 확인하는 예 if (FD_ISSET(s, &read_fds)){ // 연결용 소켓 s에서 입력 발생 // 채팅 참가 신청 처리 } // 클라이언트 소켓번호 어레이 client[]를 차례로 검색 for(i=0;i<num_chat;i++){ if(FD_ISSET(clisock_list[i], &read_fds)){ // 통신용 소켓 clisock_list[i]에서 채팅 메시지 수신 // 모든 참가자에게 채팅 메시지 방송 } }

  19. 4.3.3 채팅 서버 프로그램 • chatting server program • chat_server.c … void addClient(int s, struct sockaddr_in, *newcliaddr); // 새로운 채팅 참가자 처리 int getmax(); // 최대 소켓 번호 찾기 void removeClient(int s); // 채팅 탈퇴 처리 함수 … socket(); /* socket open */ bind(); /* call bind() */ listen(); /* wait for chatting client */ maxfdp = s + 1; /* max socket descriptor + 1 */ …

  20. 채팅 서버 프로그램 (Cont.) • chatting server program • chat_server.c … while(1) { FD_ZERO(&read_fds); /* initialize the set : all bits off */ FD_SET(s, &read_fds); /* turn on bit for listening socket descriptor */ for(i=0 ; i<num_chat ; i++) FD_SET(client_s[i], &read_fds); /* turn on bit for connected socket descriptor */ maxfdp1 = getmax(s) + 1; /* maxfdp1 recalculate */ select(maxfdp1, &read_fds, (fd_set *)0, (fd_set *)0,(struct timeval *)0); if(FD_ISSET(s, &read_fds)) { /* new client connection */ accept(); client_s[num_chat] = client_fd; /* save descriptor */ num_chat++; }

  21. 채팅 서버 프로그램 (Cont.) • chatting server program • chat_server.c … for(i=0 ; i<num_chat ; i++) { /* check all clients for data */ if(FD_ISSET(client_s[i], &read_fds)) { recv(client_s[i], rline, MAXLINE, 0); } for(j=0 ; j<num_chat ; j++) /* send data to all client */ send(client_s[j], rline, n, 0); } …

  22. 채팅 서버 프로그램 (Cont.) • chatting server program • Result (x86 Linux System : cnel-cnp1) [cnel-cnp1] %chat_server 9013 [cnel-cnp2] %client_chat 210.94.213.194 9013 manuj [cnel-cnp1] % 1번째 사용자 추가. [cnel-cnp2] %client_chat 210.94.213.194 9013 jaehwoon [cnel-cnp1] % 1번째 사용자 추가. 2번째 사용자 추가.

  23. 통신용 소켓 구분 • 채팅 서버는 클라이언트와 통신을 위해 다수의 통신용 소켓(accept()가 리턴한 소켓들)을 개설 • 다수의 소켓들이 모두 같은 포트 번호를 사용 • 각 클라이언트의 연결을 구분하기 위하여 “클라이언트의 IP 주소와 포트번호”를 내부적인 키로 사용 채팅 서버 통신용소켓 연결용소켓 상대방(클라이언트)의 (IP+포트번호)로 구분 TCP 포트 번호 4001 IP TCP 서버에서 다수의 통신용 소켓을 구분하는 방법

  24. 4.3.4 채팅 클라이언트 프로그램 • TCP 소켓을 이용한 채팅 클라이언트 프로그램 작성 • select() 시스템 콜을 이용한 non-block chatting client • 메시지 입력 • 키보드로부터의 표준 입력 • 메시지 출력 • 모니터 화면으로 표준 출력 • 프로그램 종료 • 특정 종료문자 입력 시 프로그램 종료

  25. 채팅 클라이언트 프로그램 구성 방법 • tcp_chatcli.c의 사용 방법의 예 • 클라이언트가 보내는 모든 채팅 메시지 앞부분에 클라이언트의 이름을 붙여서 보내는 방법 $ tcp_chatcli 210.94.213.194 철수 char bufall[MAXLINE+NAME_LEN], // 이름+메시지를 저장하기 위한 버퍼 *bufmsg; // bufall에서 메시지 시작부분의 포인터 sprintf(bufall, “[%s] : “, “철수”); // bufall의 앞부분에 이름을 저장 namelen=strlen(bufall); bufmsg = bufall+namelen; // 메시지의 시작 부분을 찾음 fgets(bufmsg, MAXLINE, stdin); send(s, bufall, namelen+strlen(bufmsg), 0);

  26. 채팅 클라이언트 프로그램 • chatting client program • chat_client.c … fd_set read_fds; /* fd_set struct */ FD_ZERO(&read_fds); /* initialize the set : all bits off */ maxfdp1 = s + 1; /* maxfdp1 calculate */ while(1) { FD_SET(0, &read_fds); /* turn on bit for standard input */ FD_SET(s, &read_fds); /* turn on bit for connected socket descriptor */ select(maxfdp1, &read_fds, (fd_set *)0, (fd_set *)0, (struct timeval *)0); if (FD_ISSET(s, &read_fds)) /* check receive message from server */ if (FD_ISSET(0, &read_fds)) /* check send message to server */ } …

  27. 채팅 클라이언트 프로그램 (Cont.) • chatting client program • Result (x86 Linux System : cnel-cnp2) [cnel-cnp2] %client_chat 210.94.213.194 9013 manuj [cnel-cnp2] %client_chat 210.94.213.194 9013 jaehwoon [cnel-cnp1] %chat_server 9013 1번째 사용자 추가. 2번째 사용자 추가. [cnel-cnp2] %client_chat 210.94.213.194 9013 manuj 서버에 접속되었습니다. Connected to chat_server Hello world! [manuj] Hello world! [jaehwoon] OK exit Good bye.

  28. 4.4 폴링형 채팅 프로그램 • 폴링 방식으로 채팅 서버를 구현 • 소켓을 넌블록 모드로 설정하고 채팅 메시지 수신 여부를 폴링 방식으로 점검

  29. 4.4.1 fcntl() • file control을 의미하며 소켓을 넌블록 모드나 비동기 모드로 변경할 수 있음 • 소켓을 넌블록 모드로 설정 • 소켓을 비동기 모드로 설정 • 소켓의 소유자를 설정하거나 현재 소유자를 얻어옴 • fcntl()의 사용문법 • 구체적인 옵션을 설정하는 데 사용 • O_NONBLOCK : 넌블록 모드로 설정 • O_ASYNC : SIGIO 시그널에 의해 구동되도록 비동기 모드로 설정 #include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd, long flag); • 명령 • F_SETFL : 플래그 세트 • F_GETFL : 플래그 읽기 • F_SETOWN : 소켓의 소유자를 설정 • F_GETOWN : 현재 소켓의 소유자를 얻어옴. 모드 변경을 원하는 소켓 디스크립터

  30. 모드 설정 • 넌블록 모드 설정 코드 • 비동기 모드 설정 코드 • 소켓의 소유자를 현재 프로세스로 정하는 방법과 소유자를 알아내는 코드 int val; if((val = fcntl(sock_fd, F_GETFL, 0))<0 exit(1); val |= O_NONBLOCK; if((fcntl(sock_fd, F_SETFL, val) <0) exit(1); int val; if((val = fcntl(sock_fd, F_GETFL, 0))<0 exit(1); val |= O_ASYNC; if((fcntl(sock_fd, F_SETFL, val) <0) exit(1); fcntl(fd, F_SETOWN, getpid()); fcntl(fd, F_GETOWN, &pid);

  31. 4.4.2 폴링형 채팅 서버 • 넌블록 모드 • 소켓들을 fcntl()을 이용하여 넌블록 모드로 설정한 후 무한 루프를 돌면서 입출력을 폴링 방식으로 처리 • 넌블록 모드의 소켓에 대해 read()를 호출한 경우의 처리 방법 • accept()가 리턴한 통신용 소켓의 디폴트는 블록 모드 n=recv(s, buf, length, 0); if(n>0) { // 정상적으로 읽은 데이터처리 } else if (n==-1 && errno == EWOULDBLOCK) // 에러가 아니므로 다음 작업으로 진행 else if (n==-1 && errno != EWOULDBLOCK) // 시스템 콜에서 에러가 발생함 // 에러 처리

  32. 4.4.2 폴링형 채팅 서버 (cont.) int is_nonblock(int sockfd) { int val; // 기존의 플래그 값을 얻어온다 val = fcntl(sockfd, F_GETFL, 0); //넌블록 모드인지 확인 if(val & O_NONBLOCK) return 0; return -1; } • 소켓이 넌블록 모드인지를 확인하는 함수 • 소켓이 넌블록 모드인지를 확인한 후 아니면 넌블록 모드로 변경하는 함수 addrlen=sizeof(cliaddr); accp_sock = accept(s, (struct sockaddr *)&cliaddr, &clilen); if(accp_sock == -1 && errno != EWOULDBOLCK) errquit(“accpt fail”); else if(accp_sock >0){ // 채팅 클라이언트 목록에 추가 clisock_list[num_chat] = accp_sock; if(is_nonblock(accp_sock) != 0 && set_nonblock(acp_sock) < 0) errquit(“set_nonblock fail”); num_chat++ send(accp_sock, start, strlen(start), 0); printf(“%d번째 사용자 추가. \n”, num_chat); }

  33. 폴링형 채팅 서버 프로그램

  34. Network Simulation ? Prof. Jae-Hwoon Lee Dept. of Information & Communication Engineering, Dongguk University e-mail: jaehwoon@dongguk.edu http://cnel.dongguk.ac.kr

More Related