고급 입출력 함수 School of Electronics and Information. Kyung Hee University.

Slides:



Advertisements
Similar presentations
Understanding of Socket and File I/O
Advertisements

인공지능실험실 석사 2학기 이희재 TCP/IP Socket Programming… 제 11장 프로세스간 통신 인공지능실험실 석사 2학기 이희재
Network Lab. Young-Chul Hwang
Department of Computer Science and Engineering
Department of Computer Engineering
소켓 모델 주소 지정 in_addr_t inet_addr(const char *ip_address) 연결 지향 모델 (TCP)
인공지능실험실 석사 2학기 김승겸 TCP/IP Socket Programming… 제 10장 멀티태스킹 기반의 서버구현 인공지능실험실 석사 2학기 김승겸
TCP Client/Server Program
Network Lab. Seoung Hyeon, Lee
Department of Computer Science and Engineering
Multimedia & Mobile Communications Lab.
제15장 파일 입출력 문자열을 출력하는 여러가지 방법 (15-2쪽) 문자열만 처리하는 입출력 함수
6장 비연결형 지향 프로토콜 Database Lab 강 우 석.
인터넷 주소 변환 School of Electronics and Information. Kyung Hee University.
제 12장 I/O멀티플렉싱(Multiplexing)
제 14장 Multicast & Broadcast
Using Standard I/O on Sockets
Department of Computer Engineering
Department of Computer Engineering
Department of Computer Engineering
인공지능실험실 석사 2학기 이희재 TCP/IP Socket Programming… 제 7장 소켓 연결의 우아한 종료 인공지능실험실 석사 2학기 이희재
양방향 파이프의 활용 양방향 통신 파이프는 기본적으로 단방향이므로 양방향 통신을 위해서는 파이프를 2개 생성한다.
12장 파이프.
fork로 생성한 자식 프로세스에서 exec 함수군을 호출
Department of Computer Engineering
11장. 포인터 01_ 포인터의 기본 02_ 포인터와 Const.
8장 함수 함수의 필요성 라이브러리 함수와 사용자 정의 함수 함수의 정의, 원형, 호출 배열을 함수 인자로 전달 재귀호출.
Signal & Inter-Process Communication
Term Project Team Member
컴퓨터 프로그래밍 기초 #02 : printf(), scanf()
Homework 6… 12월 2일(금) 11:59pm까지 자신의 이름과 학번을 출력해 주는 유닉스/리눅스 네트워크 소켓 서버 프로그램 과 클라이언트 프로그램 을 작성해 보세요 참고 (실습1) Hello 프로그램 helloserver.c helloclient.c 컴파일.
Department of Computer Engineering
인공지능실험실 박사 1학기 장성만 TCP/IP Socket Programming… 9장 소켓의 다양한 옵션 인공지능실험실 박사 1학기 장성만
파일 기술자 복사 파일 기술자 복사 : dup(2) 파일 기술자 복사 : dup2(3)
파일 기술자 파일 기술자 현재 열려있는 파일을 구분하는 정수값 저수준 파일 입출력에서 열린 파일을 참조하는데 사용
4장 파일.
메시지 큐[5] – test1.c 메시지 제어: msgctl(2) #include <sys/msg.h>
Department of Computer Engineering
프로젝트 발표 순서 12/7(수), 팀 별 15분 발표순서 PPT (팀 별 이름, 구현 내용, 결과-그래프 포함) 각 기법당
Department of Computer Science and Engineering
13장 고급 입출력 함수 박사 4학기 최 성자.
TCP/IP Socket Programming…
14장. 포인터와 함수에 대한 이해.
Socket Address Structure and Byte Ordering Functions
Socket Address Structure and Byte Ordering Functions
11장. 1차원 배열.
Department of Computer Engineering
13. 포인터와 배열! 함께 이해하기 IT응용시스템공학과 김 형 진 교수.
24장. 파일 입출력.
19. 함수 포인터와 void 포인터.
네트워크 프로그래밍의 이해 School of Electronics and Information.
School of Electronics and Information. Kyung Hee University.
컴퓨터 프로그래밍 기초 - 10th : 포인터 및 구조체 -
Department of Computer Engineering
Department of Computer Engineering
Signal & Inter-Process Communication
제 16장 입력과 출력 스트림의 완벽 분리 TCP/IP Socket Programming… 데이터베이스 실험실
다중처리 기술 School of Electronics and Information. Kyung Hee University.
Chapter 04. TCP 서버/클라이언트.
Department of Computer Engineering
구조체(struct)와 공용체(union)
9 파이프.
Department of Computer Engineering
06. 디바이스의 등록과 해제 김진홍
C 13장. 입출력 라이브러리 #include <stdio.h> int main(void) { int num;
13. 포인터와 배열! 함께 이해하기.
3장 파일 다루기 한빛미디어(주).
Signal & Inter-Process Communication
Department of Computer Engineering
2019 2학기 9장 배열과 포인터 1. 주소, 주소연산자(&) 2. 포인터, 역참조연산자(*) 3. 배열과 포인터.
Presentation transcript:

