그래픽 & 멀티미디어
글 수 15
2007.12.27 00:27:44 (*.33.84.154)
45846
이전 시간에는 타이머를 이용해서 직접 소켓을 읽었기 때문에 상대방이 자료를 전송하기 전까지는 프로그램이 block되어 버리는 문제가 있었습니다.
uds 자료만 가공한다면 문제 없겠지만 UDS가 IPC의 방법 중 하나라면 이렇게 사용되는 경우가 거의 없겠죠. ^^ 그러므로 block되는 것을 피하기 위해 POLL을 이용하도록 하겠습니다. POLL을 처음 접하시는 분은 꼭 아래의 글을 먼저 보십시오.
프로그램 코딩 시작
이전 프로그램에 POLL을 위한 코드 부분만 추가됩니다. 그래도 작업 순서대로 글을 올리겠습니다.
- 프로제트 파일 생성, "C++ Project"를 선택합니다.
- 적당한 프로젝트 이름을 입력합니다.
- 프로젝트 파일을 저장합니다.
- 폼 이름을 지정합니다. 이 이름이 클래스 이름이 되므로 적당한 이름을 지정해 줍니다. 여기서는 frmMain으로 입력하겠습니다.
- 필요한 위젯을 배치합니다.
- labCounter는 타이머 작동을 확인하기 위해 준비했으며, 타이머가 작동할 때 마다, 숫자가 하나씩 증가할 것입니다.
- labReceive 라벨은 수신된 자료를 출력하겠습니다.
- 폼 생성 후에 실행할 init()함수와 타이머의 슬롯함수를 등록합니다.
- 전체 소스입니다.
#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 윈도우에 전송한 문자열이 출력됩니다.