본문 바로가기

일반적인 C/C++ 네트워크 프로그래밍 학습은 Socket APIThread를 사용합니다.


Qt C++ 에서는 Socket API보다 편리한 Qt Network Modeule을 사용할 수 있고

Thread 대신 SignalSlot 을 사용할 수 있기 때문에 보다 쉽게 네트워크 응용 어플리케이션을 구현할 수 있습니다.

 

 

1. Thread 이해

 

1.1 Program

 

Program은 빌드가 끝난 후 저장 장치에 저장되어 있는 명령어 덩어리로, 메모리에 올라가 있지 않은 상태입니다.

스마트폰을 사용할 때, 스토어 같은 곳에서 앱을 설치하게 되는데 이것이 프로그램입니다.

 

프로그램을 설치하면 바로 실행이 될까요?

아닙니다. 마우스로 더블 클릭하거나 손으로 터치를 해야 실행이 되는 것이죠.

이렇게 아직 실행이 되지 않은, 메모리에 올라가지 않은 정적인 상태가 프로그램입니다. 

 

 

1.2 실행과 프로세스

위에서 프로그램은 실행되지 않고 단순히 설치되어 있는 상태라 했습니다.

 

프로그램이 마우스로 클릭하거나, 앱을 터치 하는 실행이 시작되면 

운영체제가 프로그램 실행에 필요한 쓰레드, 메모리 자원 및 영역을 할당하게 됩니다.

 

Process란, 운영체제로부터 관리받은 실행 작업의 단위입니다.

운영체제는 " Process"를 작업의 단위로 보고 자원들을 적절하게 분배합니다.

 

 

실행중인 프로세스 확인

 

윈도우에서, Win + Shift + ESC 키를 눌러 Task Manager(작업 관리자)를 실행한다.

Process 탭에서 실행중인 프로그램의 프로세스 상태를 확인할 수 있다. 

Win + Shift + ESC > [Processes]

 

1.3 메모리

 

운영체제가 프로그램 실행에 필요한 메모리를 할당하는데

이 영역에는 code, data, heap 등의 영역이 존재하게 됩니다.

"데이터 영역" - 전역 변수

"힙(Heap) 영역" - 동적 할당

"스텍(Stack) 영역" - 함수 실행

 

 

1.4 프로세스와 스레드 그리고 메모리

 

프로세스

  • 운영체제 관점에서 실행 관리 단위

쓰레드

  • 프로세스 관점에서 별도의 실행 흐름
  • 쓰레드는 하나의 프로세스 내에서, 둘 이상의 실행 흐름을 형성하기 위한 기법
  • 프로세스간의 메모리의 완전한 분리가 아닌, 스텍 영역의 함수(실행 흐름)만을 분리시킨다.
  • 별도의 실행 흐름을 분리해 실행하기 위해 위해 스텍 영역만을 독립적으로 유지한다.
더보기

Critical Section(임계 영역)

 

Synchronization(동기화)

同期化 동기화 : 작업(作業)들 사이의 수행(遂行) 시기(時機)를 맞추는 것

 한가지   기약할, 시점 기  될 

 

동기화의 예

클라우드 

 

 

 

2. Qt Signal & Slot

 

위의 그림은 개발하는 방법을 비교한 그림이다.  

  • 왼쪽은 표준 Socket Network API를 이용해 구현하는 방식
  • 오른쪽은 Qt 에서 제공하는 Qt Network Module을 이용해 구현하는 방식

 

2.1 

소켓 리스너(listener)의 실행은, C 언어의 scanf( ) 함수에서 입력이 있을때까지 로직 실행이 멈추는 상황과 같다.

리스너(listener)는 서버가 클라이언트와 연결 준비가 끝난 상태로, 클라이언트의 연결 요청을 대기하는 동작이다.

그러으로, listen( ) 함수는 클라이언트의 연결 요청이 있을때까지 대기 상태에서 다른 작업 진행이 불가능하다.

 

여기서 문제는, 일반적으로 서버는 한번에 여러 클라이언트와 연결 요청과 송수신작업을 처리해야 한다.

요청 대기 상태에서 무한정 대기 상태에 있다면 송수신 작업과 같은 실행은 진행될 수 없다.

