저 수준 파일 입출력
ANSI의 표준 함수가 아닌, 운영체제가 제공하는 함수 기반의 파일 입출력이다. 표준이 아니기에 운영체제 별 호환성이 없다.
리눅스의 경우 소켓도 파일로 간주하므로 저 수준 파일 입출력 함수를 기반으로 소켓 기반의 데이터 송 수신이 가능하다.
file descriptor (파일 디스크립터)
운영체제가 만들 파일(및 소켓)을 구분하기 위한 숫자이다. 저 수준 파일 입출력 함수는 입출력을 목적으로 파일 디스크립터를 요구한다.
저 수준 파일 입출력 함수에게 소켓의 file descriptor를 전달하면, 소켓을 대상으로 입출력을 진행한다.
file descriptor의 경우 0,1,2 는 파일 생성 시 미리 지정되어있다.
파일 열기 / 닫기
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char* path, int flag); // 성공시 file descriptor, 실패 시 -1 반환
// path : 파일 이름을 나타내는 문자열의 주소 값 전달
// flag : 파일의 오픈 모드 정보 전달
open명령어를 수행하면 file descriptor 값이 반환된다.
flag에는 파일의 오픈 모드에 대해서 설정할 값이 들어가는데 이는 다음과 같다
#include <unistd.h>
int close(int fd); // 성공 시 0, 실패 시 -1 반환
// id : 닫고자 하는 파일이나 소켓의 파일 descriptor
open을 통해서 얻은 file descriptor를 통해 파일 입출력을 진행
파일에 데이터 쓰기
#include <unistd.h>
ssize_t write(int fd, const void * buf, size_t nbytes); // 성공 시 전달한 바이트 수, 실패 시 -1 반환
// id : 데이터 전송대상을 나타내는 파일 디스크립터 전달
// buf : 전송할 데이터가 저장된 버퍼의 주소 값 전달
// nbytes : 전송할 데이터의 바이트 수 전달
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;
}
위 코드를 보자.
파일에 적을 내용을 buf배열에 담고, open을 통해 data.txt의 file descriptor를 받은 후,
write 함수를 통해 buf의 내용을 fd로 지정된 size만큼 복사한다.
실행 결과를 확인하면 아래와 같다.
root@my_linux: /tcpip# gcc low_open.c -o lopen
root@my_ linux: /tcpip# ./lopen
file descriptor: 3
root@my_linux:/tcpip# cat data.txt
Let's go!
root@my_linux: /tcpip#
파일에 저장된 데이터 읽기
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t nbytes); // 성공시 수신한 바이트 수, 실패 시 -1 반환
// fd : 데이터 수신 대상을 나타내는 파일 디스크립터 전달
// buf : 수신한 데이터를 저장할 버퍼의 주소 값 전달
// nbytes : 수신할 최대 바이트 수 전달
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;
}
위 코드를 보자.
open을 통해 파일을 열어 file descriptor를 받고, 받은 fd값을 이용해 read로 buf의 size만큼 읽어온다.
실패하지 않았다면, 읽어온 byte만큼 buf에 저장될 것이므로, buf를 출력하면 읽어온 내용을 볼 수 있다.
실행 결과는 다음과 같다.
root@my_linux: / tcpip# gcc low_read.c - o lread
root@my_linux: / tcpip# ./lread
file descriptor : 3
file data : Let's go!
root@my_linux : / tcpip#
file descriptor와 socket
int main(void)
{
int fdl, 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;
}
위 코드에서 socket과 파일을 열었을 때 모두 file discriptor 값이 할당된다. 즉 리눅스는 파일과 소켓을 동일하게 간주한다.
실행 결과는 아래와 같다.
root@my_linux: /tcpip# gcc fd_seri.c -o fds
root@my_linux:/tcpip# ./fds
file descriptor 1: 3
file descriptor 2: 4
file descriptor 3: 5
root@my_linux: /tcpip#
'개발 · 컴퓨터공학' 카테고리의 다른 글
네트워크 프로그래밍 - 소켓 IP 주소와 PORT 번호, byte order(바이트 순서), byte order convert (바이트 순서 변환) (0) | 2021.09.26 |
---|---|
네트워크 프로그래밍 - 소켓에서의 프로토콜 설정 (0) | 2021.09.25 |
컴퓨터 그래픽스 - 그래픽 하드웨어 (0) | 2021.09.23 |
네트워크 프로그래밍 - 패킷 전달[HLEN, Control Field(SYN, FIN, ACK), Checksum], handshake (0) | 2021.09.22 |
컴퓨터 그래픽스 - 컴퓨터 그래픽스의 응용 및 역사 (0) | 2021.09.21 |