# 표준 입출력과 표준 에러에 할당된 파일 디스크립터
| 파일 디스크립터 | 대상 |
| 0 | 표준입력 : Standard Input |
| 1 | 표준출력 : Standard Output |
| 2 | 표준에러 : Standard Error |
파일과 소켓은 생성의 과정을 거쳐야 파일 디스크립터가 할당됨.
위의 세가지 입출력 대상은 별도의 생성과정없이도 프로그램이 실행되면 자동으로 할당되는 파일 디스크립터.
# 파일열기
- 데이터를 읽거나 쓰기 위해 파일을 열 때 사용하는 함수
- 첫 번째 인자 : 대상이 되는 파일의 이름 및 경로 정보
- 두 번째 인자 : 파일의 오픈 모드 정보(파일의 특성 정보)를 전달
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *path, int flag);
-> 성공시 파일 디스크립터, 실패시 -1반환
- path : 파일 이름을 나타내는 문자열의 주소 값 전달
- flag : 파일의 오픈 모드 정보 전달
위 함수의 두 번째 매개변수 flag에 전달할 수 있는 값과 그 의미는 밑 표 참고
하나 이상의 정보를 비트 OR 연산자로 묶어서 전달 가능
| 오픈 모드 | 의미 |
| O_CREAT | 필요하면 파일을 생성 |
| O_TRUNC | 기존 데이터 전부 삭제 |
| O_APPEND | 기존 데이터 보존하고, 뒤에 이어서 저장 |
| O_RDONLY | 읽기 전용으로 파일 오픈 |
| O_WRONLY | 쓰기 전용으로 파일 오픈 |
| O_RDWR | 읽기, 쓰기 겸용으로 파일 오픈 |
# 파일 닫기
- 밑 함수 호출하면서 파일 디스크립터를 인자로 전달하면 해당 파일은 종료됨
- 파일 뿐만 아니라 소켓도 해당 -> 파일과 소켓을 구분하지 않는다. (리눅스 운영체제의 특징)
#include <unistd.h>
int close(int fd);
-> 성공 시 0, 실패 시 -1 반환
- fd : 닫고자 하는 파일 또는 소켓의 파일 디스크립터 전달
# 파일에 데이터 쓰기
- 파일에 데이터를 출력(전송)하는 함수
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t nbytes);
-> 성공 시 전달한 바이트 수, 실패 시 -1 반환
- fd : 데이터 전송 대상을 나타내는 파일 디스크립터 전달
- buf : 전송할 데이터가 저장된 버퍼의 주소 값 전달
- nbytes : 전송할 데이터의 바이트 수 전달
# 파일의 생성 및 데이터의 저장
low_open.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
void error_handling(char* message);
int main(void)
{
int fd;
char buf[]="Let's go!\n";
fd=open("data.txt", O_CREAT|O_WRONLY|O_TRUNC);
if(fd==-1)
error_handling("open() error!");
printf("file descriptor: %d \n", fd);
if(write(fd, buf, sizeof(buf))==-1)
error_handling("write() error!");
close(fd);
return 0;
}
void error_handling(char* message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
/*
root@com:/home/swyoon/tcpip# gcc low_open.c -o lopen
root@com:/home/swyoon/tcpip# ./lopen
file descriptor: 3
root@com:/home/swyoon/tcpip# cat data.txt
Let's go!
root@com:/home/swyoon/tcpip#
*/
12행 : 파일 오픈 모드가 O_CREAT, O_WRONLY, O_TRUNC의 조합으로 아무것도 저장되어 있지 않은 새로운 파일이 생성되어 쓰기만 가능
이미 data.txt라는 이름의 파일이 존재한다면, 이 파일의 모든 데이터는 지워져 버림.
17행 : fd에 저장된 파일 디스크립터에 해당되는 파일에 buf에 저장된 데이터를 전송하고 있음

리눅스의 cat명령을 통해 data.txt 파일에 저장된 내용을 출력,
출력내용은 파일에 데이터가 제대로 전송되었음을 보여줌
# 파일에 저장된 데이터 읽기
- write함수의 상대적인 기능을 제공하는 read함수는 데이터를 입력(수신)하는 기능의 함수
#include <unistd.h>
ssize_t read(int fd, void #buf, size_t nbytes);
-> 성공 시 수신한 바이트 수(단 파일의 끝을 만나면 0), 실패 시 -1반환
- fd : 데이터 수신대상을 나타내는 파일 디스크립터 전달
- buf : 수신한 데이터를 저장할 버퍼의 주소값 전달
- nbytes : 수신할 최대 바이트 수 전달
- 위에서 생성한 data.txt에 저장된 데이터를 read함수를 이용해 읽어오는 예제
low_read.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#define BUF_SIZE 100
void error_handling(char* message);
int main(void)
{
int fd;
char buf[BUF_SIZE];
fd=open("data.txt", O_RDONLY);
if( fd==-1)
error_handling("open() error!");
printf("file descriptor: %d \n" , fd);
if(read(fd, buf, sizeof(buf))==-1)
error_handling("read() error!");
printf("file data: %s", buf);
close(fd);
return 0;
}
void error_handling(char* message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
/*
root@com:/home/swyoon/tcpip# gcc low_read.c -o lread
root@com:/home/swyoon/tcpip# ./lread
file descriptor: 3
file data: Let's go!
root@com:/home/swyoon/tcpip#
*/
13행 : data.txt 읽기전용으로 open
18행 : read함수로 11행에 선언된 배열 buf에 읽어들인 데이터 저장

# 파일 디스크립터와 소켓
- 파일, 소켓 생성후 반환되는 파일 디스크립터의 값을 정수형태로 비교하는 예제
fd_seri.c
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/socket.h>
int main(void)
{
int fd1, fd2, fd3;
fd1=socket(PF_INET, SOCK_STREAM, 0);
fd2=open("test.dat", O_CREAT|O_WRONLY|O_TRUNC);
fd3=socket(PF_INET, SOCK_DGRAM, 0);
printf("file descriptor 1: %d\n", fd1);
printf("file descriptor 2: %d\n", fd2);
printf("file descriptor 3: %d\n", fd3);
close(fd1);
close(fd2);
close(fd3);
return 0;
}
9~11행 : 1 파일, 2 소켓 생성
13~15행 : 앞서 생성한 파일 디스크립터의 정수 값 출력

'Backend > Network' 카테고리의 다른 글
| [TCP/IP] Iterative 에코서버, 에코 클라이언트 (0) | 2021.09.18 |
|---|---|
| [TCP/IP] TCP와 UDP (0) | 2021.09.18 |
| [TCP/IP] 리눅스 환경에서 C언어로 Hello World 서버/클라이언트 구현하기 (0) | 2021.09.05 |
| [TCP_IP] VMware 설치방법 (0) | 2021.08.30 |
