2006.12.31 13:01:27 (*.138.143.127)

14819

54 / 0

이번 시간에는 시리얼 통신에서 자료를 수신하는 부분을 구현하려 합니다. 그러나 송신 보다 수신하는 부분은 생각할 점이 있습니다. 전송이야 이쪽에서 필요할 보내기만 하면 되기 때문에 "언제라는" 시간적인 문제가 없습니다. 그러나 수신은 자료가 언제 올지를 모르죠. 기다려야 한다는 인데, 자료가 때까지 마냥 시리얼 포트만 쳐다 보고 있을 없습니다. 다른 일도 처리 해야죠. 해야할 일이 산더미처럼 쌓였는데, 마냥 포트만 쳐다 없습니다

   

이럴 쉽게 생각할 있는 것이 일을 처리하는 중에 잠시잠시 포트를 확인하는 방법입니다. 가령 예를 들어서 아래와 같이 하는 것이죠.

while( 1)

{

  // 다른 업무를 실행

  if 0 < read( fd, buf, BUF_MAX_SIZE)

  {

    // 수신 자료를 처리

  }

}

물론 이와 같은 방법도 좋습니다만 ?자료 수신 이외의 이벤트 처리, 예로 통신에 에러가 발생하지 않았는지 등을 확인을 위해서는 다른 확인 루틴을 작성하고 if 절을 추가해야 합니다. 그러나 무엇보다도 read()함수가 block 버리면 루틴 자체가 block되어 버리는 매우 문제를 가지고 있습니다.

   

이럴 사용하는 것이 POLL입니다.

   

poll()

POLL 확인하고 싶은 여러 가지 사건( 이하 event) 미리 등록해 놓고 사건들이 발생했는지 확인할 있는 편리한 방법을 제공해 줍니다. POLL 이용한 작업 진행 과정을 정리해 보면,

  1. 체크하고 싶은 여러 event 등록
  2. poll() 함수를 호출하면
  3. event 발생하면 poll() 함수 호출 후에 바로 복귀하지만,
  4. 발생된 event 없으면 하나 이상이 발생할 까지 time-out 시간 만큼 대기하게 됩니다.
  5. event 발생면 해당 event 배열 아이템의 값이 변동이 되는데,
    변동을 확인하여 어떤 event 발생했는지를 있습니다.

장황한 설명 보다는 먼저 간단한 예를 보여 드리고 후에 자세한 설명을 드리도록 하겠습니다. 예제는 이해를 돕기 위해 상수를 사용하지 않았고, 함수로 분리하지 않았습니다.

예제

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/poll.h>
#include <termios.h> // B115200, CS8 등 상수 정의
#include <fcntl.h> // O_RDWR , O_NOCTTY 등의 상수 정의

int main( void)
{
int fd;
int ndx;
int cnt;
char buf[1024];
struct termios newtio;
struct pollfd poll_events; // 체크할 event 정보를 갖는 struct
int poll_state;

// 시리얼 포트를 open

fd = open( "/dev/ttyS0", O_RDWR | O_NOCTTY | O_NONBLOCK ); // 디바이스를 open 한다.
if ( 0 > fd)
{
printf("open error\n");
return -1;
}

// 시리얼 포트 통신 환경 설정

memset( &newtio, 0, sizeof(newtio) );
newtio.c_cflag = B115200 | CS8 | CLOCAL | CREAD;
newtio.c_oflag = 0;
newtio.c_lflag = 0;
newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN] = 1;

tcflush (fd, TCIFLUSH );
tcsetattr(fd, TCSANOW, &newtio );
fcntl(fd, F_SETFL, FNDELAY);

// poll 사용을 위한 준비

poll_events.fd = fd;
poll_events.events = POLLIN | POLLERR; // 수신된 자료가 있는지, 에러가 있는지
poll_events.revents = 0;

// 자료 송수신