고급 입출력 함수 School of Electronics and Information. Kyung Hee University. Dae Sun Kim <dskim@networking.khu.ac.kr>

recv & send read & write 함수와 달리 데이터 입 출력 방법에 있어서 옵션 부여. Sock: 입출력의 대상이 되틑 소켓의 파일 디스크립터 Buf: 입력 및 출력을 위한 버퍼의 포인터 Len: 전송할 데이터의 바이트 수 혹은 수신할 수 있는 최대 바이트 수 Flags: 데이터 입출력시 그 방법에 있어서 옵션을 설정하는 용도로 사용. ‘0’의 값을 넘겨줄 경 우 read, write와 완전히 동일한 기능의 함수, 옵션은 bitwise OR(|)로 묶어서 두 개 이상이 함께 전달될 수 있다. #include <sys/types.h> #include <sys/socket.h> int recv(int sock, void * buf, int len, unsigned int flags); int send(int sock, const void * buf, int len, unsigned int flags);

recv & send 옵션의 종류와 의미. flags Description recv send MSG_DONTROUTE 데이터 전송 시 라우팅 테이블 참조 하지 않음(local network상의 목적지를 찿겠다는 의미)  MSG_DONTWAIT 데이터 입출력 함수 호출 시 블로킹되지 않고 바로 리턴할 것을 요구하는 경우에 사용(넌-블록킹(non-blocking) I/O) MSG_OOB 긴급 데이터(Out-of-band data) 전송 MSG_PEEK 버퍼에 데이터 유 무 확인

긴급 데이터 전송 예제[MSG_OOB] 긴급데이터 전송 방법 긴급데이터 수신 시 “SIGURG” 시그널 발생 Fork() 함수를 통해 여러 개의 프로세스 생성시 긴급 데이터는 ? send(sock, “test”, 4, MSG_OOB); recv(sock, buf, sizeof(buf)-1, MSG_OOB); 부모프로세스 SIGURG ? 커널 ? 자식프로세스

긴급 데이터 전송 예제[MSG_OOB] 긴급 데이터 수신 시 “SIGURG” 시그널을 받을 프로 세스를 지정 해야 한다. clnt_sock이 가리키는 소켓의 소유자를 getpid 함수가 리 턴하는 ID의 프로세스로 변경 F_SETOWN: 소유자 변경 fcntl(clnt_sock, F_SETOWN, getpid()) 부모프로세스 SIGURG 커널 자식프로세스 fcntl(clnt_sock, F_SETOWN, getpid())

긴급 데이터 전송 예제[MSG_OOB] 프로그램 예제 oob_send.c, sock=socket(PF_INET, SOCK_STREAM, 0); if(sock==-1) error_handling("socket() error"); memset(&recv_addr, 0, sizeof(recv_addr)); recv_addr.sin_family=AF_INET; recv_addr.sin_addr.s_addr=inet_addr(argv[1]); recv_addr.sin_port=htons(atoi(argv[2])); if(connect(sock, (struct sockaddr*)&recv_addr, sizeof(recv_addr))==-1) error_handling("connect() error!"); write(sock, "123", 3); send(sock, "4", 1, MSG_OOB); // 긴급데이터 전송 write(sock, "567", 3); send(sock, "890", 3, MSG_OOB); // 긴급데이터 전송

