그래픽 & 멀티미디어
QT에서 UDS 통신 프로그램을 작성하면서 타이머와 POLL을 이용했습니다만, 시간이 날때 마다 UDS도 QSocket처럼 SIGNAL과 SLOT를 이용하는 방법이 없을까 찾아 보았습니다. 그러나 QSocket 소스를 뒤져바도 잘 모르겠더군요. 하는 수 없이 결국 제가 알고 있는 방법인 POLL을 이용하는 방법을 먼저 올리게 되었습니다.
그러나 제 글을 보신 (주)FALINUX의 유영창이사님께서 QSocketNotifier를 알려 주셨습니다. POLL을 이용해도 좋지만 역시 QT는 QT다웁게 작성하는 것이 어떻겠냐며, 매우 겸손하고 조심스럽게 말씀을 주셨습니다.
QSocketNotifier?!!
이런 제가 소스 분석을 수박 겉핥기식으로 했나요? 저는 그 객체가 있는지를 몰랐습니다 말씀 드렸더니,
"라이브러리 소스 중 network 디렉토리만 보셨죠? ㅋㅋ"
헉!! 어떻게 아셨지? ^^;
QSocketNotifier은 kernel 디렉토리에 있답니다. 이런...Qt Reference Documentation 페이지를 자주 보는데도 바로 밑에 있는 QSocketNotifier를 못 보았을까요? 이궁~
방법을 알았으니 코드로 직접 확인해 보아야 겠지요. ^^
프로그램 코딩 시작
역시 작업 순서대로 글을 올리겠습니다.
- 프로제트 파일 생성, "C++ Project"를 선택합니다.

- 적당한 프로젝트 이름을 입력합니다.

- 프로젝트 파일을 저장합니다.

- 폼 이름을 지정합니다. 이 이름이 클래스 이름이 되므로 적당한 이름을 지정해 줍니다. 여기서는 frmMain으로 입력하겠습니다.

- 필요한 위젯을 배치합니다.

- labCounter는 타이머 작동을 확인하기 위해 준비했으며, 타이머가 작동할 때 마다, 숫자가 하나씩 증가할 것입니다.
- labReceive 라벨은 수신된 자료를 출력하겠습니다.
- 슬롯을 등록합니다.
onCenterTimer()은 타이머를 위한 슬롯입니다.
onReceiveFromUds()는 UDS 소켓으로부터 수신된 자료를 처리하기 위한 슬롯입니다.
init()는 폼이 생성된 후에 발생되는 함수입니다.
- 전체 소스입니다. 이전 강좌 소스와는 달리 POLL이 없고 대신에 QSocketNotifier이 추가되었습니다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/un.h>
#include <qapplication.h>
#include <qtimer.h>
#include <qsocketnotifier.h>
#include <qmessagebox.h>
#define SOCK_LOCALFILE "/tmp/uds_a"
#define BUFF_SIZE 1024
char buffReceive[BUFF_SIZE+5];
size_t szAddr;
struct sockaddr_un addrLocal;
struct sockaddr_un addrGuest;
QTimer *tmrCenter;
QSocketNotifier *notUdsRead;
int sock;
int nCounter; // 타이머에서 출력할 카운터로, 프로그램이 block되었는지
// 확인하기 위해 사용합니다.
// 폼이 생성된 후에 불리워지는 함수, init()입니다.
// 타이머, 소켓 그리고 QSocketNotifier를 생성하겠습니다.
void frmMain::init()
{
// 타이머를 생성하고 카운터를 0으로 초기화 합니다.
tmrCenter = new QTimer( this);
nCounter = 0;
// UDS에서 사용할 파일이 존재하면 삭제합니다.
if ( 0 == access( SOCK_LOCALFILE, F_OK))
unlink( SOCK_LOCALFILE);
// UDS 소켓을 생성합니다.
sock = socket( PF_FILE, SOCK_DGRAM, 0);
if( -1 == sock)
{
QMessageBox::information( this, "UDS", "I cannot build a socket!!");
return;
}
// UDS 소켓 정보를 완성하고 bind()함수를 호출하여
// 다른 시스템에서 전송되어 오는 자료를 수신할 준비를 합니다.
memset( &addrLocal, 0, sizeof( addrLocal));
addrLocal.sun_family = AF_UNIX;
strcpy( addrLocal.sun_path, SOCK_LOCALFILE);
if( -1 == bind( sock, (struct sockaddr*)&addrLocal, sizeof( addrLocal)) )
{
QMessageBox::information( this, "UDS", "bind error!!");
return;
}
// UDS로부터 수신을 감시하는 QSocketNotifier를 생성합니다.
// 그리고 생성한 QSocketNotifier 시그널에 대해 슬롯을 연결합니다.
notUdsRead = new QSocketNotifier( sock, QSocketNotifier::Read, this);
connect( notUdsRead, SIGNAL( activated( int)), this, SLOT( onReceiveFromUds()));
// 타이머와 종료 버튼 시그널 처리입니다.
connect( tmrCenter, SIGNAL( timeout()), this, SLOT( onCenterTimer()));
connect( btnClose, SIGNAL( clicked()), qApp, SLOT( quit()));
// 타이머를 가동합니다.
tmrCenter->start(500, false);
}
// 이전 강좌에 올려진 타이머하고는 비교되지 않을 정도로 할 일이 없어져죠.
// 프로그램이 block되지 않았는지 확인하기 위해 카운터를 출력합니다.
void frmMain::onCenterTimer()
{
labCounter->setNum( nCounter++); // 카운터를 출력하고 증가합니다.
}
// UDS 소켓으로부터 자료가 수신되었다면, 아래의 슬롯 함수가 실행됩니다.
// 수신된 값을 읽어 들이고 화면에 출력합니다.
void frmMain::onReceiveFromUds()
{
int szRead;
szAddr = sizeof( addrGuest);
memset( buffReceive, 0, BUFF_SIZE);
szRead = recvfrom( sock, buffReceive, BUFF_SIZE, 0 ,
( struct sockaddr*)&addrGuest, &szAddr);
// 여기까지 실행되었다면 자료가 수신된 것입니다.
// 화면의 라벨에 출력하고
buffReceive[szRead] = '\0';
labReceive->setText( buffReceive);
// 상대방 시스템으로 전송합니다.
sendto( sock, buffReceive, szRead+1, 0,
( struct sockaddr*)&addrGuest, szAddr);
}
프로그램 완성
main()함수를 위해 main.cpp를 생성하고 컴파일하면 모든 작업이 끝납니다.
프로젝트를 빌드하기 위해서 main.cpp를 생성합니다. File >> New메뉴를 선택합니다. main.cpp를 선택합니다.
frmMain을 선택하고 프로젝트를 빌드합니다.
]# qmake ]# make ]# ./uds -> 프로젝트 파일 이름
프로그램 실행
프로그램을 실행하면 Count 값이 계속 증가되는 것을 보실 수 있습니다. 이렇게 증가되는 것을 보시면 프로그램이 block되지 않았음을 알 수 있습니다.
.
프로그램 테스트를 위해 .tester_user 폴더에 uds.c 파일을 실행합니다.
]$ gcc uds.c ]$ ./a.out forum.falinux.com
이렇게 UDS로 문자열을 전송하면 frmMain 윈도우에 전송한 문자열이 출력됩니다.

- QT,
- IPC,
- UDS,
- QSocketNotifier


