bdfgdfg

[온라인 서버] 네트워크 라이브러리(정적,동적) 만들기 본문

게임프로그래밍/서버 책

[온라인 서버] 네트워크 라이브러리(정적,동적) 만들기

marmelo12 2022. 1. 3. 15:09
반응형

네트워크 라이브러리를 만들기전 라이브러리를 만드는 방식 2가지를 본다.

 

1. 정적 라이브러리(Static Library)

정적 라이브러리로 만든 프로젝트의 빌드 결과물은 lib확장자로 만들어진다.

구성 형식이 정적 라이브러리로 되어있음.

빌드 후 결과물을 보면

위와 같이 실행가능한 파일(exe)이 아닌 lib확장자로 파일이 만들어 진다.

 

이제 이 정적 라이브러리를 가지고 다른 프로젝트에서 가져다가 쓸 수 있다. 사용하는 방법은 밑과 같다.

 

1. 프로젝트 속성 -> 링커 탭 -> 일반 탭으로 이동 후 추가 라이브러리 디렉토리에 lib파일이 존재하는 디렉터리의 경로를 넣어준다.

2. 디렉터리 설정이 완료 되었으면 어떤 lib(정적 라이브러리)를 쓸건지 알려줘야 한다. 방법이 2가지.

2-1 프로젝트 속성 -> 링커 탭 -> 입력 탭으로 이동후 추가 종속성에 사용할 lib을 파일이름과 확장자까지 넣어준다.

2-2 #pragma comment라는 전처리 지시문 이용.

#pragma comment(lib,"NetLib.lib")

 

라이브러리 연결은 여기서 끝.

하지만 정적 라이브러리에서 사용할 헤더파일을 include할려면 매번 그 프로젝트 디렉터리로 접근하여 사용해야 한다.

그렇기에 여기선 빌드 후 이벤트를 사용하여 헤더파일을 외부로 옮겨준다.

먼저 정적 라이브러리의 프로젝트 속성에 들어가 빌드 후 이벤트로 들어간다.

그런 다음 위와 같은 명령어를 준다음에 빌드를 하게 되면 (참고로 해당 폴더가 존재해야 한다!!)

위와 같이 복사가 되었다는 로그가 나온다.

명령줄에 해당하는 의미는 현재 프로젝트의 모든 헤더파일을(*.h) 상위x2 폴더의 include폴더에다가 복사하라는 의미.

 

이제 해당 include 폴더의 헤더파일을 가져다 쓰기 위해서 프로젝트에 추가 포함 디렉터리 경로를 설정해줘야 한다.

프로젝트 속성 -> C/C++ -> 일반 탭으로 이동 후 추가 포함 디렉터리에 헤더파일을 복사한 디렉터리의 경로를 설정해준다.

 

정적 라이브러리의 장/단점

장점 

 - 정적 라이브러리를 이용한 응용 프로그램을 빌드하면 정적 라이브러리를 포함한 실행 파일(exe)로 만들어진다.

   그렇기에 따로 LIB를 배포하지 않고 실행 파일만 배포해도 된다는 장점이 존재한다.

단점

 - 장점에서 얘기했듯이 응용 프로그램이 정적 라이브러리를 포함하여 만들어지기에 여러 프로그램들이 같은 정적 라이브러리를 사용하더라도 각각의 프로그램 마다 정적 라이브러리를 메모리 상에 올려놓기에 메모리가 낭비된다.

 - 또한 정적 라이브러리에 버그가 있어 수정을 했다면 응용 프로그램에 문제가 없더라도 다시 컴파일 해야 한다는 번거로움이 존재한다.

 

 

2. 동적 연결 라이브러리 (Dynamic Linking Library)

DLL은 응용프로그램과의 연결 방법에 따라 묵시적 연결과 명시적 연결로 나눈다. 이 두 가지 연결 방법을 본다.

 

묵시적 연결

 - 묵시적 연결은 응용 프로그램과 DLL과의 연결 시점을 사용자가 정할 수 없고 응용프로그램의 시작과 함께 연결되고 

    종료와 함께 연결 해제가 된다.

 - 그래서 이 묵시적 연결 방법을 다른말로 실행 시 연결(Load Time Linking)이라고 부른다.

 - 묵시적 연결에서는 사용자가 선언한 함수가 어떤 DLL에 어디에 위치하고 있는지 알려주기 위해 LIB파일을 응용 프로그램과 연결시킨 다음 컴파일 한다.

  -> 이 말은 즉 DLL과 묵시적 연결을 하여 응용 프로그램을 만들기 위해선 꼭 LIB파일이 필요하다는 의미.

  -> 여기서 말하는 LIB파일은 DLL을 만들면 함께 생성되는 파일. (DLL의 함수 정보와 기타 부가 정보)

      (정적 라이브러리를 빌드하여 나온 파일의 확장자(lib)와 같지만 서로 다르니 혼동x)

 - 이렇게 LIB파일과 연결되어 만등러진 으용 프로그램은 LIB파일이 가지고 있던 정보를 통해 사용자가 선언한 함수가

    DLL의 어느 위치에 있는지 알아내어 그 함수를 호출한다.

 