시그널 핸들러(SIGURG 시그널이 발생한 경우) 긴급 데이터 전송 예제[MSG_OOB] 프로그램 예제 oob_recv.c act.sa_handler=urg_handler; sigemptyset(&act.sa_mask); act.sa_flags=0; . send_sock=accept(recv_sock, (struct sockaddr*)&send_addr, &send_addr_size); fcntl(send_sock, F_SETOWN, getpid()); state=sigaction(SIGURG, &act, 0); if(state != 0) error_handling("sigaction() error "); while( (str_len=recv(send_sock, buf, sizeof(buf), 0)) != 0) { // 일반데이터를 위한 if(str_len==-1) recv 함수 continue; buf[str_len]=0; puts(buf); void urg_handler(int signo) { int str_len; char buf[BUFSIZE]; str_len=recv(send_sock, buf, sizeof(buf)-1, MSG_OOB); // 긴급데이터를 위한 buf[str_len]=0; recv 함수 printf("긴급 메시지 전송 : %s \n", buf); } SIGURG 처리를 위한 시그널 핸들러 등록 Main 함수 시그널 핸들러(SIGURG 시그널이 발생한 경우)

긴급 데이터 전송 예제[MSG_OOB] 실행결과

Urg_handler 함수에 의해 1byte 읽어드림 긴급 데이터 전송 시 생성되는 패킷 긴급 데이터 전송을 위한 패킷의 형성 긴급 데이터 전송의 특징. 버퍼 상황에 관계 없이 데이터 전송 TCP Header urg 8 9 TCP Header urg 8 9 Urg_handler 함수에 의해 1byte 읽어드림 URG Pointer Main 함수내 recv 함수가 읽어 드림

입력 버퍼 검사 예제[MSG_PEEK] MSG_PEEK process process test test test recv(sock, buf, sizeof(buf)-1,MSG_PEEK) recv(sock, buf, sizeof(buf)-1,0)

입력 버퍼 검사 예제[MSG_PEEK] 프로그램 예제 peek_send.c peek_recv.c if(connect(sock, (struct sockaddr*)&recv_addr, sizeof(recv_addr))==-1) error_handling("connect() error!"); write(sock, "123", 3); close(sock); return 0; peek_recv.c send_sock=accept(recv_sock, (struct sockaddr*)&send_addr, &send_addr_size); sleep(1); str_len=recv(send_sock, buf, sizeof(buf)-1, MSG_PEEK|MSG_DONTWAIT); buf[str_len]=0; printf("총 %d 바이트 존재합니다 : %s\n", str_len, buf); str_len=recv(send_sock, buf, sizeof(buf)-1, 0); printf("읽어 온 결과 입니다. : %s\n", buf); close(send_sock); return 0;

입력 버퍼 검사 예제[MSG_PEEK] 실행결과

readv & writev readv & writev 함수 사용 방법 fd: 데이터 전송의 목적지를 나타내는 소켓의 파일 디스 크립터를 전달 Vector: iovec 구조체 배열의 이름을 인자로 전달(전송하 는 데이터의 정보가 담겨짐) Count: 데이터를 전송하기 위해서 참고할 iovec 구조체 변수의 수를 지정 ‘3’이 인자로 전달 되면 총 3개의 iovec 변수를 참고하여 데이 터를 전송 #include <sys/uio.h> int writev(int fd, const struct iovec *vector, int count); int readv(int fd, const struct iovec *vector, int count);

readv & writev 함수의 사용 배열을 정의하기 위한 구조체의 선언. iov_base : 전송할 데이터의 시작 주소를 가리킨다. iov_len : iov_base가 가리키는 위치를 시작으로 전송하 고자 하는 바이트 수를 대입한다. struct iovec { ptr_t iov_base; size_t iov_len; }

Writev 함수의 사용 예 Iov_base=“ABC” Iov_len=3 writev(1, ptr, 2) Iov_base=“EBAD” Iov_len=4 표준출력 1: 파일 디스크립터를 나타내므로 콘솔에 출력 ptr: 전송할 데이터 정보를 지니고 있는 iovec 배열을 가리키는 포인터 2: ptr이 가리키는 주소를 시작으로 해서 총 두 개의 iovec 변수를 참조하여 그 변수가 가리키고 있는 데이터를 전송

readv & writev 함수의 데이터 입 출력 방식 Array 1 Array 2 Array 3 출력 버퍼 [write 3번 호출 ] [writev 1번 호출 ] 입력 버퍼 Array 1 Array 2 Array 3 [read 3번 호출 ] [readv 1번 호출 ]

readv & writev 함수 호출 예제 프로그램 예제 readv.c writev.c #include <stdio.h> #include <sys/uio.h> int main(int argc, char **argv) { struct iovec vec[2]; char MSG1[10]={0,}; char MSG2[10]={0,}; int str_len; vec[0].iov_base=MSG1; vec[0].iov_len=9; vec[1].iov_base=MSG2; vec[1].iov_len=9; str_len=readv(0, vec, 2); printf("\n총 %d 바이트 입력\n", str_len); printf("첫 번째 메시지 : %s \n", MSG1); printf("두 번째 메시지 : %s \n", MSG2); return 0; } #include <stdio.h> #include <sys/uio.h> int main(int argc, char **argv) { struct iovec vec[2]; char MSG1[]="Computer "; char MSG2[]="Communications"; int str_len; vec[0].iov_base=MSG1; vec[0].iov_len=strlen(MSG1); vec[1].iov_base=MSG2; vec[1].iov_len=strlen(MSG2); str_len=writev(1, vec, 2); printf("\n총 %d 바이트 출력\n", str_len); return 0; }

readv & writev 함수 호출 예제 실행결과.

소켓과 표준 입출력

표준 입출력 함수를 통한 파일 생성 예 stdio.c #include <stdio.h> #include <stdlib.h> void error_handling (char *message); int main(void) { FILE *fp; /* 표준 입출력 함수를 통한 파일 생성 */ fp = fopen("test.dat", "w"); if(fp == NULL) error_handling("file open error"); fputs("Network programming\n\n", fp); fclose(fp); return 0; } void error_handling (char *message) fputs(message, stderr); fputc('\n', stderr); exit(1); stdio.c

시스템 함수를 통한 파일 생성 sysio.c #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> void error_handling (char *message); int main(void) { int fildes; char str[] = "socket programming\n\n"; /* 시스템 함수를 통한 파일의 생성 */ fildes = open("data.daa", O_WRONLY|O_CREAT|O_TRUNC); if(fildes == -1) error_handling("file open error"); write(fildes, str, sizeof(str)-1); close(fildes); return 0; } void error_handling (char *message) fputs(message, stderr); fputc('\n', stderr); exit(1); sysio.c

표준 입출력 함수 vs 시스템 함수 공통점 차이점 참고 파일 생성 후 데이터 저장 차이점 표준입출력 함수: 파일 포인터를 이용하여 파일의 입출 력 실행 시스템 함수: 파일 디스크립터를 사용하여 파일의 입출 력 실행 참고 파일 포인터: FILE 구조체의 포인터 파일 디스크립터: 정수형 데이터 표준 입출력 함수를 이용하여 데이터 전송을 위해 서는 파일 디스크립터를 파일포인터로 만들어야 함.

파일 디스크립터를 이용하여 파일 포인터 생성하기 fdopen함수 사용 방법 fildes: 파일 포인터를 생성하기 위해 대상 파일을 가리 키는 파일 디스크립터 mode: “r” 읽기, “w” 쓰기 #include<stdio.h> FILE * fdopen(int filedes, const char * mode);

파일 디스크립터를 이용하여 파일 포인터 생성하기 fdopen함수 호출 후 파일과 파일 포인터와의 관계 File descriptor Test.dat fdopen() 호출 FILE *

파일 디스크립터를 이용하여 파일 포인터 생성 예 #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> void error_handling (char *message); int main(void) { int fildes; FILE *fp; /* 시스템 함수를 통한 파일 생성 */ fildes = open("data.dat", O_WRONLY|O_CREAT|O_TRUNC); if(fildes == -1) error_handling("file open error"); /* 파일 디스크립터를 이용하여 파일포인터 생성 */ fp=fdopen(fildes, "w"); fputs("Network C programming\n\n", fp); fclose(fp); return 0; } void error_handling (char *message) fputs(message, stderr); fputc('\n', stderr); exit(1); handle_stream.c

파일 포인터를 이용하여 파일 디스크립터 얻기 fileno함수 사용 방법 stream: 파일 포인터를 인자로 전달, 파일 포인터가 어 떤 모드로 생성 되었건 대상이 같은 파일이라면 같은 파 일 디스크립터를 리턴 #include<stdio.h> int * fileno(FILE * stream);

파일포인터를 이용하여 파일 디스크립터를 얻는 예 #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> void error_handling (char *message); int main(void) { int fildes; FILE *fp; fildes = open("data.dat", O_WRONLY|O_CREAT|O_TRUNC); if(fildes == -1) error_handling("file open error"); printf("First file descriptor : %d \n", fildes); /* 파일 디스크립터를 이용하여 파일포인터 생성 */ fp=fdopen(fildes, "w"); fputs("TCP/IP SOCKET PROGRAMMING\n\n", fp); printf("Second file descriptor : %d \n\n", fileno(fp)); fclose(fp); return 0; } stream_handle.c

표준 입출력 함수를 사용하는 echo server clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_addr,&clnt_addr_size); if(clnt_sock==-1) error_handling("accept() error"); /* 파일 디스크립터를 파일 포인터로 변환 */ readFP=fdopen(clnt_sock, "r"); writeFP=fdopen(clnt_sock, "w"); /* 데이터 수신 및 전송 */ while(!feof(readFP)){ fgets(message, BUFSIZE, readFP); fputs(message, writeFP); fflush(writeFP); // fflush 함수를 호출 해야 클라이언트로 바로 데이터 전송 보장 } fclose(writeFP); fclose(readFP); return 0; echo_stdserv.c

표준 입출력 함수를 사용하는 echo client /* 파일 디스크립터를 파일 포인터로 변환 */ readFP=fdopen(sock, "r"); writeFP=fdopen(sock, "w"); if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1) error_handling("connect() error!"); while(1) { /* 메시지 입력, 전송 */ fputs("전송할 메시지를 입력 하세요 (q to quit) : ", stdout); fgets(message, BUFSIZE, stdin); if(!strcmp(message,"q\n")) break; fputs(message, writeFP); fflush(writeFP); /* 메시지 수신, 출력 */ fgets(message, BUFSIZE, readFP); printf("서버로부터 전송된 메시지 : %s \n", message); } fclose(writeFP); fclose(readFP); return 0; echo_stdclnt.c