while ( 1)
{
poll_state = poll( // poll()을 호출하여 event 발생 여부 확인
(struct pollfd*)&poll_events, // event 등록 변수
1, // 체크할 pollfd 개수
1000 // time out 시간
);

if ( 0 < poll_state) // 발생한 event 가 있음
{
if ( poll_events.revents & POLLIN) // event 가 자료 수신?
{
cnt = read( fd, buf, 1024);
write( fd, buf, cnt);
printf( "data received - %d %s\n", cnt, buf);
}
if ( poll_events.revents & POLLERR) // event 가 에러?
{
printf( "통신 라인에 에러가 발생, 프로그램 종료");
break;
}
}
}
close( fd);
return 0;
}

  예제를 보시면 struct pollfd 사용했습니다. struct pollfd 내용을 보면 아래와 같습니다.

struct pollfd

{

  int fd;             // 대상 파일 디스크립터

  short events;   // 발생된 이벤트

  short revents;   // 돌려받은 이벤트

};

  1. fd 감시 대상인 디스크립터, 핸들이 되겠습니다.
  2. events 체크하고 싶은 event 모음입니다. 여기서 체크가 가능한 것은 아래와 같습니다.
  • #define POLLIN 0x0001 // 읽을 데이터가 있다.
  • #define POLLPRI 0x0002 // 긴급한 읽을 데이타가 있다.
  • #define POLLOUT 0x0004 // 쓰기가 봉쇄(block) 아니다.
  • #define POLLERR 0x0008 // 에러발생
  • #define POLLHUP 0x0010 // 연결이 끊겼음
  • #define POLLNVAL 0x0020 // 파일지시자가 열리지 않은 같은, Invalid request (잘못된 요청)
  1. revents event 발생 여부를 bit 별로 갖는 값입니다.

   

  , 이제 예제를 보겠습니다.

struct pollfd poll_events; // 체크할 event 정보를 갖는 struct

poll() 사용하기 위한 변수를 선언했습니다. poll_events 에는 감시 대상인 디스크립터와 어떤 event 감시할지 결정해서 bit 값으로 지정해 것입니다.

int poll_state;

poll() 수행한 결과값을 갖습니다. 값은 반드시 체크해야 하는데, 아래와 같은 반환값을 갖습니다.

   

poll() 수행 반환

  

반환

설명

음수

반환 값이 음수라면 치명적인 에러가 발생한 것입니다. 한번 이렇게 음수로 에러가 발생하면 이후 계속 음수값이 날라 옵니다. 거의 대부분 프로그램을 다시 실행해야 됩니다. 반드시 체크해야 겠지요.

0

지정한 대기시간, time-out 지나도록 발생한 event 없습니다.

양수

event 발생했습니다.

poll_events.fd = fd;

감시 대상인 디스크립터를 지정합니다.

poll_events.events = POLLIN | POLLERR; // 수신된 자료가 있는지, 에러가 있는지

체크하고 싶은 event 대해 비트값으로 설정하여 지정해 줍니다.

poll_events.revents = 0;

revents 0 으로 청소해 주고요.

poll_state = poll( // poll() 호출하여 event 발생 여부 확인
(struct pollfd*)&poll_events, // event
등록 변수
1, //
체크할 pollfd 개수
1000 // time out
시간
);

체크할 event 정보를 넘겨 줍니다. 1 체크할 pollfd 개수입니다. 예제를 가지고는 pollfd 개수가 필요한지 이해가 안되시죠. 예제에는 감시하는 디스크립터가 개이지만 프로그램에 따라서는 한번에 여러 개의 디스크립터를 관리할 경우가 많습니다.

   

관리할 디스크립터가 많을 , 각각을 변수로 처리하는 보다 배열로 처리하는 것이 편하겠죠. 이래서 poll() 편리합니다. poll() 변수 하나 외에도 배열을 받을 있으며, 한번의 호출로 모든 event 발생 여부를 확인할 있어 매우 편리합니다.

   

참고

앞으로 강좌를 진행하면서 말씀 드리겠습니다만 poll() 사용하는 다른 장점은 서로 다른 특징의 디스크립터를 사용한다 해도 프로그램 코드를 통일할 있습니다.

예로 rs232c 포트 10개와 tcp/ip 소켓 10개를 한번에 제어하는 프로그램을 작성했을 경우 역시 하나의 배열로 구성해서 poll() 사용할 있기 때문에 rs232c 처리와 tcp/ip 처리하는 프로그램 코드를 통일할 있습니다.

   

