Download presentation
Presentation is loading. Please wait.
1
Department of Computer Engineering
Advanced I/O Function Department of Computer Engineering Kyung Hee University. Choong Seon Hong
2
recv & send read & write 함수와 달리 데이터 입 출력 방법에 있어서 옵션 부여.
#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); sock: 입출력의 대상이 되는 소켓의 파일 디스크립터 buf: 입력 및 출력을 위한 버퍼의 포인터 len: 전송할 데이터의 바이트 수 혹은 수신할 수 있는 최대 바이트 수 flags: 데이터 입출력시 그 방법에 있어서 옵션을 설정하는 용도로 사용. ‘0’의 값을 넘겨줄 경우 read, write와 완전히 동일한 기능의 함수 옵션은 bitwise OR(|)로 묶어서 두 개 이상이 함께 전달될 수 있다.
3
recv & send 옵션의 종류와 의미 flags Description recv send MSG_DONTROUTE
데이터 전송 시 라우팅 테이블 참조 하지 않음 (local network상의 목적지를 찾겠다는 의미) MSG_DONTWAIT 데이터 입출력 함수 호출 시 블로킹되지 않고 바로 리턴할 것을 요구하는 경우에 사용 (넌-블록킹(non-blocking) I/O) MSG_OOB 긴급 데이터(Out-of-band data) 전송 MSG_PEEK 버퍼에 데이터 유 무 확인
4
긴급 데이터 전송 예제[MSG_OOB] SIGURG ? 긴급데이터 전송 방법 긴급데이터 수신 시 “SIGURG” 시그널 발생
fork() 함수를 통해 여러 개의 프로세스 생성시 긴급데이터는 ? send(sock, “test”, 4, MSG_OOB); recv(sock, buf, sizeof(buf)-1, MSG_OOB); 커널 ? SIGURG 부모프로세스 자식프로세스
5
긴급 데이터 전송 예제[MSG_OOB] SIGURG
clnt_sock이 가리키는 소켓의 소유자를 getpid 함수가 리턴하는 ID의 프로세스로 변경 F_SETOWN: 소유자 변경 fcntl(clnt_sock, F_SETOWN, getpid()) 부모프로세스 SIGURG 커널 자식프로세스 fcntl(clnt_sock, F_SETOWN, getpid())
6
긴급 데이터 전송 예제[MSG_OOB] 실행결과 - oob_send.c, obb_recv.c
7
긴급 데이터 전송 시 생성되는 패킷 긴급 데이터 전송을 위한 패킷의 형성 긴급 데이터 전송의 특징.
버퍼 상황에 관계 없이 데이터 전송 Urgent Pointer Offset = 0 Offset = 3 6 6 4 5 4 5 URG=1 Urgent Pointer=3 TCP Header Data Offset = 0 Offset = 3 urg_handler 함수에 의해 1byte 읽어들임 (출력버퍼) main 함수내 recv 함수가 읽어 들임 (TCP 패킷)
8
입력 버퍼 검사 예제[MSG_PEEK] MSG_PEEK
MSG_PEEK 옵션은 MSG_DONTWAIT 옵션과 함께 설정되어 입력 버퍼에 수신된 데이터가 있는지 확인하는 목적으로 사용되는 옵션 MSG_PEEK 옵션을 주고, recv 함수를 호출했을 때 데이터가 버퍼에 존재한다면 버퍼로부터 데이터를 읽어 들인다. 일반적으로 recv 함수를 호출해서 데이터를 읽어 들이게 되면, 읽어 들인 데이터는 버퍼에서 사라짐 그러나, MSG_PEEK 옵션을 주어서 데이터를 읽어 오게 되면, 읽고 나서도 데이터가 그대로 버퍼에 남아 있게 된다.
9
입력 버퍼 검사 예제[MSG_PEEK] 실행결과 – peek_recv.c, peek_send.c
10
readv & writev 함수의 데이터 입 출력 방식
Array 1 Array 2 Array 3 출력 버퍼 [write 3번 호출 ] [writev 1번 호출 ] 입력 버퍼 Array 1 Array 2 Array 3 [read 3번 호출 ] [readv 1번 호출 ]
11
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);
12
readv & writev 함수의 사용 배열을 정의하기 위한 구조체의 선언.
iov_base : 전송할 데이터의 시작 주소를 가리킨다. iov_len : iov_base가 가리키는 위치를 시작으로 전송하고자 하는 바이트 수를 대입한다. struct iovec { ptr_t iov_base; size_t iov_len; }
13
writev 함수의 사용 예 Iov_base=“ABC” Iov_len=3 writev(1, ptr, 2)
Iov_base=“EBAD” Iov_len=4 표준출력 1: 파일 디스크립터를 나타내므로 콘솔에 출력 ptr: 전송할 데이터 정보를 지니고 있는 iovec 배열을 가리키는 포인터 2: ptr이 가리키는 주소를 시작으로 해서 총 두 개의 iovec 변수를 참조하여 그 변수가 가리키고 있는 데이터를 전송
14
readv & writev 함수 호출 예제 프로그램 예제 writev.c readv.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; }
15
readv & writev 함수 호출 예제 실행결과 –readv.c, writev.c
16
소켓과 표준 입출력
17
표준 입출력 함수를 통한 파일 생성 예 d 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
18
시스템 함수를 통한 파일 생성 d 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
19
표준입출력 및 시스템 함수를 통한 파일 생성 실행결과 - stdio.c, sysio.c
20
표준 입출력 함수 vs 시스템 함수 공통점 차이점 참고
파일 생성 후 데이터 저장 차이점 표준입출력 함수: 파일 포인터를 이용하여 파일의 입출력 실행 시스템 함수: 파일 디스크립터를 사용하여 파일의 입출력 실행 참고 파일 포인터 : FILE 구조체의 포인터 파일 디스크립터 : 정수형 데이터 표준 입출력 함수를 이용하여 데이터 전송을 위해서는 파일 디스크립터를 파일포인터로 만들어야 함.
21
파일 디스크립터를 이용하여 파일 포인터 생성하기
fdopen함수 사용 방법 fildes: 파일 포인터를 생성하기 위해 대상 파일을 가리키는 파일 디스크립터 mode: “r” 읽기, “w” 쓰기 #include<stdio.h> FILE * fdopen(int filedes, const char * mode);
22
파일 디스크립터를 이용하여 파일 포인터 생성하기
fdopen함수 호출 후 파일과 파일 포인터와의 관계 File descriptor test.dat fdopen() 호출 FILE *
23
파일 디스크립터를 이용하여 파일 포인터 생성 예
d #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
24
파일 디스크립터를 이용하여 파일 포인터 생성 예
실행결과 - handle_stream.c
25
파일 포인터를 이용하여 파일 디스크립터 얻기 fileno함수 사용 방법
stream: 파일 포인터를 인자로 전달, 파일 포인터가 어떤 모드로 생성 되었건 대상이 같은 파일이라면 같은 파일 디스크립터를 리턴 #include<stdio.h> int * fileno(FILE * stream);
26
파일포인터를 이용하여 파일 디스크립터를 얻는 예
d #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
27
파일포인터를 이용하여 파일 디스크립터를 얻는 예
실행결과 - stream_handle.c
28
표준 입출력 함수를 사용하는 echo server
d 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
29
표준 입출력 함수를 사용하는 echo client
d /* 파일 디스크립터를 파일 포인터로 변환 */ 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
30
표준 입출력 함수를 사용하는 echo server & client
실행결과 –echo_stdserv.c, echo_stdclnt.c
Similar presentations