티스토리 뷰

/etc/resolv.conf 에 resolver configuration files이 존재한다. 이 conf 파일에 네임서버 주소가 적혀있다.(계속해서 쌓인다)

resolver code는 conf파일에서 도메인이름에 대한 아이피주소가 없는 경우

로컬 dns 주소를 읽어서 그 서버에게 udp요청을 한다.(tcp도가능)


이 local 네임 서버에 그 네임에 대한 아이피 주소 정보가 없으면 상위 도메인 네임 서버에게 요청 하고 거기에도 없으면 또 상위에 요청한다.

한국에는 korea 전체를 커버하는 네임서버가 존재하고 각 국의 네임서버를 커버하는 네임서버가 미국 캘리포니아(dns 루트)에 위치한다고 한다.


만약에 내가 어떤 도메인을 사용하고 싶은 경우 한국 도메인 네임 서버에 등록을 해놓으면 나중에 그 정보가 루트 dns에 전달된다.


resolve code는 대충 다음과 같은 형태를 띈다.

int resolve(const char *name, struct in_addr *addr) {

    struct hostent *he = gethostbyname(name);

    if (!he)
        return 1;

    memcpy(addr,he->h_addr_list[0],4);

    return 0;
}


gethostbyname을 호출하는경우 데몬이라고 불리는 프로세스를 호출 한다.

이 데몬이라는 프로세스가 도메인 네임 서버에 udp요청을 보내서 도메인을 아이피 주소로 바꿔주는 역할을 담당한다.


gethostbyname이 리턴시키는 hostent라는 구조체에는 5개의 멤버변수들을 가진다.

h_name은 도메인의 이름이다.

h_aliases는 그 도메인에 대한 별명들에 대한 정보이다. 자료형이 char**이다.

h_length는 바이트 단위이다. 즉 4바이트 = ip주소길이

그 도메인에 대한 아이피 주소들의 리스트(멀티 홈일 경우 여러개의 아이피 주소 존재 가능)가 h_addr_list에 들어간다.


gethostbyname이라는 시스템콜은 IPV4에서만 적용 가능하다.

-> 유닉스에서 hostent라는 구조체가 미리 시스템에 만들어져있긴 하지만 static 변수이다.

그래서 멀티쓰레드가 언제 해당 struct를 접근하냐에 따라 race condition이 발생할수 있다.


getservbyname 은 그 도메인에 대한 포트번호를 알아내는 시스템 콜이다.

hostent 구조체는 프로세스당 하나씩 존재한다.



pptr은 alias를 의미하며, inetaddrp배열은 ip주소의 배열이다.



중요 : 위의 gethostbyname과 getservbyname을 이용한 

daytime클라이언트 프로그램을 에코 클라이언트 프로그램으로 바꿔보기


re-entrancy (재진입성)


어떤 함수가 있는데, 어떤 쓰레드가 해당 함수를 호출해서 리턴하기 전인데 다른 쓰레드가 동일한 함수를 호출할수 있도록 허락하는게 reentrant하다라고 한다.


멀티 쓰레드 프로그래밍을 할때는 공유변수에 대해서 프로그램상에서 언제 어떤 쓰레드가 접근할지 제어할수가없다.

hostent라는 구조체는 static변수이고 프로세스당 하나씩 공유변수로 존재한다.


그래서 멀티 쓰레딩을 할때 race condition이 생기지 않게 주의해야한다.

내가 어떤 함수를 들어갈때 static변수를 old값으로 save해놓았다가, read/write를 하고 리턴하기 직전에 다시 old값으로 돌려놓아야 한다.


static변수에 한번더 encapsulation을 해서(세마포어를 흉내냄) hostent를 한번더 감싸는 rapper function을 만들어서 임계구역을 잘 조절해야한다.


이렇게 함으로써 재진입이 불가능한 함수인 gethostbyname등을 여러 쓰레드들이 차례대로 한번에 한 쓰레드만 사용하게끔 해서 리턴값이 꼬이는 일이 발생하지 않게끔 하는것이다.


현재 임계구역이 어떤 쓰레드에게 점유되어있다라는 정보를 다른 쓰레드가 알수 있게끔 해야한다.


세마포어라는것은 유닉스가 만들어지기 전부터 있던 개념이지만, 실제로 유닉스에 구현된것은 한참 오래 뒤에 일이다.


gethostbyname 시스템콜이 도메인에 대한 아이피주소를 구해오는 와중에 어떤 이벤트가 발생해서 시그널 핸들러가 호출 되었다고 해보자.

그 시그널 핸들러 안에서 gethostbyname을 또한번 호출하는 경우 문제가 생긴다.


재진입성 문제는 gethostbyname or gethostbyaddr을 main flow of control 와 시그널 핸들러에서 동시에 호출하는경우 생기기 때문에 주의 해야한다.

main ()
{
     struct hostent *hptr;
     ...
     signal (SIGALRM, sig_alrm);
     ...
     hptr = gethostbyname ( ... ) ;
     ...
}
void
sig_alrm (int signo)
{
    struct hostent *hptr;
    ...
    hptr = gethostbyname ( ... ) ;
    ...
}


이렇게하면 주 제어 흐름의 호출에 대해 계산 된 값이 시그널 핸들러의 호출에 대해 계산 된 값으로 덮어 씁니다.


gethostbyname, gethostbyaddr, getservbyname 및 getservbyport는 모두 static 변수인 hostent 에 대한 포인터를 반환하기 때문에 재진입이 불가능합니다.( hostent는 프로세스당 하나 존재하기 때문에)

-> 재진입이 불가하다 -> 어떤 프로세스 또는 쓰레드가 한번 이 함수를 호출했는데 또 다시 다른 쓰레드 또는 프로세스가 같은 함수를 호출한경우

잘못된 값을 읽고 쓸 가능성 존재.


하지만 멀티 쓰레드를 지원하는 경우 위의 4가지 시스템콜에 대한 재진입 버전인 시스템콜이 존재한다 끝에 _r을 추가하면 된다.

재진입 버전 -> 여러 멀티 쓰레드들이 동시에 같은 시스템콜을 호출해도 문제가 생기지 않음.








댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함