Linux/Linux_programing

Linux : dup과 dup2

sosal 2010. 7. 2. 16:30
반응형


/*
 http://sosal.tistory.com/
 * made by so_Sal
 */

이 포스팅은 open, read, write 등의 시스템콜을 기본적으로
안다는 가정 하에 작성된 글입니다.
위 시스템콜에 대해서 모르신다면 :: LINK_

1. dup
2. dup2

1.dup - 파일 식별자를 복제한다.
#include<unistd.h> // man  page 참조
   int dup( int fd );

(dup은 duplication의 약자겠죠?.. 아마.. ㅋㅋ)
새로운 파일 서술자를 반환하지만, 숫자만 다를 뿐
원래의 서술자, 복제된 서술자 모두 완벽히 같은 파일을 가리킨다.
실패 : -1 반환 (파라미터로 전달된 값이 fd가 아닐경우, 더이상 fd를 할당하지 못할경우)

/*
 * fd1 파일 디스크립터에 open을 이용하여 password라는 파일을 만든 후
 * fd1을 이용하여 "hello?\n" 라는 문자열을 write합니다.
 * fd2 파일 디스크립터에 dup(int) 시스템콜을 이용하여
 * fd2에 fd1을 복사합니다.
 *
 * fd1와 fd2가 가지는 파일디스크립터 숫자와,
 * password라는 파일에 fd1, fd2 두가지 파일 디스크립터로
 * 쓰기가 가능한지 확인하는 예제입니다.
 */


#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<string.h>

int main(){
    int fd1 = open("./password",O_CREAT | O_WRONLY, 0755);

    printf("fd1 is :: %d\n",fd1);
    write(fd1,"hello?\n",strlen("hello?\n"));

    int fd2 = dup(fd1);

    printf("fd2 is :: %d\n",fd2);
    write(fd2,"hi?\n",strlen("hi?\n"));
    return 0;
}




fd1과 fd2가 각각 3,4로 다른 번호를 가지고있습니다.
하지만 write를 쓴 결과 똑같은 파일 (password)에 문자열이 쓰기가 되네요.
완벽한 복제가 일어났습니다. ㅎㅎ
그렇다면 close(fd1)을 시행했을 때, fd2가 계속 살아 있을까요?
당연히 살아있습니다. 파일디스크립터가 같은 파일(inode)를 지정하여
하나 더 열리는 것이기 때문에, dup 시스템콜이 호출된 이후에는
fd1과 fd2는 완전히 다른 파일 디스크립터입니다. (물론 같은 파일을 가리키지만)





2. dup2

dup2입니다. dup과 이름이 비슷하고, dup과 dup2..
dup2니까 뭔가 더 발전된 시스템콜이라고 보여질 수 있겠네요.
하지만 dup과 dup2의 사용 용도는 완벽하게 다릅니다.


1.dup2 - 파일 식별자를 복제한다.
#include<unistd.h> //man page 참조
   int dup2( int old_fd1 ,int new_fd2 );

똑같이 파일 식별자를 복제한다고 되어있지만,
매개변수로 생각해 볼 수 있는 전개는
old_fd1을 new_fd2로 바꿔버린다! 인데,
사실 그게 아니라 fd2라는 녀석을 fd1으로 바꿔버린다! 입니다.
좀 어색하죠?

예를들어 int dup2( fd, stdout ); 이라고 한다면 // 물론 stdout은 1번
이제부터 모든 출력은 fd로 향하게 됩니다.
잘 이해가 안된다구요? 사실 제가 써놓고도 잘 이해가 안되네요. 어렵습니다.
예제로 확인하시면 바로 아?! 하실겁니다. 화팅!


/*
 * 파일 디스크립터 fd를 생성한 후, dup2() 시스템콜을 호출합니다.
 * dup2(fd, 1)이 호출된 이후에는
 * 모든 출력이 fd라는 파일 디스크립터로 write되게 됩니다.
 */
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<string.h>

int main(){

    int fd=open("password1",O_CREAT | O_WRONLY, 0755);
    dup2(fd,1);

    char buffer[20] = "welcome!\n";

   printf("%s",buffer);
    fflush(stdout); //write 시스템콜이 printf() 보다 빠르기 때문에, 버퍼를 비워줌
   write(1,  buffer, strlen(buffer) );
   write(fd, buffer, strlen(buffer) );


    close(fd);
    return 0;

}



dup2 메소드를 이용하여 fd라는 녀석을 stdout(1) 로 바꿔버렸습니다.
하지만 실행후 모습을 보니 dup2는 여전히 3번이네요.?
위 프로그램에서 printf(~) 와 write(1~)은 출력을 해야하지만
dup2를 실행한 후에 아무것도 출력이 되지 않았습니다.
그 이유는, dup2의 두번째 인자 stdout이 이제부터 fd가 된것이기 때문입니다.

아오.. 적으면서 뭔가.. 뭔가가 부족하네요
최후의 수단으로 머리에 전구를 띄워드리겠습니다.



/proc/~pid/fd/ 풀더에 들어가면 ~pid 프로세스의 파일 서술자를 확인할 수 있습니다.
아? 1번이 (stdout. 표준출력) 3번과 완벽하게 같아졌네요?
그럼 dup2를 이용해서 부모프로세스가 자식프로세스에게
표준입력으로 문자열을 주는 프로그램을 짤 수 있겠습니다.

참고자료 : Advanced Unix Programming 제 2판 | MARC J.ROCHKIND저 | 정보문화사