2010-05-27 4 views
39

통신을 위해 직렬 COM 포트를 사용하고 싶습니다. 그리고 read 함수 호출을 호출 할 때마다 타임 아웃을 구현하고 싶습니다.읽기 함수 호출에서 시간 초과를 구현하는 방법은 무엇입니까?

int filedesc = open("dev/ttyS0", O_RDWR); 

read(filedesc, buff, len); 

편집 : 나는 리눅스 OS를 사용하고

. 함수 호출을 사용하여 구현하는 방법?

+3

http://linux.die.net/man/2/select를 참조하십시오. – sizzzzlerz

답변

64

select() 은 5 개의 매개 변수 (첫 번째는 가장 높은 파일 설명자 +1)를 취한 다음 읽기의 경우 fd_set, 쓰기의 경우 하나, 예외의 경우 하나를 취합니다. 마지막 매개 변수는 struct timeval이며 시간 초과에 사용됩니다. 오류가 발생하면 -1을, 시간 제한을 설정하면 0을 반환하고 설정된 세트에있는 파일 설명자의 수를 반환합니다.

#include <stdio.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <sys/select.h> 

int main(void) 
{ 
    fd_set set; 
    struct timeval timeout; 
    int rv; 
    char buff[100]; 
    int len = 100; 
    int filedesc = open("dev/ttyS0", O_RDWR); 

    FD_ZERO(&set); /* clear the set */ 
    FD_SET(filedesc, &set); /* add our file descriptor to the set */ 

    timeout.tv_sec = 0; 
    timeout.tv_usec = 10000; 

    rv = select(filedesc + 1, &set, NULL, NULL, &timeout); 
    if(rv == -1) 
    perror("select"); /* an error accured */ 
    else if(rv == 0) 
    printf("timeout"); /* a timeout occured */ 
    else 
    read(filedesc, buff, len); /* there was data to read */ 
} 
+2

이 솔루션은 좋지 않습니다. 우리가 5 바이트를 기다리고 있지만 1 시간 만에받은 경우 select가 정상이 될 것이므로 읽은 후 영원히 차단할 것이기 때문입니다. – Roskoto

+7

아니요. 1 바이트 만 사용할 수 있고 5를 읽으려고 시도하면 read()가 차단되지 않고 1 (읽은 바이트 수)을 반환합니다. 읽힌 맨 페이지에서 : "이 숫자가 요청 된 바이트 수보다 작 으면 오류가 아닙니다. 예를 들어 실제로 사용할 수있는 바이트 수가 더 적기 때문에이 오류가 발생할 수 있습니다. 지금은 (아마도 우리가 end- 또는 이 파이프 나 터미널에서 읽거나, read()가 신호로 인해 끼어 들었기 때문에 이 신호로 인해 중단되었습니다. " – Puppe

+0

및 시간을 "선택"하는 방법, 두 번째 시간은 즉시 반환됩니다. 왜 그런지 알고 싶습니까? – kangear

7

do를 비 차단 모드로 작동하도록 설정하면 read를 호출 할 때마다 현재 사용 가능한 데이터 만 읽을 수 있습니다 (있는 경우). 따라서 이는 즉각적인 제한 시간과 동일합니다.

이 같은 기능을 소켓에 비 차단 모드를 설정할 수 있습니다합니다 (read 매뉴얼 페이지를 참조하십시오 비 블로킹 소켓에서 읽기에 대한 자세한 내용은)

int setnonblock(int sock) { 
    int flags; 
    flags = fcntl(sock, F_GETFL, 0); 
    if (-1 == flags) 
     return -1; 
    return fcntl(sock, F_SETFL, flags | O_NONBLOCK); 
} 

4

당신 돈 운영 체제가 무엇인지 말할 수는 없지만 Linux에서 실행중인 경우에는 선택 호출을 사용할 수 있습니다. 파일 디스크립터에서 읽을 내용이 있으면 반환하거나 읽지 않을 경우 시간 초과되도록 설정할 수 있습니다. 반환 코드는 어느 것을 나타냅니다.

35

select()의 대안으로 직렬 포트 (터미널)의 특정 경우에 tcsetattr()을 사용하여 파일 디스크립터를 읽기 제한 시간과 함께 비표준 모드로 설정할 수 있습니다.

는 해제 상기 ICANON 플래그 이렇게하여 VTIME 제어 문자 설정하는 방법 :

struct termios termios; 

tcgetattr(filedesc, &termios); 
termios.c_lflag &= ~ICANON; /* Set non-canonical mode */ 
termios.c_cc[VTIME] = 100; /* Set timeout of 10.0 seconds */ 
tcsetattr(filedesc, TCSANOW, &termios); 

참고 VTIME 초 단위로 측정을하고, 즉, 사용되는 유형의 통상적 unsigned char 의미이며 최대 시간 초과는 25.5 초입니다.

+3

터미널 읽기 시간 제한에 대해 언급 한 사람은 거의 없습니다. – nategoose

+5

제 경우에는 VMIN을 0으로 설정해야했습니다 :'termios.c_cc [VMIN] = 0'. –

+0

t = T1에서 UART를 통해 통신하는 두 개의 장치 TxDev 및 RxDev가 있다고 가정하면 TxDev가 데이터를 보내기 시작합니다.이 시점에서 RxDev는 읽기 명령에 도달하지 못하고 TxDev가 보낸 첫 번째 바이트는 손실됩니까? 또는 RxDev read가 호출되지 않아도 수신 된 데이터를 저장하는 버퍼가 있습니까? – fedi

-2

Linux는 두 가지 유형의 장치를 고려합니다. '느림'(예 : 네트워크) 및 '빠름'(예 : 디스크) 비 차단 모드는 "느린"장치를위한 것이지 "빠른"것이 아닙니다. 장치가 "빠름"으로 간주되도록 장치를 차단하십시오. 따라서 선택/폴링은 항상 I/O 준비가되었음을 알려줍니다. 일부 플래시 장치의 경우 이것은 거짓말이며 select/poll이 장치가 준비되었음을 알리는 경우에도 몇 바이트 동안 몇 초 동안 사용하는 일부 I/O 호출을 보았습니다. 이것은 느린 장치 일지라도 읽기 지연 자체에 대한 강력한 보증은 없다고 말했습니다. 충분히 큰 버퍼를 제공하고 데이터를 사용할 수있는 경우 (선택 또는 폴링을 사용하여 확인한 경우) 읽기 호출 자체가 상당한 시간 (네트워크에서 100 밀리 초)을 사용할 수 있습니다.

+4

스택 오버플로에 오신 것을 환영합니다. 이 사이트의 주요 목표 중 하나는 일반적인 탄젠트 관련 정보뿐만 아니라 질문에서 요구되는 것과 일치하는 대답을 갖는 것입니다. 문제는 "일반적인 장치에 대한 타임 아웃 고려 사항은 무엇입니까?"가 아니라 "시간 초과를 구현하는 방법"이었습니다. 행운을 빕니다. –

관련 문제