Unix System Programming 8 - :namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />김성호(moohou) :namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
_________________________________________________________________________
제8장. 단말기
8.1. 서론
프로그램과 사용자가 단말기를 통해 교신할 때는 언제나 보기보다 훨씬 많은
일들이 벌어진다. 예를 들어 프로그램이 단말기 장치에 문자열을 쓸 때 이 문
자열은 단말기 장치 구동기라는 커널의 한부분에 의해 우선 처리된다. 시스템
이 유지하는 상태 플래그가 갖는 값에 따라서, 문자열은 축약된 형태로 전달되
기도 하고 구동기에 의해 변형되기도 한다.
- 프로그램
이는 출력 문자열을 생성하고 입력 문자열을 해석한다.
- 단말기 장치 구동기
이는 kernel 의 일부, 즉 소프트웨어의 일종이다. 구동기의 주요부분은
컴퓨터가 단말기와 통신하도록 해 주는 특정 하드웨어와 상호작용을 한다. 단
말기 장치 구동기의 주요 기능은 프로그램과 단말기 장치 사이에 자료를 전달
하는 것이다.
- 키보드와 화면
이들 두 노드는 단말기 자체를 나타내며 단말기가 두가지 측면을 갖고 있
음을 강조한다. 단말기의 키보드는 입력 장치에 해당하고 화면은 출력장치로
작동한다.
두가지 주의할 점이 있다. 첫째, 우리는 UNIX에서 사용되는 단말기의 대부분
인 비동기식 단말기 만을 다룬다. 둘째, UNIX 나 그 변중에서의 단말기 조작은
서로 일치하지 않는 것으로 악명이 높다.
8.2. UNIX 단말기
제 4 장에서 언급했듯이 단말기는 특수화일로 인식된다. (그리고 단말기의 특
성상 문자 장치 로서 취급된다). 단말기 이름으로는 다음의 것 들이 많이 쓰인
다.
/dev/console
/dev/tty01
/dev/tty02
/dev/tty03
tty 는 단말기를 지칭하는 UNIX 용어이다.
8.2.1. 제어 단말기
프로세스의 표준 화일 기술어를 통하여 접근할 수 있는 단말기를 프로세스와
프로세스 그룹의 제어 단말기라 한다. 프로세스가 자신의 화일 기술어 상태와
무관 하게 제어 단말기에 접근하려면 /dev/tty 란 화일이름을 사용하면 된다.
이는 항상 프로세스 의 현재 제어 단말기를 가리킨다.
8.2.2. 자료전송
단말기 장치 구동기는 프로그램과 단말기 장치 사이에 문자를 전달하는 것이
주 임무이다.
8.2.3. 반향과 미리 쳐넣기
가장 기초적인 편의 기능으로는 문자의 반향(echoing)을 꼽을수 있다. 이는
사용자가 키보드 에서 문자 'A' 를 칠때 화면에 'A' 가 나타나게 하는 기능이
다. 이는 프로그램이 화면에 출력 하는 도중에 사용자가 입력을 하는 경우에
출력 의 중간에 입력의 반향이 나타나는 상황을 초래 한다. 다른 시스템의 경
우에는 프로그램이 입력 을 읽을 준비를 갖출 때까지 반향이 억제된다.
8.2.4. 규준모드, 라이편집, 특수문자.
UNIX 구동기는 단순하고 라인 중심이며 대화식인 용도에 특별히 맞춘 작동 모
드를 제공한다. 이는 규준 모드(canonical mode)라 하며 쉘이나 ed 편집기, 그
리고 기타 유사한 프로그램에서 많이 사용된다. 규준모드에서 사용되는 편집
키 중 가장 친숙한 것은 erase 문자이다. 이를 누르면 해당 라인의 앞서의 문
자가 지워진다.
$whp<erase>o
쉘 수준에서 이를 정하는 방법은 stty 를 사용하는 것이다.
$stty erase "^h"
는 erase 문자로서 CTRL-H 를 지정한다. 이는 backspase 의 또 다른 이름이
다. 이때 CTRL-H 문자를 직접 입력하지 않아도 문자열 '^h' 를 사용하면 된다
는 사실에 주목하라. erase, kill, 또는 eof 문자의 특수 의미를 제거하려면
바로 앞에 역 슬래쉬 문자(\)를 사용한다. 이 경우에는 특수 문자에 결부된 기
능이 수행되지 않고 문자 자체가 프로그램으 로 전달된다.
aa\<erase>b<erase>c
은 단말기에서 입력을 얻는 프로그랩에게 aa\<erase>c 로 전달된다.
8.3. 프로그램의 관점
지금부터는 단말기를 사용하는 프로그램의 관점에서 살펴보자.
8.3.1. open 시스템 호출
open 은 보통의 디스크 화일과 매우 유사한 방법으로 단말기를 개방하는데 사
용된다.
fd = open("/dev/tty0a", O_RDWR);
8.3.2. read 시스템 호출
화일에 접근하는 기본 호출 중에서 단말기 특수 화일을 사용하는 경우에 가장
큰 영향을 받는 것이 read 시스템 호출이다. read 호출은 항상 newline 이 입
력되어야 끝난다.
nread = read(0, buffer, 256);
8.3.3. write 시스템 호출
이는 단말기와 함깨 사용되는 한 매우 간단하게 수행된다. 단지 제한접이란
해당 단말기의 출력 큐가 모두 차 있는 경우에 write 가 블럭되는 것 뿐이다.
프로그램의 수행이 재개되려면 큐에 남아있는 문자들이 일정수준 이하로 빠져
나가야 한다.
8.3.4. ttyname 과 isatty
ttyname 은 개방된 단말기 화일 기술어의 해당 단말기 장치에 대한 이름을 돌
려준다. isatty 는 화일 기술어가 단말기 장치의 것이면 1 을, 아니면 0 을 돌
려준다.
int filedes, bool;
char *name, *ttyname();
.
.
name = ttyname(filedes);
bool = isatty(filedes);
두기지 경우 모두 filedes 는 개방된 화일 기술어를 나타낸다. filedes 가 단
말기를 나타내지 않으면 ttynam 은 NULL 을 돌려준다.
8.3.5. termio 구조를 사용하여 단말기 특성을 변경하는 법
쉘에서는 단말기의 특성을 변경하기 위하여 stty 명령을 사용했다. 프로그램
에서는 ioctl 시스템 호출과 termino 구조를 사용하여 같은 일을 할 수 있다.
- 생략
8.3.6. MIN 과 TIME 인수
인수 MIN 과 TIME 은 플래그 ICANON 이 0 일때만 효력을 갖는다. 이들은 자료
의 입력, 즉 read 호출에 대한 프로그의 제어권을 정밀하게 조정한다. MIN 은
단말기에 대한 read 호출이 끝나기 전에 단말기 구동기가 받아 들여야 하는 문
자의 최소 갯수를 나타낸다. TIME 는 또 다른 제어권으로서 시간 종료의 기간
을 나타 낸다.
MIN 과 TIME 의 값에는 다음의 4 가지 경우가 있을 수 있다.
1. MIN 과 TIME 모두 0 일때.
이 때는 read 호출이 항상 즉시 끝난다. 해당 단말기의 입력 큐에 문자가 들
어 있으면(입력은 아무때고 도착한다는 것을 상기하라), 프로그램 버퍼에 옮
겨진다.
2. MIN 은 0 보다 코고 TIME 은 0 과 같을때.
이 경우에는 타이머가 아무 역할도 하지 않는다. read 호출이 끝마쳐 지려면
읽혀지길 기다리는 문자가 MIN 만큼은 있어야 한다.
3. MIN 은 0 이고 TIME 은 0 보다 클때.
이 경우 MIN 은 아무일도 하지 못한다. 타이머는 read 가 호출되는 순간부터
작동한다.
4. MIN 과 TIME 모두 0 보다 큰 경우.
이 경우가 가장 유용하고도 유연성이 있다. 타이머가 작동되는 순간은 이제
는 read 가 호출된 순간이 아니라 첫번째 문자가 들어왔을 때이다. 시간이
종료되면 그 순간까지 입력 큐 에 있는 문자들만이 프로그램에 전달된다.
8.3.7. ioctl 시스템 호출
ioctl 은 문자형 특수 화일이 나타내는 외부장치를 제어하기 위한 다목적 호
출로서 인수의 유형이 매우 다양하다. 단말기에 대한 ioctl 호출은 크게 기본
호출과 추가호출의 두가지 유형으로 분리된다. 기본호출의 사용법은 다음과 같
다.
#include <termio.h>
struct termio targ;
int ttyfd, cmd, retval;
.
.
retval = ioctl(ttyfd, cmd, &targ);
ttyfd 는 단말기에 대한 개방된 화일 기술어라야 한다. targ 는 termio 구조
의 변섭 단말기의 상태를 저장한다. 인수 cmd 는 ioctl 의 수행양식을 지정하
며 termio.h 에 정의된 바와 같이 다음과 같은 값을 가질 수 있다.
TCGETA
이는 icctl 이 단말기의 현재상태를 targ 에 복사하게 한다.
TCSETA
TCGETA 의 역으로서, targ 에 있는 값으로 단말기의 상태를 지정한다.
TCSETAW
이는 TCSETA 와 같은 기능을 하지만 새로운 값을 지정하기전에 현재의 출력
큐가 비워질 때까지 기다린다.
TCSETAF
이는 TCSETA 의 또 다른 형태로서 출력 큐가 비워질 때까지 기다린 후에 입
력 큐를 청소하고 난 다음에야 단말기의 상태를 targ 의 값으로 지정한다.
이는 기본 호출과 추가 호출 경우에 모두 적용된다. 추가적인 ioctl 호출은
프로그래머에게 단말기 구동기가 관리하는 입출력 큐에 대한 어느 정도의 제어
권을 부여한다.
#include <termio.h>
int ttyfd, cmd, arg, retval;
.
.
retval = ioctl(ttyfd, cmd, arg);
여기서 ttyfd 와 cmd 의 의미는 앞에서의 경우 동일하다. arg 는 정수형로 추
가적인 정보를 전달한다. 추가 ioctl 호출에서 사용할 수 있는 cmd 의 값은 다
음과 같다.
TCFLSH
arg 가 0 이면 입력 큐를 청소한다. 즉 입력 큐의 모든 문자를 무시한다.
arg 가 1 이면 큐를 청소한다. arg 가 2 이면 입출력 큐를 모두 청소한다.
TCXONC
이것은 단말기 구동기에 대한 중단/재개를 제어한다. arg 가 0 면 출력이
중단된다. 중단된 출력을 재개하려면 arg 값을 1 로 해서 ioctl 을 다시 호
출해야 한다.
TCBRK
이것은 break 를 전송하는 데 사용된다. 이것은 1/4 초동안 0 비트들을 전
송하는 것과 같다. 이 기능은 출력 큐가 빈 다음에만 사용되어야 한다.
8.3.8. 단절 시그널
6 장에서 프로세스 그룹 리더가 제어 단말기를 갖고 있을 때 수행이 종료되면
해당 프로세스그룹의 구성원들에게 단절 시그널 SIGHUP 이 전달됨을 보았다.
여기에는 또 다른 용도가 있어서, 컴퓨터와 단말기 사이의 접속이 끊어져서 단
말기 라인의 반송파가 검출되지 않는 상황을 대변 할 수 있다. 이러한 상황은
단말기가 전화선이나 지역 네트워크를 사용하여 연결된 경우에 발생할 수 있
다. 이런 상황이 발생하면, 단말기 구동기는 해당 단말기를 제어 단말기로 하
는 모든 프로세스에게 SIGHUP 을 보낸다. (SIGINT와는 달리 SIGHUP 은 쉘을 정
상적으로 로그아웃되게 한다.) 보통의 경우 프로그래머는 SIGHUP 에 손대지 말
아야 한다. 이는 훌륭한 안전장치를 제공한다. 그러나 때에 따라서는 프로그램
이 이를 포착하여 마무리 작업을 수행해야 할 필요성이 있을 수 있다.
8.4. connect 의 예
connect 는 통신 프로그램으로서 두가지 작동모드를 갖는다. 하나는 사용자가
두 개의 UNIX 컴퓨터를 연결하게 해준다. 다른 하나는 두 컴퓨터 간에 텍스트
화일을 전송하게 해준다. 우선 헤더화일 connect.h 를 살펴보자. 이 화일은 다
시 termio.h 와 같은 시스템 헤더 화일을 포함한다. 이외에도 다수의 상수가
정의 되어 있다. 이 중에서 STARTCOM 이란 문자열은 현지 컴퓨터에서 원격 컴
퓨터로의 자료전달을 초기화 하는데 사용된다.
#include <stdio.h>
#include <fcntl.h>
#include <termio.h>
#include <signal.h>
#include <setjmp.h>
#define ERROR (-1)
#define SUCCESS 0
#define TRUE 1
#define FALSE 0
#define SENDFILE 1
#define EXIT 2
#define MAXTIME 30
#define STARTCOM\
"mesg n; stty -opost; cat -> %s; stty
opost; mesg y"
#define CTRLD 004
#define CTRLP 020
#define CTRLY 031
connect 프로그램을 호출 하려면 다음과 같이 명령을 준다.
$connect term-name speed
예를 들어서
$connect /dev/ttya 9600
main 에서 호출하는 함수로는 표준시스템 호출 과 라이브러리루틴을 제외하
면, getspeed, ttyopen, cfatal, 그리고 connect 등이 있다. 함수 getspeed 는
명령어 라인 인수의 두 번째 것을 ioctl 에 적합한 형태로 변환한다. ttyopen
은 앞서 소개했듯이 단말기를 개방하는 함수이다(ttyopen 을 수정하여
connect.h 에 정의된 상수들을 이용하는 것도 고려해보라). 함수 cfatal 은 오
류메시지를 출력하고 프로그램의 수행을 중단시킨다. connect 는 main 이 호출
하는 마지막 함수이다. 여기서는 두개의 자식 프로세스를 생성하여 화일 전송
을 담당하 는 중추적 역할을 한다. 함수 connect 는 두개의 인수가 있는데 하
나는 ttyopen 이 개방한 화일기술어이고, 다른 하나 는 getspeed 가 변환해 준
전송속도이다. 임무 는 프로세스를 두개 생성하여 부모 프로세스는 원격 시스
템에서 오는 문자들을 전달하게 하고 자식 프로세스는 원격 시스템에서 오는
문자들 을 받아들이게 하는 것이다. 필요한 경우에는 원격 시스템으로 화일 전
송을 개시할 수도 있다. 여기서 명심할 사실이 있다. 하나는 자식 프로세스가
수행하는 from 함수는 절대는 끝나지 않는다는 것이다. 따라서 부모 프로세스
가 kill 함수를 호출해야 한다. 다른 하나는 함수 to 가 돌려주는 변수 status
는 사용자가 입력 하는 명령어에 해당한다는 것이다. SENDFILE 과 EXIT 가 정
의된 곳은 물론 connect.h 이다.
8.5. 과거
UNIX 버전 7 과 같은 경우에는 termio 구조는 존재하지 않았다. 대신에 단말
기의 상태를 기술하기 위해서 보다 간다한 구조 sgttyb 를 사용했다. 이 구조
의 자료형을 사용했을때는 ioctl 의 기능이 좀 더 제한되었었다. 단말기의 특
성은 gtty 라는 시스템 호출에 의해 얻어지고 stty 에 의해 지정되었다.
8.6. 그리고 미래
스트림이란 본질적으로는 프로세싱 모듈의 선형 구조로서 쉘의 파이프 라인과
유사하지만 모듈 사이의 자료전달이 양방향으로 모두 될 수 있는 점이 다르다.
스트림의 한쪽 끝은 사용자 프로세스에게 연결되어 있고 다른쪽 끝은 스트립을
위한 장치 구동기에 연결된다. 사용자 프로세스에게 가장 가까운 모듈은 스트
림에 대한 프로그래머의 인터페이스 역할을 한다. 사용자 프로세스가 write 를
호출하면 이는 스트림에 전달되는 메시지로 변환되고, read 를 호출되면 가장
가까운 모듈에서 자료를 읽어 들이게 된다. 일관성을 유지하기 위해서 제어 정
보도 모듈간의 메시지와 같은 형태로 전달된다. 스트림이 open 호출을 통해 개
방되면 두개의 말단 모듈이 자동적으로 연결된다. 이것이 스트림의 가장 기본
적인 형태이며 프로그래머에게 매우 원시적인 수준의 인터페이스를 제공한다.
추가적인 모듈이 스트림에 삽입되려면 확장된 형태의 ioctl 을 호출해야 한
다.(단말기가 최초에 매우 원시적 상태로 개방된다는 사실은 사용자 수준의 코
드를 약간 수정하게 만든다.)'Academy I > Tech Academy' 카테고리의 다른 글
Linux gdb 사용법 [I] (0) | 2014.12.19 |
---|---|
Linux make 사용법 [I] (0) | 2014.12.18 |
Unix System Programming 10 (0) | 2014.12.16 |
Unix System Programming 9 (0) | 2014.12.16 |
Unix System Programming 7 (0) | 2014.12.16 |
Unix System Programming 6 (0) | 2014.12.16 |
Unix System Programming 5 (0) | 2014.12.16 |
Unix System Programming 4 (0) | 2014.12.16 |