본문 바로가기
일상,취미

다시 시작하는 TIL 14일차

by 진득한진드기 2024. 6. 26.

오늘 한일 

window 프로그램을 만드는 과정이 숙달되야하는데 아직 버거운거 같다. 오히려 처음 해보는 윈도우 프로그래밍이 더 낯설고 어려운 느낌이다.

 

이번에 window32 api를 이용하다가 알아낸 정보가 있다.

 

그 정보는 아래와 같다.


윈도우에서 각 프로세스는 핸들 테이블이란게 존재하는데 이 핸들 테이블은 해당 프로세스가 접근할 수 있는 개체에 대한 개체의 실제 메모리 주소, 액세스 권한, 참조 횟수 등이 들어가 있다.

 

윈도우에서는 파일 , 쓰레드 ,뮤텍스 이런 개체에 직접 접근이 안되는데  간접적으로 추상화된 개념인 핸들이라는거를 통해서 접근한다.

 

간단하게 생각해서 내부는 잘몰라도 다루기 쉽게 만들어 놨다고 생각하면 된다.

 

윈도우 API에선 OpenProcess나 OpenThread 같은 함수로 개체를 생성하고 이 개체에 접근하려면 이 개체에 대한 핸들이 요구된다.

 

또 그 객체에 대한 엑세스 권한을 가지고 있는지 확인하여 가지고 있지 않다면 엑세스를 거부한다.

 

전에 선임이 말해준거지만 생성한 핸들을 CloseHandle로 닫아줘야 한다. 그렇지 않으면 좀비 프로세스가 되기 때문이다.

 

우리는 추상화해서 사용하기 때문에 CloseHandle이라는 신호를 보내지 않으면 특정 프로세스가 끝난줄 모른다고 생각하면 된다.

 

그러면 여기서 왜 굳이 닫아줘야하나?

 

위와 같은 생각이 들거다.

 

윈도우에선 모든 개체를 생성하고 삭제하는 개체 관리자가 존재한다. 이중 윈도우 커널 내에서 존재하는 개체를 커널 오브젝트라고 하는데 파일, 쓰레드 , 프로세스등이 이에 해당된다.

 

모든 커널 오브젝트는 참조횟수라는 변수가 있는데 커널 오브젝트에 접근하거나 핸들을 얻거나 하면 참조 횟수가 증가하고 반대로 커널 오브젝트에 더 이상 접근안하거나 핸들을 닫으면 참조횟수가 감소한다.

 

이게 0이 되면 그 커널 오브젝트가 삭제가 가능해진다. 이렇게 특정 프로세스가 Close되지 않으면 참조 횟수가 0이 아니기에 해당 프로세스 플래그에 삭제 플래그(DELETE BIT)를 포함만 하고 바로 삭제는 안한다.

 

결국 그 프로세스의 모든 핸들이 닫혀있어야 비로소 0 이 되므로 삭제가 가능해진다.

 

이런 내용들 때문에 선임분 께서 엔진에서 프로세스를 사용했을때  프로세스에 할당한 메모리는 직집 다 메모리 할당을 깔끔하게 해제하라는 이야기를 한 것 같다. 당연한 이야기지만 실수하지 말라는 소리였구나 싶다.

 

이제 막 시작해서 그런지 단지 프론트엔드 개발 같다고 생각하면 안될 것 같다. 생각보다 알아야 하는 CS나 운영체제적인 지식이 좀 강한 느낌이다.

 

퇴근 후 공부 

 


listen 소켓
= 소켓을 생성을 한 다음 용도를 설정을 해줘야한다.

여기서 listen 함수는 클라이언트가 연결 요청을 했을 때 연결을 수락하는 함수를 만들어 호출을 하려고하는 것 이다.

 

listen함수로 클라이언트의 요청을 이 소켓을 사용하겠다를 알려주는것 즉, 그 소켓을 리스닝 소켓으로 만드는것은 결국 운영체제 이다.

 

완료가 되면 요청을 받아들일 수 있는 소켓이 되는 것이다.

 

두 개의 인자를 요구 한다.

 

 

연결요청 대기 상태로의 진입


int listen(int sock, int backlog);

 

return -> 성공시 0 실패시 -1 

 

sock = 연결요청 대기 상태에 두고자 하는 소켓의 파일 디스크립터를 전달, 이 함수의 인자로 전달된 디스크립터의 소켓이 서버 소켓이 된다.

 

backlog = 연결 요청 대기큐의 크기정보 전달 , 5개 전달되면 큐의 크기가 5가되어 클라이언트의 연결요청을 5개까지 대기 시킬 수 있다.

 

listen함수를 호출하게 되면 요청을 수락하고 관리하는 문지기를 생성하는 것이고 이와 함께 뒤에 전달되는 backlog는 대기 인원들을 기다리게 하는 방을 생성하는 것과 같다.(연결요청 대기 큐)