이때 thread 작업로 병렬 처리하는 로직이 필요하다. 

 

그리고 특정 클라이언트가 보내는 메시지가 있는지 검사하고,

메시지가 있다면 접속한 클라이언트에게 전달하고, 

접속한 클라이언트가 종료에 대한 실행도 Thread로 작업되어야 한다.

예로 3개의 Thread를 예로 들었지만 실제 서버 프로그램에서는 이것보다 더 많은 Thread 구현이 필요하다. 

Thread 가 많이 사용 될수록 프로그램 소스코드의 복잡성도 높아지며 유지보수도 어려워 진다. 

 

2.2

Qt 의 경우, Qt 에서 제공하는 Network 모듈을 사용하면, Thread를 사용하여 복잡한 로직을 구현하는 대신

Connect( ) 함수로 Signal 과 Slot을 연결하여 보다 쉽게 네트워크 구성이 가능하다. 

 

요약하면, Qt는 네트워크 프로그래밍 구현 시에 Signal 과 Slot 개념을 사용하기 때문에 표준 네트워크 라이브러리와 Thread와 구현하는 것보다 쉽고 빠르게 소프트웨어를 개발할 수 있다.

(물론, 일반적인 콜백 함수보다 느리다.)

 

3. Qt Networkt Module 예시

void Widget::initialize()
{
    //... 생략
    
    // 순서 5. tcpServer 서버 소켓 생성
    // [1] 생성 : 서버 소켓 생성
    // [2] 결합 : 서버 IP 결합
    tcpServer = new QTcpServer(this);

    // 순서 6. tcpServer 소켓 대기 시작
    // [3] 대기 : 클라이언트의 연결 요청 대기
    // listen(호스트ip, 포트)
    if (!tcpServer->listen(hostAddress, 25000)) {
        QMessageBox::critical(this, tr("TCP Server"),tr("서버를 시작할 수 없습니다. 에러메세지 : %1.").arg(tcpServer->errorString()));
        close();
        return; // 실패시 종료
    }    
    //... 생략

    // tcpServer 소켓에 클라이언트의 연결 요청 Signal 이 생기면, 동작할 Slot 연결
    // thread 작업 대신 Signal 과 Slot 을 사용할 수 있다.
    connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection()));	
    //... 생략
}

 

예를 들어 새로운 클라이언트 접속 로직을 구현한다면, Qt의 QTcpServer 클래스는 새로운 접속 연결이 있을 때 이벤트를 newConnection( ) Signal 함수를 제공하기에, 이 Signal 을 slot newConnection( ) 함수와 연결하면 새로운 클라 연결 요청 Signal이 발생할때마다 newConnection( ) 함수가 호출된다.

 

위의 소스코드 처럼  Qt에서는 새로운 접속자를 처리하기 위한 Thread를 사용한 구현 없이, Slot 함수로 연결하면 매우 간단하게 네트워크 프로그램을 구현할 수 있다.

 

4. LOW 레벨 네트워크 클래스

 

  • QTcpSocket – TCP 프로토콜 기반의 네트워크 클래스
  • QTcpServer – TCP 프로토콜 기반의 서버 구현에 적합한 클래스
  • QUdpSocket – UCP 프로토콜 기반의 네트워크 클래스

 

QTcpSocket 클래스와 QUdpSocket 클래스는 QAbstracktSocket 클래스로부터 상속받아 구현 되었다.

TCP/UDP 프로토콜의 기반이 아닌 새로운 네트워크 프로토콜을 구현하기 위해서 QAbstracktSocket 클래스를 상속 받아 구현한다면 많은 시간을 절약할 수 있다.

 

QTcpServer는 QTcpSocket 과 동일한 TCP 프로토콜 기반의 클래스이다.

차이점은 QTcpServer 클래스는 서버 기반의 응용 어플리케이션 구현에 편리한 기능을 제공한다.

 

 

Qt에서 제공하는 네트워크 모듈을 사용하기 위해서는 프로젝트 파일(.pro)에 다음과 같 이 추가해야 한다.

QT += network

BasicLike

어? 나 프로그래밍 좋아하네?