C++
38 posts
Server
TCP/IP
C
C++
February 12, 2024
Overlapped IO와 IOCP

Overlapped IO와 IOCP Non-Blocking 모드의 소켓 구성하기 앞서 epoll관련 포스팅에서 논블로킹 모드로 동작하는 소켓의 생성한 적이 있다. 이와 유사하게 윈도우에서는 다음의 함수호출을 통해서 논블로킹 모드로 소켓의 속성을 변경한다. 위의 코드에서 호출하는 ioctlsocket 함수는 소켓의 IO방식을 컨트롤하는 함수이다. 그리고 위와 같은 형태로의 함수호출이 의미하는 바는 다음과 같다. “핸들 hLisnSock이 참조하는 소켓의 입출력 모드(FIONBIO)를 변수 mode에 저장된 값의 형태로 변경한다.” 즉, FIONBIO는 소켓의 입출력 모드를 변경하는 옵션이며, 이 함수의 세 번쨰 인자로 전달된 주소 값의 변수에 0이 저장되어 있으면 블로킹 모드로, 0이 아닌 값이 저장되어 있으면 논블로킹 모드로 소켓의 입출력 속성을 변경한다. 그리고 이렇게 속성이 논블로킹 모드로 변경되면, 논블로킹 모드로 입출력 되는 것 이외에 다음의 특징도 지니게 된다. 클라이언트…

Server
TCP/IP
C
C++
February 04, 2024
Overlapped IO 모델

Overlapped IO 모델 이전 Asychronous Notification I/O 모델에서 비동기로 처리되었던 것은 ‘IO’가 아닌 ‘Notification(알림)‘이었다. 그러나 여기서는 IO를 비동기로 처리하는 방법에 대해 설명한다. 이 둘의 차이점을 명확히 알고 장단점 구분할 수 있어야 이후의 IOCP를 쉽게 공부할 수 있다. IO 중첩 💡 헷갈려서 정리하는 비동기와 논블로킹 차이 동기 / 비동기 : IO 작업 A,B,C를 요청했을때, 응답 순서가 A,B,C가 보장되면 동기, 보장되지 않으면 비동기 블로킹 / 논블로킹 : 함수가 작업 완료 전까지 반환되지 않으면 블로킹, 작업 완료 전에 호출과 거의 동시에 반환하면 논블로킹 Overlapped IO socket의 생성 : 프로토콜 체계 정보 전달 : 소켓의 데이터 전송방식에 대한 전달 : 두 소켓 사이에 사용되는 프로토콜 정보 전달 : 생성되는 소켓의 특정 정보를 담고 있는 WSAPROTOCOL_INFO 구조체 변수의 주…

Server
TCP/IP
C
C++
February 03, 2024
Asynchronous Notification IO 모델

Asynchronous Notification IO 모델 WSAEventSelect 함수와 Notification : 관찰대상인 소켓의 핸들 전달 : 이벤트 발생유무의 확인을 위한 Event 오브젝트의 핸들 전달. : 감시하고자 하는 이벤트의 유형 정보전달. 즉, WSAEventSelect 함수는 매개변수 s에 전달된 핸들의 소켓에서 lNetworkEvents에 전달된 이벤트 중 하나가 발생하면, hEventObject에 전달된 핸들의 커널 오브젝트를 상태로 바꾸는 함수이다. 때문에 이 함수를 가리켜 “Event 오브젝트와 소켓을 연결하는 함수”라고 하기도 한다. 세번째 인자인 에 전달할 수 있는 이벤트의 종류는 다음과 같다. : 수신할 데이터가 존재하는가? : 블로킹 없이 데이터 전송이 가능한가? : Out-of-Band 데이터가 수신되었는가? : 연결 요청이 있었는가? : 연결의 종료가 요청되었는가? select 함수는 여러 소켓을 대상으로 호출이 가능한데, WSAEventS…

Server
TCP/IP
C
C++
February 03, 2024
동기화 기법의 분류와 CRITICAL_SECTION 동기화

동기화 기법의 분류와 CRITICAL_SECTION 동기화 유저모드와 커널모드 유저모드: 응용 프로그램이 실행되는 기본 모드로, 물리적인 영역으로의 접근이 허용되지 않으며, 접근할 수 있는 메모리의 영역에도 제한이 따른다. 커널모드: 운영체제가 실행될 때의 모드로, 메모리 뿐만 아니라, 하드웨어의 접근에도 제한이 따르지 않는다. 유저모드 동기화 운영체제의 도움 없이 응용 프로그램 상에서 진행되는 동기화가 바로 유저모드 동기화이다. 유저모드 동기화의 가장 큰 장점은 다음과 같다. “속도가 빠르다.” CRITICAL_SECTION 기반의 동기화 또한 유저모드 동기화의 일종이다. 커널모드 동기화 유저모드 동기화에 비해 제공되는 기능이 더 많다. Dead-Lock에 걸리지 않도록 타임아웃의 지정이 가능하다. Mutex, Semaphore, Event 기반의 동기화가 커널모드 동기화의 일종이다. CRITICAL_SECTION 기반의 동기화 CRITICAL_SECTION 기반의 동기화에서는 …

Server
TCP/IP
C
C++
February 03, 2024
Windows 쓰레드

