이전 시간에는 타이머를 이용해서 직접 소켓을 읽었기 때문에 상대방이 자료를 전송하기 전까지는 프로그램이 block되어 버리는 문제가 있었습니다.

uds 자료만 가공한다면 문제 없겠지만 UDS가 IPC의 방법 중 하나라면 이렇게 사용되는 경우가 거의 없겠죠. ^^ 그러므로 block되는 것을 피하기 위해 POLL을 이용하도록 하겠습니다. POLL을 처음 접하시는 분은 꼭 아래의 글을 먼저 보십시오.

프로그램 코딩 시작

이전 프로그램에 POLL을 위한 코드 부분만 추가됩니다. 그래도 작업 순서대로 글을 올리겠습니다.

  1. 프로제트 파일 생성, "C++ Project"를 선택합니다.


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


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


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


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


  6. labCounter는 타이머 작동을 확인하기 위해 준비했으며, 타이머가 작동할 때 마다, 숫자가 하나씩 증가할 것입니다.

  7. labReceive 라벨은 수신된 자료를 출력하겠습니다.

  8. 폼 생성 후에 실행할 init()함수와 타이머의 슬롯함수를 등록합니다.


  9. 전체 소스입니다.
#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 <sys/poll.h>
#include <qapplication.h>
#include <qtimer.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;
int      sock;
int      nCounter;

struct pollfd poll_events;            // POLL을 위한 변수 선언

// 폼이 생성된 후에 불리워지는 함수, init()입니다.
// 타이머를 생성하고 소켓을 생성하겠습니다.

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;
   }

   // POLL 이벤트를 등록합니다.

   poll_events.fd       = sock;
   poll_events.events   = POLLIN;
   poll_events.revents  = 0;

   // 타이머와 종료 버튼의 시그널에 대해 슬롯을 연결합니다.

   connect( tmrCenter, SIGNAL( timeout()), this, SLOT( onCenterTimer()));
   connect( btnClose, SIGNAL(  clicked()), qApp, SLOT( quit()));

   // 타이머를 가동합니다.

   tmrCenter->start(500, false);
}

// init() 함수에서는 타이머와 소켓을 준비했습니다.
// 이제 타이머 가동되면 labCounter에 숫자를 증가하여 출력하고,
// 상대방으로부터 수신된 자료가 있다면 반송하겠습니다.

void frmMain::onCenterTimer()
{
    int   poll_state;
    int   szRead;

   // 카운터를 출력하고 증가합니다.

   labCounter->setNum( nCounter++);

   // poll()함수로 수신된 자료가 있는지를 확인합니다.
   // 수신된 자료가 있을 때에만 자료를 수신하기 때문에
   // 프로그램이 block 되지 않습니다.

   poll_state = poll( ( struct pollfd*)&poll_events, 1, 500);
   if ( 0 < poll_state)
   {
      if ( poll_events.revents & POLLIN)
      {
         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 값이 계속 증가되는 것을 보실 수 있습니다.

.

프로그램 테스트를 위해 .tester_user 폴더에 uds.c 파일을 실행합니다.

]$ gcc uds.c
]$ ./a.out forum.falinux.com

이렇게 UDS로 문자열을 전송하면 frmMain 윈도우에 전송한 문자열이 출력됩니다.