1000 time-out 시간으로 발생한 event 없을 경우 poll() event 발생할 까지 time-out 시간 동안 대기하게 됩니다.

시간 값은 msec 1000 1초를 의미합니다. 0 이면? 바로 복귀합니다. -1 이면? evevnt 발생할 까지 기다리게 됩니다. , block 버리죠.

if ( 0 < poll_state)

poll() 함수 결과가 양수라면 event 발생한 것입니다.

if ( poll_events.revents & POLLIN)

발생한 event 중에 POLLIN 있는 지를 확인합니다. POLLIN 해당되는 bit 1 세트되어 있다면 POLLIN으로 AND 값은 0 아닐 것입니다. 이렇게 비트값을 확인하여 event 발생 여부를 확인할 있습니다.

cnt = read( fd, buf, 1024);

write( fd, buf, cnt);

printf( "data received - %d %s\n", cnt, buf);

자료 수신 event 발생했으므로 fd로부터 자료 값을 읽어 들이고, 예제 테스트를 위해 다시 자료를 전송합니다. 또한 화면에도 수신한 자료를 뿌리고 있죠.

예제에 대한 설명은 여기 까지 드리겠습니다. 어떻게 자료 송신부터 수신까지 이해가 되시나요? 다음 시간에는 지금까지의 예제를 좀더 발전시켜서 한번에 여러 포트와 통신하는 방법을 말씀드리겠습니다. 조금씩 조금씩 발전 시켜 나가는 거죠.....^^

   

글을 읽어 주셔서 감사합니다.

게시물을...

목록 수정 삭제

엮인글 주소 : http://forum.falinux.com/zbxe/?document_srl=405838&act=trackback&key=2fe

   

   

2007.11.07 15:35:11 (*.126.183.43)

최강산

좋은공부되었습니다

요즘 통신관련 프로그램을 짜고 있는데 도움이 많이 되네요^^

2008.04.10 17:20:30 (*.94.41.89)

xerxer

감사합니다. 대략 감을 잡는데 도움이 되네요.

번호

제목

글쓴이

날짜

조회

19

TCP/IP 프로그래밍 방법

3

   

장길석

2007-03-19

21449

18

TCP/IP, UDP/IP 2

장길석

2007-03-14

12124

17

TCP/IP, UDP/IP 1

1

장길석

2007-03-14

17479

16

시리얼 통신에서 전송 속도 계산

장길석

2007-03-11

14785

15

CRC 위치는 어디가 좋을까?

장길석

2007-03-11

11932

14

CRC 계산

2

장길석

2007-03-10

19695

13

DLE 프로토콜 소개

5

   

장길석

2007-03-10

15188

12

프로토콜에 대해서

   

장길석

2007-03-10

20903

11

poll 이야기 1

장길석

2007-02-28

12714

10

rs232c 라이브러리 상세 분석

   

장길석

2007-02-23

16492

9

rs232c 통신 라이브러리

6

   

장길석

2007-02-23

16850

  

시리얼 통신 - 자료 수신을 위한 poll

2

장길석

2006-12-31

14819

7

시리얼 통신 예제 전체 설명

장길석

2006-12-29

14978

6

시리얼 통신 - data bit size parity

장길석

2006-12-29

10968

5

시리얼 통신 - start bit stop bit

1

장길석

2006-12-29

11594

4

시리얼 통신 - 통신 속도 결정

장길석

2006-12-29

11466

3

시리얼 통신 - 통신포트 열기

2

장길석

2006-12-29

23781

2

시리얼 통신 - 프로그램 분해 설명 시작!!

장길석

2006-12-29

15260

1

시리얼 통신 첫회

   

장길석

2006-12-24

20326

 

반응형

'Linux' 카테고리의 다른 글

LINUX 디스크, CPU 정보 확인 명령  (14) 2012.07.11
VI 에디터 사용팁  (8) 2012.07.09
NMS의 기본 개념 - 장애관리  (4) 2011.08.23
Unix Domain Socket UDP  (4) 2011.08.19
[명령어]Message Queue 설정 및 확인  (8) 2011.08.11

+ Recent posts