Windows 쓰레드 윈도우에서의 쓰레드 생성방법 운영체제는 쓰레드의 관리를 위해서 커널 오브젝트도 함께 생성한다. 이 커널 오브젝트의 구분자 역할을 하는, 정수로 표현되는 ‘핸들(Handle)‘을 반환한다. 참고로 핸들은 리눅스의 파일 디스크립터에 비유된다. : 쓰레드의 보안관련 정보전달, 디폴트 보안설정을 위해서 NULL 전달. : 쓰레드에게 할당할 스택의 크기를 전달, 0 전달시 디폴트 크기의 스택 생성. : 쓰레드의 main 함수정보 전달. : 쓰레드의 main 함수호출 시 전달할 인자정보 전달. : 쓰레드 생성 이후의 행동을 결정, 0을 전달하면 생성과 동시에 실행 가능한 상태가 된다. : 쓰레드 ID의 저장을 위한 변수의 주소 값 전달. 복잡해 보이지만, 실제로 신경 쓸 것은 와 두 가지 정도이며, 나머지는 0 또는 NULL을 전달하면 된다. 윈도우 쓰레드의 소멸시점 윈도우 쓰레드의 소멸시점은 쓰레드에 의해서 처음 호출된 쓰레드의 main 함수가 반환하는 시점이다(이렇…

Server
TCP/IP
C
C++
January 31, 2024
Epoll의 이해와 활용

Epoll의 이해와 활용 select 기반의 IO 멀티플렉싱이 느린 이유 함수호출 이후에 항상 등장하는 모든 파일 디스크립터를 대상으로 하는 반복문 함수를 호출할 때마다 인자로 매번 전달해야 하는 관찰대상에 대한 정보들 epoll의 경우는 다음의 장점이 있다. 상태변화의 확인을 위한,전체 파일 디스크립터를 대상으로 하는 반복문이 필요 없다. 함수에 대응하는 함수호출 시, 관찰대상의 정보를 매번 전달할 필요가 없다. Epoll의 함수 : epoll 파일 디스크립터 저장소 생성 : 저장소에 파일 디스크립터 등록 및 삭제 : select 함수와 마찬가지로 파일 디스크립터의 변화를 대기한다. select 방식에서는 관찰대상인 파일 디스크립터의 저장을 위해서 fd_set형 변수를 직접 선언했었다. 하지만 epoll 방식에서는 관찰대상인 파일 디스크립터의 저장을 운영체제가 담당한다. 이때 사용되는 함수가 로, 파일 디스크립터의 저장을 위한 저장소의 생성을 운영체제에게 요청한다. 관찰대상…

Server
TCP/IP
C
C++
January 19, 2024
다양한 입출력 함수

다양한 입출력 함수 send & recv 입출력 함수 윈도우 기반이 아닌 리눅스의 send & recv 함수는 다음과 같다. : 데이터 전송 대상과의 연결을 의미하는 소켓의 파일 디스크립터 전달 : 전송할 데이터를 저장하고 있는 버퍼의 주소 값 전달 : 전송할 바이트 수 전달 : 데이터 전송 시 적용할 다양한 옵션 정보 전달 : 데이터 수신 대상과의 연결을 의미하는 소켓의 파일 디스크립터 전달 : 수신된 데이터를 저장할 버퍼의 주소값 전달 : 수신할 수 있는 최대 바이트 수 전달 : 데이터 수신 시 적용할 다양한 옵션 정보 전달 flags 매개변수에 전달 가능한 옵션 목록 옵션(Option) 의 미 send recv MSG_OOB 긴급 데이터(Out-of-band data)이 전송을 위한 옵션 ⭕️ ⭕ MSG_PEEK 입력버퍼에 수신된 데이터의 존재유무 확인을 위한 옵션 ⭕ MSG_DONTROUTE 데이터 전송과정에서 라우팅(Routing) 테이블을 참조하지 않을 것을 요구하는 옵…

Server
TCP/IP
C
C++
January 19, 2024
IO 멀티플렉싱 기반의 서버(select)

IO 멀티플렉싱 기반의 서버 멀티플렉싱 : 하나의 통신채널을 통해서 둘 이상의 데이터를 전송하는데 사용되는 기술 여기서는 하나의 프로세스로 서비스를 제공하는 것을 말함. select 함수의 이해와 서버의 구현 함수를 이용하는 것이 멀티플렉싱 서버의 구현에 있어서 가장 대표적인 방법이다. 윈도우에도 이와 동일한 이름으로 동일한 기능을 제공하는 함수가 있어 이식성도 좋다. select 함수의 기능과 호출 순서 함수를 사용하면 한곳에 여러 개의 파일 디스크립터를 모아놓고 동시에 이들을 관찰할 수 있다. 이때 관찰할 수 있는 항목은 다음과 같다. 수신한 데이터를 지니고 있는 소켓이 존재하는가? 블로킹되지 않고 데이터의 전송이 가능한 소켓은 무엇인가? 예외상황이 발생한 소켓은 무엇인가? 💡관찰항목 각각을 가리켜 ‘이벤트(event)‘라 한다. 위에서 정리한 관찰항목 각각을 가리켜 이벤트라 하고, 관찰항목에 속하는 상황이 발생했을 때, ‘이벤트(event)가 발생했다’ 라고 표현한다. 이…

Server
TCP/IP
C
C++
January 18, 2024
다중 접속 서버

다중 접속 서버 위 그림에서 보이듯이 클라이언트의 서비스 요청(연결 요청)이 있을 때마다 에코 서버는 자식 프로세스를 생성해서 서비스를 제공한다. 즉, 서비스를 요청하는 클라이언트의 수가 다섯이라면 에코 서버는 추가로 다섯 개의 자식 프로세스를 생성해서 서비스를 제공한다. 이를 위해서 에코 서버는 다음의 과정을 거쳐야 한다. 이것이 기존 에코 서버와의 차이점이다. 1단계 : 에코 서버(부모 프로세스)는 accept 함수호출을 통해서 연결요청을 수락한다. 2단계 : 이때 얻게 되는 소켓의 파일 디스크립터를 자식 프로세스를 생성해서 넘겨준다. 3단계 : 자식 프로세스는 전달받은 파일 디스크립터를 바탕으로 서비스를 제공한다. 다중접속 에코 서버의 구현 함수로 인해 부모 프로세스의 모든 것이 복사된다. 그러나, 소켓은 복사되지 않는다! 소켓을 가리키는 파일 디스크립터만이 복사되었을 뿐이다. 소켓은 프로세스가 아닌 운영체제가 관리하기 때문이다. 하나의 소켓에 두 개의 파일 디스크립터가 …

Server
TCP/IP
C
C++
January 17, 2024
좀비 프로세스

좀비 프로세스 본 포스팅의 내용은 windows os에서 적용되지 않는 linux os의 내용임. 로 생성된 자식 프로세스의 소멸을 위해서는 부모 프로세스가 자식 프로세스의 전달 값을 요청해야 한다. 요청을 위한 구체적인 방법을 이 포스팅에서 설명한다. 좀비 프로세스의 소멸1: wait 함수의 사용 위 함수 호출 시 이미 종료된 자식 프로세스가 있는 경우 : 자식 프로세스가 종료되면서 전달한 값이 매개변수로 전달된 주소의 변수에 저장됨 종료된 자식 프로세스가 없는 경우 : 자식 프로세스가 종료될때까지 블로킹(blocking)됨 블로킹(대기) 상태에서는 CPU 코어를 점유하지 않는다. 자식 프로세스가 종료되면 부모 프로세스는 운영체제로부터 해당 상태를 전달받아 블로킹이 해제된다. 에 저장되는 값은 다음과 같다. : 자식 프로세스가 정상 종료한 경우 TRUE 반환 : 자식 프로세스의 전달 값(return value)을 반환 ⛔️는 statloc 하위 8비트 값만 추출하기 때문에 0~…

Server
TCP/IP
C
C++
January 16, 2024
소켓의 옵션과 입출력 버퍼의 크기

소켓의 옵션과 입출력 버퍼의 크기 소켓의 다양한 옵션 지금까지의 예제들은 매우 간단했기 때문에 특별히 소켓의 특성을 조작할 필요가 없었다. 그러나 소켓의 특성을 변경시켜야만 하는 경우도 흔히 발생한다. 그럼 먼저 다양한 소켓의 옵션 중 일부를 표를 통해 정리해 보이겠다. Protocol Level Option Name Get Set SOL_SOCKET SO_SNDBUF SO_RCVBUF SO_REUSEADDR SO_KEEPALIVE SO_BROADCAST SO_DONTROUTE SO_OOBINLINE SO_ERROR SO_TYPE O O O O O O O O O O O O O O O O X X IPPROTO_IP IP_TOS IP_TTL IP_MULTICAST_TTL IP_MULTICAST_LOOP IP_MULTICST_IF O O O O O O O O O O IPPROTO_TCP TCP_KEEPALIVE TCP_N…

Server
TCP/IP
C
C++
January 16, 2024
IP 주소와 도메인 이름 사이의 변환

IP 주소와 도메인 이름 사이의 변환 도메인 이름을 이용해서 IP 주소 얻어오기 해당 함수는 구조체 변수에 담겨서 반환되는데, 이 구조체는 다음과 같이 정의되어 있다. 위의 구조체 정의를 보니, IP정보만 반환되는 것이 아니라, 여러가지 다른 정보들도 덤으로 반환되는 것을 알 수 있다. 복잡하게 생각하지 않아도 된다. 도메인 이름을 IP로 변환하는 경우에는 만 신경써도 된다. : 공식 도메인 이름(Ofiicial domain name)이 저장된다. : 하나의 IP에 매핑된 다른 여러 도메인 이름의 별칭리스트를 반환한다. : IPv4만 아니라 IPv6도 지원한다. IPv4의 경우는 이 저장된다. : 함수호출의 결과로 반환된 IP주소의 크기가 담긴다. IPv4는 4바이트, IPv6는 16바이트이다. : 이 멤버를 통해서 도메인 이름에 대한 IP주소가 정수의 형태로 반환된다. 접속자가 많은 서버는 여러 IP주소를 둬서 부하를 분산시킨다. gethostbyname 다음은 간단한 예제를 …

Server
TCP/IP
C
C++
January 16, 2024
TCP 기반의 Half-close

TCP 기반의 Half-close TCP에서는 연결과정보다 중요한 것이 중료과정이다. 연결과정에서는 큰 변수가 발생하지 않지만 종료과정에서는 예상치 못한 일이 발생할 수 있기 때문이다. 따라서 종료과정은 명확해야 한다. 일방적인 연결종료의 문제점 리눅스의 함수호출과 윈도우의 함수호출은 완전종료를 의미한다. 완전종료라는 것은 데이터를 전송하는 것은 물론이거니와 수신하는 것 조차 더 이상 불가능한 상황을 의미한다. 때문에 한쪽에서의 일방적인 또는 함수호출은 경우에 따라서 우아해 보이지 못할 수 있다. 위 그림은 양방향을 통신하고 있는 두 호스트의 상황을 묘사한 것이다. 호스트 A가 마지막 데이터를 전송하고 나서 close 함수의 호출을 통해서 연결을 종료하였다. 때문에 그 이후부터 호스트 A는 호스트 B가 전송하는 데이터를 수신하지 못한다. 아니! 데이터 수신과 관련돤 함수의 호출 자체가 불가능하다. 때문에 결국엔 호스트 B가 전송한, 호스트 A가 반드시 수신해야 할 데이터라…

Server
TCP/IP
C
C++
January 15, 2024
UDP기반 서버, 클라이언트 구현

UDP기반 서버, 클라이언트 구현 UDP 서버, 클라이언트는 TCP와 같이 연결된 상태로 데이터를 송수진하지 않는다. 때문에 TCP와 달리 연결 설정의 과정이 필요 없다. 따라서 TCP 서버 구현과정에서 거쳤던 listen 함수와 accept 함수의 호출은 불필요하다. UDP 소켓의 생성과 데이터의 송수신 과정만 존재할 뿐이다. UDP에서는 서버건 클라이언트건 하나의 소켓만 있으면 된다. UDP 기반의 데이터 입출력 함수 : 데이터 전송에 사용될 UDP 소켓의 파일 디스크립터를 인자로 전달 : 전송할 데이터를 저장하고 있는 버퍼의 주소 값 전달 : 전송할 데이터 크기를 바이트 단위로 전달 : 옵션 지정에 사용되는 매개변수, 지정할 옵션이 없다면 0 전달 : 목적지 주소정보를 담고 있는 sockaddr 구조체 변수의 주소 값 전달 : 매개변수 to로 전달된 주소 값의 구조체 변수 크기 전달 TCP 기반의 출력함수와 가장 비교되는 것은 목적지 주소정보를 요구한다는 점이다. : 데이터 …

Server
TCP/IP
C
C++
January 14, 2024
TCP기반 서버, 클라이언트 구현

TCP기반 서버, 클라이언트 구현 TCP 서버에서의 기본적인 함수호출 순서 제일 먼저 socket 함수의 호출을 통해서 소켓을 생성한다. 그리고 주소정보를 담기 위한 구조체 변수를 선언 및 초기화해서 bind함수를 호출하여 소켓에 주소를 할당한다. 이 두 단계는 이미 여러분에게 설명한 내용이니, 이제 그 이후의 과정에 대해서 설명하겠다. 연결요청 대기상태로의 진입(listen) bind 함수호출을 통해서 소켓에 주소까지 할당했다면, 이번에는 listen 함수호출을 통해서 ‘연결요청 대기상태’로 들어갈 차례이다. 그리고 listen 함수가 호출되어야 클라이언트가 연결요청을 할 수 있는 상태가 된다. 즉, listen 함수가 호출되어야 클라이언트는 연결요청을 위해서 connect 함수를 호출할 수 있다. : 연결요청 대기상태에 두고자 하는 소켓의 파일 디스크립터 전달, 이 함수의 인자로 전달된 디스크립터의 소켓이 서버 소켓(리스닝 소켓)이 된다. : 연결요청 대기 큐(Queue)의 …

Server
TCP/IP
C
C++
January 13, 2024
주소 체계와 데이터 정렬

주소 체계와 데이터 정렬 주소정보의 표현 이 구조체는 함수에 구조체를 전달하는 용도로 사용된다. POSIX 이나 내부의 구조체에는 생소한 자료형이 있다. 이들은 POSIX 표준에 정의되어 있다. (확장성을 고려)      자료형 이름                          자료형에 담길 정보                     선언된 헤더파일 int8_t uint8_t int16_t uint16_t int32_t uint32_t signed 8-bit int unsigned 8-bit int (unsigned char) signed 16-bit int unsigned 16-bit int (unsigned short) signed 32-bit int unsigned 32-bit int (unsigned long) sys/types.h sa_family_t socklen_t 주소체계(address family) 길이정보(length of struct) sy…

Server
TCP/IP
C
C++
January 13, 2024
소켓의 타입과 프로토콜의 결정

소켓의 타입과 프로토콜의 결정 소켓의 생성 : 소켓이 사용할 프로토콜 체계(Protocol Family) 정보 전달 : 소켓의 데이터 전송방식에 대한 정보 전달 : 두 컴퓨터간 통신에 사용되는 프로토콜 정보 전달 프로토콜 체계(Protocol Family) 이름                               프로토콜 체계(Protocol Family)                               PF_INET IPv4 인터넷 프로토콜 체계 PF_INET6 IPv6 인터넷 프로토콜 체계 PF_LOCAL 로컬 통신을 위한 UNIX 프로토콜 체계 PF_PACKET Low Level 소켓을 위한 프로토콜 체계 PF_IPX IPX 노벨 프로토콜 체계 소켓의 타입 연결지향형 소켓(SOCK_STREAM) 중간에 데이터가 소멸되지 않고 목적지로 전송된다. 전송 순서대로 데이터가 수신된다. 전송된 데이터의 경계가 존재하지 않는다. 데이터를 전송하는 컴퓨터가 세 번의 write…

Server
TCP/IP
C
C++
January 12, 2024
네트워크 프로그래밍과 소켓의 이해

네트워크 프로그래밍과 소켓의 이해 소켓의 전화기에의 비유 OS의 소켓은 전화기에 비유할 수 있다. 서버 비유 함수 반환 전화기의 장만 성공 시 파일 디스크립터, 실패 시 -1 전화번호의 부여 성공 시 0, 실패 시 -1 전화 케이블에 연결 성공 시 0, 실패 시 -1 수화기를 들기 성공 시 파일 디스크립터, 실패 시 -1 클라이언트          비유          함수                  반환                  전화 걸기 성공 시 0, 실패 시 -1 서버 프로그램의 구현 클라이언트 프로그램의 구현 Linux기반 파일(소켓) 조작하기 💡 리눅스는 “모든 것은 파일이다”라는 철학을 가지고 있어서, 파일과 소켓을 포함하여 다양한 자원을 파일로 취급함. 리눅스에서는 소켓을 파일처럼 다루기 때문에, 파일 입출력과 동일하게 조작할 수 있다. 명칭 리눅스 : 파일 디스크립터 윈도우 : 파일 핸들 표준 입출력 및 표준 에러 파일 디스크립터 파일 디스크립터 대…

C
C++
Understanding_and_Using_C_Pointers
January 11, 2024
동적 메모리 관리

동적 메모리 관리 Understanding and Using C Pointers: Core Techniques for Memory Management 1st Edition을 읽고 정리한 내용을 기술합니다. 포인터를 잘 알아야 하는 이유 포인터 선언하기 Null의 개념 void포인터와 전역, 정적포인터 포인터의 크기와 데이터 타입 일반적인 포인터 사용 동적 메모리 관리 동적 메모리 관리 C 프로그램은 런타임 시스템 안에서 실행된다. 런타임 시스템은 일반적으로 운영체제에서 제공되는 환경이며, 많은 프로그램 기능들과 함께 스택(stack)과 힙(heap)을 지원한다. C99 표준에서 가변 길이 배열(Variable Length Array)이 도입되었다. 이 배열의 크기는 컴파일 될 때가 아니라 실행될 때 결정된다. 하지만 일단 가변 길이 배열이 생성되고 나면, 여전히 크기를 변경할 수 없다. 동적 메모리 할당은 할당, 해제 함수를 사용하여 수동으로 처리된다. 이 과정을 동적 메모리 관…

C
C++
Understanding_and_Using_C_Pointers
January 11, 2024
일반적인 포인터 사용

일반적인 포인터 사용 Understanding and Using C Pointers: Core Techniques for Memory Management 1st Edition을 읽고 정리한 내용을 기술합니다. 포인터를 잘 알아야 하는 이유 포인터 선언하기 Null의 개념 void포인터와 전역, 정적포인터 포인터의 크기와 데이터 타입 일반적인 포인터 사용 동적 메모리 관리 일반적인 포인터 사용 포인터는 매우 다양한 방법으로 사용된다. 이번 포스팅에서는 다음을 포함한 포인터의 다양한 사용법에 대해서 다룬다. 다중 수준 간접지정 상수 포인터(중요) 다중 수준 간접지정 포인터는 다중 수준 간접지정(indirection)을 이용할 수 있다. 어떤 변수가 포인터에 대한 포인터로 선언된 경우를 흔하게 볼 수 있는데, 이를 이중 포인터(double pointer) 라고 부르기도 한다. 이중 포인터에 대한 좋은 예는 main 함수에 전통적인 argc와 argv 매개변수를 통해 프로그램 실행 인자…

C
C++
Understanding_and_Using_C_Pointers
January 11, 2024
포인터의 크기와 데이터 타입

포인터의 크기와 데이터 타입 Understanding and Using C Pointers: Core Techniques for Memory Management 1st Edition을 읽고 정리한 내용을 기술합니다. 포인터를 잘 알아야 하는 이유 포인터 선언하기 Null의 개념 void포인터와 전역, 정적포인터 포인터의 크기와 데이터 타입 일반적인 포인터 사용 동적 메모리 관리 포인터 크기 포인터의 크기는 애플리케이션의 호환성과 다른 환경으로의 이식 가능성을 고민할 때 문제가 된다. 최근의 대부분의 OS에서 포인터의 크기는 일반적으로 포인터 타입에 상관없이 같다. 예를 들면, char에 대한 포인터(char*)는 구조체에 대한 포인터와 크기가 같다! C 표준에서 모든 데이터 타입에 대한 포인터의 크기가 같아야 한다고 명시하고 있지만 않지만, 일반적으로 포인터의 크기는 동일하다. 하지만 함수에 대한 포인터와 데이터에 대한 포인터의 크기는 다를 수도 있다. C는 코드와 데이터 포인터…

C
C++
Understanding_and_Using_C_Pointers
January 10, 2024
void포인터와 전역, 정적포인터

void포인터와 전역, 정적포인터 Understanding and Using C Pointers: Core Techniques for Memory Management 1st Edition을 읽고 정리한 내용을 기술합니다. 포인터를 잘 알아야 하는 이유 포인터 선언하기 Null의 개념 void포인터와 전역, 정적포인터 포인터의 크기와 데이터 타입 일반적인 포인터 사용 동적 메모리 관리 void 포인터 void 포인터는 어떤 타입의 데이터도 참조할 수 있는 범용 포인터다. 아래에 void 포인터 선언의 예제가 있다. void 선언에는 두 가지 흥미로운 것이 있다. void 포인터는 char 포인터와 같은 표현과 메모리 정렬 방법을 사용한다. void 포인터는 다른 포인터와 절대 같지 않다. 하지만 NULL 값이 할당된 두 개의 void 포인터는 서로 같다. void 포인터의 실제 동작은 시스템에 따라 다르다. ⚠️ void 포인터는 데이터 타입의 포인터에 사용되며, 함수 포인터에는 사…

C
C++
Understanding_and_Using_C_Pointers
January 09, 2024
Null의 개념

Null의 개념 Understanding and Using C Pointers: Core Techniques for Memory Management 1st Edition을 읽고 정리한 내용을 기술합니다. 포인터를 잘 알아야 하는 이유 포인터 선언하기 Null의 개념 void포인터와 전역, 정적포인터 포인터의 크기와 데이터 타입 일반적인 포인터 사용 동적 메모리 관리 Null의 개념 널(Null)은 매우 흥미로운 주제다. 하지만 종종 널이 가진 다양한 개념들이 잘못 이해되거나 혼란을 일으킨다. 널은 다음과 같은 개념들을 포함한다. 널 개념 널 포인터 상수 NULL 매크로 NUL 아스키 문자(\0) 널 문자열 널 문장(;) 포인터에 NULL이 할당되면 해당 포인터는 아무것도 가리키지 않음을 의미한다. 널 개념은 포인터가 다른 포인터와 다른 특별한 값을 가질 수 있음을 의미한다. 널이 할당된 포인터는 메모리의 어떤 영역도 가리키지 않으며 두 개의 널 포인터는 항상 서로 같다. 실제 널…

C
C++
Understanding_and_Using_C_Pointers
January 09, 2024
포인터 선언하기

포인터 선언하기 Understanding and Using C Pointers: Core Techniques for Memory Management 1st Edition을 읽고 정리한 내용을 기술합니다. 포인터를 잘 알아야 하는 이유 포인터 선언하기 Null의 개념 void포인터와 전역, 정적포인터 포인터의 크기와 데이터 타입 일반적인 포인터 사용 동적 메모리 관리 포인터 선언하기 포인터 변수는 가리킬 대상의 데이터 타입과 별표 그리고 변수 이름을 순서대로 나열하여 선언한다. 별표 주위에 공백 문자를 사용하는지 여부는 선언에 전혀 영향을 주지 않는다. 다음 선언들은 모두 동등하다 공백 사용은 단지 사용자 취향의 문제다. 별표는 변수를 포인터로 선언하는 데도 사용되지만, 두 수를 곱하거나 포인터를 역참조하는 데도 사용된다. 포인터 선언을 읽는 방법 포인터 선언을 이해하기 쉽게 읽는 방법은 바로 뒤에서부터 읽는 것이다. 변수 pci : 포인터 변수 pci : 정수를 가리키는 포인…

C
C++
Understanding_and_Using_C_Pointers
January 09, 2024
포인터를 잘 알아야 하는 이유

포인터를 잘 알아야 하는 이유 Understanding and Using C Pointers: Core Techniques for Memory Management 1st Edition을 읽고 정리한 내용을 기술합니다. 포인터를 잘 알아야 하는 이유 포인터 선언하기 Null의 개념 void포인터와 전역, 정적포인터 포인터의 크기와 데이터 타입 일반적인 포인터 사용 동적 메모리 관리 포인터를 잘 알아야 하는 이유 포인터는 다음과 같은 용도로 사용된다. 빠르고 효율적인 코드 작성 다양한 문제에 대한 효과적인 해결 방법 제공 동적 메모리 할당 지원 작고 간결한 표현의 사용 큰 오버헤드 없이 데이터 구조를 포인터로 전달 함수의 매개변수로 전달된 데이터 보호 포인터는 하드웨어의 구조에 좀 더 가까우므로 빠르고 효율적인 코드의 작성이 가능하다. ⇨ 컴파일러는 좀 더 쉽게 포인터의 동작을 머신 코드로 변환할 수 있다. 포인터는 다른 연산자에 비해 발생하는 오버헤드가 적다. (ex: 배열과 포인…

Server
C++
Backend
January 08, 2024
TLS(Thread Local Storage)

TLS(Thread Local Storage) 쓰레드마다 갖고 있는 로컬 저장소 != 스택 동물원의 호랑이를 생각해보자 공통 영역에서 큼지막한 덩어리를 가져온 다음 필요한걸 꺼내쓰면 처음 가져올 때만 경합이 발생하고 큰 덩어리에서 고를 때는 경합이 필요 없다. TLS 예제 로 받는 난수 id가 아닌 쓰레드마다 직접 id를 할당하고 싶다면? 실행 결과 각 쓰레드 마다 자신의 id를 TLS에 저장했음을 확인할 수 있다. 이를 응용해서 쓰레드별 Stack이나 Queue를 구현할 수도 있다. 이어지는 궁금증… TLS는 스택영역과는 별개의 개념이라고 했다. 그럼 각 쓰레드의 TLS 공간은 전역변수 데이터 영역에 저장되며 다른 쓰레드에 의해 침범될 수 있을까? 이에 관련한 문답을 링크 : Stack overflow 에서 찾았다. TLS 예제 이어지는 궁금증…

Server
C++
Backend
January 08, 2024
CPUPipeline 과 Memory Model

CPU Pipeline 여기서는 Pipeline의 효율 최대화를 위한 코드 재배치에 대해 알아볼 것이며, Pipeline Hazard, RISC, CISC에 관한 내용은 생략합니다. 개요 CPU가 연산 속도를 향상시키고 노는 시간을 최대한 줄이기 위해 CPU 파이프라인을 도입한다는 사실은 익숙하다. CPU는 각 연산 모듈(ALU 등)간 연산 속도, Task당 분배해야하는 시간 등을 고려하여 속도를 최적화 시키기 위해 로직이 엉키지 않는 선에서 코드 재배치를 수행한다. 일반적인 상황(싱글 쓰레드 = 중량 프로세스)에서는 이러한 코드 재배치가 논리 구조를 건드리지 않는 선에서 동작하기 때문에 문제를 일으키지 않지만, 멀티 쓰레드 환경에서는 이야기가 조금 다르다. 쓰레드간 논리 구조가, CPU의 코드 재배치에 의해 엉키게 되면, 나와선 안되는 결과가 나올 수 있다. 따라서 우리는 이러한 코드 재배치를 신경쓰며 멀티 쓰레드 프로그래밍을 해야 한다. 예제 코드 인 상황이 로직상 발생하면 …

Server
C++
Backend
January 07, 2024
Future

Future 동기 vs 비동기 위 코드는 동기적이다. 만약 Calculate가 굉장히 오랜 시간동안 연산하고, 그것을 기다리는 동안 다른 작업을 하고 싶다면? 우리가 배운 내용을 토대로 아래와 같이 작성 가능하다. Thread 이용 thread를 생성 후 task를 위임하여 비동기적으로 작동한다.= 간단한 작업을 하는데도 불구하고, 굳이 쓰레드까지 만들어서 관리하기 귀찮다. -> & 를 통해 해결 가능하다. + async에는 두가지 policy가 있다. Options deferred lazy evaluation : 지연해서 실행하세요 -> 테스트 결과 을 호출할 때가 돼서야 쓰레드로 분기되는듯? async 별도의 쓰레드를 만들어서 실행하세요 deferred | async 둘 중 알아서 골라주세요 + 🏳️이 부분은 아직 모던 C++에 대해 배우지 않아 대충 이해만 하고 넘어갔다. 모던 C++ 학습 후 오른값 참조에 대해 복습해야할 것 + 의 타입은 함수타입과 맞춰줘야 …

Server
C++
Backend
January 07, 2024
Condition Variable

Condition Variable Condition Variable은 Event의 변종 앞선 Event 코드에서… 생산자가 데이터를 넣고 파란불을 켜고, 소비자는 파란불을 확인하고 데이터를 꺼내고 빨간불로 바꾸고… 를 반복하면 q.size()는 0만 출력되지 않을까? 실제로 실행해보면 데이터가 무한정 계속 늘어나는 것을 확인할 수 있다. 왜 데이터가 계속 늘어나는가? 생산자가 데이터를 삽입하고 초록불로 바꿈 소비자는 초록불을 확인하고 빨간불로 바꿈, 진입 !!여기서 생산자가 또 다시 데이터를 삽입하려고 함 소비자는 락을 걸고 큐 사이즈를 읽어야 하는데, 이미 생산자가 락을 건 상태 ㅠㅠ 결과적으로 다음에 운 좋게 락이 풀렸을떄 큐에서 pop하고 사이즈를 읽는데, 이때는 이미 큐에 여러개의 데이터가 삽입된 상태임. Consumer 따라서 이런경우 if 대신 while을 사용하여 큐를 전부 비워주는 등의 조치를 취해야 함. Condition Variable 💡 참고 : CV는 Use…

Server
C++
Backend
January 07, 2024
Event

Event 난 소중하니 직원한테 부탁 (갑질메타) 예제 생산자() 쓰레드는 10초 마다 한번씩 생산하고, 소비자() 쓰레드는 바쁜 대기를 통해 계속해서 CPU 코어를 점유함. 한 번 데이터를 소비하기 위해 10초동안 코어를 점유하는 것은 너무나 비효율적임. 큐에 데이터가 들어올때 알려주는 무언가가 있으면 좋을 것 같다. => Create Event HANDLE CreateEventW(LPSECURITY lpEventAttributes, BOOL bManualReset, Bool bInitialState, LPCWSTR lpName) 는 커널에서 만들어주기 때문에 라고도 불린다. 커널에서 관리하는 오브젝트다. Usage Count : 해당 오브젝트를 사용중인 프로세스나 쓰레드의 수. 커널 오브젝트가 공통으로 가진다. Signal / Non-Signal : 파란불, 빨간불 << bool Auto / Manual : 예제에선 Auto HANDLE은 int와 같은 숫자를 의미한다. ex…

Server
C++
Backend
January 06, 2024
Sleep

Sleep sleep_for, yield Spin Lock 코드에서 이어서 을 통해 일정 시간 CPU 제어권을 넘겨줄 수 있음 는 과 같으며 딱 한번 제어권을 넘겨줌. 프로세스가 block 상태로 전이 sleep_for, yield

Server
C++
Backend
January 06, 2024
SpinLock

Spin Lock lock이 해제될때까지 바쁜 대기(busy waiting) 스핀락은 유저 레벨에서 무한 while 루프를 돌고 있기 때문에 쓰레드 교체를 하지 않고 계속 CPU 자원(코어를 계속 점유)을 소모하면서 버티는 것 -> 컨텍스트 스위칭이 발생하지 않음. Spin Lock 구현 ver 1. 실행 결과 ⭐️ TIP C++ 에서의 키워드 : 최적화를 하지 말아달라. 왜 0이 안나오는가 ?? 락이 걸려있는가를 확인한다. 걸려있지 않으면 락을 걸고 통제권을 획득한다. 위 경우에서 만약 두 쓰레드가 i. 번을 동시에 확인하여 락이 걸려있지 않음을 확인한다면? 통제권을 함께 얻는 경우가 발생함. -> i, ii 가 한 묶음으로 동작하지 않음! 즉, 원자성이 보장되지 않음. 해결방안 -> 가 한 묶음으로 동작해야 함. ver 2. ⭐️ TIP 에는 volatile이 포함되어 있다! 실행 결과 참조 링크 CAS 란? Spin Lock 구현 ver 1. ver 2.

Server
C++
Backend
January 05, 2024
MutexLock

Mutex atomic은 일반적인 상황에서 쓰이기 힘들다. 객체에 대한 원자성을 보장해야 하는 일이 훨씬 많기 때문 Mutex 문제 발생 코드 실행 결과 오류 발생 이유 : vector는 크기가 2^n에 도달했을때 기존 capacity의 두배가 되는 공간을 새로 할당받고 기존 공간을 없애는데, 원자성 보장이 되지 않기 때문에, 이미 없어진 공간을 다시 없애려 하기 때문. 으로 미리 20000크기의 공간을 할당받으면 오류는 사라지지만, 여전히 원자성은 보장이 되지 않아 결과가 20000이 나오지 않음. Mutex Lock 실행 결과 mutex lock을 통해 상호배제 달성 속도는 기존보다 많이 느려짐. mutex lock은 재귀적으로 걸 수 없음. m.lock(); m.lock();을 연속으로 하면 crash발생. 재귀적 lock을 허용하는 recursive mutex에 관해서는 추후 학습. RAII(Resource acquisition is initialization) 패턴 래퍼 …

Server
C++
Backend
January 05, 2024
Atomic

원자성 각 쓰레드가 임계영역에서 경쟁(경합)할때, 공유자원에 대한 일관성이 보장되지 않는다. a++의 경우 load a a + 1 store a 위 과정이 CPU instruction level에서 일어나는데, 이 중간과정에 다른 쓰레드의 instruction이 개입하면 결과의 일관성이 보장되지 않음. atomic 을 통해 통합 원자성 라이브러리를 추가할 수 있다. int 사용 실행 결과 atomic 사용 실행 결과 atomic의 경우, 일반 int와의 구분을 위해 , 등과 같이 사용하는 것이 좋다. 그냥 을 사용해도 똑같이 동작한다. 내부적으로 오버로딩이 되어있기 때문. atomic int 사용 atomic 사용

Server
C++
Backend
January 05, 2024
C++ 쓰레드

C++ 쓰레드 Windows IOCP기반 Stateful Server 구현에 관한 학습 내용을 정리한 것입니다. Linux OS 및 epoll 기반의 서버 구현과는 다소 차이점이 있을 수 있습니다. 쓰레드 기본 하나의 프로세스는 여러개의 쓰레드로 분리할 수 있다. 쓰레드는 같은 프로세스 내의 힙과 데이터 영역을 공유하고, 개별적인 스택영역을 갖는다. TCB를 통해 관리된다. CPU 코어 개수 = 쓰레드의 개수 일 때 가장 이상적(ideal)임. api Type.h를 통해 타입의 이름이 변경된 부분이 있습니다. 예) int32, int64, … : 쓰레드의 id 확인, 유효하지 않은 쓰레드는 0 : 사용 가능한 CPU 코어 개수 확인 : 쓰레드를 stb::thread 객체에서 분리. 더 이상 join할 필요 없음 linux의 데몬 프로세스와 유사함. : 해당 쓰레드가 join 가능한 상태인지 확인. : 쓰레드 종료를 기다림 인자가 있는 쓰레드 실행결과 쓰레드…

C++
January 03, 2024
배열의 인덱스 연산자 오버로딩

배열의 인덱스 연산자 오버로딩 인덱스 연산자 C++에는 인덱스 연산자 오버로딩도 존재한다 int 배열의 경우 : 이를 통해 새로운 클래스를 정의하고 배열의 버퍼를 벗어나는 상황의 예외처리가 가능해짐 예 : arr[-1], arr[-100], 크기 3인 arr에서 arr[3] 등 const 함수를 이용한 오버로딩의 활용 위 코드는 컴파일 에러가 발생한다. 이유는? 위 코드에서 인자로 가 const로 전달되어 수정을 막고 있다. 그러나 연산자 오버로딩 함수는 const 함수가 아니기 때문에 컴파일 오류를 발생시킴. ⚠️ 인자가 const로 들어오면, const함수가 아닌 모든 함수를 사용할 수 없음에 유의 해결방안 연산자 오버로딩 함수를 const인것 하나, 아닌것 하나로 오버로딩한다. 거의 완전히 같은 함수이지만, const가 붙냐 안붙냐의 차이만 있음. 이러면 const로 들어온 인자에 대해서도 배열 인덱스 연산자 오버로딩 함수 호출이 가능해진다. 인덱스 연산자 const 함수…

C++
January 02, 2024
연산자 오버로딩과 대입연산자

연산자 오버로딩과 대입연산자 연산자 오버로딩 C++에는 및 와 같은 연산자를 오버로딩하는 기능이 존재한다. 이를 통해 객체간의 연산을 직관적으로 표현할 수 있다. 멤버 함수를 통한 오버로딩 는 와 같다. 객체인 Point간의 + 연산을 가능하도록 한다. 전역 함수를 통한 오버로딩 private 멤버인 xpos, ypos에 접근해야 하므로 friend함수로 정의한다. 마찬가지로 객체인 Point간의 + 연산을 가능하도록 한다. 전역함수에서는 피연산자 두 개를 모두 인자로 받아야 한다. cout, cin, endl의 비밀 cout, cin, endl과 , 에도 연산자 오버로딩이 사용된다. cout는 ostream클래스이며, cin은 istream클래스이다. ostream의 경우 Point 객체에 , 오버로딩하기 대입연산자 대입 연산자는 복사 생성자와 매우 유사하다. 정의하지 않으면 디폴트 대입 연산자가 삽입된다. 디폴트 대입 연산자는 멤버 대 멤버의 얕은 복사를 진행한다.…

C++
January 01, 2024
가상함수(Virtual)

가상함수 가상함수 가상 함수는 C++에서 다형성(polymorphism)을 구현하기 위한 중요한 개념 중 하나다. 다형성은 동일한 인터페이스를 가진 객체들이 서로 다른 구현을 제공할 수 있도록 하는 프로그래밍 개념이다. 가상 함수는 기본 클래스(Base class)와 파생 클래스(Derived class) 간의 다형성을 지원하는데 사용된다. 기본 클래스에서 선언된 함수를 파생 클래스에서 재정의(override)할 때 사용한다. Keyword : 💡 MyFunc가 가상함수가 아닌경우 위와 같이 포인터 기준으로 함수를 호출함. 💡 MyFunc가 가상함수인 경우, 포인터가 아닌 실제 인스턴스를 기준으로 함수를 호출함. 가상함수 Keyword :