명시적 연결

 - 묵시적 연결에서는 DLL의 연결과 연결 해제 시점을 사용자가 정할 수 없었지만 명시적 연결에서는 사용자가 연결과

   연결 해제 시점을 정할 수 있다.

  -> 이를 위해 연결과 연결 해제를 위한 함수를 따로 제공.

 - 또한 묵시적 연결에서는 응용 프로그램을 만들 때 DLL과 연결하기 위해 DLL과 함께 생성된 LIB파일이 필요하지만

   명시적 연결에서는 LIB 파일 없이 DLL만 있다면 DLL내에 있는 함수를 호출할 수 있다.

  -> 하지만 그러기 위해선 윈도우즈에서 제공하는 함수를 이용하여 DLL내에 있는 함수의 주소를 직접 가져오고 그 주        소를 저장하기 위해서 함수 포인터를 사용해야 한다는 번거로움이 존재한다.

 

두 연결방법의 특징을 정리해보면

묵시적 연결 방법은 사용하기는 간편하지만 연결과 연결 해제 시점이 자유롭지 못하고 정해져 있다는 단점이 존재.

명시적 연결 방법은 연결과 연결 해제 시점이 자유롭지만 사용하는데는 번거로움이 있다는 단점이 존재.

 

여기서는 묵시적 연결 방법을 사용한다.

1. 먼저 동적 연결 라이브러리 프로젝트를 생성

2. 테스트를 위한 DllTest 헤더파일 및 소스파일 생성

#pragma once
#define DLLTEST_API __declspec(dllimport) // 묵시적 연결을 위하여 가져올 함수나 클래스등에 선언되어짐.

#include <iostream>


// DLLTEST_API는 묵시적 연결. 밑의 클래스는 class DLLTEST_API MyClass로 선언이 되어있음
// 이것은 MyClass를 외부에서 사용하겠다는것을 의미.
// 일반 프로그램과 dll이 다른부분은 이게 끝.

class DLLTEST_API MyClass
{
public:
	void Sum(int a, int b);
	void OutputSum();
private:
	int m_sum;
};

헤더파일

#include "DllTest.h"


void MyClass::Sum(int a, int b)
{
	m_sum = a + b;
}

void MyClass::OutputSum()
{
	std::cout << m_sum << std::endl;
}

소스 파일

 

__delcspec(dllimport)를 선언해주면 묵시적 연결. (함수나 클래스에 선언)

__delcspec(dllexport)를 선언해주면 명시적 연결. (함수나 클래스에 선언)

 

출력 디렉터리 설정 후 빌드를 해준다.

그럼 위와 같이 dll파일과 lib파일이 만들어진다.

이제 다른 프로젝트에서 사용해보자.

 -> 기본 라이브러리 연결 방법, 헤더파일 가져오기등은 정적 라이브러리와 방식이 같으므로 넘어간다

 -> 다만 dll파일은 해당 프로젝트로 옮겨준다.

 

세팅해준 후 실행해보면

#include <iostream>
#include "DllTest.h"
int main()
{
    MyClass a;
    a.Sum(10, 20);
    a.OutputSum();
}

 

동적 라이브러리의 장/단점

장점

 - 동적 연결 라이브러리에 버그가 있어 수정이 되었더라도 응용 프로그램은 다시 컴파일 할 필요없이 라이브러리만

 다시 컴파일 하면 된다. (코드상에서 라이브러리를 포함하므로 -> 윈속처럼)

 - 또한 여러 프로그램들이 같은 동적 라이브러리(dll)를 사용한다면 정적 라이브러리와는 다르게 메모리 상에 한 개의

   라이브러리를 올려놓고 공유하여 사용하기에 메모리 낭비가 없다.

단점

 - 정적 라이브러리와 다르게 실행 파일에 라이브러리가 포함 되지 않는다. 

  -> 그렇기에 동적 라이브러리를 이용한 응용 프로그램을 배포하려면 동적 라이브러리(dll)을 꼭 함께 배포해야 한다.

 

 

 

반응형
Comments