여기서 주의 할것은 Listen함수는 연결을 위해 관리 해주는 녀석이지 직접적으로 연결해주는 녀석이 아니다.

 

TCP란 녀석은 애초에 1대1 관계이다.

 

연결요청 데이터를 보내려면 애초에 연결이 되어야하기에 연결요청 부탁을 한다.

 

우리가 만들어놓은 대기실(연결요청 대기큐)에 연결요청들을 담아 놓는다.

 

연결 요청 대기큐에서 대기하는 소켓을 확인하고 하나의 또 다른 소켓을 생성하여 그 소켓과 요청을 보낸 소켓과 1대1 매칭이 되어 통신이 가능해진다.

 

리스닝 소켓 (서버 소켓)은 실질적으로 서비스를 제공하는 소켓은 아니다.

 

여기서 설명한 새 소켓을 만드는 과정이 accpet 함수이다.

 

클라이언트의 연결요청 수락

int accpet(int sock,struct sockaddr p_addr, socklen_t p_addrlen);

 

성공 시 생성된 소켓의 파일 디스크립터, 실패 시 -1

sock = 서버 소켓의 파일 디스크립터 전달

addr = 연결요청 한 클라이언트의 주소정보를 담을 변수의 주소 값 전달, 함수호출이 완료되면 인자로 전달된 주소의 변수에는 클라이언트 주소 정보가 채워진다.

 

addrlen = 두 번째 매개변수 addr에 전달된 주소의 변수 크기를 바이트 단위로 전달, 단 크기 정보를 변수에 저장한 다음에 변수의 주소 값을 전달한다. 그리고 함수호출이 완료되면 크기정보로 채워져 있던 변수에는 클라이언트의 주소정보 길이가 바이트 단위로 계산되어 채워진다.

 

운영체제는 accpet 함수를 호출하면 바로 소켓을 생성한다.

 

sock를 구분해 놓은 이유는 서버 소켓은 하나만 있는게 아니라 여러개의 서버소켓(listen socket)이 존재할 수 있고 이를 통해 특정 파일 디스크립터에 연결요청 대기큐에서 작업을 진행하라라고 구분을 하기 위해서 존재한다.

 



중요한 내용 

예를들어 서버소켓 포트가 8080이면 다른 소켓이 연결 요청을 하면 대기 큐에서 대기하고 accept가 호출되어 소켓을 생성한다. 그렇다면 이 소켓의 port는 몇번이 되어야하는가 클라이언트는 자기 만의 ip가 있기때문에 port 번호가 상관이 없다. 서버는 하나인데 같은 포트를 써도 될까? => 운영체제는 똑같은 8080port번호로 보낸다. 

 


그러면 클라이언트는 주소랑 포트번호가 똑같은데 어떻게 구별할까? = 운영체제가 매핑 정보를 가지고 있다. 즉 특정 클라이언트 ip와 port번호를 가지고 매핑할 소켓을 정하는것.

 




TCP 클라이언트의 기본적인 함수 호출 순서

socket () 소캣 생성 -> connect() 연결요청 -> read()/write() 데이터 송수신 -> close() 연결종료

 

연결요청 함수 

int connect(int sock, const struct p_serv_addr, socklen_t addrlen);

 


sock = 클라이언트 소켓의 파일 디스크립터 전달

 


servaddr = 연결요청 한 클라이언트의 주소정보를 담을 변수의 주소 값 전달, 함수호출이 완료되면 인자로 전달된 주소의 변수에는 클라이언트의 주소정보가 채워진다.

 

addrlen = 두 번째 매개변수 servaddr에 전달한 주소의 변수 크기를 바이트 단위로 전달. 단 , 크기정보를 변수에 저장한 다음에 변수의 주소 값을 전달한다. 그리고 함수호출이 완료되면 크기정보로 채워져 있던 변수에는 클라이언트의 주소정보 길이가 바이트 단위로 계산되어 채워진다.

connect()함수를 요청하면 서버 소켓(listen socket)을 통해 연결요청 대기큐에 들어가는것

후에 accpet를 통해서 연결이 되면 connect()를 탈출한다.


순서상 listen 함수 후 connect()함수로 연결 요청이 오는게 맞지만 이러면 비효율적이다 언제올지 모르기 때문에 그래서 사실 널널한 서버는 바로 listen다음에 accept()를 갈긴다. accept는 대기하기때문에 accept함수가 블로킹 상태일때 connect()를 불러서 연결후에 데이터를 송수신한다.

'일상,취미' 카테고리의 다른 글

다시 시작하는 TIL 16일차  (0) 2024.06.28
다시 시작하는 TIL 15일차  (0) 2024.06.27
다시 시작하는 TIL 13일차  (0) 2024.06.24
다시 시작하는 TIL 12일차  (0) 2024.06.22
다시 시작하는 TIL 11일차  (0) 2024.06.20