입출력 스트림의 분리 전용 입력 스트림과 전용 출력 스트림으로 분리 하 는 방법 입력스트림 입력스트림 출력스트림 출력스트림

입출력 스트림으로 분리한 echo server clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_addr,&clnt_addr_size); /* 연결요청 수락 */ if(clnt_sock==-1) error_handling("accept() error"); rstrm = fdopen(clnt_sock, "r"); /* 입력 스트림 생성 */ wstrm = fdopen(clnt_sock, "w"); /* 출력 스트림 생성 */ /* 출력 스트림을 통한 데이터 전송 */ fputs("FROM SERVER : Hello?\n", wstrm); fputs("I like network programming\n", wstrm); fputs("I like socket programming\n\n", wstrm); fflush(wstrm); /* 1차 종료 : 문제의 요소. 소켓 종료*/ fclose(wstrm); /* 입력 스트림을 통한 데이터 수신 */ fgets(buf, sizeof(buf), rstrm); fputs(buf, stdout); /* 2차 종료 */ fclose(rstrm); return 0; sep_server.c

입출력 스트림으로 분리한 echo client if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1) error_handling("connect() error!"); rstrm = fdopen(sock, "r"); /* 입력 스트림 생성 */ wstrm = fdopen(sock, "w"); /* 출력 스트림 생성 */ while(1) /* EOF가 입력 될 때까지 데이터 수신 후 출력 */ { if(fgets(buf, sizeof(buf), rstrm)==NULL) break; fputs(buf, stdout); fflush(stdout); // 모니터에 출력 } /* 인사 메시지 전송 */ fputs("FROM CLIENT : Thanks you!\n", wstrm); fflush(wstrm); // 서버로 감사 메시지 전송 fclose(wstrm); fclose(rstrm); return 0; sep_client.c

입출력 스트림의 분리한 echo server/client 문제점 server client connect() Send(“FROM SERVER: Hello?”) Send(“I like network programming”) Send(“I like socket programming”) Send(EOF) 소켓 소멸 Send(“Thank you”)

입출력 스트림의 분리한 echo server 종료 과정 소켓종료 socket File descriptor fdopen(fd,r) fdopen(fd,w) 파일디스크립터 종료 파일포인터 입력 스트림 파일포인터 출력 스트림 fclose()

입출력 스트림 분리 문제점 해결 방안 연결 유지 상태 socket 복사 File descriptor fdopen(fd,r) fdopen(fd,w) 파일디스크립터 종료 파일포인터 입력 스트림 파일포인터 출력 스트림 fclose()

파일 디스크립터 복사 dup, dup2함수 사용 방법 fildes: 복사하고자 하는 파일 디스크립터를 인자로 전 달 #include<unistd.h> int dup(int fildes); Int dup2(int fildes, int fildes2);

파일 디스크립터 복사 예 dup1.c dup2.c #include <stdio.h> #include <unistd.h> int main(void) { int fd; fd=dup(1); /* standard out */ printf("복사된 파일 디스크립터 : %d\n", fd); write(fd, "복사된 파일 디스크립터에 의한 출력 \n",36); return 0; } dup1.c int main(void) { int fd; int state; fd=dup(1); /* standard out */ printf("복사된 파일 디스크립터 : %d\n", fd); write(fd, "복사된 파일 디스크립터에 의한 출력 \n",36); state = close(1); if(state ==-1){ puts("에러 발생\n"); exit(1); } return 0; dup2.c

파일 디스크립터 복사 후 스트림 생성 예 sep_server2.c clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_addr,&clnt_addr_size); if(clnt_sock==-1) error_handling("accept() error"); rstrm = fdopen(clnt_sock, "r"); /* 입력 스트림 생성 */ /* 디스크립터 복사 후 출력 스트림 생성 */ wstrm = fdopen(dup(clnt_sock), "w"); /* 메시지 전송 */ fputs("FROM SERVER : Hello?\n", wstrm); fputs("I like network programming\n", wstrm); fputs("I like socket prograaming\n\n", wstrm); fflush(wstrm); /* 1차 종료, EOF 메시지 전송 */ shutdown(fileno(wstrm), SHUT_WR); fclose(wstrm); /* 메시지 수신 */ fgets(buf, sizeof(buf), rstrm); fputs(buf, stdout); /* 2차 종료(완전 종료) */ fclose(rstrm); return 0; } sep_server2.c

Half-close 기능의 함수 #include <sys/socket.h> int shutdown(int s, int how); 상수값 모드 정의 SHUT_RD 입력 스트림 종료 1 SHUT_WR 출력 스트림 종료 2 SHUT_RDWR 입 출력 스트림 종료

프로그램 예제 file_server.c, file_client.c 실행하기

2. File list(1. movie1.dat , 2. movie2.dat) 실습과제 간단한 파일 전송 프로그램 Server Client 1. connect 부모 프로세스 부모 프로세스 2. File list(1. movie1.dat , 2. movie2.dat) 3. 1 또는 2 선택 자식 프로세스 자식 프로세스 4. 해당파일 전송