VI에서 CTRL+] 또는 CTRL+t를 가능하게 함
C소스 루트 디렉토리에서 [root@waf a_sc]#ctags -R .
1Day Study
[[[[[리눅스와 C 기본]]]]]
/bin: 바이너리, 시스템을 부팅하는 데 사용되는 프로그램
/usr/bin: 사용자 바이너리, 사용자가 사용할 수 있는 표준 프로그램
/usr/local/bin: 로컬 바이너리, 설치에 사용되는 프로그램
실행파일 만들기
gcc -o hello hello.c
헤더파일 디렉토리 지정
gcc -I/usr/openwin/include fred.c
라이브러리를 지정하여 실행파일 만들기
gcc -o fred fred.c /usr/lib/libm.a
gcc -o fred fred.c -lm
gcc -o fred fred.c -L/usr/lib/ -lm
테스트 오브젝트 파일 만들기
gcc -c bill.c fred.c
lib.h 파일 작성 후 테스트 오브젝트 파일의 펑션들 선언 => 컴파일러가 에러를 찾을 수 있도록 도와줌
void bill(char *);
void fred(int);
오브젝트 파일을 링크해서 실행파일 만들기
gcc -c program.c => #include "lib.h" 선언된 파일
gcc -o program program.o bill.o
오브젝트 파일을 정적 라이브러리로 만들기
ar crv libfoo.a bill.o fred.o
버클릭 유닉스계열을 위해서 목차표로 만들기
ranlib libfoo.a
정적 라이브러리를 이용한 실행파일 만들기
gcc -o program program.o libfoo.a
gcc -o program program.o -L. -lfoo => -lfoo는 libfoo.a 또는 libfoo.so를 참조함
사용한 함수명 파악하기
mn ./libfoo.a
mn ./program
공유 라이브러리는 확자가가 .so 임
사용되는 공유 라이브러리 파악하기
ldd program
도움말보기
man은 간략하게 보기
info는 자세하게 보기(info를 위한 도움말 ctrl+H)
================================================================================================================================================================
2Day Study
[[[[[Shell Script 관련]]]]]
Shell 종류
sh(Bourne) => 유닉스 초기 버전의 원본 쉘
csh, tcsh, zsh => C 쉘 및 파생형 쉘 버클리 유닉스에서 사용됨
ksh, pdksh => 상당수의 상용 유직스의 기본 쉘
bash => GNU 리눅스 기본 쉘 Ksh와 유사함
명령어 결과 파일 출력
ls -l > lsoutput.txt => New
ls -l >> lsoutput.txt => Append
에러 정보가 화면에 나타나지 못하게 방지하며 에러 정보를 버릴때(표준 에러 파일 설명자 2)
ls -l 2> lsoutput.txt
kill 명령 결과를 killout에 저장, 에러는 killerr에 저장
kill -HUP 1234 >killout 2>killerr
양 출력을 하나의 파일로 저장
kill -1 1234 >killouterr 2>&1
표준에러 저장 안 하기
kill -1 1234 >/dev/null 2>&1
입력 리다이렉트
more < longtext
프로세서끼리 연결하기(ps의 출력을 받아서 알파벳순으로 정렬 후 uniq를 이용하여 프로세스만 추출하고 grep -v 를 이용하여 sh를 프로세서를 제거하고 more를 이용해서 페이지 단위로 보게함)
ps -xo comm | sort | uniq | grep -v sh | more
ps의 출력을 정렬 후 pssort에 저장
ps | sort > pssort
문자열에서 POSIX를 포함하고 있는 파일 이름을 출력
more 'grep -l POSIX *'
more $(grep -l POSIX *)
grep -l POSIX * | more
Shell Script FOR문
#!/bin/sh => 시스템에게 이 줄의 인자가 이 파일을 실행시키기 위한 프로그램임을 지정(문자 32개 이하로 지정 구 버전 유닉스들이 지원 못 할 수도 있기 때문)
for file in *
do
if grep -q POSIX $file
then
echo $file
fi
done
exit 0 => 쉘 프로그래밍에서 0은 성공을 의미한다. 스크립트 자체만으로는 어떠한 실패도 지각하지 못함으로 항상 0을 반환한다
쉘 스크립트의 기본 선언 변수는 문자열로 간주됨
쉘에서 $를 변수 이름 앞에 붙여서 변수의 내용을 액세스 할 수 있음
echo를 통해서 변수값을 화면에서 검사 가능(예: echo $data)
= 기호의 양쪽에는 어떠한 공백도 없어야 함
쓰기권한 제거
chown root ./filename
chgrp root ./filename
chmod 755 ./filename
chmod u=rwx,go=rx ./filename
사용자값 입력받기
read inputmsg
read 후 문자열 비교시 "로 꼭 싸주자
if [ $data = "yes" ] => if [ "$data = "yes" ]
쉘에서 ",',\ 차이점
#!/bin/sh
myvar="Hi there"
echo $myvar
echo "$myvar" => 값으로 인식
echo '$myvar" => 문자열로 인식
echo \$myvar < \을 앞에 붙여서 $ 기호의 특수한 의미를 제거
echo Enter some text
read myvar
echo '$myvar' now equals $myvar
exit 0
결과는
Hi there
Hi there
$myvar
$myvar
Enter some text
Hello World => 키보드 입력을 받음
$myvar now equals Hello World
사용자의 환경 보기 명령어
env
환경변수 설정하는 명령어
export
환경변수
$HOME => 현재 사용자 홈 디렉토리
$PATH => PATH 디렉토리
$PS1 => 명령어 프롬프트(예: [\u@\h \W]$는 사용자, 컴퓨터 이름, 현재 디렉토리를 보여줌
$PS2 => 두번째 프롬프트(예: >)
$IFS => 입력 필드 구분자
$0 => 쉘 스크립트의 이름
$# => 전달된 매개변수의 갯수
$$ => 쉘 스크립느의 프로세스 ID
매개변수를 이용하는 방법
$ IFS=' '
$ set foo bar bam
$ echo "$@"
foo bar bam
$ echo "$*"
foobarbam
$ unset IFS
$ echo "$*"
foo bar bam
일반적으로 $@가 많이 쓰임
매개 변수와 환경 변수 실습 (try_var 로 저장)
#!/bin/sh
salutation="Hello"
echo $salutation
echo "$0"
echo "$2"
echo "$1"
echo "$*"
echo "$HOME"
exit 0
결과는
Hello
./try_bar
bar
foo
foo bar baz
/home/rick
쉘의 부울 검사를 할 때 쓰이는 명령어
test 혹은 [ => [는 test이 축약형(도움말 보기는 help test)
ls -l /usr/bin/[
파일 존재 확인 스크립트(IF문 사용하기)
if test -f fred.c
then
...
elif
...
else
...
fi
if [ -f fred .c ]
then
...
elif
...
else
...
fi
if [ -f .tcsshrc ]; then ... ; elif ... ; else ... ; fi
위 3개의 if은 같은 스크립트다([ 괄호와 확인할 조건 사이에 공백을 반드시 넣어야 함)([ 명령을 사용하여 변수 내용을 테스트 한다. if 명령이 결과를 계산하고 다른 줄의 코드를 실행함)
출력값 응용(if와 elif 조건까지도 통과 된다면 else 출력 후 스크립트값을 1로 종료한다. 이 값을 사용하여 스크립트가 성공하였는지 검사를 할 수 있다)
if [ -f fred .c ];
then
...
elif
...
else
...
exit 1
fi
exit 0
문자열 비교
str1 = str2 => 두 문자가 같으면 true
str1 != str2 => 두 문자가 같이 않으면 true
-n str1 => str1이 널(빈 문자열)이 아니면 true
-z str1 => 문자열이 널(빈 문자열)이면 true
산술 비교
exp1 -eq exp2 => 두 표현식이 같으면 true
-ne => 두 표현식이 같지 않으면 true
-gt => 왼쪽이 크면 true
-ge => 왼쪽이 크거나 같으면 true
-lt => 왼쪽이 작으면 true
-le => 왼쪽이 작거나 같으면 true
! exp => exp가 false면 true이고 그 역도 성립
파일 비교
-d file => file이 디렉토리면 true
-e => file이 존재하면 true(-e는 유닉스에서 잘 안 될수도 있기 때문에 -f가 흔히 사용됨)
-f => 보통파일이면 true
-g => set-group-id가 file이 설정되면 true(set-gid는 프로그램에게 자신의 그룹의 권한을 줌)
-r => 파일을 읽을 수 있으면 true
-s => 파일 크기가 0이 아니면 true
-u => set-user-id가 file에 설정되면 true(set-user는 프로그램에게 자신의 사용자가 아닌 소유자의 권한을 줌)
-w => 파일에 쓸 수 있으면 true
-x => 파일이 실행 가능하면 true
echo 호환여부
echo -e는 모든 시스템에서 지원은 안 됨
bash는 echo -n을 지원하여 read시 줄 바꿈을 없애줌
FOR문 => 지저분한다 다른 언어랑 좀 틀리다 ㅡㅡ; 버려!
#!/bin/sh
for foo in bar1 bar2 bar3
do
echo $foo
done
exit 0
결과는
bar1
bar2
bar3
#!/bin/sh
for foo in "bar1 bar2 bar3"
do
echo $foo
done
exit 0
결과는(bar1 bar2 bar3를 한 문자로 인식)
bar1 bar2 bar3
WHILE문
문자비교
#!/bin/sh
while [ "$data" = "true" ]
do
...
done
숫자비교 => 우리가 일반적으로 쓰는 FOR문 대체
#!/bin/sh
data=1
while [ "$data" -le 20 ]
do
...
data=$(($data+1))
done
UNTIL문(명령줄에서 전달한 로그인 이름을 가진 사용자가 로그온 할 때 작동하도록 알람을 설정)
#!/bin/sh
until who | grep "$1" > /dev/null
do
sleep 60
done
echo "**** $1 has just logged in ****"
exit 0
CASE문(다른 언어에서는 switch문 이라고도 함)
case "$data" in
yes | zz ) echo "yes or zz";;
no ) echo "no";;
y ) echo "y";;
n ) echo "n";;
p* ) echo "p char start string";;
* ) echo "etc default";;
esac
AND 리스트
touch file_one
rm -f file_two
if [ -f file_one ] && echo "hello" && [ -f file_two ] && echo " there"
then
echo "in fi"
else
echo "in else"
fi
exit 0
결과는(file_one는 있으므로 hello를 출력하고 file_two는 없으므로 there를 출력하지 않고 else이 in else를 출력함)
hello
in else
OR 리스트
rm -f file_one
if [ -f file_one ] || echo "hello" || echo "there"
then
echo "in if"
else
echo "in else"
fi
exit 0
결과는(file_one가 없지만 OR 조건이므로 hello를 출력하고 in if를 출력함
hello
in if
SUB함수 쓰는 방법
#!/bin/sh
foo() {
echo "Function"
}
echo "script start"
foo
echo "script end"
exit 0
결과값
script start
Function
script end
SUB함수에서 지역변수는 local data="hahaha" 로 선언함
SUB함수 결과값 return 하기
#!/bin/sh
yes_or_no() {
echo "Is your name $* ?"
while true
do
echo -n "Enter yes or no: "
read x
case "$x" in
y | yes ) return 0;;
n | no ) return 1;;
* ) echo "Answer yes or no"
esac
done
}
echo "Rriginal parameters are $*"
if yes_or_no "$1" => Rick Neil에서 첫번째 Rick만 넘김
then
echo "Hi $1, nice name"
else
echo "Naver mind"
fi
exit 0
결과값은
$ ./my_name Rick Neil
Original parameters are Rick Neil
Is your name Rick ?
Enter yes or no: yes
Hi Rick, nice name
================================================================================================================================================================
3Day Study
쉘 스크립트 내장 명령어
break; => 중간에 빠저나올때 사용
: => 널 명령 or true(예: while : 와 while true와 같다)
: ${var:=value} => :이 없으면 쉘은 $var을 명령으로 연산하고자 시도한다
continue => 반복문에서 사용
for x in 1 2 3
do
echo before $x
continue 1
echo after $x
done
결과값
before 1
before 2
before 3
. => 현재 쉘에서 명령 실행(예: . ./shell_script) C에서 #include 지시어와 약간 비슷
파일명 classic_set
#!/bin/sh
version=classic
PATH=/usr/local/old_bin:/usr/bin:/bin:.
PS1="calssic> "
파일명 lastst_set
#!/bin/sh
version=latest
PATH=/usr/local/new_bin:/usr/bin:/bin:.
PS1=" latest version> "
결과는
# . ./calssic_set
calssic> echo $version
classic
classic> . latest_set
latest version> echo $version
latest
latest version>
echo => 문자열과 줄 바꿈 문자를 출력하기 위해서 사용(이식성을 위해서는 tr 명령을 이용
echo -n "string to output"
echo -e "string to output\c" => \t(탭), \n(캐리지 리턴)
eval => 인자를 연산할 때
foo=10
x=foo
y='$' $x
echo $y
결과값
foo
foo=10
x=foo
eval y='$' $x
echo $y
결과값
10
exec => 다른 프로그램을 실행 및 현재 파일 설명자를 수정
exec wall "Thanks for all the fish"
exec 3< afile =>이것은 파일 asfile로 부터 읽기 위해 설명자 3을 사용하여 연다
exit => 스크립트 종료 기능
exit 0 => 성공 종료(에러코드는 1~125 까지 존재함)
125 => 파일이 실행 가능이 아니다
127 => 명령을 찾을 수 없다
128이상 값 => 신호(signal)가 발생하였다
AND OR 응용
#!/bin/sh
if [ -f .file ]; then
exit 0
fi
exit 1
과
[ -f .profile] && exit 0 || exit 1
는 같다
export => 매개변수로 받은 이름의 변수를 하위 쉘에서 사용 가능하도록 만들어줌
파일명 export2
#!/bin/sh
echo "$foo"
echo "$bar"
파일명 export1
foo="foo"
export bar="bar"
export2
결과값은
$ export1
bar
set -a 또는 set -allexport => 모든 변수를 내보낸다
expr => 자신의 인자를 표현식으로 연산
x=`expr $x + 1`
x=$(expr $x + 1)
요즘은 expr 보단 $((수식)) 이 쓰임(expr 보다 빠르다)
x=$((3+1))
printf => 화면출력하기(echo 보다 좋지만 최신의 쉘에서 사용 가능, 소수점은 지원안됨)
\\ => 백슬래시 문자
\a => 벨 울리기
\b => 백스페이스 문자
\f => 폼 피드 문자
\n => 줄 바꿈 문자
\r => 캐리지 리턴
\t => 탭 문자
\v => 수평 탭 문자
\ooo => 8진수 값 ooo을 가진 단일 문자
%d => 십진수를 출력
%c => 문자를 출력
%s => 문자열을 출력
$ printf "%s %d\t%s" "Hi There" 15 people
Hi Theere 15 people
return => 기본적으로 마지막 명령의 종료 코드 반환
set => 매개변수을 설정할 때
#!/bin/sh
echo the date is $(date)
set $(date)
echo The month is $2
exit 0
결과는(set으로 매개변수를 설정 후 $2를 사용해서 달(Month)를 갖고온다)
the date is Mon Mar 2 11:46:12 KST 2009
The month is Mar
set -x => 스크립트가 현재 실행 명령들의 추적을 표시함
shift => 매개변수를 하나씩 아래로 옮긴다($2->$1, $0은 변하지 않음, $* $@ $# 매개변수들이 새로운 정렬에 따라 값이 변하게 됨)
모든 매개변수 검사
#!/bin/sh
while [ "$1" != "" ]; do
echo "$1"
shift
done
exit 0
trap -l => SIG 신호들 보기(신호를 이용해서 작동을 지정)
trap 중요한 신호들
HUP(1) => 행업(대개 터미널을 끊고 사용자가 로그아웃할 때 전송)
INT(2) => 인터럽트(대개 Ctrl+C를 눌러서 전송)
QUIT(3) => 끝내기(대개 Ctrl+\를 눌러서 전송)
ABRT(6) => 중단(대개 어떤 심각한 실행 에러일 때 전송)
ALRM(14) => 알람(대개 시간 제한을 처리할 때 사용)
TERM(15) => 종료(대개 시스템이 종료할 때 전송)
#!/bin/sh
trap 'rm -f /tmp/my_tmp_file_$$' INT
echo creating file /tmp/my_tmp_file_$$
date > /tmp/my_tmp_file_$$
echo "press interrupt (CTRL-C) to interrupt ...."
while [ -f /tmp/my_tmp_file_$$ ]; do
echo File exists
sleep 1
done
echo The file no longer exists
trap INT
echo creating file /tmp/my_tmp_file_$$
date > /tmp/my_tmp_file_$$
echo "press interrupt (control-C) to interrupt ...."
while [ -f /tmp/my_tmp_file_$$ ]; do
echo File exists
sleep 1
done
echo we never get here
exit 0
결과는(처음 while 까지 실행 후 Ctrl+C를 누르면 두번째 while문 진입 후 Ctrl+C를 누르면 바로 종료가 되서 echo we never get here 밑으로는 실행되지 않음) => 잘 안됨
creating file /tmp/my_tmp_file_141
press interrupt (CTRL-C) to interrupt ....
File exists
File exists
The file no longer exists
creating file /tmp/my_tmp_file_141
press interrupt (CTRL-C) to interrupt ....
File exists
File exists
unset => 변수나 함수를 환경에서부터 메모리에서 완전 삭제함(IFS 같은 읽기 전용 변수는 사용이 안됨)
#!/bin/sh
foo="Hello World"
echo $foo
unset foo
echo $foo
결과(foo=과 틀림 foo가 완전히 사라짐)
Hello World
유용한 명령어들
파일 찾기
find [경로] [옵션] [테스트] [작동]
fine / -mount -name wish -print => wish파일을 찾는데 마운트된 시스템은 안 찾음
-depth => 디렉토리의 내용을 먼저 검색
-follow => 기호화된 링크를 따라감
-maxdepths N => 검색할때 최대 N 수준까지의 디렉토리를 검색
-mount => 다른 파일 시스템의 디렉토리는 검색하지 않음
-atime N => 파일이 N일 이전에 마지막으로 액세스 되었다
-mtime N => 파일이 N일 이전에 마지막으로 수정되었다
-name "패턴" => 경로를 제외한 파일의 이름이 주어진 패턴에 일치
-newer otherfile => 파일이 otherfile보다 최신이다
-type C => 파일 형식이 C, d는 디렉토리, f는 보통 파일
-user 사용자이름 => 주어진 이름을 가진 사용자가 파일을 소유하고 있다
! or -not => 테스트를 역으로 수행
-a or -and => 두 테스트가 모두 true
-o or -or => 둘 중 하나의 테스트가 true
파일 X보다 최신이거나 밑줄로 시작하는 이름의 보통파일만 찾아서 출력
find / \( -newer X -or -name "_*"\ ) -type f -print => (는 특별한 의미기 때문에 \ 필요
find 작동후 수행 옵션은
-exec 명령 => 명령을 실행
-ok 명령 => -exec와 같지만 실행하기 전에 사용자에게 여부를 물음
위 두가지는 \;로 끝냄 {}은 현재 파일에 대한 전체 경로로 인식
-print => 파일의 이름을 출력
-ls => 현재 파일에 대해서 ls -dils 명령을 사용
파일 X보다 최신이거나 밑줄로 시작하는 이름의 보통파일만 찾아서 ls -l 하기
find / \( -newer X -or -name "_*"\ ) -type f -exec ls -l {} \;
결과는
-rwxr-xr-x 1 root root 5984 Mar 15 2007 /usr/lib/python2.4/site-packages/rhpl/_diskutil.so
find / \( -newer X -or -name "_*"\ ) -type f -exec ls -l \;
결과는
-rwxr-xr-x 1 root root 75 Mar 2 11:46 setsample.sh
grep => 일반 정규식 파서
grep [옵션] 패턴 [파일]
-c => 일치하는 줄의 갯수 출력
-E => 확장 표현식을 적용
-h => 파일명 붙이는거 제거(일반적으로 grep는 찾은 패턴의 앞에 파일명이 나옴)
-i => 대소문자를 구별 안함
-l => 일치된 줄에 해당하는 파일 이름만 나열
-v => 일치된 패턴 제거
grep -c -v in words.txt => words.txt안에 in 문자가 없는 줄의 갯수 파악
많이 쓰이는 정규표현식(상세한 정규표현식은 info grep에서 Regular Expressions 부분 보기)
^ => 문자의 시작
$ => 문자의 끝
. => 어떤 단일 문자
? => 필수가 아니여도 1번 일치
* => 0번 혹은 더 많이 일치
+ => 1번 혹은 더 많이 일치
{n} => n번 일치
{n,} => n번이상 일치
{n,m} => n번에서 m번 사이에 일치
[ ] => 일치되는 문자의 범위(예: ^[a-e]는 a에서 e까지의 역이다)
grep e$ words.txt => e로 끝나는 문자 찾기
grep a[[:blank:]] words.txt => a로 끝나는 단어 찾기([[:blank:]]는 공백이나 탭)
grep Th. [[:space:]] word.txt => Th로 시작되는 단어 찾기
grep -E [a-z]\{10\} word.txt => 소문자가 10자로 단어 찾기
!!중요 포인트!!
명령 실행의 오래된 형식에서는 작은 따옴표가 아니라 백틱 혹은 백따옴표)`_를 사용하였음을 명심하자
$(명령}은 단순히 명령의 출력임
!!중요 포인트!!
1_tmp와 2_tmp 제어할때
#!/bin/sh
for i in 1 2
do
my_secret_rpocess $i_tmp
done
결과는(에러가 남)
my_secret_process: too few arguments
에러 수정 방법
my_secret_rpocess $i_tmp => my_secret_rpocess ${i}_tmp
매개변수 확장
${param:-default} => param이 널이면 default의 값으로 설정
${param:=default} => param이 널이 아니면 변수의 값을 반환하며, 그렇지 않으면 foo를 bar로 설정하고 이 값을 대신 반환
${param:?default} => param: default를 출력하고, param이 존재하지 않거나 널이면 명령 중지
${param:+default} => param이 존재하고 널이 아니면 default를 반환
${#param} => param의 길이를 준다
${param%word} => 끝에서부터 word에 일치하는 param의 가장 짧은 부분을 제거하고 나머지 반환
${param%%word} => 끝에서부터 workd에 일치하는 param의 가장 긴 부분을 제거하고 나머지를 반환
${param#word} => 처음부터 word에 일치하는 param의 가장 짮은 부분을 제거하고 나머지를 반환
${param##word} => 처음부터 word에 일치하는 가장 긴 부분을 제거하고 나머지를 반환
#!/bin/sh
unset foo => foo 메모리 삭제
echo ${foo:-bar} => 기본으로 foo에 bar 넣고 출력
foo=fud => foo에 fud 넣기
echo ${foo:-bar} => foo에 fud가 있기 때문에 fud 출력
foo=/usr/bin/X11/startx => foo에 /usr/bin/X11/startx 입력
echo ${foo#*/} => foo에서 처음부터 오직 왼쪽 */ 제거하고 출력
echo ${foo##*/} => foo에서 처음부터 */ 찾아서 최대한 많이 제거하고 출력
bar=/usr/local/etc/local/networks
echo ${bar%local*} => bar에서 끝부터 local이 오면 중지
echo ${bar%%local*} => bar에서 끝부터 계속 local까지 비교 후 중지
exit 0
결과는
bar
fud
usr/bin/X11/startx
startx
/usr/local/etc/
/usr/
모든 *.gif파일을 *.jpg로 바꾸기
#!/bin/sh
for image in *.gif
do
cjpeg $image > ${image%%gif}jpg
done
히어 도규먼트(<<) => 실제로는 명령이 스크립트로부터 입력을 받고 있음에도 파일이나 키보드로부터 입력을 받아들이는 것처럼 실행(echo를 사용 안할때 도 사용하거나 ed(Text 편집기)명령을 제어함)
#!/bin/sh
cat <<!FUNKY!
hello
this is a here
document
!FUNKY!
결과는
hello
this is a here
document
히어 도규먼트 두번째 예제
파일명 a_text_file
That is line 1
That is line 2
That is line 3
That is line 4
#!/bin/sh
ed a_text_file <<!FunkyStuff! => 히어 도큐먼트 시작
3 => a_text_file 3번째 줄로 가기
d => a_text_file 해당 위치에서 줄 삭제
.,\$s/is/was/ => 3번째 행이 삭제되었기 때문에 기존 4번째 행에서 is를 was로 변경
w => 저장
q => 나가기
!FunkyStuff! => 히어 도큐먼트 끝
exit 0
결과는
That is line 1
That is line 2
That was line 4
디버그 하기
sh -n <스크립트> => 문법 검사
sh -v <스크립트> => 소스 보기
sh -x <스크립트> => 출력값마다 출력을 위한 소스를 보여줌(가장 좋다)
trap 'echo 변수명 = $변수명' EXIT => 종료될때 변수값 출력
그래픽으로 보여주기 => dialog 유틸을 사용(yum install dialog)
diaglog --msgbox "Hello World" 9 18
결과는 사이즈가 넓이 9 높이 18인 Hello World라고 다이얼로그 박스가 나옴
--더이상의 그래픽 부분은 생략함--
================================================================================================================================================================
4Day Study
[[[[[파일(File) 작업]]]]]
아이노드(inode) => 파일 시스템의 데이터의 특정 블록이며, 파일의 길이와 파일이 디스크의 어디에 저장되어 있는가를 포함(ls -i)
디렉토리 => 아이노드 숫자와 파일의 이름을 저장하고 있는 파일이다. 각 디렉토리 항목은 파일의 아이노드에 대한 연결이다. 파일 이름을 삭제하면 연결이 삭제된다
사용자 디렉토리 => 틸트(tilde) ~를 가지고 있음
/bin => 시스템 바이너리 디렉토리
/etc => 시스템 구성 파일 디렉토리
/lib => 시스템 라이브러기 디렉토리
/dev => 장치 인터페이스 파일 디렉토리
CD-ROM 마운트
# mount -t iso9660 /dev/hdc /mnt/cdrom
# cd /mnt/cdrom
/dev/console => 시스템 콘솔을 표현
/dev/tty => 프로세스의 제어 터미널(키보드와 화면 혹은 윈도우)에 대한 별칭
/dev/zero => 0을 포함하는 파일을 생성하기 위해 null 바이트의 원본처럼 작동
/dev/null => 이 장치로 쓰여진 모든 출력은 버려짐
빈파일 만들기
cp /dev/null empty_file
touch .empty_file => 기존 파일이 있을 경우 파일의 수정시간 만 바뀜
장치 드라이버 액세스를 위한 저수준 함수인 시스템 호출(시스템 호출은 성능부하가 큼으로 한번에 큰 파일을 쓰기 위함)
open => 파일 혹은 장치 열기
read => 열린 파일 혹은 장치로 부터 읽기
write => 파일이나 장치에 쓰기
close => 파일이나 장치를 닫기
ioctl => 제어 정보를 장치 드라이버에 전달(각 드라이버 마다 고유한 ioctl 명령 집합이 있음)
리눅스 시스템
사용자 프로그램(라이브러리) => 사용자 공간
↓
시스템 호출/커널(장치 드라이버) => 커널 공간
↓
하드웨어 장치
write의 설명자
0 => 표준 입력
1 => 표준 출력
2 => 표준 에러
write 예시 => 반환값(0 데이터 안씀, -1 에러 발생, 1이상의 실제로 쓰여진 바이트 수)
size_t write(int fildes, const void *buf, size_t nbytes);
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main()
{
if ((write(1, "Here is some data\n", 18)) != 18)
write(2, "A write error has occurred on file descriptor 1\n",46);
exit(0);
}
결과는
Here is some data
read 예시 => 반환값(0 데이터 안읽기, -1 에러 발생, 1이상의 실제로 읽어진 바이트 수)
size_t read(int fildes, const void *buf, size_t nbytes);
int main()
{
char buffer[128];
int nread;
nread = read(0, buffer, 128);
if (nread == -1)
write(2, "A read error has occurred\n", 26);
if ((write(1,buffer,nread__ != nread)
write(2, "A write error has occurred\n",27);
exit(0);
}
결과는
echo hello there | simple_read
hello there
open => 새로운 파일 설명자를 만들기 위해
int open(const char *path, int oflags);
int open(const char *path, int oflags, mode_t mode);
mode 맴버는
O_RDONLY => 읽기 전용
O_WRONLY => 쓰기 전용
O_RDWR => 읽고 쓰기용
oflags 맴버는
O_APPEND => 파일 끝에 붙이기
O_TRUNC => 파일의 길이를 0으로 설정하여 기존 내용을 삭제함
O_CREAT => 필요하다면 파일을 생성
O_EXCL => O_CREAT와 함께 사용하며 파일이 만들었음을 확실 할 수 있음
#include <sys/types,h>
#include <sys/stat.h>
파일을 만들때(O_CREAT)는 플래그 필요 맴버는
S_IRUSR : 읽기 권한, 소유자
S_IWUSR : 쓰기 권한, 소유자
S_IXUSR : 실행 권한, 소유자
S_IRGRP : 읽기 권한, 그룹
S_IWGRP : 쓰기 권한, 그룹
S_IXGRP : 실행 권한, 그룹
S_IROTH : 읽기 권한, 다른 사용자
S_IWOTH : 쓰기 권한, 다른 사용자
S_IXOTH : 실행 권한, 다른 사용자
예: myfile 파일을 만들면서 소유자의 읽기 권한과 다른 사용자의 실행 권한을 부여
open ("myfile", O_CREAT, S_IRUSR|S_IXOTH);
umask => 파일을 만들 때 사용할 파일의 권한 마스크를 인코드 하는 시스템 변수
close => 파일 간의 연결을 종료(반환값 : 0 성공, -1 실패)
int close(int fildes);
limits.h => 실행중에 한번에 열수 있는 파일의 개수 제한(OPEN_MAX)
ioctl => 장치 제어
int ioctl(int fildes, int cmd, ...);
TIMEFORMAT="" time copy_system => 복사에 대해서 점유율 파악
Command exited with non-zero status 127
0.00user 0.00system 0:00.00elapsed 0%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+49minor)pagefaults 0swaps
저수준의 파일 복사하기 기능 예:
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{
char block[1024];
int in, out;
int nread;
in = open("file.in", O_RDONLY);
out = open("file.out", O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
while((nread = read(in,block,sizeof(block))) > 0)
write(out,block,nread);
exit(0);
}
lseek => 파일 설명자 filedes의 읽기/쓰기 포인터를 설정
off_t lseek(int fildes, off_t offset, int whence);
fstat => 열린 파일 설명자에 연결된 파일의 관한 상태 정보를 반환
stat => 명명된 파일의 상태 정보를 반환
lstat => 명명된 파일의 상태 정보를 기호화된 링크로 반환
int fstat(int fildes, struct stat *buf)
int stat(const char *path, struct stat *buf);
int lstat(const char *path, struct stat *buf);
stat의 맴버는
st_mode => 파일 권한과 파일 형식 정보
st_ino => 파일과 관련된 inode
st_dev => 파일이 존재하는 장치
st_uid => 파일 소유자의 사용자 ID
st_gid => 파일 소유자의 그룹 ID
st_atime => 마지막 액세스 시간
st_ctime => 권한, 소유자, 그룹 혹은 내용이 마지막으로 변한 시간
st_mtime => 내용이 마지막으로 변한 시간
st_nlink => 파일에 대한 하드 링크의 갯수
예: 파일이 디렉토리가 아니고 소유자에 대한 실행 권한을 가지고 있지만 다른 권한을 가지고 있지 않은지 테스트
struct stat statbuf;
mode_t modes;
stat("filename",&statbuf);
modes = statbuf.st_mode;
if(!S_ISDIR(modes && (modes & S_ISWXU) == S_IXUSR)
...
dup, dup2 => 파일 설명자를 복제하는 방법
int dup(int fildes);
int dup2(int fildes, int fildes2);
기본 라이브러리(stdio.h)를 이용한 파일 입출력
fopen => 저수준 open 시스템 호출과 유사하나 저수준 시스템 호출은 입출력 버퍼링과 같은 잠재적 버그로 원하지 않는 부작용을 없애줌
FILE *fopen(const char *filename, const char *mode);
반환값(null 실패, FILE * 성공)
r 또는 rb => 읽기 전용
w 또는 wb => 쓰기, 내용을 모두 지움
a 또는 ab => 쓰기, 내용을 추가
r+ 또는rb+ 또는 r+b => 갱신(읽기와 쓰기)
w 또는 wb+ 또는 w+b => 갱신, 내용을 모두 지움
a+ 또는 ab+ 또는 a+b => 갱신, 내용을 추가
b는 파일이 텍스트가 아니라 바이너리 파일임을 가르킴(유닉스와 리눅스는 텍스트 파일은 없음 모두 바이너리로 취급함)
fread => 파일 스트림으로 부터 데이터를 읽기
size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);
fwrite => 지정된 데이터 버퍼에 있는 데이터 레코드를 출력 스트림으로 쓴다
size_t fwrite (const void *ptr, size_t size, size_t nitems, FILE *stream);
!!중요!!
구조화된 데이터를 사용하는 목적으로 fread와 fwrite를 권장하지 않는다. fwrite로 쓰여진 파일들이 다른 컴퓨터에서 잠재적으로 이식되지 않을 수도 있어서 문제의 소지가 있다
fclose => 지정된 stream을 닫으며 쓰여지지 않은 모든 데이터를 쓴다
int fclose(FILE *stream);
stream의 제한은 stdio.h에 FOPEN_MAX로 정의되어있고 최소 8이다
fflush => 파일 스트림의 모든 데이터가 즉시 쓰여짐
int fflush(FILE *stream);
fclose전에 fflush는 자동으로 호출됨으로 fclose 전에 호출할 필요가 없다
fseek => 저수준의 lseek에 해당하는 stream 함수이나 lseek는 off_t를 반환하고
int fseek(FILE *stream, long int offset, int whence);
fseek는 정수를 반환한다(반환값 -1 실패, 0 성공)
fgetc => 파일 스트림으로부터 다음 바이트를 문자로 반환(반환값 EOF 파일 끝, EOF 에러)
int fgetc(FILE *stream);
fgetc의 반환값이 EOF가 2가지가 존재함으로 ferror 혹은 feof를 사용 해야함
getc => 매크로로 구현된 fgetc임(지역 변수가 아니거나 함수의 매개변수로 전달되지
앟은 변수에 영향을 끼치지 못하고 getc의 주소를 함수 포인터로 사용할 수 없다)
int getc(FILE *stream);
getchar => getc(stdin)과 동일하며 표준 입력으로부터 다음 문자를 읽는다
int getchar();
fputc => 문자를 출력 스트림에 쓴다(반환값 : 쓴값 성공, EOF 실패)
int fputc(int c, FILE *stream);
putc => getc의 경우와 같음
int putc(int c, FILE *stream);
putchar => putc(cm, stdout)와 동일하며, 하나의 문자를 표준 출력으로 쓴다(문자를 char가 아닌 int로 취하고 반환함)(반환값: -1 문자끝)
int putchar(int c);
fgets => stream으로부터 문자열을 읽는다(최대 n-1 문자까지 한번에 전송가능)(반환값: 문자열 s에 대한 포인터를 반환)(반환값: EOF 파일끝, NULL 읽기에러)
char *fgets(char *s, int n, FILE *stream);
gets => fgets와 동일하며 표준 입력으로부터 읽고 줄 바꿈 문자를 없앤다는 차이가 있다
char *gets(char *s)
!!중요!!
gets는 전송할 수 있는 문자의 개수에 제한을 두지 않기 때문에 버퍼오버플로우 공격에 취약함으로 fgets로 쓰길 권장함
printf => 다른 형식을 가진 인자들을 형식화해서 출력
int printf(const char *format, ...);
예:
printf("Some numbers: %d, %d, and %d\n", 1, 2, 3);
결과는
Some numbers: 1, 2, and 3
fprintf => 자신의 출력을 지정된 stream에 작성
int fprintf(FILE *stream, const char *format, ...);
sprintf => 자신의 출력과 종료 널 문자를 매개변수로 전달된 문자열 s에 쓴다
int sprintf(char *s, const char *format, ...);
%d, %i => 정수를 십진 형태로 출력
%o, %x => 8진, 16진으로 출력
%c => 문자를 출력
%s => 문자열을 출력
%f => 부동 소수점 단위로 출력
%e => 배정밀도(double) 숫자를 고정된 형식으로 출력
%g => 배정밀도 숫자를 일반적인 형식으로 출력
예:
char initial = 'A';
char *surname "Matthew";
double age = 14.5;
printf("Hello Miss %c %s, aged %g\n", initial, surname, age);
결과는
Hello Miss A Matthew, aged 14.5
예: 181페이지 참조
%10s의 인자값이 Hello일때 결과는 | Hello|
scanf => 스트림으로부터 항목을 읽고 변수에 값을 저장(반환값: 0 실패, EOF 항목이 일치하기 전에 끝에 도달하면, 읽어들인 변수의 갯수 성공)
int scanf(const char *format, ...);
예:
int num;
scanf("Hello %d", &num);
실행방법(밑에 2개 모두 num에 1234가 들어감, Hello와 일치할 경우 %d에 따라 숫자가 오면 들어감)
Hello 1234
Hello1234
!!중요!!
정수를 입력받기 위해 스캔하면서 입력에 숫자가 아닌 문자가 들어온다면 무한 반복문이 발생할 수 있다
%d => 십진 정수 스캔
%o, %x => 8진, 16진 정수를 스캔
$f, $e, $g => 부동 소수점 숫자를 스캔
$s => 문자열 스캔(첫번째 공백에서 멈춤으로 단어용으로 씀)
$[] => 문자들의 집합을 스캔
%% => %문자를 스캔
%c => 하나의 문자만 스캔
예:
Hello, 1234, 5.678, X, string to the of the line를 스캔할 경우
char s[256];
int n;
float f;
char c;
scanf("Hello, %d, %g, %c, %[^\n]", &n, &f, &c, s);
!!중요!!
한 줄을 입력 받고 스캔하기 위해서는 필드 지정자를 사용하거나 fgets와 sscanf를 혼용하는것이 좋다)
int fscanf(FILE *stream, const char *format, ...);
int sscanf(const char *s, const char *format, ...);
!!중요!!
scanf 계열은 사용을 자제(여러 줄의 입력을 읽기 이해서는 fread나 ggets와 같은 함수를 사용)
정통적으로 구현상에 버그가 있음
사용하기에 유연하지 않음
구문 분석된 항목에 대해 작업하기 어려운 방향의 코드가 됨
기타 스트림 함수
fgetpos : 파일 스트림의 현재 위치를 얻는다
fsetpos : 파일 스트림의 현재 위치를 설정한다
ftell : 스트림의 현재 파일 옵셋을 반환한다
rewind : 스트림이 파일 위치를 처음으로 설정한다
freopen : 파일 스트림을 다시 사용한다
setvvuf : 스트림을 위한 버퍼링 방법을 설정한다
remove : 파일이면 unlink와 동일하고 디렉토리면 rmdir과 동일
표준라이브러리를 이용한 파일 복사하기 기능(저수준 보다 느림) 예:
#include <stdio,h>
#include <stdlib.h>
int main()
{
int c;
FILE *in, *out;
in = fopen("file.n", "r");
out = fopen("file.out","w");
while((c=fgetc(in)) != EOF)
fputc(c,out);
exit(0);
}
저수준의 파일 복사하기 기능 예(다시):
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{
char block[1024];
int in, out;
int nread;
in = open("file.in", O_RDONLY);
out = open("file.out", O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
while((nread = read(in,block,sizeof(block))) > 0)
write(out,block,nread);
exit(0);
}
스트림 에러 처리
errno => 저수준의 에러 값을 반환하는데 이때 에러는 외부 변수 errno에 명시됨
#include <errno,h>
extern int errno;
!!중요!!
여러 함수가 errno의 값을 변경시킬수 있으므로 함수 에러 발생시 즉시 검사를 시행하고 항상 이 변수의 값을 사용하기 전에 다른 변수에 복사하고 쓴다
ferror => 스트림에 대한 에러 표시(반환값: 0 설정안됨, 0이외 설정됨)
int ferror(FILE *stream);
feof => 스트림에서 파일 끝 표시(반환값: 0 설정안됨, 0이외 설정됨)
int feof(FILE *stream);
예:
if(feof(some_stream))
/* 끝에 도달 */
clearerr => 스트림이 가리키는 스트림에서 파일 끝 표시와 에러 표시를 초기화("디스크 공간 부족" 에러가 해결된 다음 스트림에 쓰기 작업을 계속 수행할 때 쓰임)
void clearerr(FILE *stream);
fileno => 어떤 저수준 파일 설명자를 파일 스트림에 대해서 사용할 때(반환값: -1 실패, 주어진 스트림의 파일 설명자 성공)(열린 스트림에 대해서 fstat를 호출하는 것과 같이 저수준 액세스가 필요한 경우 유용하게 쓰임)
int fileno(FILE *stream);
FILE *fdopen(int fildes, const char *mode); => 이미 열린 파일 설명자를 기반으로 새로운 파일 스트림을 생성할 수 잇다(이미 열린 파일 설명자 주변에 stdio 버퍼를 제공)(fopen 함수와 동일한 방식으로 작동하는데 파일 이름 대신 저수준 파일 설명자를 받음)(반환값: NULL 실패, 새로운 파일 스트림 성공)
chmod => 시스템 호출을 사용하여 파일이나 디렉토리에 대한 권한을 변경(쉘 기반)
#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
chown => 시스템 호출을 사용하여 파일의 소유자를 변경
#include <unistd.h>
int chown(const char *path, uid_t owner, gid_t group);
unlink => 시스템 호출을 사용하여 파일에 대한 디렉토리 항목을 지우고 링크 개수를 감소시킴(반환값: 0 성공, -1 에러)(unlink를 사용하려면 파일의 디렉토리 항목에 포함된 모든 디렉토리에 대해 쓰기와 실행 권한이 필요함)(rm 프로그램은 이 호출을 사용)
#include <unistd.h>
int unlink(const char *path)
link => 기존파일 path1에 대해서 새로운 링크를 만들고 새로운 디렉토리 항목을 path2로 지정
int link(const char *path1, const char *path2);
symlink => 기호화된 링크 만들기(일반(하드) 링크와는 달리 파일이 효과적으로 삭제되는 것을 방지해 주지 않음)
int symlink(const char *path1, const char *path2);
!!중요!!
프로그램이 종료하면 파일을 자동삭제 하기 위해서 임시 파일로 쓰겠다면 open으로 파일을 만들고 바로 unlink를 호출함
mkdir => 디렉토리 생성
#include <sys/stat.h>
int mkdir(const char *path, mode_t mode);
rmdir => 디렉토리 삭제(디렉토리가 비어있을 때만 가능)
#include <unistd.h>
int rmdir(const char *path);
chdir => 디렉토리 변경
#include <unistd.h>
int chdir(const char *path);
getcwd => 현재 작업 디렉토리 변경(반환값: null 에러(size보다 클때, 디렉토리가 삭제되었을때), buf반환 성공)
#include <unistd.h>
char *getcwd(char *buf, size_t size);
opendir => (저수준)디렉토리를 열고 디렉토리 스트림을 생성(저수준임으로 너무 많은 파일을 열면 실패할 수도 있다)(반환값: 널 실패)
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
readdir => 디렉토리 스트림 dirp 내부에 다음 디렉토리 항목에 관한 구조체의 포인터 반환하고 디렉토리 끝에서는 NULL을 반환한다
#include <sys/types.h>
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
dirent 구조체는(더 많은 사항을 결정하려면 stat를 호출한다)
ino_t d_ino: 파일의 inode
char d_name[] : 파일의 이름
telldir => 디렉토리 스트림의 현재 위치를 기록하는 값을 반환
#include <sys/types.h>
#include <dirent.h>
long int telldir(DIR *dirp);
seekdir => telldir 후에 디렉토리 스캔을 현재 위치로 다시 설정
#include <sys/types.h>
#include <dirent.h>
void seekdir(DIR *dirp, long int loc);
closedir => 디렉토리 스트림을 닫음(반환값: 0 성공, 1 에러)
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
간단한 디렉토리 목록을 생성 예: 193페이지 참조
결과는
디렉토리의 각 파일은 한줄에 나열되고 각 하위 디렉토리의 이름에는 마지막에 슬래시(/)가 붙어있고 하위 디렉토리 하의 파일들은 공백 4자로 들여쓴다
lstat(entry ->d_name, &statbuf); // entry에 저장된 디렉토리명을 상태 버퍼에 저장
errno <= 에러처리(errno.h 안에 나열되어 있음)
EPERM : 연산이 허용되지 않음
ENOENT : 그러한 파일이나 디렉토리가 없다
strerror => 에러 번호를 문자열에 대응 시킴
#include <string.h>
char *strerror(int errnum);
perror => errno에 보고된 현재 에러를 문자열에 대응 시키고 표준 에러 스트림에 출력
#include <stdio.h>
void perror(const char *s);
예:
perror("program");
결과
program: Too many open files
/proc => 파일 시스템에 하드웨어 장치에 대한 목록화(리눅스는 대부분의 사항을 파일로 다룸)(리눅스는 특수한 파일 시스템인 procfs를 제공)
/dev => 저수준 시스템 호출을 사용하는 특벽한 방법으로 하드웨어 액세스
cat /proc/net/sockstat => 소켓 사용량 보기
cat /proc/sys/fs/file-max => 한개의 프로세스에서 파일을 최대로 열수 있는 갯수
!!중요!!(튜닝)
echo 60000 > /proc/sys/fs/file-max => 60000으로 변경(DB 용)
부팅 후도 계속 => /etc/sysctl.conf에 fs.file-max = 60000 추가
/etc/security/limits.conf 끝에 * - nofile 60000 추가
ulimit -a 또는 -Sa => soft 한도
ulimit -Ha => Hard 한도
lsof => 프로세스에서 열어놓은 파일 보기
PID는 기본적으로 1~32,000 사이의 값
od -c /proc/"PID"/cmdline => vi에서 어떤 파일을 열었는지 확인
/proc/"PID"/fd/ => 이 프로세스가 사용하고 있는 열린 파일 설명자에 관한 정보가 있음(설명자 0,1,2는 표준 입력,출력,에러 설명자임)
fcntl => 저수준 파일 설명자를 조작(파일 설명자 복제, 파일 설명자 플래그 설정하고 구하기, 파일 상태 플래그 설정하고 구하기, 관고 파일 잠금 관리)
#include <fcntl.h>
int fcntl(int fildes, int cmd);
int fcntl(int fildes, int cmd, long arg);
mmap => 메모리 맵을 이용해서 두개 이상의 프로그램이 함께 쓰고 읽을 수 있는 메모리 세그먼트를 설정(공유메모리)(off 매개변수를 전달하여 공유 세그먼트에 의해 액세스되는 파일 데이터의 시작 위치를 변경할 수 있고 열린 파일 설명자는 filedes로 전달되고 액세스 할 수 잇는 데이터의 양은 len 매개변수로 설정된다)(addr 틀정 메모리 주소를 요청(보통 0을 넣어서 자동 할당으로 설정))
#include <sys/mman.h>
void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);
msync => 메모리 세그먼트 부분 혹은 전부에 가해진 변경 사항을 매핑된 파일로 쓰거나 매핑된 파일로 부터 읽는다
#include <sys/mman.h>
int msync(void *addr, size_t len, int flags);
mnumap => 메모리 세그먼트를 해지함
#include <sys/mman.h>
int munmap(void *addr, size_t len);
mmap 예: 205페이지 참조
================================================================================================================================================================
5Day Study
[[[[[리눅스(Linux) 환경(environment)]]]]]
프로그램 인자
main은 암시적으로 반환값은 int임
main() = int main(int arc, char *argv[])
프로그램 인자값 표시 예제:
#include <stdio.h>
int main(int argc, char *argv[])
{
int arg;
for(arg = 0; arg < argc; arg++)
{
if(argv[arg][0] == '-')
printf("option: %s\n", argv[arg]+1);
else
printf("argument %d: %s\n", arg, argv[arg]);
}
exit(0);
}
결과는
$ ./args -i -lr 'hi there' -f fred.c
argment 0: args
option: i
option: lr
argument 3: ya there
option: f
argument 5: fred.c
getopt => 리눅스 arg값의 가이드라인을 지킬 수 있도록 도와주는 함수(반환값: 더 이상 처리할 옵션이 없을 때 -1, 인식할 수 없는 옵션의 경우 ?)
#include <unistd.h>
int getopt(int argc, char *const argv[], const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
POSIX 명세에는 opterr 변수가 0이 아니면 getopt는 에러 메시지를 stderr에 출력한다고 나와있다
getopt 예: 214페이지 참조
getopt_long => 이중 대시로 시작하는 소위 긴 인자를 받아들임(GNU C)
$ ./longopt --initialize
putenv => 환경변수 넣기(반환값: -1 실패)(환경변수는 지역적인 변수임으로 다른 쉘에는 적용이 안됨)
#include <stdlib.h>
char *getenv(const char *name);
getenv => 환경변수 반환(반환값: Null 존재안함)
int putenv(const char *string);
getenv와 putenv 예: 218페이지 참조
environ => 환경값을 문자배열로 사용
#include <stdlib.h>
extern char **environ;
environ 변수를 사용하여 환경 변수를 출력하는 프로그램 예:
#include <stdlib.h>
#include <stdio.h>
extern char **environ;
int main()
{
char **env = environ;
while(*env)
{
printf("%s\n", *env);
env++;
}
exit(0);
}
time_t => 시간과 날짜 함수(long)
#include <time.h>
time_t time(time_t *tloc);
time_t 예: 223페이지 참조
difftime => 두개의 시간 값 사이의 차를 게산하고 부동 소수점 숫자로 반환
#include <time.h>
double difftime(time_t time1, time_t time2);
gmtime => 저수준 시간 값을 좀더 평범한 필드를 포함하는 구조체로 분리
#include <time.h>
struct tm *gmtime(const time_t timeval);
tm 구조체와 gmtime를 이용하여 현재 시간과 날짜를 출력 예: 225페이지 참조
localtime => 지역 시간 보기
#include <time.h>
struct tm *localtime(const time_t *timeval);
mktime => tm 구조체를 원시 time_t 값으로 변환(반환값: -1 실패)
#include <time.h>
time_t mktime(struct tm *timeptr);
asctime => 사람에게 친숙한 시간과 날짜 구하기
#include <time.h>
char *asctime(const struct tm *timeptr);
ctime => 원시 시간 값을 받아들여 좀더 읽기 쉬운 지역 시간으로 반환
char *ctime(const time_t *timevarl);
ctime 예:
#inlcude <time.h>
#include <stdio.h>
int main()
{
time_t timeval;
(void)time(&timeval);
printf("The date is:%s", ctime(%timeval));
exit(0);
}
결과는
The date is: Sat Feb 8 09:21:17 2003
strftime => 시간과 날짜 문자열의 형식으로 더욱 정확하게 제어할 때(반환값 포인터)
#include <time.h>
#define _XOPEN_SOURCE
char *strptime(const char *buf , const char *format, struct tm *timeptr);
strftime을 이용한 예(시간값 구하는 함수 중에는 가장 좋다): 230페이지 참조
tmpnam => 임시 파일 만들기(문자열 *s가 널이아니면 파일 이름을 저장)
#include <stdio.h>
char *tmpnam(char *s);
tmpfile => 임시 파일의 이름을 만듦과 동시에 열기(반환값: Null 에러)
#include <stdio.h>
FILE *tmpfile(void);
tmpnam과 tmpfile의 예: 233페이지 참조
mktemp => tmpnam와 유사하고 사용자가 임시 파일의 위치와 이름을 좀더 제어(유닉스 예전버전에서 지원)
#include <stdlib.h>
char *mktemp(char *template);
mkstemp => tmpfile와 유사하고 사용자가 임시 파일의 위치와 이름을 좀더 제어(유닉스 예전버전에서 지원)
int mkstemp(char *template);
getuid => 프로그램과 연관된 UID를 반환
#include <sys/types.h>
#include <unistd.h>
uid_t getuid(void);
getlogin => 현재 상요자와 연관된 로그인 이름을 반환
char *getlogin(void);
/etc/passwd의 구성은
사용자 이름:암호화된 패스워드:사용자 식별자(UID):그룹 식별자(GID):전체 이름:홈 디레고리:기본 쉘
예: root:x:0:0:root:/root:/bin/bash
/etc/shadow => 암호화된 패스워드 파일
getpwuid => 사용자 정보를 표현하는 passwd 구조체로 UID로 사용자 식별
#include <sys/types.h>
#include <pwd.h>
struct passwd *getpwuid(uid_t uid);
getpwnam => 사용자 정보를 표현하는 passwd 구조체로로그인 이름으로 사용자 식별
struct passwd *getpwnam(const char *name);
사용자 정보 예: 236페이지 참조
getpwent => 전체 각 사용자 정보 항목을 차례대로 반환(반환값: 아무것도 없다 Null)
endpwent => getpwent 처리 종료
setpwent => 패스워드 파일에서 위치를 처음으로 설정
위 3개의 함수들은 디렉토리 스캔 함수인 opendir, readdir, closedir과 유사하게 작동함
#include <sys/types.h>
#include <unistd.h>
uid_t geteuid(void);
gid_t getgid(void);
gid_t getegid)void);
int setuid(uid_t uid);
int setgid(gid_t gid);
gethostname => 시스템의 네트워크 이름(호스트 정보)을 갖어 옴(반환값: 성공 0, 실패 -1)
#include <unistd.h>
int gethostname(char *name, size_t namelen);
uname => 시스템 호출을 통해 호스트 컴퓨터의 좀더 세부적인 정보를 구함(운영체제, 호스트 이름, 시스템의 출시 수준, 시스템의 버전 번호, 하드웨어 형식)(반환값: 실패 -1)
#include <sys/utsname.h>
int uname(struct utsname *name);
호스트 정보 예: 239페이지 참조
기본 로그 디렉토리 => /usr/adm 또는 /var/log
/var/log/messages => 모든 시스템 메시지 포함
/var/log/mail => 메일 시스템 로그
/var/log/debug => 디버그 메시지
/etc/syslog.conf => 시스템 구성을 확인
syslog => 로그 저장
#include <syslog.h>
void syslog(int priority, const char *message, arguments...);
priority 멤버들
LOG_EMERG : 긴급상황
LOG_ALERT : 데이터베이스 손상과 같은 높은 순위
LOG_CRIT : 하드웨어 고장과 같은 치명적인 에러
LOG_ERR : 에러
LOG_WARNING : 경고
LOG_NOTICE : 주의가 필요한 특별한 조건
LOG_INFO : 정보 메시지
LOG_DEBUG : 디버그 메시지
syslog 예:
#include <syslog.h>
#include <stdio.h>
int main()
{
FILE *f;
f=fopen("not_here","r");
if(!f)
syslog(LOG_ERR|LOG_USER,"opps - %m\n");
exit(0);
}
결과
/var/log/messages 마지막 줄에
Feb 8 09:59:14 beast syslog: opps - No such file or directory
openlog => 로그 메시지가 나타나는 방식을 변경
#include <syslog.h>
void openlog(const char *ident, int logopt, int facility);
closelog => openlog를 닫아줌
void closelog(void);
setlogmask => 로그 마스크ㅡ를 설정하여 우선순위 수준을 제어
int setlogmask(int maskpri);
logmask 예:
#include <syslog.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
int logmask;
openlog("logmask", LOG_PID|LOG_CONS, LOG_USER);
syslog(LOG_INFO, "infomative message, pid=%d", getpid());
syslog(LOG_DEBUG, "debug message, should appear");
logmask = setlogmask(LOG_NOTICE)); <= NOTICE 이하 우선순위는 무시
syslog(LOG_DEBUG, "debug message, should not appear"); <= 위 마스크 기능 때문에 표시가 안됨
exit(0);
}
결과는
/var/log/messages 끝에
Feb 8 10:00:50 beast logmask[1833]: informative message, pid = 1833
/var/log/debug 끝에
Feb 8 10:00:50 beast logmask[1833]: debug message, should appear
!!중요!!
혹시 /var/log/debug에 로그가 출력되지 않는다면 /etc/syslog.conf 밑에
*.debug /ar/log/debug
를 추가하자
getpid => PID 반환
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
gettpid => 부모 PID 반환
pid_t getppid(void);
getpriority => 자신 또는 다른 응용프로그램 우선순위를 받아오기
#include <sys/resource.h>
int getpriority(int which, id_t who);
setpriority => 자신 또는 다른 응용프로그램 우선순위를 설정하기
int setpriority(int which, id_t who, int priority);
getrlimit => 시스템 리소스의 제한을 받아오기
int getrlimit(int resource, struct rlimit *r_limit);
setrlimit => 시스템 리소스의 제한을 설정하기
int setrlimt(int resource, const struct rlimit *r_limit);
int getrusage => CPU 정보를 받아옴
int getrusage(int who, struct rusage *r_usage);
리소스 제한 예: 251페이지 참조
================================================================================================================================================================
6Day Study
[[[[[터미널(terminal)]]]]]
getchar => 터미널의 데이터 받기
printf => 터미널에 데이터 출력
터미널에서 읽고 쓰기 예: 257페이지 참조
!!중요!!
리눅스와 유닉스는 항상 라인 피드를 텍스트의 줄 끝으로 사용함(텍스트와 바이너리 동일처리)(리눅스는 캐리지 리턴은 프린터나 플로터 출력할 때 처리함)
윈도우는 캐리지 리턴(CR 십진수 13, 16진수 0D)과 라인 피드(LF 십진수 10, 16진수 0A)를 쌍으로 사용함
isatty => 저수준 파일 설명자가 터미널과 연결되어 있는지 조사하며 표준 출력이 리디렉트되어있는지 확인(반환값: fd가 터미널에 연결되어 있으면 1, 이외는 0)
#include <unistd.h>
int isatty(int fd);
출력 리디렉션(터미널 연결확인) 예: 260페이지 참조
/dev/tty => 터미널과 대화하기
getchoice => 출력을 좀더 제어하기 위한 매개변수 제어 예: 262페이지 참조
일반 터미널 인터페이스(termios.h)가 제어 할 수 있는 일(입력/출력/제어/로컬/특수제어문자) => 266페이지 참조
줄 편집: 편집을 위해 백스페이스를 허용할지 여부
버퍼링: 문자를 바로 읽을 것인지 혹은 설정 가능한 지연 후 읽을 것인지 선택
에코: 패스워드를 읽을 때와 같이 에코를 제어할 수 있다
CR/LF: 입력과 출력에 대한 매핑(\n을 출력할 때 어떤 일이 일어나는가)을 결정
회선 속도: PC 콘솔에서는 거의 쓰이지 않으나 모뎀과 직력 회선의 터미널에서는 매우 중요
stty => 쉘에서 터미널 모드 액세스 하기(273페이지 참조)
stty -a => termios 전체 설정 보기
stty sane => 줄바꿈 문자에 대한 캐리지 리턴 키의 매핑을 잃어버렸다면, stty sane을 입력하고 엔터키보다 Ctrl+J(줄 바꿈 문자)를 누를 필요가 있다
stty -icanon min 1 time 0 => 쉘 스크립트가 문자 하나를 읽을 수 있도록 모드를 설정
stty -echo => 패스워드를 입력받기 전에 에코를 꺼서 패스워드 검사 과정을 개선
stty echo => 에코 켜기
tcdrain => 모든 대기딘 출력이 전송될 때까지 호출 프로그램을 기다림
tcflow => 출력을 일시 중단하거나 다시 시작함
tcflush => 입력 및 출력 혹은 둘다 플러시하기 위해서 사용
newrsettings => 터미널 특성 설정
termios.h를 통해서 Enter password: 프롬프트에서 에코되지 않고 사용자가 엔터를 누를 때까지 어떠한 출력도 발생하지 않는 예: 277페이지 참조
echo $TERM => 현자 사용중인 터미널 시스템 보기
/usr/lib/terminofo 또는 /usr/share/terminofo => 터미널의 특성들이 저장되는 곳
infocmp vt100 => vt100 터미널의 형식의 항목을 읽기(VT100의 F1 기능키는 Esc+O+P를 전송한다는 표현은 kf1=\EOP, 좀 더 상세한것은 284페이지 참조)
setupterm => 터미널 형식 설정하기
#include <term.h>
int setupterm(char *term, int fd, int *errret);
현재 터미널 사이즈 받아오는 예: 286페이지 참조
종합 터미널 제어 예: 289페이지 참조
kbhit => 키 입력 검출 함수(윈도우로 부터 프로그램을 이식할 때, kbhit를 에뮬레이트하면 편리한 경우가 있음, 비정식 입력 모드 사용하면 된다) 예: 291페이지
who => 로그인한 사용자 보기
ps => 현재 가상 콘솔에서 실행중인 쉘과 프로그램 보기(mingetty는 가상 콘솔에서 사용자의 로그인을 기다리는 데몬)
Ctrl+Alt+F<N> => 가상 콘솔 사이 전환하기(예: Ctrl+Alt+F1), X윈도우 그래픽 tty는 7번
sstartx -- :1 => X윈도우 그래픽 세션 추가(가장 마지막 tty 세션 +1에 생김)
================================================================================================================================================================
7Day Study
[[[[[텍스트 기반 화면 관리(curses 사용)]]]]]
297~384페이지 참조
P.S 내용이 서버 프로그램 개발시 별로 필요가 없을 것 같아서 생략함
================================================================================================================================================================
8Day Study
[[[[[데이터 관리]]]]]
malloc => 메모리 할당하기
#include <stdlib.h>
void *malloc(size_t size);
!!중요!!
유닉스에서는 malloc.h 헤더파일 필요
사용가능한 메모리 예:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#define ONE_K (1024 * 1024000)
int main()
{
char *some_memory;
int size_to_allocate = ONE_K;
int megs_ob = 0;
int ks_ob = 0;
while (1)
{
for(ks_ob=0;ks_ob>1024;ks_ob++)
{
some_memory=(char *)malloc(size_to_allocate);
if(some_memory == NULL) exit(EXIT_FAILURE);
sprintf(some_memory, "Hello world");
}
megs_ob++;
printf("Now allocated %d Megabytes\n", megs_ob);
}
exit(EXIT_SUCCESS);
}
리눅스는 모든 메모리를 페이지로 나누는데, 보통 한 페이지는 4096바이트 이다
free => 메모리 해지하기
#include <stdlib.h>
void free(void *ptr_to memory);
calloc => 구조체의 배열에 해당하는 메모리를 할당하며 요소의 개수와 각 요소의 크기를 매개변수로 가짐
#include <stdlib.h>
void *calloc(size_t number_of_elements, size_t element_size);
realloc => 할당된 메모리 블록의 크기 변경(반환값: Null 실패, 포인터 성공)
void *realloc(void *existing_memory, size_t new_size);
Lock 파일 만들기 예: 362페이지 참조
int file_desc;
file_desc=open("/tmp/lock.test", O_RDWR | O_CREAT | O_EXCL, 0444);
프로그램이 단순히 실행하는 짧은 기간동안 리소스를 독점해야한다면, 즉 임계 영역(critical secction)이 필요하다면, 임계 영역에 진입하기 전에 잠금 파일을 만들고 임계 영역을 빠져나와서 unlink로 지워주어야 한다
10번 반복해라 예:
int tries = 10;
while(tries--) {
...
}
fcntl => 파일의 특정 부분만 잠그고 다른 프로그램이 파일의 다른 부분에는 액세스할 수 있도록 하기(lockf도 같은 기능을 함) 366페이지 참조
#include <fcntl.h>
int fcntl(int fildes, int command, struct flock *flock_structure);
!!파일 영역에 대한 잠금기능 사용시는 고수준 fread보다는 저수준 read를 사용하는 것이 좋다!!
실습 예: 370페이지 참조
#include <unistd.h>
int lockf(int fildes, int function, off_t size_to_lock);
dbm => 리눅스용 데이터베이스(단순 색인 파일 저장소) ndbm과 gdbm 중에 호환성은 ndbm이 좋음
#include <ndbm.h>
DBM *dbm_open(...); => 데이터 베이스 열기
int dbm_store(...); => 데이터 베이스 저장
datum dbm_fetch(...); => 데이터 베이스 갖어오기
void dbm_close(...); => 데이터 베이스 닫기
dbm 데이터베이스 예: 387~417페이지 참조
================================================================================================================================================================
9Day Study
[[[[[Mysql 관련]]]]]
Mysql: Mysql의 장점은 무료고 속도가 빠르다
PostgreSQL: PostgreSQL의 장점은 완전 무료고 일반 기본 쿼리 속도는 mysql에 뒤처지지만 복잡한 쿼리 속도는 Mysql보다 빠름
주요서버 패키지: MySQL-server-<버전>.<아키텍처>.rpm
클라이언트 패키지: MySQL-client-<버전>.<아키텍처>.rpm
공유 구성요소 패키지: MySQL-share-<버전>.<아키텍처>.rpm
개발 패키지: MySQL-devel-<버전>.<아키텍처>.rpm
실행수준 1,3에 msyql을 시작를 추가
ln -s /etc/rc.d/init.d/mysql /etc/rc.d/rc1.d/S97mysql
ln -s /etc/rc.d/init.d/mysql /etc/rc.d/rc3.d/S97mysql
chkconfig --add mysql
chkconfig --level 13 mysql on
실행수준 2에 mysql을 정지를 추가
ln -s /etc/rc.d/init.d/mysql /etc/rc.d/rc2.d/K97mysql
chkconfig --add mysql
chkconfig --level 2 mysql off
mysql 실행 수준 보기
chkconfig --list 또는 chkconfig --list 서비스명
$mysqladmin -u root password 설정패스워드 <= 초기 패스워드 설정을 함
$mysql -u root -p <= mysql root로 접속
rick 사용자 만들기
mysql> GRANT ALL ON *.* TO rick@localhost IDENTIFIED BY '패스워드';
192.168.0 클래스 C 서브넷에서 연결만
mysql> GRANT ALL ON *.* TO rick@'192.168.0.0/255.255.255.0' IDENTIFIED BY '패스워드';
도메인 wiley.com 속한 컴퓨터는 모두 통과
mysql> GRANT ALL ON *.* TO rick@'%.wiley.com' IDENTIFIED BY '패스워드';
특정 DB만 권한 주기
mysql> GRANT ALL ON database_name.* TO rick@'%.wiley.com' IDENTIFIED BY '패스워드';
Mysql 로그보기
$mysql_safed -log
myisamchk => mysql db 점검(테이블이 저장되어 있는 디렉토리에서 실행)
$myisamchk -e -r *.MYI
-c: 테이블의 에러를 점검
-e: 확장된 점검을 수행한다
-r: 발견한 에러를 복구(수정) 함
mysqldump => mysql 백업 프로그램
mysql 데이터 형식 => 438페이지 참조
MySQLCC => mysql GUI 관리툴
mysql 프로그램 예: 469, 480페이지 참조
컴파일 명령어:
$gcc -I/usr/include/mysql connect.c -L/usr/lib/mysql -lmysqlclient -lz -o connect
mysql> SELECT LAST_INSERT_ID(); <= 마지막 AUTO_INCREMENT 값 갖고 오기
mysql_store_result => SELECT 결과값 뭉탱이로 갖고 오기
mysql_use_result => SELECT 결과값 한 행씩 가져오기
================================================================================================================================================================
10Day Study
[[[[[개발 도구]]]]]
메이크파일 문법
-k : 에러를 발견 했더라도 멈추지 않고 계속 진행
-n : 실제로 작업을 수행하지 않고 어떤 작업을 수행할 것인지 출력한다
-f <파일 이름> : 메이크파일로 이 파일을 사용함
make 실행시 첫번째 대상이 make 됨(예: all이 맨 첨이면 all)
make 파일안에 종속표현(:)
myapp: main.o 2.o 3.o => myapp는 main.o와 2.o와 3.o에 종속
all: myapp myapp.1 => 응용프로그램이 바이너리 파일 myapp와 메뉴얼 페이지 myapp.1로 이루어 질때
!!중요!!
메이크 파일은 매우 이상한 문법이다.
모든 법칙은 탭으로 시작하는 줄로 작성된다. 공백은 안 된다. 여러 개의 공백과 탭은 매우 유사해 보이고, 메이크파일 이외 거의 모든 분야의 리눅스 프로그래밍에서 공백과 탭은 구분하지 않기 때문에, 이러한 문법은 문제를 일으킬 수 있다. 또한 메이크파일의 마지막 줄에 있는 공백 때문에 make 명령이 실패할 수도 있다.
현재 이러한 문법을 고수하며 존재하는 메이크파일이 수도 없이 많다. 그러므로 조심해야 한다. 다행스럽게도 탭이 빠져서 make 명령이 작동하지 않는 경우가 상당히 자주 발생함으로 안될때는 탭 검사를 해보자
메이크 파일의 주석은? #
make 특별 내부 메크로
$? : 현재 대상보다 더 최근에 변경된 파일 이름
$@ : 현재 대상의 이름
$< : 현재 파일 이름
$* : 접미사(suffix)를 제거한 현재 파일 이름
앞에 -를 지정하면 make는 에러를 무시
앞에 @를 지정하면 표준 출력으로 표시 안 함
이전 명령이 성공해야 다음 명령을 실행 조건은 &&로 표시(and 기능)
make -p => make의 내장 법칙 보기
cpp 확장자(suffix)를 컴파일 하기
.SUFFIXES: .cpp
.cpp.o:
$(CC) -xc++ $(CFLAGS) -I$(INCLUDE) -c $<
%.cpp: %o
$(CC) -xc++ $(CFLAGS) -I$(INCLUDE) -c $<
위 2개는 같은것임
라이브러리 관리하기 예: 510페이지 참조
RCS => 소스 코드 관리(형상관리) 1인용
rcs 제어 초기화
$ rcs -i important.c => 나갈때는 Ctrl+D 또는 .
결과는 rcs는 ,v 확장자를 가진 새로운 읽기 전용 파일을 만듬
!!중요!!
RCS 파일을 별도 디렉토리에 저장하고 싶다면, 단순히 rcs를 처음 사용하기 전에 RCS라는 하위디렉토리를 만들면 된다. 모든 rcs 명령은 자동으로 rcs 파일을 위해 RCS 하위 디렉토리를 사용함
co => 파일 변경 하기전 체크 아웃
co important.c => 최신 버전으로 복구
co -l important.c => 소스 수정을 위한 읽기 전용 해제
ci => 소스 변경 저장(기존 소스 파일이 지워짐)
ci important.c
복구(버전 1.1로 복구)
co -r1.1 important.c
rlog important.c => 파일의 변경 사항 요약 보기
rcsdiff -r1.1 -r1.2 important.c => 버전 1.1과 1.2를 비교해 보기
개정 자동 식별 추가
static char *RCSinfo = "$Id$"; => 소스안에 추가
실행파일의 개정 자동 식별 하기
$ ident ./important
CVS => 인터넷을 통한 소스 코드 관리(형상관리) 다인용
cvs 초기 디렉토리 만들기
mkdir /usr/local/repository
cvs 초기화
cvs -d /usr/local/repository init
현재 디렉토리에 있는 소스를 /usr/local/repository/wrox/chap9-cvs에 저장
cvs import -d /usr/local/repository/ -m"Initial versoin of Simple Project" wrox/chap9-cvs wrox start
밑에 cvs의 -d 옵션을 제거하기 위해서 해야할 일
export CVSROOT=/usr/local/repository
cvs로 체크 후 갖고오기
cvs checkout wrox/chap9-cvs
cvs로 비교
cvs diff
cvs로 뭘 체크하는지 보기
cvs commit
세부사항 보기
cvs rdiff -r1.1 wrox/chap9-cvs
cvs 업데이트
cvs update -Pd wrox/chap9-cvs
cvs 네트워크로 액세스 => 527페이지 참조
diff로 차이점 목록 만들기
diff file1.c file2.c > diffs
file1.c와 diffs를 이용해서 패치
patch file1.c diffs
패치 원복하기
patch -R file1.c diffs
spec 파일 빌드하기
rpmbuild -ba myapp.spec
================================================================================================================================================================
11Day Study
[[[[[디버깅(Debuging)]]]]]
gcc 오류를 추적하면서 컴파일 하기
gcc -Wall -pedantic -ansi
인스트루먼트 예:
#ifdef BEBUG
printf("variable x has value = %d\n", x);
#endif
인스트루먼트 복합 적용 예:
#ifndef DEBUG
#define DEBUG 0
#endif
#define BASIC_DEBUG 1
#define EXTRA_DEBUG 2
#define SUPER_DEBUG 4
#if (DEBUG & EXTRA_DEBUG)
printf...
#endif
컴파일 방법
gcc -o cinfo --DEBUG cinfo.c
그냥 print를 활용하기
if(debug) {
sprintf(msg,...);
write_debug(msg)
}
gdb를 이용한 디버깅
gcc -g -o debugex debugex.c <= 꼭 -g 옵션이 필요함
gdb debugex
GNU gdb Red Hat Linux (6.5-37.el5_2.2rh)
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) run => debugex를 실행
Starting program: /root/cstudy/maxusermem
Program received signal SIGSEGV, Segmentation fault.
0x080483ef in main () at ./maxusermem.c:14
14 *scan_ptr='\0'; => 14번째 줄 에러
(gdb) bt <= 스택을 추적하여 코드 에러 부분을 호출한 부분을 찾을 수 있음
#0 0x080483ef in main () at ./maxusermem.c:14
(gdb) backtrace => 스택을 추적하여 코드 에러 부분을 호출한 부분을 찾을 수 있음
#0 0x080483ef in main () at ./maxusermem.c:14
(gdb) print scan_ptr => scan_ptr 변수값 보기
$2 = 0x9a6f000 <Address 0x9a6f000 out of bounds>
(gdb) print ex[$-1] => ex배열의 마지막 결과값 바로 전꺼 보기
(gdb) print ex[3].key => ex배열 3번째의 key 값 보기
(gdb) print ex[0]@ => ex배열 전체 보기
(gdb) list => 소스 보기
9
10 some_memory=(char *)malloc(ONE_K);
11 if(some_memory == NULL) exit(EXIT_FAILURE);
12 scan_ptr=some_memory;
13 while(1) {
14 *scan_ptr='\0';
15 scan_ptr++;
16 }
17 exit(EXIT_SUCCESS);
18 }
(gdb) help breakpoint => 브레이크 포인트 설명 보기
(gdb) break 11 => 11번째 줄에 중단점 만들기
Breakpoint 1 at 0x80483d4: file ./maxusermem.c, line 11.
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/cstudy/maxusermem
Breakpoint 1, main () at ./maxusermem.c:11
11 if(some_memory == NULL) exit(EXIT_FAILURE);
(gdb) print some_memory
$8 = 0x8de0008 ""
(gdb) cont => 중단점을 지나서 계속 진행
Continuing.
(gdb) next => 중단점을 지나서 다음으로 진행
(gdb) display ex[0]@ => 실행될때 마다 보여줌
(gdb) commands => 브레이크 포인트 만날 때를 제어함
Type commands for when breakpoint 1 is hit, one per line.
End with a line saying just "end".
>cont => 중단점 무시하여 진행
>end => commands 나가기
(gdb) info display => 디스플레이 정보 보기
Auto-display expressions now in effect:
Num Enb Expression
1: y some_memory
(gdb) info break => 브레이크 포인트 정보 보기
Num Type Disp Enb Address What
1 breakpoint keep y 0x080483d4 in main at ./maxusermem.c:11
breakpoint already hit 1 time
cont
(gdb) disable break 1 => 브레이크 포인트 1 비활성
(gdb) disable display 1 => 디스플레이 1 비활성
(gdb) commands 1 => 브레이크 포인트 1번을 제어
Type commands for when breakpoint 1 is hit, one per line.
End with a line saying just "end".
>set variable ex = 2; => ex 변수를 2로 변경하여 처리함
>cont
>end
(gdb) run
(gdb) quit
The program is running. Exit anyway? (y or n) y
[root@waf cstudy]#
최적화 컴파일
gcc -O -g -o test ./test.c
$ splint -strict maxusermem.c => 컴파일 전에 프로그램 에러 잡기
코어 덤프 파일 만들기
gcc -g -o test ./test.c
옵션 후
#include <sys/resource.h>
static void
set_limit(void)
{
struct rlimit rlp;
rlp.rlim_cur = RLIM_INFINITY;
rlp.rlim_max = RLIM_INFINITY;
/* Core file size를 시스템 최대치로 설정 */
if (setrlimit(RLIMIT_CORE, &rlp))
Log(ERROR, "Failed to set rlimit core file size: %s",
strerror(errno));
}
위가 안 되면
ulimit -c unlimited >/dev/null 2>&1
http://my.oops.org/77 참조
[root@waf cstudy]# gdb debugex --core=./core.9794 ==> 코어 파일을 이용하여 디버그
GNU gdb Red Hat Linux (6.5-37.el5_2.2rh)
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".
warning: Can't read pathname for load map: Input/output error.
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
Core was generated by `./max'.
Program terminated with signal 11, Segmentation fault.
#0 0x080483ef in main () at maxusermem.c:15
15 *scan_ptr='\0';
(gdb) bt
#0 0x080483ef in main () at maxusermem.c:15
(gdb)
prof/gprof를 이용하여 서브함수별 속도를 나타냄
gcc -pg -o program program.c
./program
ls -la하면 gmon.out이 생김
메모리 디버깅(malloc와 free 이용할 때 사용)
gcc -o test test.c -lefence
./test
gdb test
(gdb) run
valgrind => 가장 좋은 디버거
$ valgrind --leak-check=yes -v ./test
================================================================================================================================================================
12Day Study
[[[[[프로세스와 신호(Process and Signal)]]]]]
[root@waf ~]# ps -lf
F S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME CMD
4 S root 13443 13441 0 75 0 - 1466 wait 08:21 pts/1 00:00:00 -bash
4 R root 13666 13443 0 76 0 - 543 - 09:31 pts/1 00:00:00 ps -l
위에서 NI는 nice값이다 프로세서의 우선순위를 말함(높을 수록 높음 기본은 0)
nice 값 변경:
$nice <프로세스명> &
nice 값 10으로 재설정:
$renice 10 <PID>
system을 이용한 새 프로세스 시작 예:
#include <stdlib.h>
#include <stdio.h>
int main()
{
system("ps -ax");
exit(0);
}
프로세스 이미지 교체하기(따른 PID가 안 생기고 실행됨):
#include <unistd.h>
int execl("bin/ps", "ps", "-ax", 0); => 반환값(에러 -1), errno 에러변수
프로세스 이미지 복제하기(fork) => 반환값(실패 -1), errno 에러변수
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
!!중요!!
부모 프로세스에서 fork를 호출하면 새로운 자식 프로세서 PID를 반환하고 자식 프로세스에서 다시 fork를 하면 0을 반환한다
fork 예제: 608페이지 참조
또 다른 fork 예:
#include <stdio.h>
#include <iostream.h>
#include <unistd.h>
#include <sys/wait.h>
void pfork(int a);
int main(){
int index=0;
pfork(index);
return 0;
}
void pfork(int a){
if(a==10) return;
else if(fork()==0) {
printf("Child %d\n",a);
pfork(a+1);
}
else {
wait(0);
printf("Parent %d \n", a);
}
}
결과값
Child 0
Child 1
Child 2
Child 3
Child 4
Child 5
Child 6
Child 7
Child 8
Child 9
Parent 9
Parent 8
Parent 7
Parent 6
Parent 5
Parent 4
Parent 3
Parent 2
Parent 1
Parent 0
프로세스 종료 기달리기(wait 시스템 호출은 부모 프로세스의 자식 프로세스 중 하나가 정지할 때까지 부모 프로세스를 일시 중지시킨다) => 반환값(정상 0)
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *stat_log);
wait 예: 611페이지 참조
좀비 프로세스(<defunct> 또는 <zombie>)
특정 프로세스 종료 기다리기
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *stat_log, int options); => 종료하였거나 정지했으면 PID, 에러 -1, 종료안하거나 정지안했으면 0
입출력 리디렉션 예:
[root@waf cstudy]# cat upper.c
#include <stdio.h>
#include <ctype.h>
int main()
{
int ch;
while((ch=getchar()) != EOF) {
putchar(toupper(ch));
}
exit(0);
}
[root@waf cstudy]# ./upper
hahaha hohoho
HAHAHA HOHOHO
!!중요!!
리눅스에서 쓰레드를 프로그래밍하는 것은 여러 프로세스를 사용하는 것 만큼 흔하지 않다. 그 이유는 리눅스 프로세스는 경량이며, 협력하는 여러 프로세스를 프로그래밍하는 것이 쓰레드 프로그래밍보다 쉽기 때문이다
신호처리 하기 예:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void ouch(int sig)
{
printf("OUCH! = I got signal %d\n", sig);
(void) signal(SIGINT, SIG_DEF); => SIG_DEF 기본 동작으로 복구, SIG_IGN 무시하기
}
int main()
{
(void) signal(SIGINT, ouch);
while(1) {
printf("Hello World!\n");
sleep(1);
}
}
$ ./ctrlc
Hello World!
Hello World!
Hello World!
Hello World!
^C => CTRL+C를 누른 시점
OUCH! - I got signal 2
Hello World!
Hello World!
Hello World!
Hello World!
^C => CTRL+C를 누른 시점
$
!!중요!!
signal보단 sigaction을 사용을 권한다
신호 보내기 => 우리가 아는 kill이긴 하지만 신호를 보낼 때도 이용됨
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig); => 반환값(실패 1)
알람
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
!!중요!!
신호를 조심스럽게 프로그램밍해야 한다. 왜냐하면 신호를 사용하는 프로그램에서 발생할 수 있는 "경쟁 조건(race condition)"이 많기 떄문이다. 예를 들어 pause를 호출하여 신호를 기다리고자 할때 pause를 호출하기 전에 신호가 발생하면 프로그램은 일어나지도 않을 이벤트를 무한히 기다리는 수가 생긴다.
알람 예:
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
static int alarm_fired = 0;
void ding(int sig)
{
alarm_fired = 1;
}
int main()
{
pid_t pid;
printf("alarm app starting\n");
pid = fork();
switch(pid) {
case -1:
perror("fork failed");
exit(1);
case 0:
sleep(5); => 포크한 후에 자식 프로세서 일시정지 5초
kill(getppid(), SIGALRM); => 부모 프로세스에 SIGALRM 보내기
exit(0);
}
printf("waiting for alarm to go off\n");
(void) signal(SIGALRM, ding);
pause(); => SIGALRM이 올때까지 기달리다가 오면 ding함수 호출
if(alarm_fired) printf("Ding!\n"); => alarm_fired==1 이면 Ding! 출력
printf("done\n");
exit(0);
}
견고한 신호 프로그래밍
#include <signal.h>
int sigaction(int sig, const struct sigaction *act, struct sigaction *oact);
반환값(성공 0, 실패 -1)
sigaction 예: 627페이지 참조
================================================================================================================================================================
13Day Study
[[[[[POSIX 쓰레드(Thread)]]]]]
Native POSION Thread Library(NPTL)를 사용
기본값
#include <pthread.h>
int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); => 스레드 생성
void pthread_exit(void *retval); => 스레드 종료
int pthread_join(pthread_t th, void **thread_return); => wait 기능
스레드 예:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
void *thread_function(void *arg);
char message[] = "Hello World";
int main() {
int res;
pthread_t a_thread;
void *thread_result;
res=pthread_create(&a_thread, NULL, thread_function, (void *)message);
if(res != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
printf("Waiting for thread to finish...\n");
res=pthread_join(a_thread, &thread_result);
if(res != 0) {
perror("Thread join failed");
exit(EXIT_FAILURE);
}
printf("Thread joined, it returned %s\n", (char *)thread_result);
printf("Message is now %s\n",message);
exit(EXIT_SUCCESS);
}
void *thread_function(void *arg) {
printf("thread_function is running. Argument was %s\n", (char *)arg);
sleep(3);
strcpy(message, "Bye!");
pthread_exit("Thank you for the CPU time");
}
[root@waf cstudy]# ./thread
Waiting for thread to finish...
thread_function is running. Argument was Hello World
Thread joined, it returned Thank you for the CPU time
Message is now Bye!
스레드 최대 갯수 세는 프로그램 예:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
unsigned int total=0;
unsigned int threadcount=0;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
void update_size( unsigned size) {
}
void *threadFunc(void *arg) {
int tnum = (int) arg;
// add our thread number to the total
pthread_mutex_lock(&m);
total += tnum;
threadcount--;
printf("I am thread %d, and I am done!\n",tnum);
pthread_mutex_unlock(&m);
return(NULL);
}
int main(int argc, char **argv) {
int i,n;
pthread_t tid;
if (argc!=2) {
fprintf(stderr,"Error - I need the number of threads!\n");
exit(1);
}
n = atoi(argv[1]);
if (n<=0) {
fprintf(stderr,"Give me a number greater than 0\n");
exit(1);
}
for (i=1;i<=n;i++) {
threadcount++;
if (pthread_create(&tid,NULL,threadFunc,(void *)i)) {
fprintf(stderr,"Error creating thread number %d\n",i);
}
}
while (threadcount);
printf("total is %d\n",total);
return(0);
}
동기화(synchronization)
뮤텍스와 세마포 둘 다 공유자원의 크리티컬 섹션 문제를 해결하는 방법이다.
뮤텍스는 공유자원에 접근할 수 있는 열쇠라고 보면 된다.
열쇠가 있는 녀석만이 공유자원에 접근할 수 있는 것이다.
이렇게 해서 크리티컬 섹션 문제를 해결한다.
그럼 세마포는?
세마포는 뮤텍스보다 더 범용적으로 쓰일 수 있다.
왜? 세마포는 공유자원의 접근에 대한 한계값(n)을 부여하고
n보다 작으면 프로세스가 공유자원에 접근할 수 있다.
그럼 뮤텍스와 세마포의 차이점은???
세마포를 뮤텍스와 똑같은 기능을 하게 할 수 있다.
그것이 바로 바이너리세마포 이다.
바이너리... 말 그대로 0과 1 둘 밖에 없다.
즉 0이면 못하는 거고 1이면 접근 가능하다.
이러면 세마포와 뮤텍스의 기능이 같아진다.
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_wait(sem_t *sem);
int sem_post(sem_t *sem);
int sem_destory(sem_t *sem);
세마포어를 이용하여 쓰레드가 작업을 완료할 때까지 메인 쓰레드가 기다리도록 만들 수 있음
뮤텍스
#include <pthread.h>
pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
pthread_mutex_lock(pthread_mutex_t *mutex);
pthread_mutex_unlock(pthread_mutex_t *mutex);
pthread_mutex_destroy(pthread_mutex_t *mutex);
P.S 책이 넘 후졌다... 인터넷으로 따로 공부하자
================================================================================================================================================================
14Day Study
[[[[[프로세스간 통신: 파이프(pipe)]]]]]
<myserver 서버에 id로 로그인 하여 ls명령 실행>
ssh id@myserver ls
<ssh키를 등록해놓았을 때는 id는 생략하고 로그인 절차 없이 바로 실행, ;로 구분하여 여러 명령 실행>
ssh myserver "ls -la;df"
그러면 여러줄의 명령이나 특정 쉘스크립트,Perl스크립트 등등을 원격서버에 실행 시키면 어떻게 해야 할까? 간단한 쉘명령이야 ;로 나눠서 한 줄에 넣어서 실행하면 되지만 작업이 복잡해지면 그런 형태로는 한계가 있다. 그럴때는 다음과 같은 방법을 쓸 수 있다.
<HEREDOC을 사용하는 방법>
ssh myserver <<\EOF
ls -la
df
EOF
<별도의 쉘스크립트를 만들고 원격에 스크립트 해석기를 실행시키고 파이프나 리다이렉션으로 보내는 방법>
#!/bin/sh
ls -la
df
가 test_script.sh 이라고 하면
cat test_script.sh | ssh myserver sh
또는
ssh myserver sh < test_script.sh
<Perl 스크립트를 ssh를 통해 실행>
cat perl_script.pl | ssh myserver perl
또는
ssh myserver perl < perl_script.pl
이것을 기초로 여러 서버에 명령을 내리려면 다음처럼 서버의 리스트를 만들고 리스트에 대해 루프를 돌면서 위의 명령을 서버별로 실행하면 될 것이다.
<여러 서버에 루프를 돌면서 지정한 스크립트를 실행하는 스크립트>
#!/bin/sh
SERVERS="
myserver1
myserver2
"
for m in $SERVERS
do
ssh $m sh < test_script.sh
done
이렇게 하면 문제는 순차적으로 실행을 하기 때문에 한 서버씩 실행이 끝날 때 까지 기다려야 해서 속도가 늦고 나중에 결과를 보기가 힘들다는 것이다.
그러면
ssh $m sh < test_script.sh
줄을 다음과 같이
ssh $m sh < test_script.sh > $m.log &
고치면 각 ssh 명령이 fork되어서 백그라운드로 돌고 각 서버에 대한 결과는 서버이름.log 파일로 남게 된다. ( 작업결과는 *.log 파일들에 대해 grep이나 기타 유틸리티로 일괄적으로 확인 가능할 것이다. )
발췌 URL:
http://209.85.173.132/search?q=cache:yXBNexjGI0QJ:aero.dnip.net/blog/2008/11/ssh.html+ssh+%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8&cd=11&hl=ko&ct=clnk&gl=kr&client=firefox-a
파이프(pipe)란 하나의 프로세스로부터 데이터 흐름을 다른 프로세스로 연결
#include <stdio.h>
FILE *popen(const char *command, const char *open_mode);
open_mode 멤버: r 출력 읽기, w 출력 보내기(반환값 NULL 실패)
int pclose(FILE *stream_to_close); => popen이 종료할 때 까지 기달렸다가 종료시킴
POPEN 예:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
FILE *read_fp;
char buffer[BUFSIZ + 1];
int chars_read;
memset(buffer, '\0', sizeof(buffer));
read_fp = popen("cat ./popen.c | wc -l", "r");
if(read_fp != NULL)
{
chars_read=fread(buffer, sizeof(char), BUFSIZ, read_fp);
while(chars_read > 0)
{
buffer[chars_read - 1] = '\0';
printf("Reading:-\n %s\n", buffer);
chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);
}
pclose(read_fp);
exit(EXIT_SUCCESS);
}
exit(EXIT_FAILURE);
}
결과는
[root@waf cstudy]# ./popen
Reading:-
27
저수준의 파이프(pipe) => 쉘 호출을 사용하지 않음
#include <unistd.h>
int pipe(int file_descriptor[2]);
pipe 실습 예: 681페이지 참조
포크와 exec와 pipe 실습 예: 685페이지 참조
명명된 파이프(named pipe): FIFO 예: 696페이지 참조(CPU 리소스에 가장 효율이 좋다)
고급 주제: FIFO를 사용하는 클라이언트/서버 예: 703페이지 참조
실제 응용프로그램에서는 sleep를 하지 않음
실제 응용프로그램 DB 클라이언트/서버 예: 712페이지 참조
실제 응용프로그램 DB 검색 예: 720페이지 참조
================================================================================================================================================================
15Day Study
[[[[[세마포어, 공유 메모리, 메시지 대기열 IPC(Inter=Process Communication)]]]]]
세마포어의 정의
가장 간단한 세마포어는 오직 0과 1만의 값만 받아들이는 변수, 바이너리 세마포어
다양한 양의 값을 받아들이는 세마포어는 일반 세마포어
P와 V의 정의는 간단하다. 세마포어 변수 sv가 있다고 하자
P(sv) : sv가 0보다 크면 sv를 감소시킨다. sv가 0이라고 하면 이 프로세스의 실행을 일시 중단한다( -1)
V(sv) : 다른 프로세스가 sv를 가르켰을 때 일시 중단되어 있다면, 이 프로세스의 실행을 재개시킨다. sv를 기다리며 일시 중단되어 있는 프로세스가 없다면 sv를 증가시킨다( +1)
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
새로운 세마포러를 만들거나 기존 세마포어의 세마포어 키를 반환
int semget(key_t key, int num_sems, int sem_flags);
세마포어의 값을 변경
int semop(int sem_id, struct sembuf *sem_ops, size-t num_sem_ops);
세마포어 정보를 직접 제어
int semctl(int sem_id, int sem_num, int command, ...);
command 맴버: SETVAL(세마포어 초기화), IPC_RMID(세마포어 식별자 삭제)
공유메모리(shared memory)는 세 가지 IPC 기능 중에서 두번째임
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
공유메모리 할당하기
int shmget(key_t key, size_t size, int shmflg);
shmflg를 통해서 읽고쓰기 가능 및 읽기전용에 대한 권한 설정
반환값: 실패 -1, 성공 0 이상
처음 공유 메모리 세그먼트를 만들고 쓸 수 없기 때문에 프로세스의 주소 공간에 공유메모리 연결
void *shmat(int shm_id, const void *shm_addr, int shmflg);
shmflg 멤버 : SHM_RND 공유 메모리가 연결되는 주소를 제어
SHM_RDONLY 연결된 메모리를 읽기 전용으로 만듬
반환값: 실패 -1, 성공 공유 메모리의 첫번째 바이트에 대한 포인터 반환
공유 메모리를 현재 프로세스로 부터 분리(삭제되지 않고 현 프로세스가 공유 메모리를 사용을 불가능 하게함)
shmdt(int shm_id);
반환값: 실패 -1
공유메모리 제어
int shmctl(int shm_id, int command, struct shmid_ds *buf);
shm_id는 shmget가 반환한 값
command는 취해야 할 동작(IPS_STAT, IPC_SET, IPC_RMID);
*buf는 공유메모리 모드와 권한
반환값: 실패 -1, 성공 0
공유메모리 예: 753페이지 참조
IPC(메시지 대기열)
메시지 대기열은 두개의 연관이 없는 프로세스끼리 쉽고 표율적으로 데이터를 주고받을 수 있다. 메시지 대기열은 송신 프로세스와 수신 프로세스에 대해 독립적으로 존재하기 때문에, 명명된 파이프를 열고 닫을 때 동기화를 수행하면서 따르는 어려움을 다소 없애준다. 이것이 메시지가 명명된 파이프에 비해 가지는 장점이다
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
메시지 대기열 만들기
int msgget(key_t key, int msgflg);
반환값: 실패 -1, 성공 양의 정수인 대기열 식별자
메시지 대기열에 메시지 추가
int msgsnd(int msqid, const void *msg_ptr, size_t msg_sz, int msgflg);
메시지 대기열에서 메시지 갖어오기
int msgrcv(int msqid, void *msg_ptr, size_t msg_sz, long int msgtype, int msgflg);
메시지 대기열에서 메시지 제어
int msgctl(int msqid, int command, struct msqid_ds *buf);
command 맴버: IPC_STAT, IPC_STAT, IPC_RMID
반환값: 실패 -1, 성공 0
프로세스가 msgsnd 함수나 msgrcv 함수에서 기다리고 있는 동안 메시지 대기열을 삭제하면, 송신 함수나 수신 함수는 실패한다.
메시지 대기열 예: 762페이지 참조(사용자 1), 766페이지 참조(사용자 n
IPC 상태 명령
세마포어을 사용하여 개발한 프로그램이 세마포어을 삭제하지 않고 죽었을 경우 메모리에 찌꺼기가 남아서 위험하다. 그것을 확인할 수 있는 명령어는
세마포어 상태 보기 명령
$ ipcs - s
--- Semaphore Arrays ----
semid owner perms nsems status
768 rick 666 1
세마포어 죽이기(최신 리눅스)
$ ipcrm -s 768
세마포어 죽이기(오래된 리눅스)
$ ipcrm sem 768
공유 메모리 상태 보기 명령
$ ipcs -m
공유 메모리 죽이기
$ ipcrm -m <ID>
메시지 대기열 상태 보기 명령
$ ipcs -q
메시지 대기열 죽이기
$ ipcrm -q <ID>
================================================================================================================================================================
16Day Study
[[[[[소켓(Socket)]]]]]
소켓은 소켓 이름으로 /tmp나 /usr/tmp 에 저장이 된다
$ ls -lF
C소스 루트 디렉토리에서 [root@waf a_sc]#ctags -R .
1Day Study
[[[[[리눅스와 C 기본]]]]]
/bin: 바이너리, 시스템을 부팅하는 데 사용되는 프로그램
/usr/bin: 사용자 바이너리, 사용자가 사용할 수 있는 표준 프로그램
/usr/local/bin: 로컬 바이너리, 설치에 사용되는 프로그램
실행파일 만들기
gcc -o hello hello.c
헤더파일 디렉토리 지정
gcc -I/usr/openwin/include fred.c
라이브러리를 지정하여 실행파일 만들기
gcc -o fred fred.c /usr/lib/libm.a
gcc -o fred fred.c -lm
gcc -o fred fred.c -L/usr/lib/ -lm
테스트 오브젝트 파일 만들기
gcc -c bill.c fred.c
lib.h 파일 작성 후 테스트 오브젝트 파일의 펑션들 선언 => 컴파일러가 에러를 찾을 수 있도록 도와줌
void bill(char *);
void fred(int);
오브젝트 파일을 링크해서 실행파일 만들기
gcc -c program.c => #include "lib.h" 선언된 파일
gcc -o program program.o bill.o
오브젝트 파일을 정적 라이브러리로 만들기
ar crv libfoo.a bill.o fred.o
버클릭 유닉스계열을 위해서 목차표로 만들기
ranlib libfoo.a
정적 라이브러리를 이용한 실행파일 만들기
gcc -o program program.o libfoo.a
gcc -o program program.o -L. -lfoo => -lfoo는 libfoo.a 또는 libfoo.so를 참조함
사용한 함수명 파악하기
mn ./libfoo.a
mn ./program
공유 라이브러리는 확자가가 .so 임
사용되는 공유 라이브러리 파악하기
ldd program
도움말보기
man은 간략하게 보기
info는 자세하게 보기(info를 위한 도움말 ctrl+H)
================================================================================================================================================================
2Day Study
[[[[[Shell Script 관련]]]]]
Shell 종류
sh(Bourne) => 유닉스 초기 버전의 원본 쉘
csh, tcsh, zsh => C 쉘 및 파생형 쉘 버클리 유닉스에서 사용됨
ksh, pdksh => 상당수의 상용 유직스의 기본 쉘
bash => GNU 리눅스 기본 쉘 Ksh와 유사함
명령어 결과 파일 출력
ls -l > lsoutput.txt => New
ls -l >> lsoutput.txt => Append
에러 정보가 화면에 나타나지 못하게 방지하며 에러 정보를 버릴때(표준 에러 파일 설명자 2)
ls -l 2> lsoutput.txt
kill 명령 결과를 killout에 저장, 에러는 killerr에 저장
kill -HUP 1234 >killout 2>killerr
양 출력을 하나의 파일로 저장
kill -1 1234 >killouterr 2>&1
표준에러 저장 안 하기
kill -1 1234 >/dev/null 2>&1
입력 리다이렉트
more < longtext
프로세서끼리 연결하기(ps의 출력을 받아서 알파벳순으로 정렬 후 uniq를 이용하여 프로세스만 추출하고 grep -v 를 이용하여 sh를 프로세서를 제거하고 more를 이용해서 페이지 단위로 보게함)
ps -xo comm | sort | uniq | grep -v sh | more
ps의 출력을 정렬 후 pssort에 저장
ps | sort > pssort
문자열에서 POSIX를 포함하고 있는 파일 이름을 출력
more 'grep -l POSIX *'
more $(grep -l POSIX *)
grep -l POSIX * | more
Shell Script FOR문
#!/bin/sh => 시스템에게 이 줄의 인자가 이 파일을 실행시키기 위한 프로그램임을 지정(문자 32개 이하로 지정 구 버전 유닉스들이 지원 못 할 수도 있기 때문)
for file in *
do
if grep -q POSIX $file
then
echo $file
fi
done
exit 0 => 쉘 프로그래밍에서 0은 성공을 의미한다. 스크립트 자체만으로는 어떠한 실패도 지각하지 못함으로 항상 0을 반환한다
쉘 스크립트의 기본 선언 변수는 문자열로 간주됨
쉘에서 $를 변수 이름 앞에 붙여서 변수의 내용을 액세스 할 수 있음
echo를 통해서 변수값을 화면에서 검사 가능(예: echo $data)
= 기호의 양쪽에는 어떠한 공백도 없어야 함
쓰기권한 제거
chown root ./filename
chgrp root ./filename
chmod 755 ./filename
chmod u=rwx,go=rx ./filename
사용자값 입력받기
read inputmsg
read 후 문자열 비교시 "로 꼭 싸주자
if [ $data = "yes" ] => if [ "$data = "yes" ]
쉘에서 ",',\ 차이점
#!/bin/sh
myvar="Hi there"
echo $myvar
echo "$myvar" => 값으로 인식
echo '$myvar" => 문자열로 인식
echo \$myvar < \을 앞에 붙여서 $ 기호의 특수한 의미를 제거
echo Enter some text
read myvar
echo '$myvar' now equals $myvar
exit 0
결과는
Hi there
Hi there
$myvar
$myvar
Enter some text
Hello World => 키보드 입력을 받음
$myvar now equals Hello World
사용자의 환경 보기 명령어
env
환경변수 설정하는 명령어
export
환경변수
$HOME => 현재 사용자 홈 디렉토리
$PATH => PATH 디렉토리
$PS1 => 명령어 프롬프트(예: [\u@\h \W]$는 사용자, 컴퓨터 이름, 현재 디렉토리를 보여줌
$PS2 => 두번째 프롬프트(예: >)
$IFS => 입력 필드 구분자
$0 => 쉘 스크립트의 이름
$# => 전달된 매개변수의 갯수
$$ => 쉘 스크립느의 프로세스 ID
매개변수를 이용하는 방법
$ IFS=' '
$ set foo bar bam
$ echo "$@"
foo bar bam
$ echo "$*"
foobarbam
$ unset IFS
$ echo "$*"
foo bar bam
일반적으로 $@가 많이 쓰임
매개 변수와 환경 변수 실습 (try_var 로 저장)
#!/bin/sh
salutation="Hello"
echo $salutation
echo "$0"
echo "$2"
echo "$1"
echo "$*"
echo "$HOME"
exit 0
결과는
Hello
./try_bar
bar
foo
foo bar baz
/home/rick
쉘의 부울 검사를 할 때 쓰이는 명령어
test 혹은 [ => [는 test이 축약형(도움말 보기는 help test)
ls -l /usr/bin/[
파일 존재 확인 스크립트(IF문 사용하기)
if test -f fred.c
then
...
elif
...
else
...
fi
if [ -f fred .c ]
then
...
elif
...
else
...
fi
if [ -f .tcsshrc ]; then ... ; elif ... ; else ... ; fi
위 3개의 if은 같은 스크립트다([ 괄호와 확인할 조건 사이에 공백을 반드시 넣어야 함)([ 명령을 사용하여 변수 내용을 테스트 한다. if 명령이 결과를 계산하고 다른 줄의 코드를 실행함)
출력값 응용(if와 elif 조건까지도 통과 된다면 else 출력 후 스크립트값을 1로 종료한다. 이 값을 사용하여 스크립트가 성공하였는지 검사를 할 수 있다)
if [ -f fred .c ];
then
...
elif
...
else
...
exit 1
fi
exit 0
문자열 비교
str1 = str2 => 두 문자가 같으면 true
str1 != str2 => 두 문자가 같이 않으면 true
-n str1 => str1이 널(빈 문자열)이 아니면 true
-z str1 => 문자열이 널(빈 문자열)이면 true
산술 비교
exp1 -eq exp2 => 두 표현식이 같으면 true
-ne => 두 표현식이 같지 않으면 true
-gt => 왼쪽이 크면 true
-ge => 왼쪽이 크거나 같으면 true
-lt => 왼쪽이 작으면 true
-le => 왼쪽이 작거나 같으면 true
! exp => exp가 false면 true이고 그 역도 성립
파일 비교
-d file => file이 디렉토리면 true
-e => file이 존재하면 true(-e는 유닉스에서 잘 안 될수도 있기 때문에 -f가 흔히 사용됨)
-f => 보통파일이면 true
-g => set-group-id가 file이 설정되면 true(set-gid는 프로그램에게 자신의 그룹의 권한을 줌)
-r => 파일을 읽을 수 있으면 true
-s => 파일 크기가 0이 아니면 true
-u => set-user-id가 file에 설정되면 true(set-user는 프로그램에게 자신의 사용자가 아닌 소유자의 권한을 줌)
-w => 파일에 쓸 수 있으면 true
-x => 파일이 실행 가능하면 true
echo 호환여부
echo -e는 모든 시스템에서 지원은 안 됨
bash는 echo -n을 지원하여 read시 줄 바꿈을 없애줌
FOR문 => 지저분한다 다른 언어랑 좀 틀리다 ㅡㅡ; 버려!
#!/bin/sh
for foo in bar1 bar2 bar3
do
echo $foo
done
exit 0
결과는
bar1
bar2
bar3
#!/bin/sh
for foo in "bar1 bar2 bar3"
do
echo $foo
done
exit 0
결과는(bar1 bar2 bar3를 한 문자로 인식)
bar1 bar2 bar3
WHILE문
문자비교
#!/bin/sh
while [ "$data" = "true" ]
do
...
done
숫자비교 => 우리가 일반적으로 쓰는 FOR문 대체
#!/bin/sh
data=1
while [ "$data" -le 20 ]
do
...
data=$(($data+1))
done
UNTIL문(명령줄에서 전달한 로그인 이름을 가진 사용자가 로그온 할 때 작동하도록 알람을 설정)
#!/bin/sh
until who | grep "$1" > /dev/null
do
sleep 60
done
echo "**** $1 has just logged in ****"
exit 0
CASE문(다른 언어에서는 switch문 이라고도 함)
case "$data" in
yes | zz ) echo "yes or zz";;
no ) echo "no";;
y ) echo "y";;
n ) echo "n";;
p* ) echo "p char start string";;
* ) echo "etc default";;
esac
AND 리스트
touch file_one
rm -f file_two
if [ -f file_one ] && echo "hello" && [ -f file_two ] && echo " there"
then
echo "in fi"
else
echo "in else"
fi
exit 0
결과는(file_one는 있으므로 hello를 출력하고 file_two는 없으므로 there를 출력하지 않고 else이 in else를 출력함)
hello
in else
OR 리스트
rm -f file_one
if [ -f file_one ] || echo "hello" || echo "there"
then
echo "in if"
else
echo "in else"
fi
exit 0
결과는(file_one가 없지만 OR 조건이므로 hello를 출력하고 in if를 출력함
hello
in if
SUB함수 쓰는 방법
#!/bin/sh
foo() {
echo "Function"
}
echo "script start"
foo
echo "script end"
exit 0
결과값
script start
Function
script end
SUB함수에서 지역변수는 local data="hahaha" 로 선언함
SUB함수 결과값 return 하기
#!/bin/sh
yes_or_no() {
echo "Is your name $* ?"
while true
do
echo -n "Enter yes or no: "
read x
case "$x" in
y | yes ) return 0;;
n | no ) return 1;;
* ) echo "Answer yes or no"
esac
done
}
echo "Rriginal parameters are $*"
if yes_or_no "$1" => Rick Neil에서 첫번째 Rick만 넘김
then
echo "Hi $1, nice name"
else
echo "Naver mind"
fi
exit 0
결과값은
$ ./my_name Rick Neil
Original parameters are Rick Neil
Is your name Rick ?
Enter yes or no: yes
Hi Rick, nice name
================================================================================================================================================================
3Day Study
쉘 스크립트 내장 명령어
break; => 중간에 빠저나올때 사용
: => 널 명령 or true(예: while : 와 while true와 같다)
: ${var:=value} => :이 없으면 쉘은 $var을 명령으로 연산하고자 시도한다
continue => 반복문에서 사용
for x in 1 2 3
do
echo before $x
continue 1
echo after $x
done
결과값
before 1
before 2
before 3
. => 현재 쉘에서 명령 실행(예: . ./shell_script) C에서 #include 지시어와 약간 비슷
파일명 classic_set
#!/bin/sh
version=classic
PATH=/usr/local/old_bin:/usr/bin:/bin:.
PS1="calssic> "
파일명 lastst_set
#!/bin/sh
version=latest
PATH=/usr/local/new_bin:/usr/bin:/bin:.
PS1=" latest version> "
결과는
# . ./calssic_set
calssic> echo $version
classic
classic> . latest_set
latest version> echo $version
latest
latest version>
echo => 문자열과 줄 바꿈 문자를 출력하기 위해서 사용(이식성을 위해서는 tr 명령을 이용
echo -n "string to output"
echo -e "string to output\c" => \t(탭), \n(캐리지 리턴)
eval => 인자를 연산할 때
foo=10
x=foo
y='$' $x
echo $y
결과값
foo
foo=10
x=foo
eval y='$' $x
echo $y
결과값
10
exec => 다른 프로그램을 실행 및 현재 파일 설명자를 수정
exec wall "Thanks for all the fish"
exec 3< afile =>이것은 파일 asfile로 부터 읽기 위해 설명자 3을 사용하여 연다
exit => 스크립트 종료 기능
exit 0 => 성공 종료(에러코드는 1~125 까지 존재함)
125 => 파일이 실행 가능이 아니다
127 => 명령을 찾을 수 없다
128이상 값 => 신호(signal)가 발생하였다
AND OR 응용
#!/bin/sh
if [ -f .file ]; then
exit 0
fi
exit 1
과
[ -f .profile] && exit 0 || exit 1
는 같다
export => 매개변수로 받은 이름의 변수를 하위 쉘에서 사용 가능하도록 만들어줌
파일명 export2
#!/bin/sh
echo "$foo"
echo "$bar"
파일명 export1
foo="foo"
export bar="bar"
export2
결과값은
$ export1
bar
set -a 또는 set -allexport => 모든 변수를 내보낸다
expr => 자신의 인자를 표현식으로 연산
x=`expr $x + 1`
x=$(expr $x + 1)
요즘은 expr 보단 $((수식)) 이 쓰임(expr 보다 빠르다)
x=$((3+1))
printf => 화면출력하기(echo 보다 좋지만 최신의 쉘에서 사용 가능, 소수점은 지원안됨)
\\ => 백슬래시 문자
\a => 벨 울리기
\b => 백스페이스 문자
\f => 폼 피드 문자
\n => 줄 바꿈 문자
\r => 캐리지 리턴
\t => 탭 문자
\v => 수평 탭 문자
\ooo => 8진수 값 ooo을 가진 단일 문자
%d => 십진수를 출력
%c => 문자를 출력
%s => 문자열을 출력
$ printf "%s %d\t%s" "Hi There" 15 people
Hi Theere 15 people
return => 기본적으로 마지막 명령의 종료 코드 반환
set => 매개변수을 설정할 때
#!/bin/sh
echo the date is $(date)
set $(date)
echo The month is $2
exit 0
결과는(set으로 매개변수를 설정 후 $2를 사용해서 달(Month)를 갖고온다)
the date is Mon Mar 2 11:46:12 KST 2009
The month is Mar
set -x => 스크립트가 현재 실행 명령들의 추적을 표시함
shift => 매개변수를 하나씩 아래로 옮긴다($2->$1, $0은 변하지 않음, $* $@ $# 매개변수들이 새로운 정렬에 따라 값이 변하게 됨)
모든 매개변수 검사
#!/bin/sh
while [ "$1" != "" ]; do
echo "$1"
shift
done
exit 0
trap -l => SIG 신호들 보기(신호를 이용해서 작동을 지정)
trap 중요한 신호들
HUP(1) => 행업(대개 터미널을 끊고 사용자가 로그아웃할 때 전송)
INT(2) => 인터럽트(대개 Ctrl+C를 눌러서 전송)
QUIT(3) => 끝내기(대개 Ctrl+\를 눌러서 전송)
ABRT(6) => 중단(대개 어떤 심각한 실행 에러일 때 전송)
ALRM(14) => 알람(대개 시간 제한을 처리할 때 사용)
TERM(15) => 종료(대개 시스템이 종료할 때 전송)
#!/bin/sh
trap 'rm -f /tmp/my_tmp_file_$$' INT
echo creating file /tmp/my_tmp_file_$$
date > /tmp/my_tmp_file_$$
echo "press interrupt (CTRL-C) to interrupt ...."
while [ -f /tmp/my_tmp_file_$$ ]; do
echo File exists
sleep 1
done
echo The file no longer exists
trap INT
echo creating file /tmp/my_tmp_file_$$
date > /tmp/my_tmp_file_$$
echo "press interrupt (control-C) to interrupt ...."
while [ -f /tmp/my_tmp_file_$$ ]; do
echo File exists
sleep 1
done
echo we never get here
exit 0
결과는(처음 while 까지 실행 후 Ctrl+C를 누르면 두번째 while문 진입 후 Ctrl+C를 누르면 바로 종료가 되서 echo we never get here 밑으로는 실행되지 않음) => 잘 안됨
creating file /tmp/my_tmp_file_141
press interrupt (CTRL-C) to interrupt ....
File exists
File exists
The file no longer exists
creating file /tmp/my_tmp_file_141
press interrupt (CTRL-C) to interrupt ....
File exists
File exists
unset => 변수나 함수를 환경에서부터 메모리에서 완전 삭제함(IFS 같은 읽기 전용 변수는 사용이 안됨)
#!/bin/sh
foo="Hello World"
echo $foo
unset foo
echo $foo
결과(foo=과 틀림 foo가 완전히 사라짐)
Hello World
유용한 명령어들
파일 찾기
find [경로] [옵션] [테스트] [작동]
fine / -mount -name wish -print => wish파일을 찾는데 마운트된 시스템은 안 찾음
-depth => 디렉토리의 내용을 먼저 검색
-follow => 기호화된 링크를 따라감
-maxdepths N => 검색할때 최대 N 수준까지의 디렉토리를 검색
-mount => 다른 파일 시스템의 디렉토리는 검색하지 않음
-atime N => 파일이 N일 이전에 마지막으로 액세스 되었다
-mtime N => 파일이 N일 이전에 마지막으로 수정되었다
-name "패턴" => 경로를 제외한 파일의 이름이 주어진 패턴에 일치
-newer otherfile => 파일이 otherfile보다 최신이다
-type C => 파일 형식이 C, d는 디렉토리, f는 보통 파일
-user 사용자이름 => 주어진 이름을 가진 사용자가 파일을 소유하고 있다
! or -not => 테스트를 역으로 수행
-a or -and => 두 테스트가 모두 true
-o or -or => 둘 중 하나의 테스트가 true
파일 X보다 최신이거나 밑줄로 시작하는 이름의 보통파일만 찾아서 출력
find / \( -newer X -or -name "_*"\ ) -type f -print => (는 특별한 의미기 때문에 \ 필요
find 작동후 수행 옵션은
-exec 명령 => 명령을 실행
-ok 명령 => -exec와 같지만 실행하기 전에 사용자에게 여부를 물음
위 두가지는 \;로 끝냄 {}은 현재 파일에 대한 전체 경로로 인식
-print => 파일의 이름을 출력
-ls => 현재 파일에 대해서 ls -dils 명령을 사용
파일 X보다 최신이거나 밑줄로 시작하는 이름의 보통파일만 찾아서 ls -l 하기
find / \( -newer X -or -name "_*"\ ) -type f -exec ls -l {} \;
결과는
-rwxr-xr-x 1 root root 5984 Mar 15 2007 /usr/lib/python2.4/site-packages/rhpl/_diskutil.so
find / \( -newer X -or -name "_*"\ ) -type f -exec ls -l \;
결과는
-rwxr-xr-x 1 root root 75 Mar 2 11:46 setsample.sh
grep => 일반 정규식 파서
grep [옵션] 패턴 [파일]
-c => 일치하는 줄의 갯수 출력
-E => 확장 표현식을 적용
-h => 파일명 붙이는거 제거(일반적으로 grep는 찾은 패턴의 앞에 파일명이 나옴)
-i => 대소문자를 구별 안함
-l => 일치된 줄에 해당하는 파일 이름만 나열
-v => 일치된 패턴 제거
grep -c -v in words.txt => words.txt안에 in 문자가 없는 줄의 갯수 파악
많이 쓰이는 정규표현식(상세한 정규표현식은 info grep에서 Regular Expressions 부분 보기)
^ => 문자의 시작
$ => 문자의 끝
. => 어떤 단일 문자
? => 필수가 아니여도 1번 일치
* => 0번 혹은 더 많이 일치
+ => 1번 혹은 더 많이 일치
{n} => n번 일치
{n,} => n번이상 일치
{n,m} => n번에서 m번 사이에 일치
[ ] => 일치되는 문자의 범위(예: ^[a-e]는 a에서 e까지의 역이다)
grep e$ words.txt => e로 끝나는 문자 찾기
grep a[[:blank:]] words.txt => a로 끝나는 단어 찾기([[:blank:]]는 공백이나 탭)
grep Th. [[:space:]] word.txt => Th로 시작되는 단어 찾기
grep -E [a-z]\{10\} word.txt => 소문자가 10자로 단어 찾기
!!중요 포인트!!
명령 실행의 오래된 형식에서는 작은 따옴표가 아니라 백틱 혹은 백따옴표)`_를 사용하였음을 명심하자
$(명령}은 단순히 명령의 출력임
!!중요 포인트!!
1_tmp와 2_tmp 제어할때
#!/bin/sh
for i in 1 2
do
my_secret_rpocess $i_tmp
done
결과는(에러가 남)
my_secret_process: too few arguments
에러 수정 방법
my_secret_rpocess $i_tmp => my_secret_rpocess ${i}_tmp
매개변수 확장
${param:-default} => param이 널이면 default의 값으로 설정
${param:=default} => param이 널이 아니면 변수의 값을 반환하며, 그렇지 않으면 foo를 bar로 설정하고 이 값을 대신 반환
${param:?default} => param: default를 출력하고, param이 존재하지 않거나 널이면 명령 중지
${param:+default} => param이 존재하고 널이 아니면 default를 반환
${#param} => param의 길이를 준다
${param%word} => 끝에서부터 word에 일치하는 param의 가장 짧은 부분을 제거하고 나머지 반환
${param%%word} => 끝에서부터 workd에 일치하는 param의 가장 긴 부분을 제거하고 나머지를 반환
${param#word} => 처음부터 word에 일치하는 param의 가장 짮은 부분을 제거하고 나머지를 반환
${param##word} => 처음부터 word에 일치하는 가장 긴 부분을 제거하고 나머지를 반환
#!/bin/sh
unset foo => foo 메모리 삭제
echo ${foo:-bar} => 기본으로 foo에 bar 넣고 출력
foo=fud => foo에 fud 넣기
echo ${foo:-bar} => foo에 fud가 있기 때문에 fud 출력
foo=/usr/bin/X11/startx => foo에 /usr/bin/X11/startx 입력
echo ${foo#*/} => foo에서 처음부터 오직 왼쪽 */ 제거하고 출력
echo ${foo##*/} => foo에서 처음부터 */ 찾아서 최대한 많이 제거하고 출력
bar=/usr/local/etc/local/networks
echo ${bar%local*} => bar에서 끝부터 local이 오면 중지
echo ${bar%%local*} => bar에서 끝부터 계속 local까지 비교 후 중지
exit 0
결과는
bar
fud
usr/bin/X11/startx
startx
/usr/local/etc/
/usr/
모든 *.gif파일을 *.jpg로 바꾸기
#!/bin/sh
for image in *.gif
do
cjpeg $image > ${image%%gif}jpg
done
히어 도규먼트(<<) => 실제로는 명령이 스크립트로부터 입력을 받고 있음에도 파일이나 키보드로부터 입력을 받아들이는 것처럼 실행(echo를 사용 안할때 도 사용하거나 ed(Text 편집기)명령을 제어함)
#!/bin/sh
cat <<!FUNKY!
hello
this is a here
document
!FUNKY!
결과는
hello
this is a here
document
히어 도규먼트 두번째 예제
파일명 a_text_file
That is line 1
That is line 2
That is line 3
That is line 4
#!/bin/sh
ed a_text_file <<!FunkyStuff! => 히어 도큐먼트 시작
3 => a_text_file 3번째 줄로 가기
d => a_text_file 해당 위치에서 줄 삭제
.,\$s/is/was/ => 3번째 행이 삭제되었기 때문에 기존 4번째 행에서 is를 was로 변경
w => 저장
q => 나가기
!FunkyStuff! => 히어 도큐먼트 끝
exit 0
결과는
That is line 1
That is line 2
That was line 4
디버그 하기
sh -n <스크립트> => 문법 검사
sh -v <스크립트> => 소스 보기
sh -x <스크립트> => 출력값마다 출력을 위한 소스를 보여줌(가장 좋다)
trap 'echo 변수명 = $변수명' EXIT => 종료될때 변수값 출력
그래픽으로 보여주기 => dialog 유틸을 사용(yum install dialog)
diaglog --msgbox "Hello World" 9 18
결과는 사이즈가 넓이 9 높이 18인 Hello World라고 다이얼로그 박스가 나옴
--더이상의 그래픽 부분은 생략함--
================================================================================================================================================================
4Day Study
[[[[[파일(File) 작업]]]]]
아이노드(inode) => 파일 시스템의 데이터의 특정 블록이며, 파일의 길이와 파일이 디스크의 어디에 저장되어 있는가를 포함(ls -i)
디렉토리 => 아이노드 숫자와 파일의 이름을 저장하고 있는 파일이다. 각 디렉토리 항목은 파일의 아이노드에 대한 연결이다. 파일 이름을 삭제하면 연결이 삭제된다
사용자 디렉토리 => 틸트(tilde) ~를 가지고 있음
/bin => 시스템 바이너리 디렉토리
/etc => 시스템 구성 파일 디렉토리
/lib => 시스템 라이브러기 디렉토리
/dev => 장치 인터페이스 파일 디렉토리
CD-ROM 마운트
# mount -t iso9660 /dev/hdc /mnt/cdrom
# cd /mnt/cdrom
/dev/console => 시스템 콘솔을 표현
/dev/tty => 프로세스의 제어 터미널(키보드와 화면 혹은 윈도우)에 대한 별칭
/dev/zero => 0을 포함하는 파일을 생성하기 위해 null 바이트의 원본처럼 작동
/dev/null => 이 장치로 쓰여진 모든 출력은 버려짐
빈파일 만들기
cp /dev/null empty_file
touch .empty_file => 기존 파일이 있을 경우 파일의 수정시간 만 바뀜
장치 드라이버 액세스를 위한 저수준 함수인 시스템 호출(시스템 호출은 성능부하가 큼으로 한번에 큰 파일을 쓰기 위함)
open => 파일 혹은 장치 열기
read => 열린 파일 혹은 장치로 부터 읽기
write => 파일이나 장치에 쓰기
close => 파일이나 장치를 닫기
ioctl => 제어 정보를 장치 드라이버에 전달(각 드라이버 마다 고유한 ioctl 명령 집합이 있음)
리눅스 시스템
사용자 프로그램(라이브러리) => 사용자 공간
↓
시스템 호출/커널(장치 드라이버) => 커널 공간
↓
하드웨어 장치
write의 설명자
0 => 표준 입력
1 => 표준 출력
2 => 표준 에러
write 예시 => 반환값(0 데이터 안씀, -1 에러 발생, 1이상의 실제로 쓰여진 바이트 수)
size_t write(int fildes, const void *buf, size_t nbytes);
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main()
{
if ((write(1, "Here is some data\n", 18)) != 18)
write(2, "A write error has occurred on file descriptor 1\n",46);
exit(0);
}
결과는
Here is some data
read 예시 => 반환값(0 데이터 안읽기, -1 에러 발생, 1이상의 실제로 읽어진 바이트 수)
size_t read(int fildes, const void *buf, size_t nbytes);
int main()
{
char buffer[128];
int nread;
nread = read(0, buffer, 128);
if (nread == -1)
write(2, "A read error has occurred\n", 26);
if ((write(1,buffer,nread__ != nread)
write(2, "A write error has occurred\n",27);
exit(0);
}
결과는
echo hello there | simple_read
hello there
open => 새로운 파일 설명자를 만들기 위해
int open(const char *path, int oflags);
int open(const char *path, int oflags, mode_t mode);
mode 맴버는
O_RDONLY => 읽기 전용
O_WRONLY => 쓰기 전용
O_RDWR => 읽고 쓰기용
oflags 맴버는
O_APPEND => 파일 끝에 붙이기
O_TRUNC => 파일의 길이를 0으로 설정하여 기존 내용을 삭제함
O_CREAT => 필요하다면 파일을 생성
O_EXCL => O_CREAT와 함께 사용하며 파일이 만들었음을 확실 할 수 있음
#include <sys/types,h>
#include <sys/stat.h>
파일을 만들때(O_CREAT)는 플래그 필요 맴버는
S_IRUSR : 읽기 권한, 소유자
S_IWUSR : 쓰기 권한, 소유자
S_IXUSR : 실행 권한, 소유자
S_IRGRP : 읽기 권한, 그룹
S_IWGRP : 쓰기 권한, 그룹
S_IXGRP : 실행 권한, 그룹
S_IROTH : 읽기 권한, 다른 사용자
S_IWOTH : 쓰기 권한, 다른 사용자
S_IXOTH : 실행 권한, 다른 사용자
예: myfile 파일을 만들면서 소유자의 읽기 권한과 다른 사용자의 실행 권한을 부여
open ("myfile", O_CREAT, S_IRUSR|S_IXOTH);
umask => 파일을 만들 때 사용할 파일의 권한 마스크를 인코드 하는 시스템 변수
close => 파일 간의 연결을 종료(반환값 : 0 성공, -1 실패)
int close(int fildes);
limits.h => 실행중에 한번에 열수 있는 파일의 개수 제한(OPEN_MAX)
ioctl => 장치 제어
int ioctl(int fildes, int cmd, ...);
TIMEFORMAT="" time copy_system => 복사에 대해서 점유율 파악
Command exited with non-zero status 127
0.00user 0.00system 0:00.00elapsed 0%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+49minor)pagefaults 0swaps
저수준의 파일 복사하기 기능 예:
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{
char block[1024];
int in, out;
int nread;
in = open("file.in", O_RDONLY);
out = open("file.out", O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
while((nread = read(in,block,sizeof(block))) > 0)
write(out,block,nread);
exit(0);
}
lseek => 파일 설명자 filedes의 읽기/쓰기 포인터를 설정
off_t lseek(int fildes, off_t offset, int whence);
fstat => 열린 파일 설명자에 연결된 파일의 관한 상태 정보를 반환
stat => 명명된 파일의 상태 정보를 반환
lstat => 명명된 파일의 상태 정보를 기호화된 링크로 반환
int fstat(int fildes, struct stat *buf)
int stat(const char *path, struct stat *buf);
int lstat(const char *path, struct stat *buf);
stat의 맴버는
st_mode => 파일 권한과 파일 형식 정보
st_ino => 파일과 관련된 inode
st_dev => 파일이 존재하는 장치
st_uid => 파일 소유자의 사용자 ID
st_gid => 파일 소유자의 그룹 ID
st_atime => 마지막 액세스 시간
st_ctime => 권한, 소유자, 그룹 혹은 내용이 마지막으로 변한 시간
st_mtime => 내용이 마지막으로 변한 시간
st_nlink => 파일에 대한 하드 링크의 갯수
예: 파일이 디렉토리가 아니고 소유자에 대한 실행 권한을 가지고 있지만 다른 권한을 가지고 있지 않은지 테스트
struct stat statbuf;
mode_t modes;
stat("filename",&statbuf);
modes = statbuf.st_mode;
if(!S_ISDIR(modes && (modes & S_ISWXU) == S_IXUSR)
...
dup, dup2 => 파일 설명자를 복제하는 방법
int dup(int fildes);
int dup2(int fildes, int fildes2);
기본 라이브러리(stdio.h)를 이용한 파일 입출력
fopen => 저수준 open 시스템 호출과 유사하나 저수준 시스템 호출은 입출력 버퍼링과 같은 잠재적 버그로 원하지 않는 부작용을 없애줌
FILE *fopen(const char *filename, const char *mode);
반환값(null 실패, FILE * 성공)
r 또는 rb => 읽기 전용
w 또는 wb => 쓰기, 내용을 모두 지움
a 또는 ab => 쓰기, 내용을 추가
r+ 또는rb+ 또는 r+b => 갱신(읽기와 쓰기)
w 또는 wb+ 또는 w+b => 갱신, 내용을 모두 지움
a+ 또는 ab+ 또는 a+b => 갱신, 내용을 추가
b는 파일이 텍스트가 아니라 바이너리 파일임을 가르킴(유닉스와 리눅스는 텍스트 파일은 없음 모두 바이너리로 취급함)
fread => 파일 스트림으로 부터 데이터를 읽기
size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);
fwrite => 지정된 데이터 버퍼에 있는 데이터 레코드를 출력 스트림으로 쓴다
size_t fwrite (const void *ptr, size_t size, size_t nitems, FILE *stream);
!!중요!!
구조화된 데이터를 사용하는 목적으로 fread와 fwrite를 권장하지 않는다. fwrite로 쓰여진 파일들이 다른 컴퓨터에서 잠재적으로 이식되지 않을 수도 있어서 문제의 소지가 있다
fclose => 지정된 stream을 닫으며 쓰여지지 않은 모든 데이터를 쓴다
int fclose(FILE *stream);
stream의 제한은 stdio.h에 FOPEN_MAX로 정의되어있고 최소 8이다
fflush => 파일 스트림의 모든 데이터가 즉시 쓰여짐
int fflush(FILE *stream);
fclose전에 fflush는 자동으로 호출됨으로 fclose 전에 호출할 필요가 없다
fseek => 저수준의 lseek에 해당하는 stream 함수이나 lseek는 off_t를 반환하고
int fseek(FILE *stream, long int offset, int whence);
fseek는 정수를 반환한다(반환값 -1 실패, 0 성공)
fgetc => 파일 스트림으로부터 다음 바이트를 문자로 반환(반환값 EOF 파일 끝, EOF 에러)
int fgetc(FILE *stream);
fgetc의 반환값이 EOF가 2가지가 존재함으로 ferror 혹은 feof를 사용 해야함
getc => 매크로로 구현된 fgetc임(지역 변수가 아니거나 함수의 매개변수로 전달되지
앟은 변수에 영향을 끼치지 못하고 getc의 주소를 함수 포인터로 사용할 수 없다)
int getc(FILE *stream);
getchar => getc(stdin)과 동일하며 표준 입력으로부터 다음 문자를 읽는다
int getchar();
fputc => 문자를 출력 스트림에 쓴다(반환값 : 쓴값 성공, EOF 실패)
int fputc(int c, FILE *stream);
putc => getc의 경우와 같음
int putc(int c, FILE *stream);
putchar => putc(cm, stdout)와 동일하며, 하나의 문자를 표준 출력으로 쓴다(문자를 char가 아닌 int로 취하고 반환함)(반환값: -1 문자끝)
int putchar(int c);
fgets => stream으로부터 문자열을 읽는다(최대 n-1 문자까지 한번에 전송가능)(반환값: 문자열 s에 대한 포인터를 반환)(반환값: EOF 파일끝, NULL 읽기에러)
char *fgets(char *s, int n, FILE *stream);
gets => fgets와 동일하며 표준 입력으로부터 읽고 줄 바꿈 문자를 없앤다는 차이가 있다
char *gets(char *s)
!!중요!!
gets는 전송할 수 있는 문자의 개수에 제한을 두지 않기 때문에 버퍼오버플로우 공격에 취약함으로 fgets로 쓰길 권장함
printf => 다른 형식을 가진 인자들을 형식화해서 출력
int printf(const char *format, ...);
예:
printf("Some numbers: %d, %d, and %d\n", 1, 2, 3);
결과는
Some numbers: 1, 2, and 3
fprintf => 자신의 출력을 지정된 stream에 작성
int fprintf(FILE *stream, const char *format, ...);
sprintf => 자신의 출력과 종료 널 문자를 매개변수로 전달된 문자열 s에 쓴다
int sprintf(char *s, const char *format, ...);
%d, %i => 정수를 십진 형태로 출력
%o, %x => 8진, 16진으로 출력
%c => 문자를 출력
%s => 문자열을 출력
%f => 부동 소수점 단위로 출력
%e => 배정밀도(double) 숫자를 고정된 형식으로 출력
%g => 배정밀도 숫자를 일반적인 형식으로 출력
예:
char initial = 'A';
char *surname "Matthew";
double age = 14.5;
printf("Hello Miss %c %s, aged %g\n", initial, surname, age);
결과는
Hello Miss A Matthew, aged 14.5
예: 181페이지 참조
%10s의 인자값이 Hello일때 결과는 | Hello|
scanf => 스트림으로부터 항목을 읽고 변수에 값을 저장(반환값: 0 실패, EOF 항목이 일치하기 전에 끝에 도달하면, 읽어들인 변수의 갯수 성공)
int scanf(const char *format, ...);
예:
int num;
scanf("Hello %d", &num);
실행방법(밑에 2개 모두 num에 1234가 들어감, Hello와 일치할 경우 %d에 따라 숫자가 오면 들어감)
Hello 1234
Hello1234
!!중요!!
정수를 입력받기 위해 스캔하면서 입력에 숫자가 아닌 문자가 들어온다면 무한 반복문이 발생할 수 있다
%d => 십진 정수 스캔
%o, %x => 8진, 16진 정수를 스캔
$f, $e, $g => 부동 소수점 숫자를 스캔
$s => 문자열 스캔(첫번째 공백에서 멈춤으로 단어용으로 씀)
$[] => 문자들의 집합을 스캔
%% => %문자를 스캔
%c => 하나의 문자만 스캔
예:
Hello, 1234, 5.678, X, string to the of the line를 스캔할 경우
char s[256];
int n;
float f;
char c;
scanf("Hello, %d, %g, %c, %[^\n]", &n, &f, &c, s);
!!중요!!
한 줄을 입력 받고 스캔하기 위해서는 필드 지정자를 사용하거나 fgets와 sscanf를 혼용하는것이 좋다)
int fscanf(FILE *stream, const char *format, ...);
int sscanf(const char *s, const char *format, ...);
!!중요!!
scanf 계열은 사용을 자제(여러 줄의 입력을 읽기 이해서는 fread나 ggets와 같은 함수를 사용)
정통적으로 구현상에 버그가 있음
사용하기에 유연하지 않음
구문 분석된 항목에 대해 작업하기 어려운 방향의 코드가 됨
기타 스트림 함수
fgetpos : 파일 스트림의 현재 위치를 얻는다
fsetpos : 파일 스트림의 현재 위치를 설정한다
ftell : 스트림의 현재 파일 옵셋을 반환한다
rewind : 스트림이 파일 위치를 처음으로 설정한다
freopen : 파일 스트림을 다시 사용한다
setvvuf : 스트림을 위한 버퍼링 방법을 설정한다
remove : 파일이면 unlink와 동일하고 디렉토리면 rmdir과 동일
표준라이브러리를 이용한 파일 복사하기 기능(저수준 보다 느림) 예:
#include <stdio,h>
#include <stdlib.h>
int main()
{
int c;
FILE *in, *out;
in = fopen("file.n", "r");
out = fopen("file.out","w");
while((c=fgetc(in)) != EOF)
fputc(c,out);
exit(0);
}
저수준의 파일 복사하기 기능 예(다시):
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int main()
{
char block[1024];
int in, out;
int nread;
in = open("file.in", O_RDONLY);
out = open("file.out", O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
while((nread = read(in,block,sizeof(block))) > 0)
write(out,block,nread);
exit(0);
}
스트림 에러 처리
errno => 저수준의 에러 값을 반환하는데 이때 에러는 외부 변수 errno에 명시됨
#include <errno,h>
extern int errno;
!!중요!!
여러 함수가 errno의 값을 변경시킬수 있으므로 함수 에러 발생시 즉시 검사를 시행하고 항상 이 변수의 값을 사용하기 전에 다른 변수에 복사하고 쓴다
ferror => 스트림에 대한 에러 표시(반환값: 0 설정안됨, 0이외 설정됨)
int ferror(FILE *stream);
feof => 스트림에서 파일 끝 표시(반환값: 0 설정안됨, 0이외 설정됨)
int feof(FILE *stream);
예:
if(feof(some_stream))
/* 끝에 도달 */
clearerr => 스트림이 가리키는 스트림에서 파일 끝 표시와 에러 표시를 초기화("디스크 공간 부족" 에러가 해결된 다음 스트림에 쓰기 작업을 계속 수행할 때 쓰임)
void clearerr(FILE *stream);
fileno => 어떤 저수준 파일 설명자를 파일 스트림에 대해서 사용할 때(반환값: -1 실패, 주어진 스트림의 파일 설명자 성공)(열린 스트림에 대해서 fstat를 호출하는 것과 같이 저수준 액세스가 필요한 경우 유용하게 쓰임)
int fileno(FILE *stream);
FILE *fdopen(int fildes, const char *mode); => 이미 열린 파일 설명자를 기반으로 새로운 파일 스트림을 생성할 수 잇다(이미 열린 파일 설명자 주변에 stdio 버퍼를 제공)(fopen 함수와 동일한 방식으로 작동하는데 파일 이름 대신 저수준 파일 설명자를 받음)(반환값: NULL 실패, 새로운 파일 스트림 성공)
chmod => 시스템 호출을 사용하여 파일이나 디렉토리에 대한 권한을 변경(쉘 기반)
#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
chown => 시스템 호출을 사용하여 파일의 소유자를 변경
#include <unistd.h>
int chown(const char *path, uid_t owner, gid_t group);
unlink => 시스템 호출을 사용하여 파일에 대한 디렉토리 항목을 지우고 링크 개수를 감소시킴(반환값: 0 성공, -1 에러)(unlink를 사용하려면 파일의 디렉토리 항목에 포함된 모든 디렉토리에 대해 쓰기와 실행 권한이 필요함)(rm 프로그램은 이 호출을 사용)
#include <unistd.h>
int unlink(const char *path)
link => 기존파일 path1에 대해서 새로운 링크를 만들고 새로운 디렉토리 항목을 path2로 지정
int link(const char *path1, const char *path2);
symlink => 기호화된 링크 만들기(일반(하드) 링크와는 달리 파일이 효과적으로 삭제되는 것을 방지해 주지 않음)
int symlink(const char *path1, const char *path2);
!!중요!!
프로그램이 종료하면 파일을 자동삭제 하기 위해서 임시 파일로 쓰겠다면 open으로 파일을 만들고 바로 unlink를 호출함
mkdir => 디렉토리 생성
#include <sys/stat.h>
int mkdir(const char *path, mode_t mode);
rmdir => 디렉토리 삭제(디렉토리가 비어있을 때만 가능)
#include <unistd.h>
int rmdir(const char *path);
chdir => 디렉토리 변경
#include <unistd.h>
int chdir(const char *path);
getcwd => 현재 작업 디렉토리 변경(반환값: null 에러(size보다 클때, 디렉토리가 삭제되었을때), buf반환 성공)
#include <unistd.h>
char *getcwd(char *buf, size_t size);
opendir => (저수준)디렉토리를 열고 디렉토리 스트림을 생성(저수준임으로 너무 많은 파일을 열면 실패할 수도 있다)(반환값: 널 실패)
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
readdir => 디렉토리 스트림 dirp 내부에 다음 디렉토리 항목에 관한 구조체의 포인터 반환하고 디렉토리 끝에서는 NULL을 반환한다
#include <sys/types.h>
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
dirent 구조체는(더 많은 사항을 결정하려면 stat를 호출한다)
ino_t d_ino: 파일의 inode
char d_name[] : 파일의 이름
telldir => 디렉토리 스트림의 현재 위치를 기록하는 값을 반환
#include <sys/types.h>
#include <dirent.h>
long int telldir(DIR *dirp);
seekdir => telldir 후에 디렉토리 스캔을 현재 위치로 다시 설정
#include <sys/types.h>
#include <dirent.h>
void seekdir(DIR *dirp, long int loc);
closedir => 디렉토리 스트림을 닫음(반환값: 0 성공, 1 에러)
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
간단한 디렉토리 목록을 생성 예: 193페이지 참조
결과는
디렉토리의 각 파일은 한줄에 나열되고 각 하위 디렉토리의 이름에는 마지막에 슬래시(/)가 붙어있고 하위 디렉토리 하의 파일들은 공백 4자로 들여쓴다
lstat(entry ->d_name, &statbuf); // entry에 저장된 디렉토리명을 상태 버퍼에 저장
errno <= 에러처리(errno.h 안에 나열되어 있음)
EPERM : 연산이 허용되지 않음
ENOENT : 그러한 파일이나 디렉토리가 없다
strerror => 에러 번호를 문자열에 대응 시킴
#include <string.h>
char *strerror(int errnum);
perror => errno에 보고된 현재 에러를 문자열에 대응 시키고 표준 에러 스트림에 출력
#include <stdio.h>
void perror(const char *s);
예:
perror("program");
결과
program: Too many open files
/proc => 파일 시스템에 하드웨어 장치에 대한 목록화(리눅스는 대부분의 사항을 파일로 다룸)(리눅스는 특수한 파일 시스템인 procfs를 제공)
/dev => 저수준 시스템 호출을 사용하는 특벽한 방법으로 하드웨어 액세스
cat /proc/net/sockstat => 소켓 사용량 보기
cat /proc/sys/fs/file-max => 한개의 프로세스에서 파일을 최대로 열수 있는 갯수
!!중요!!(튜닝)
echo 60000 > /proc/sys/fs/file-max => 60000으로 변경(DB 용)
부팅 후도 계속 => /etc/sysctl.conf에 fs.file-max = 60000 추가
/etc/security/limits.conf 끝에 * - nofile 60000 추가
ulimit -a 또는 -Sa => soft 한도
ulimit -Ha => Hard 한도
lsof => 프로세스에서 열어놓은 파일 보기
PID는 기본적으로 1~32,000 사이의 값
od -c /proc/"PID"/cmdline => vi에서 어떤 파일을 열었는지 확인
/proc/"PID"/fd/ => 이 프로세스가 사용하고 있는 열린 파일 설명자에 관한 정보가 있음(설명자 0,1,2는 표준 입력,출력,에러 설명자임)
fcntl => 저수준 파일 설명자를 조작(파일 설명자 복제, 파일 설명자 플래그 설정하고 구하기, 파일 상태 플래그 설정하고 구하기, 관고 파일 잠금 관리)
#include <fcntl.h>
int fcntl(int fildes, int cmd);
int fcntl(int fildes, int cmd, long arg);
mmap => 메모리 맵을 이용해서 두개 이상의 프로그램이 함께 쓰고 읽을 수 있는 메모리 세그먼트를 설정(공유메모리)(off 매개변수를 전달하여 공유 세그먼트에 의해 액세스되는 파일 데이터의 시작 위치를 변경할 수 있고 열린 파일 설명자는 filedes로 전달되고 액세스 할 수 잇는 데이터의 양은 len 매개변수로 설정된다)(addr 틀정 메모리 주소를 요청(보통 0을 넣어서 자동 할당으로 설정))
#include <sys/mman.h>
void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);
msync => 메모리 세그먼트 부분 혹은 전부에 가해진 변경 사항을 매핑된 파일로 쓰거나 매핑된 파일로 부터 읽는다
#include <sys/mman.h>
int msync(void *addr, size_t len, int flags);
mnumap => 메모리 세그먼트를 해지함
#include <sys/mman.h>
int munmap(void *addr, size_t len);
mmap 예: 205페이지 참조
================================================================================================================================================================
5Day Study
[[[[[리눅스(Linux) 환경(environment)]]]]]
프로그램 인자
main은 암시적으로 반환값은 int임
main() = int main(int arc, char *argv[])
프로그램 인자값 표시 예제:
#include <stdio.h>
int main(int argc, char *argv[])
{
int arg;
for(arg = 0; arg < argc; arg++)
{
if(argv[arg][0] == '-')
printf("option: %s\n", argv[arg]+1);
else
printf("argument %d: %s\n", arg, argv[arg]);
}
exit(0);
}
결과는
$ ./args -i -lr 'hi there' -f fred.c
argment 0: args
option: i
option: lr
argument 3: ya there
option: f
argument 5: fred.c
getopt => 리눅스 arg값의 가이드라인을 지킬 수 있도록 도와주는 함수(반환값: 더 이상 처리할 옵션이 없을 때 -1, 인식할 수 없는 옵션의 경우 ?)
#include <unistd.h>
int getopt(int argc, char *const argv[], const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
POSIX 명세에는 opterr 변수가 0이 아니면 getopt는 에러 메시지를 stderr에 출력한다고 나와있다
getopt 예: 214페이지 참조
getopt_long => 이중 대시로 시작하는 소위 긴 인자를 받아들임(GNU C)
$ ./longopt --initialize
putenv => 환경변수 넣기(반환값: -1 실패)(환경변수는 지역적인 변수임으로 다른 쉘에는 적용이 안됨)
#include <stdlib.h>
char *getenv(const char *name);
getenv => 환경변수 반환(반환값: Null 존재안함)
int putenv(const char *string);
getenv와 putenv 예: 218페이지 참조
environ => 환경값을 문자배열로 사용
#include <stdlib.h>
extern char **environ;
environ 변수를 사용하여 환경 변수를 출력하는 프로그램 예:
#include <stdlib.h>
#include <stdio.h>
extern char **environ;
int main()
{
char **env = environ;
while(*env)
{
printf("%s\n", *env);
env++;
}
exit(0);
}
time_t => 시간과 날짜 함수(long)
#include <time.h>
time_t time(time_t *tloc);
time_t 예: 223페이지 참조
difftime => 두개의 시간 값 사이의 차를 게산하고 부동 소수점 숫자로 반환
#include <time.h>
double difftime(time_t time1, time_t time2);
gmtime => 저수준 시간 값을 좀더 평범한 필드를 포함하는 구조체로 분리
#include <time.h>
struct tm *gmtime(const time_t timeval);
tm 구조체와 gmtime를 이용하여 현재 시간과 날짜를 출력 예: 225페이지 참조
localtime => 지역 시간 보기
#include <time.h>
struct tm *localtime(const time_t *timeval);
mktime => tm 구조체를 원시 time_t 값으로 변환(반환값: -1 실패)
#include <time.h>
time_t mktime(struct tm *timeptr);
asctime => 사람에게 친숙한 시간과 날짜 구하기
#include <time.h>
char *asctime(const struct tm *timeptr);
ctime => 원시 시간 값을 받아들여 좀더 읽기 쉬운 지역 시간으로 반환
char *ctime(const time_t *timevarl);
ctime 예:
#inlcude <time.h>
#include <stdio.h>
int main()
{
time_t timeval;
(void)time(&timeval);
printf("The date is:%s", ctime(%timeval));
exit(0);
}
결과는
The date is: Sat Feb 8 09:21:17 2003
strftime => 시간과 날짜 문자열의 형식으로 더욱 정확하게 제어할 때(반환값 포인터)
#include <time.h>
#define _XOPEN_SOURCE
char *strptime(const char *buf , const char *format, struct tm *timeptr);
strftime을 이용한 예(시간값 구하는 함수 중에는 가장 좋다): 230페이지 참조
tmpnam => 임시 파일 만들기(문자열 *s가 널이아니면 파일 이름을 저장)
#include <stdio.h>
char *tmpnam(char *s);
tmpfile => 임시 파일의 이름을 만듦과 동시에 열기(반환값: Null 에러)
#include <stdio.h>
FILE *tmpfile(void);
tmpnam과 tmpfile의 예: 233페이지 참조
mktemp => tmpnam와 유사하고 사용자가 임시 파일의 위치와 이름을 좀더 제어(유닉스 예전버전에서 지원)
#include <stdlib.h>
char *mktemp(char *template);
mkstemp => tmpfile와 유사하고 사용자가 임시 파일의 위치와 이름을 좀더 제어(유닉스 예전버전에서 지원)
int mkstemp(char *template);
getuid => 프로그램과 연관된 UID를 반환
#include <sys/types.h>
#include <unistd.h>
uid_t getuid(void);
getlogin => 현재 상요자와 연관된 로그인 이름을 반환
char *getlogin(void);
/etc/passwd의 구성은
사용자 이름:암호화된 패스워드:사용자 식별자(UID):그룹 식별자(GID):전체 이름:홈 디레고리:기본 쉘
예: root:x:0:0:root:/root:/bin/bash
/etc/shadow => 암호화된 패스워드 파일
getpwuid => 사용자 정보를 표현하는 passwd 구조체로 UID로 사용자 식별
#include <sys/types.h>
#include <pwd.h>
struct passwd *getpwuid(uid_t uid);
getpwnam => 사용자 정보를 표현하는 passwd 구조체로로그인 이름으로 사용자 식별
struct passwd *getpwnam(const char *name);
사용자 정보 예: 236페이지 참조
getpwent => 전체 각 사용자 정보 항목을 차례대로 반환(반환값: 아무것도 없다 Null)
endpwent => getpwent 처리 종료
setpwent => 패스워드 파일에서 위치를 처음으로 설정
위 3개의 함수들은 디렉토리 스캔 함수인 opendir, readdir, closedir과 유사하게 작동함
#include <sys/types.h>
#include <unistd.h>
uid_t geteuid(void);
gid_t getgid(void);
gid_t getegid)void);
int setuid(uid_t uid);
int setgid(gid_t gid);
gethostname => 시스템의 네트워크 이름(호스트 정보)을 갖어 옴(반환값: 성공 0, 실패 -1)
#include <unistd.h>
int gethostname(char *name, size_t namelen);
uname => 시스템 호출을 통해 호스트 컴퓨터의 좀더 세부적인 정보를 구함(운영체제, 호스트 이름, 시스템의 출시 수준, 시스템의 버전 번호, 하드웨어 형식)(반환값: 실패 -1)
#include <sys/utsname.h>
int uname(struct utsname *name);
호스트 정보 예: 239페이지 참조
기본 로그 디렉토리 => /usr/adm 또는 /var/log
/var/log/messages => 모든 시스템 메시지 포함
/var/log/mail => 메일 시스템 로그
/var/log/debug => 디버그 메시지
/etc/syslog.conf => 시스템 구성을 확인
syslog => 로그 저장
#include <syslog.h>
void syslog(int priority, const char *message, arguments...);
priority 멤버들
LOG_EMERG : 긴급상황
LOG_ALERT : 데이터베이스 손상과 같은 높은 순위
LOG_CRIT : 하드웨어 고장과 같은 치명적인 에러
LOG_ERR : 에러
LOG_WARNING : 경고
LOG_NOTICE : 주의가 필요한 특별한 조건
LOG_INFO : 정보 메시지
LOG_DEBUG : 디버그 메시지
syslog 예:
#include <syslog.h>
#include <stdio.h>
int main()
{
FILE *f;
f=fopen("not_here","r");
if(!f)
syslog(LOG_ERR|LOG_USER,"opps - %m\n");
exit(0);
}
결과
/var/log/messages 마지막 줄에
Feb 8 09:59:14 beast syslog: opps - No such file or directory
openlog => 로그 메시지가 나타나는 방식을 변경
#include <syslog.h>
void openlog(const char *ident, int logopt, int facility);
closelog => openlog를 닫아줌
void closelog(void);
setlogmask => 로그 마스크ㅡ를 설정하여 우선순위 수준을 제어
int setlogmask(int maskpri);
logmask 예:
#include <syslog.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
int logmask;
openlog("logmask", LOG_PID|LOG_CONS, LOG_USER);
syslog(LOG_INFO, "infomative message, pid=%d", getpid());
syslog(LOG_DEBUG, "debug message, should appear");
logmask = setlogmask(LOG_NOTICE)); <= NOTICE 이하 우선순위는 무시
syslog(LOG_DEBUG, "debug message, should not appear"); <= 위 마스크 기능 때문에 표시가 안됨
exit(0);
}
결과는
/var/log/messages 끝에
Feb 8 10:00:50 beast logmask[1833]: informative message, pid = 1833
/var/log/debug 끝에
Feb 8 10:00:50 beast logmask[1833]: debug message, should appear
!!중요!!
혹시 /var/log/debug에 로그가 출력되지 않는다면 /etc/syslog.conf 밑에
*.debug /ar/log/debug
를 추가하자
getpid => PID 반환
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
gettpid => 부모 PID 반환
pid_t getppid(void);
getpriority => 자신 또는 다른 응용프로그램 우선순위를 받아오기
#include <sys/resource.h>
int getpriority(int which, id_t who);
setpriority => 자신 또는 다른 응용프로그램 우선순위를 설정하기
int setpriority(int which, id_t who, int priority);
getrlimit => 시스템 리소스의 제한을 받아오기
int getrlimit(int resource, struct rlimit *r_limit);
setrlimit => 시스템 리소스의 제한을 설정하기
int setrlimt(int resource, const struct rlimit *r_limit);
int getrusage => CPU 정보를 받아옴
int getrusage(int who, struct rusage *r_usage);
리소스 제한 예: 251페이지 참조
================================================================================================================================================================
6Day Study
[[[[[터미널(terminal)]]]]]
getchar => 터미널의 데이터 받기
printf => 터미널에 데이터 출력
터미널에서 읽고 쓰기 예: 257페이지 참조
!!중요!!
리눅스와 유닉스는 항상 라인 피드를 텍스트의 줄 끝으로 사용함(텍스트와 바이너리 동일처리)(리눅스는 캐리지 리턴은 프린터나 플로터 출력할 때 처리함)
윈도우는 캐리지 리턴(CR 십진수 13, 16진수 0D)과 라인 피드(LF 십진수 10, 16진수 0A)를 쌍으로 사용함
isatty => 저수준 파일 설명자가 터미널과 연결되어 있는지 조사하며 표준 출력이 리디렉트되어있는지 확인(반환값: fd가 터미널에 연결되어 있으면 1, 이외는 0)
#include <unistd.h>
int isatty(int fd);
출력 리디렉션(터미널 연결확인) 예: 260페이지 참조
/dev/tty => 터미널과 대화하기
getchoice => 출력을 좀더 제어하기 위한 매개변수 제어 예: 262페이지 참조
일반 터미널 인터페이스(termios.h)가 제어 할 수 있는 일(입력/출력/제어/로컬/특수제어문자) => 266페이지 참조
줄 편집: 편집을 위해 백스페이스를 허용할지 여부
버퍼링: 문자를 바로 읽을 것인지 혹은 설정 가능한 지연 후 읽을 것인지 선택
에코: 패스워드를 읽을 때와 같이 에코를 제어할 수 있다
CR/LF: 입력과 출력에 대한 매핑(\n을 출력할 때 어떤 일이 일어나는가)을 결정
회선 속도: PC 콘솔에서는 거의 쓰이지 않으나 모뎀과 직력 회선의 터미널에서는 매우 중요
stty => 쉘에서 터미널 모드 액세스 하기(273페이지 참조)
stty -a => termios 전체 설정 보기
stty sane => 줄바꿈 문자에 대한 캐리지 리턴 키의 매핑을 잃어버렸다면, stty sane을 입력하고 엔터키보다 Ctrl+J(줄 바꿈 문자)를 누를 필요가 있다
stty -icanon min 1 time 0 => 쉘 스크립트가 문자 하나를 읽을 수 있도록 모드를 설정
stty -echo => 패스워드를 입력받기 전에 에코를 꺼서 패스워드 검사 과정을 개선
stty echo => 에코 켜기
tcdrain => 모든 대기딘 출력이 전송될 때까지 호출 프로그램을 기다림
tcflow => 출력을 일시 중단하거나 다시 시작함
tcflush => 입력 및 출력 혹은 둘다 플러시하기 위해서 사용
newrsettings => 터미널 특성 설정
termios.h를 통해서 Enter password: 프롬프트에서 에코되지 않고 사용자가 엔터를 누를 때까지 어떠한 출력도 발생하지 않는 예: 277페이지 참조
echo $TERM => 현자 사용중인 터미널 시스템 보기
/usr/lib/terminofo 또는 /usr/share/terminofo => 터미널의 특성들이 저장되는 곳
infocmp vt100 => vt100 터미널의 형식의 항목을 읽기(VT100의 F1 기능키는 Esc+O+P를 전송한다는 표현은 kf1=\EOP, 좀 더 상세한것은 284페이지 참조)
setupterm => 터미널 형식 설정하기
#include <term.h>
int setupterm(char *term, int fd, int *errret);
현재 터미널 사이즈 받아오는 예: 286페이지 참조
종합 터미널 제어 예: 289페이지 참조
kbhit => 키 입력 검출 함수(윈도우로 부터 프로그램을 이식할 때, kbhit를 에뮬레이트하면 편리한 경우가 있음, 비정식 입력 모드 사용하면 된다) 예: 291페이지
who => 로그인한 사용자 보기
ps => 현재 가상 콘솔에서 실행중인 쉘과 프로그램 보기(mingetty는 가상 콘솔에서 사용자의 로그인을 기다리는 데몬)
Ctrl+Alt+F<N> => 가상 콘솔 사이 전환하기(예: Ctrl+Alt+F1), X윈도우 그래픽 tty는 7번
sstartx -- :1 => X윈도우 그래픽 세션 추가(가장 마지막 tty 세션 +1에 생김)
================================================================================================================================================================
7Day Study
[[[[[텍스트 기반 화면 관리(curses 사용)]]]]]
297~384페이지 참조
P.S 내용이 서버 프로그램 개발시 별로 필요가 없을 것 같아서 생략함
================================================================================================================================================================
8Day Study
[[[[[데이터 관리]]]]]
malloc => 메모리 할당하기
#include <stdlib.h>
void *malloc(size_t size);
!!중요!!
유닉스에서는 malloc.h 헤더파일 필요
사용가능한 메모리 예:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#define ONE_K (1024 * 1024000)
int main()
{
char *some_memory;
int size_to_allocate = ONE_K;
int megs_ob = 0;
int ks_ob = 0;
while (1)
{
for(ks_ob=0;ks_ob>1024;ks_ob++)
{
some_memory=(char *)malloc(size_to_allocate);
if(some_memory == NULL) exit(EXIT_FAILURE);
sprintf(some_memory, "Hello world");
}
megs_ob++;
printf("Now allocated %d Megabytes\n", megs_ob);
}
exit(EXIT_SUCCESS);
}
리눅스는 모든 메모리를 페이지로 나누는데, 보통 한 페이지는 4096바이트 이다
free => 메모리 해지하기
#include <stdlib.h>
void free(void *ptr_to memory);
calloc => 구조체의 배열에 해당하는 메모리를 할당하며 요소의 개수와 각 요소의 크기를 매개변수로 가짐
#include <stdlib.h>
void *calloc(size_t number_of_elements, size_t element_size);
realloc => 할당된 메모리 블록의 크기 변경(반환값: Null 실패, 포인터 성공)
void *realloc(void *existing_memory, size_t new_size);
Lock 파일 만들기 예: 362페이지 참조
int file_desc;
file_desc=open("/tmp/lock.test", O_RDWR | O_CREAT | O_EXCL, 0444);
프로그램이 단순히 실행하는 짧은 기간동안 리소스를 독점해야한다면, 즉 임계 영역(critical secction)이 필요하다면, 임계 영역에 진입하기 전에 잠금 파일을 만들고 임계 영역을 빠져나와서 unlink로 지워주어야 한다
10번 반복해라 예:
int tries = 10;
while(tries--) {
...
}
fcntl => 파일의 특정 부분만 잠그고 다른 프로그램이 파일의 다른 부분에는 액세스할 수 있도록 하기(lockf도 같은 기능을 함) 366페이지 참조
#include <fcntl.h>
int fcntl(int fildes, int command, struct flock *flock_structure);
!!파일 영역에 대한 잠금기능 사용시는 고수준 fread보다는 저수준 read를 사용하는 것이 좋다!!
실습 예: 370페이지 참조
#include <unistd.h>
int lockf(int fildes, int function, off_t size_to_lock);
dbm => 리눅스용 데이터베이스(단순 색인 파일 저장소) ndbm과 gdbm 중에 호환성은 ndbm이 좋음
#include <ndbm.h>
DBM *dbm_open(...); => 데이터 베이스 열기
int dbm_store(...); => 데이터 베이스 저장
datum dbm_fetch(...); => 데이터 베이스 갖어오기
void dbm_close(...); => 데이터 베이스 닫기
dbm 데이터베이스 예: 387~417페이지 참조
================================================================================================================================================================
9Day Study
[[[[[Mysql 관련]]]]]
Mysql: Mysql의 장점은 무료고 속도가 빠르다
PostgreSQL: PostgreSQL의 장점은 완전 무료고 일반 기본 쿼리 속도는 mysql에 뒤처지지만 복잡한 쿼리 속도는 Mysql보다 빠름
주요서버 패키지: MySQL-server-<버전>.<아키텍처>.rpm
클라이언트 패키지: MySQL-client-<버전>.<아키텍처>.rpm
공유 구성요소 패키지: MySQL-share-<버전>.<아키텍처>.rpm
개발 패키지: MySQL-devel-<버전>.<아키텍처>.rpm
실행수준 1,3에 msyql을 시작를 추가
ln -s /etc/rc.d/init.d/mysql /etc/rc.d/rc1.d/S97mysql
ln -s /etc/rc.d/init.d/mysql /etc/rc.d/rc3.d/S97mysql
chkconfig --add mysql
chkconfig --level 13 mysql on
실행수준 2에 mysql을 정지를 추가
ln -s /etc/rc.d/init.d/mysql /etc/rc.d/rc2.d/K97mysql
chkconfig --add mysql
chkconfig --level 2 mysql off
mysql 실행 수준 보기
chkconfig --list 또는 chkconfig --list 서비스명
$mysqladmin -u root password 설정패스워드 <= 초기 패스워드 설정을 함
$mysql -u root -p <= mysql root로 접속
rick 사용자 만들기
mysql> GRANT ALL ON *.* TO rick@localhost IDENTIFIED BY '패스워드';
192.168.0 클래스 C 서브넷에서 연결만
mysql> GRANT ALL ON *.* TO rick@'192.168.0.0/255.255.255.0' IDENTIFIED BY '패스워드';
도메인 wiley.com 속한 컴퓨터는 모두 통과
mysql> GRANT ALL ON *.* TO rick@'%.wiley.com' IDENTIFIED BY '패스워드';
특정 DB만 권한 주기
mysql> GRANT ALL ON database_name.* TO rick@'%.wiley.com' IDENTIFIED BY '패스워드';
Mysql 로그보기
$mysql_safed -log
myisamchk => mysql db 점검(테이블이 저장되어 있는 디렉토리에서 실행)
$myisamchk -e -r *.MYI
-c: 테이블의 에러를 점검
-e: 확장된 점검을 수행한다
-r: 발견한 에러를 복구(수정) 함
mysqldump => mysql 백업 프로그램
mysql 데이터 형식 => 438페이지 참조
MySQLCC => mysql GUI 관리툴
mysql 프로그램 예: 469, 480페이지 참조
컴파일 명령어:
$gcc -I/usr/include/mysql connect.c -L/usr/lib/mysql -lmysqlclient -lz -o connect
mysql> SELECT LAST_INSERT_ID(); <= 마지막 AUTO_INCREMENT 값 갖고 오기
mysql_store_result => SELECT 결과값 뭉탱이로 갖고 오기
mysql_use_result => SELECT 결과값 한 행씩 가져오기
================================================================================================================================================================
10Day Study
[[[[[개발 도구]]]]]
메이크파일 문법
-k : 에러를 발견 했더라도 멈추지 않고 계속 진행
-n : 실제로 작업을 수행하지 않고 어떤 작업을 수행할 것인지 출력한다
-f <파일 이름> : 메이크파일로 이 파일을 사용함
make 실행시 첫번째 대상이 make 됨(예: all이 맨 첨이면 all)
make 파일안에 종속표현(:)
myapp: main.o 2.o 3.o => myapp는 main.o와 2.o와 3.o에 종속
all: myapp myapp.1 => 응용프로그램이 바이너리 파일 myapp와 메뉴얼 페이지 myapp.1로 이루어 질때
!!중요!!
메이크 파일은 매우 이상한 문법이다.
모든 법칙은 탭으로 시작하는 줄로 작성된다. 공백은 안 된다. 여러 개의 공백과 탭은 매우 유사해 보이고, 메이크파일 이외 거의 모든 분야의 리눅스 프로그래밍에서 공백과 탭은 구분하지 않기 때문에, 이러한 문법은 문제를 일으킬 수 있다. 또한 메이크파일의 마지막 줄에 있는 공백 때문에 make 명령이 실패할 수도 있다.
현재 이러한 문법을 고수하며 존재하는 메이크파일이 수도 없이 많다. 그러므로 조심해야 한다. 다행스럽게도 탭이 빠져서 make 명령이 작동하지 않는 경우가 상당히 자주 발생함으로 안될때는 탭 검사를 해보자
메이크 파일의 주석은? #
make 특별 내부 메크로
$? : 현재 대상보다 더 최근에 변경된 파일 이름
$@ : 현재 대상의 이름
$< : 현재 파일 이름
$* : 접미사(suffix)를 제거한 현재 파일 이름
앞에 -를 지정하면 make는 에러를 무시
앞에 @를 지정하면 표준 출력으로 표시 안 함
이전 명령이 성공해야 다음 명령을 실행 조건은 &&로 표시(and 기능)
make -p => make의 내장 법칙 보기
cpp 확장자(suffix)를 컴파일 하기
.SUFFIXES: .cpp
.cpp.o:
$(CC) -xc++ $(CFLAGS) -I$(INCLUDE) -c $<
%.cpp: %o
$(CC) -xc++ $(CFLAGS) -I$(INCLUDE) -c $<
위 2개는 같은것임
라이브러리 관리하기 예: 510페이지 참조
RCS => 소스 코드 관리(형상관리) 1인용
rcs 제어 초기화
$ rcs -i important.c => 나갈때는 Ctrl+D 또는 .
결과는 rcs는 ,v 확장자를 가진 새로운 읽기 전용 파일을 만듬
!!중요!!
RCS 파일을 별도 디렉토리에 저장하고 싶다면, 단순히 rcs를 처음 사용하기 전에 RCS라는 하위디렉토리를 만들면 된다. 모든 rcs 명령은 자동으로 rcs 파일을 위해 RCS 하위 디렉토리를 사용함
co => 파일 변경 하기전 체크 아웃
co important.c => 최신 버전으로 복구
co -l important.c => 소스 수정을 위한 읽기 전용 해제
ci => 소스 변경 저장(기존 소스 파일이 지워짐)
ci important.c
복구(버전 1.1로 복구)
co -r1.1 important.c
rlog important.c => 파일의 변경 사항 요약 보기
rcsdiff -r1.1 -r1.2 important.c => 버전 1.1과 1.2를 비교해 보기
개정 자동 식별 추가
static char *RCSinfo = "$Id$"; => 소스안에 추가
실행파일의 개정 자동 식별 하기
$ ident ./important
CVS => 인터넷을 통한 소스 코드 관리(형상관리) 다인용
cvs 초기 디렉토리 만들기
mkdir /usr/local/repository
cvs 초기화
cvs -d /usr/local/repository init
현재 디렉토리에 있는 소스를 /usr/local/repository/wrox/chap9-cvs에 저장
cvs import -d /usr/local/repository/ -m"Initial versoin of Simple Project" wrox/chap9-cvs wrox start
밑에 cvs의 -d 옵션을 제거하기 위해서 해야할 일
export CVSROOT=/usr/local/repository
cvs로 체크 후 갖고오기
cvs checkout wrox/chap9-cvs
cvs로 비교
cvs diff
cvs로 뭘 체크하는지 보기
cvs commit
세부사항 보기
cvs rdiff -r1.1 wrox/chap9-cvs
cvs 업데이트
cvs update -Pd wrox/chap9-cvs
cvs 네트워크로 액세스 => 527페이지 참조
diff로 차이점 목록 만들기
diff file1.c file2.c > diffs
file1.c와 diffs를 이용해서 패치
patch file1.c diffs
패치 원복하기
patch -R file1.c diffs
spec 파일 빌드하기
rpmbuild -ba myapp.spec
================================================================================================================================================================
11Day Study
[[[[[디버깅(Debuging)]]]]]
gcc 오류를 추적하면서 컴파일 하기
gcc -Wall -pedantic -ansi
인스트루먼트 예:
#ifdef BEBUG
printf("variable x has value = %d\n", x);
#endif
인스트루먼트 복합 적용 예:
#ifndef DEBUG
#define DEBUG 0
#endif
#define BASIC_DEBUG 1
#define EXTRA_DEBUG 2
#define SUPER_DEBUG 4
#if (DEBUG & EXTRA_DEBUG)
printf...
#endif
컴파일 방법
gcc -o cinfo --DEBUG cinfo.c
그냥 print를 활용하기
if(debug) {
sprintf(msg,...);
write_debug(msg)
}
gdb를 이용한 디버깅
gcc -g -o debugex debugex.c <= 꼭 -g 옵션이 필요함
gdb debugex
GNU gdb Red Hat Linux (6.5-37.el5_2.2rh)
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) run => debugex를 실행
Starting program: /root/cstudy/maxusermem
Program received signal SIGSEGV, Segmentation fault.
0x080483ef in main () at ./maxusermem.c:14
14 *scan_ptr='\0'; => 14번째 줄 에러
(gdb) bt <= 스택을 추적하여 코드 에러 부분을 호출한 부분을 찾을 수 있음
#0 0x080483ef in main () at ./maxusermem.c:14
(gdb) backtrace => 스택을 추적하여 코드 에러 부분을 호출한 부분을 찾을 수 있음
#0 0x080483ef in main () at ./maxusermem.c:14
(gdb) print scan_ptr => scan_ptr 변수값 보기
$2 = 0x9a6f000 <Address 0x9a6f000 out of bounds>
(gdb) print ex[$-1] => ex배열의 마지막 결과값 바로 전꺼 보기
(gdb) print ex[3].key => ex배열 3번째의 key 값 보기
(gdb) print ex[0]@ => ex배열 전체 보기
(gdb) list => 소스 보기
9
10 some_memory=(char *)malloc(ONE_K);
11 if(some_memory == NULL) exit(EXIT_FAILURE);
12 scan_ptr=some_memory;
13 while(1) {
14 *scan_ptr='\0';
15 scan_ptr++;
16 }
17 exit(EXIT_SUCCESS);
18 }
(gdb) help breakpoint => 브레이크 포인트 설명 보기
(gdb) break 11 => 11번째 줄에 중단점 만들기
Breakpoint 1 at 0x80483d4: file ./maxusermem.c, line 11.
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/cstudy/maxusermem
Breakpoint 1, main () at ./maxusermem.c:11
11 if(some_memory == NULL) exit(EXIT_FAILURE);
(gdb) print some_memory
$8 = 0x8de0008 ""
(gdb) cont => 중단점을 지나서 계속 진행
Continuing.
(gdb) next => 중단점을 지나서 다음으로 진행
(gdb) display ex[0]@ => 실행될때 마다 보여줌
(gdb) commands => 브레이크 포인트 만날 때를 제어함
Type commands for when breakpoint 1 is hit, one per line.
End with a line saying just "end".
>cont => 중단점 무시하여 진행
>end => commands 나가기
(gdb) info display => 디스플레이 정보 보기
Auto-display expressions now in effect:
Num Enb Expression
1: y some_memory
(gdb) info break => 브레이크 포인트 정보 보기
Num Type Disp Enb Address What
1 breakpoint keep y 0x080483d4 in main at ./maxusermem.c:11
breakpoint already hit 1 time
cont
(gdb) disable break 1 => 브레이크 포인트 1 비활성
(gdb) disable display 1 => 디스플레이 1 비활성
(gdb) commands 1 => 브레이크 포인트 1번을 제어
Type commands for when breakpoint 1 is hit, one per line.
End with a line saying just "end".
>set variable ex = 2; => ex 변수를 2로 변경하여 처리함
>cont
>end
(gdb) run
(gdb) quit
The program is running. Exit anyway? (y or n) y
[root@waf cstudy]#
최적화 컴파일
gcc -O -g -o test ./test.c
$ splint -strict maxusermem.c => 컴파일 전에 프로그램 에러 잡기
코어 덤프 파일 만들기
gcc -g -o test ./test.c
옵션 후
#include <sys/resource.h>
static void
set_limit(void)
{
struct rlimit rlp;
rlp.rlim_cur = RLIM_INFINITY;
rlp.rlim_max = RLIM_INFINITY;
/* Core file size를 시스템 최대치로 설정 */
if (setrlimit(RLIMIT_CORE, &rlp))
Log(ERROR, "Failed to set rlimit core file size: %s",
strerror(errno));
}
위가 안 되면
ulimit -c unlimited >/dev/null 2>&1
http://my.oops.org/77 참조
[root@waf cstudy]# gdb debugex --core=./core.9794 ==> 코어 파일을 이용하여 디버그
GNU gdb Red Hat Linux (6.5-37.el5_2.2rh)
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1".
warning: Can't read pathname for load map: Input/output error.
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
Core was generated by `./max'.
Program terminated with signal 11, Segmentation fault.
#0 0x080483ef in main () at maxusermem.c:15
15 *scan_ptr='\0';
(gdb) bt
#0 0x080483ef in main () at maxusermem.c:15
(gdb)
prof/gprof를 이용하여 서브함수별 속도를 나타냄
gcc -pg -o program program.c
./program
ls -la하면 gmon.out이 생김
메모리 디버깅(malloc와 free 이용할 때 사용)
gcc -o test test.c -lefence
./test
gdb test
(gdb) run
valgrind => 가장 좋은 디버거
$ valgrind --leak-check=yes -v ./test
================================================================================================================================================================
12Day Study
[[[[[프로세스와 신호(Process and Signal)]]]]]
[root@waf ~]# ps -lf
F S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME CMD
4 S root 13443 13441 0 75 0 - 1466 wait 08:21 pts/1 00:00:00 -bash
4 R root 13666 13443 0 76 0 - 543 - 09:31 pts/1 00:00:00 ps -l
위에서 NI는 nice값이다 프로세서의 우선순위를 말함(높을 수록 높음 기본은 0)
nice 값 변경:
$nice <프로세스명> &
nice 값 10으로 재설정:
$renice 10 <PID>
system을 이용한 새 프로세스 시작 예:
#include <stdlib.h>
#include <stdio.h>
int main()
{
system("ps -ax");
exit(0);
}
프로세스 이미지 교체하기(따른 PID가 안 생기고 실행됨):
#include <unistd.h>
int execl("bin/ps", "ps", "-ax", 0); => 반환값(에러 -1), errno 에러변수
프로세스 이미지 복제하기(fork) => 반환값(실패 -1), errno 에러변수
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
!!중요!!
부모 프로세스에서 fork를 호출하면 새로운 자식 프로세서 PID를 반환하고 자식 프로세스에서 다시 fork를 하면 0을 반환한다
fork 예제: 608페이지 참조
또 다른 fork 예:
#include <stdio.h>
#include <iostream.h>
#include <unistd.h>
#include <sys/wait.h>
void pfork(int a);
int main(){
int index=0;
pfork(index);
return 0;
}
void pfork(int a){
if(a==10) return;
else if(fork()==0) {
printf("Child %d\n",a);
pfork(a+1);
}
else {
wait(0);
printf("Parent %d \n", a);
}
}
결과값
Child 0
Child 1
Child 2
Child 3
Child 4
Child 5
Child 6
Child 7
Child 8
Child 9
Parent 9
Parent 8
Parent 7
Parent 6
Parent 5
Parent 4
Parent 3
Parent 2
Parent 1
Parent 0
프로세스 종료 기달리기(wait 시스템 호출은 부모 프로세스의 자식 프로세스 중 하나가 정지할 때까지 부모 프로세스를 일시 중지시킨다) => 반환값(정상 0)
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *stat_log);
wait 예: 611페이지 참조
좀비 프로세스(<defunct> 또는 <zombie>)
특정 프로세스 종료 기다리기
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *stat_log, int options); => 종료하였거나 정지했으면 PID, 에러 -1, 종료안하거나 정지안했으면 0
입출력 리디렉션 예:
[root@waf cstudy]# cat upper.c
#include <stdio.h>
#include <ctype.h>
int main()
{
int ch;
while((ch=getchar()) != EOF) {
putchar(toupper(ch));
}
exit(0);
}
[root@waf cstudy]# ./upper
hahaha hohoho
HAHAHA HOHOHO
!!중요!!
리눅스에서 쓰레드를 프로그래밍하는 것은 여러 프로세스를 사용하는 것 만큼 흔하지 않다. 그 이유는 리눅스 프로세스는 경량이며, 협력하는 여러 프로세스를 프로그래밍하는 것이 쓰레드 프로그래밍보다 쉽기 때문이다
신호처리 하기 예:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void ouch(int sig)
{
printf("OUCH! = I got signal %d\n", sig);
(void) signal(SIGINT, SIG_DEF); => SIG_DEF 기본 동작으로 복구, SIG_IGN 무시하기
}
int main()
{
(void) signal(SIGINT, ouch);
while(1) {
printf("Hello World!\n");
sleep(1);
}
}
$ ./ctrlc
Hello World!
Hello World!
Hello World!
Hello World!
^C => CTRL+C를 누른 시점
OUCH! - I got signal 2
Hello World!
Hello World!
Hello World!
Hello World!
^C => CTRL+C를 누른 시점
$
!!중요!!
signal보단 sigaction을 사용을 권한다
신호 보내기 => 우리가 아는 kill이긴 하지만 신호를 보낼 때도 이용됨
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig); => 반환값(실패 1)
알람
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
!!중요!!
신호를 조심스럽게 프로그램밍해야 한다. 왜냐하면 신호를 사용하는 프로그램에서 발생할 수 있는 "경쟁 조건(race condition)"이 많기 떄문이다. 예를 들어 pause를 호출하여 신호를 기다리고자 할때 pause를 호출하기 전에 신호가 발생하면 프로그램은 일어나지도 않을 이벤트를 무한히 기다리는 수가 생긴다.
알람 예:
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
static int alarm_fired = 0;
void ding(int sig)
{
alarm_fired = 1;
}
int main()
{
pid_t pid;
printf("alarm app starting\n");
pid = fork();
switch(pid) {
case -1:
perror("fork failed");
exit(1);
case 0:
sleep(5); => 포크한 후에 자식 프로세서 일시정지 5초
kill(getppid(), SIGALRM); => 부모 프로세스에 SIGALRM 보내기
exit(0);
}
printf("waiting for alarm to go off\n");
(void) signal(SIGALRM, ding);
pause(); => SIGALRM이 올때까지 기달리다가 오면 ding함수 호출
if(alarm_fired) printf("Ding!\n"); => alarm_fired==1 이면 Ding! 출력
printf("done\n");
exit(0);
}
견고한 신호 프로그래밍
#include <signal.h>
int sigaction(int sig, const struct sigaction *act, struct sigaction *oact);
반환값(성공 0, 실패 -1)
sigaction 예: 627페이지 참조
================================================================================================================================================================
13Day Study
[[[[[POSIX 쓰레드(Thread)]]]]]
Native POSION Thread Library(NPTL)를 사용
기본값
#include <pthread.h>
int pthread_create(pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); => 스레드 생성
void pthread_exit(void *retval); => 스레드 종료
int pthread_join(pthread_t th, void **thread_return); => wait 기능
스레드 예:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
void *thread_function(void *arg);
char message[] = "Hello World";
int main() {
int res;
pthread_t a_thread;
void *thread_result;
res=pthread_create(&a_thread, NULL, thread_function, (void *)message);
if(res != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
printf("Waiting for thread to finish...\n");
res=pthread_join(a_thread, &thread_result);
if(res != 0) {
perror("Thread join failed");
exit(EXIT_FAILURE);
}
printf("Thread joined, it returned %s\n", (char *)thread_result);
printf("Message is now %s\n",message);
exit(EXIT_SUCCESS);
}
void *thread_function(void *arg) {
printf("thread_function is running. Argument was %s\n", (char *)arg);
sleep(3);
strcpy(message, "Bye!");
pthread_exit("Thank you for the CPU time");
}
[root@waf cstudy]# ./thread
Waiting for thread to finish...
thread_function is running. Argument was Hello World
Thread joined, it returned Thank you for the CPU time
Message is now Bye!
스레드 최대 갯수 세는 프로그램 예:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
unsigned int total=0;
unsigned int threadcount=0;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
void update_size( unsigned size) {
}
void *threadFunc(void *arg) {
int tnum = (int) arg;
// add our thread number to the total
pthread_mutex_lock(&m);
total += tnum;
threadcount--;
printf("I am thread %d, and I am done!\n",tnum);
pthread_mutex_unlock(&m);
return(NULL);
}
int main(int argc, char **argv) {
int i,n;
pthread_t tid;
if (argc!=2) {
fprintf(stderr,"Error - I need the number of threads!\n");
exit(1);
}
n = atoi(argv[1]);
if (n<=0) {
fprintf(stderr,"Give me a number greater than 0\n");
exit(1);
}
for (i=1;i<=n;i++) {
threadcount++;
if (pthread_create(&tid,NULL,threadFunc,(void *)i)) {
fprintf(stderr,"Error creating thread number %d\n",i);
}
}
while (threadcount);
printf("total is %d\n",total);
return(0);
}
동기화(synchronization)
뮤텍스와 세마포 둘 다 공유자원의 크리티컬 섹션 문제를 해결하는 방법이다.
뮤텍스는 공유자원에 접근할 수 있는 열쇠라고 보면 된다.
열쇠가 있는 녀석만이 공유자원에 접근할 수 있는 것이다.
이렇게 해서 크리티컬 섹션 문제를 해결한다.
그럼 세마포는?
세마포는 뮤텍스보다 더 범용적으로 쓰일 수 있다.
왜? 세마포는 공유자원의 접근에 대한 한계값(n)을 부여하고
n보다 작으면 프로세스가 공유자원에 접근할 수 있다.
그럼 뮤텍스와 세마포의 차이점은???
세마포를 뮤텍스와 똑같은 기능을 하게 할 수 있다.
그것이 바로 바이너리세마포 이다.
바이너리... 말 그대로 0과 1 둘 밖에 없다.
즉 0이면 못하는 거고 1이면 접근 가능하다.
이러면 세마포와 뮤텍스의 기능이 같아진다.
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_wait(sem_t *sem);
int sem_post(sem_t *sem);
int sem_destory(sem_t *sem);
세마포어를 이용하여 쓰레드가 작업을 완료할 때까지 메인 쓰레드가 기다리도록 만들 수 있음
뮤텍스
#include <pthread.h>
pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
pthread_mutex_lock(pthread_mutex_t *mutex);
pthread_mutex_unlock(pthread_mutex_t *mutex);
pthread_mutex_destroy(pthread_mutex_t *mutex);
P.S 책이 넘 후졌다... 인터넷으로 따로 공부하자
================================================================================================================================================================
14Day Study
[[[[[프로세스간 통신: 파이프(pipe)]]]]]
<myserver 서버에 id로 로그인 하여 ls명령 실행>
ssh id@myserver ls
<ssh키를 등록해놓았을 때는 id는 생략하고 로그인 절차 없이 바로 실행, ;로 구분하여 여러 명령 실행>
ssh myserver "ls -la;df"
그러면 여러줄의 명령이나 특정 쉘스크립트,Perl스크립트 등등을 원격서버에 실행 시키면 어떻게 해야 할까? 간단한 쉘명령이야 ;로 나눠서 한 줄에 넣어서 실행하면 되지만 작업이 복잡해지면 그런 형태로는 한계가 있다. 그럴때는 다음과 같은 방법을 쓸 수 있다.
<HEREDOC을 사용하는 방법>
ssh myserver <<\EOF
ls -la
df
EOF
<별도의 쉘스크립트를 만들고 원격에 스크립트 해석기를 실행시키고 파이프나 리다이렉션으로 보내는 방법>
#!/bin/sh
ls -la
df
가 test_script.sh 이라고 하면
cat test_script.sh | ssh myserver sh
또는
ssh myserver sh < test_script.sh
<Perl 스크립트를 ssh를 통해 실행>
cat perl_script.pl | ssh myserver perl
또는
ssh myserver perl < perl_script.pl
이것을 기초로 여러 서버에 명령을 내리려면 다음처럼 서버의 리스트를 만들고 리스트에 대해 루프를 돌면서 위의 명령을 서버별로 실행하면 될 것이다.
<여러 서버에 루프를 돌면서 지정한 스크립트를 실행하는 스크립트>
#!/bin/sh
SERVERS="
myserver1
myserver2
"
for m in $SERVERS
do
ssh $m sh < test_script.sh
done
이렇게 하면 문제는 순차적으로 실행을 하기 때문에 한 서버씩 실행이 끝날 때 까지 기다려야 해서 속도가 늦고 나중에 결과를 보기가 힘들다는 것이다.
그러면
ssh $m sh < test_script.sh
줄을 다음과 같이
ssh $m sh < test_script.sh > $m.log &
고치면 각 ssh 명령이 fork되어서 백그라운드로 돌고 각 서버에 대한 결과는 서버이름.log 파일로 남게 된다. ( 작업결과는 *.log 파일들에 대해 grep이나 기타 유틸리티로 일괄적으로 확인 가능할 것이다. )
발췌 URL:
http://209.85.173.132/search?q=cache:yXBNexjGI0QJ:aero.dnip.net/blog/2008/11/ssh.html+ssh+%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8&cd=11&hl=ko&ct=clnk&gl=kr&client=firefox-a
파이프(pipe)란 하나의 프로세스로부터 데이터 흐름을 다른 프로세스로 연결
#include <stdio.h>
FILE *popen(const char *command, const char *open_mode);
open_mode 멤버: r 출력 읽기, w 출력 보내기(반환값 NULL 실패)
int pclose(FILE *stream_to_close); => popen이 종료할 때 까지 기달렸다가 종료시킴
POPEN 예:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
FILE *read_fp;
char buffer[BUFSIZ + 1];
int chars_read;
memset(buffer, '\0', sizeof(buffer));
read_fp = popen("cat ./popen.c | wc -l", "r");
if(read_fp != NULL)
{
chars_read=fread(buffer, sizeof(char), BUFSIZ, read_fp);
while(chars_read > 0)
{
buffer[chars_read - 1] = '\0';
printf("Reading:-\n %s\n", buffer);
chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);
}
pclose(read_fp);
exit(EXIT_SUCCESS);
}
exit(EXIT_FAILURE);
}
결과는
[root@waf cstudy]# ./popen
Reading:-
27
저수준의 파이프(pipe) => 쉘 호출을 사용하지 않음
#include <unistd.h>
int pipe(int file_descriptor[2]);
pipe 실습 예: 681페이지 참조
포크와 exec와 pipe 실습 예: 685페이지 참조
명명된 파이프(named pipe): FIFO 예: 696페이지 참조(CPU 리소스에 가장 효율이 좋다)
고급 주제: FIFO를 사용하는 클라이언트/서버 예: 703페이지 참조
실제 응용프로그램에서는 sleep를 하지 않음
실제 응용프로그램 DB 클라이언트/서버 예: 712페이지 참조
실제 응용프로그램 DB 검색 예: 720페이지 참조
================================================================================================================================================================
15Day Study
[[[[[세마포어, 공유 메모리, 메시지 대기열 IPC(Inter=Process Communication)]]]]]
세마포어의 정의
가장 간단한 세마포어는 오직 0과 1만의 값만 받아들이는 변수, 바이너리 세마포어
다양한 양의 값을 받아들이는 세마포어는 일반 세마포어
P와 V의 정의는 간단하다. 세마포어 변수 sv가 있다고 하자
P(sv) : sv가 0보다 크면 sv를 감소시킨다. sv가 0이라고 하면 이 프로세스의 실행을 일시 중단한다( -1)
V(sv) : 다른 프로세스가 sv를 가르켰을 때 일시 중단되어 있다면, 이 프로세스의 실행을 재개시킨다. sv를 기다리며 일시 중단되어 있는 프로세스가 없다면 sv를 증가시킨다( +1)
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
새로운 세마포러를 만들거나 기존 세마포어의 세마포어 키를 반환
int semget(key_t key, int num_sems, int sem_flags);
세마포어의 값을 변경
int semop(int sem_id, struct sembuf *sem_ops, size-t num_sem_ops);
세마포어 정보를 직접 제어
int semctl(int sem_id, int sem_num, int command, ...);
command 맴버: SETVAL(세마포어 초기화), IPC_RMID(세마포어 식별자 삭제)
공유메모리(shared memory)는 세 가지 IPC 기능 중에서 두번째임
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
공유메모리 할당하기
int shmget(key_t key, size_t size, int shmflg);
shmflg를 통해서 읽고쓰기 가능 및 읽기전용에 대한 권한 설정
반환값: 실패 -1, 성공 0 이상
처음 공유 메모리 세그먼트를 만들고 쓸 수 없기 때문에 프로세스의 주소 공간에 공유메모리 연결
void *shmat(int shm_id, const void *shm_addr, int shmflg);
shmflg 멤버 : SHM_RND 공유 메모리가 연결되는 주소를 제어
SHM_RDONLY 연결된 메모리를 읽기 전용으로 만듬
반환값: 실패 -1, 성공 공유 메모리의 첫번째 바이트에 대한 포인터 반환
공유 메모리를 현재 프로세스로 부터 분리(삭제되지 않고 현 프로세스가 공유 메모리를 사용을 불가능 하게함)
shmdt(int shm_id);
반환값: 실패 -1
공유메모리 제어
int shmctl(int shm_id, int command, struct shmid_ds *buf);
shm_id는 shmget가 반환한 값
command는 취해야 할 동작(IPS_STAT, IPC_SET, IPC_RMID);
*buf는 공유메모리 모드와 권한
반환값: 실패 -1, 성공 0
공유메모리 예: 753페이지 참조
IPC(메시지 대기열)
메시지 대기열은 두개의 연관이 없는 프로세스끼리 쉽고 표율적으로 데이터를 주고받을 수 있다. 메시지 대기열은 송신 프로세스와 수신 프로세스에 대해 독립적으로 존재하기 때문에, 명명된 파이프를 열고 닫을 때 동기화를 수행하면서 따르는 어려움을 다소 없애준다. 이것이 메시지가 명명된 파이프에 비해 가지는 장점이다
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
메시지 대기열 만들기
int msgget(key_t key, int msgflg);
반환값: 실패 -1, 성공 양의 정수인 대기열 식별자
메시지 대기열에 메시지 추가
int msgsnd(int msqid, const void *msg_ptr, size_t msg_sz, int msgflg);
메시지 대기열에서 메시지 갖어오기
int msgrcv(int msqid, void *msg_ptr, size_t msg_sz, long int msgtype, int msgflg);
메시지 대기열에서 메시지 제어
int msgctl(int msqid, int command, struct msqid_ds *buf);
command 맴버: IPC_STAT, IPC_STAT, IPC_RMID
반환값: 실패 -1, 성공 0
프로세스가 msgsnd 함수나 msgrcv 함수에서 기다리고 있는 동안 메시지 대기열을 삭제하면, 송신 함수나 수신 함수는 실패한다.
메시지 대기열 예: 762페이지 참조(사용자 1), 766페이지 참조(사용자 n
IPC 상태 명령
세마포어을 사용하여 개발한 프로그램이 세마포어을 삭제하지 않고 죽었을 경우 메모리에 찌꺼기가 남아서 위험하다. 그것을 확인할 수 있는 명령어는
세마포어 상태 보기 명령
$ ipcs - s
--- Semaphore Arrays ----
semid owner perms nsems status
768 rick 666 1
세마포어 죽이기(최신 리눅스)
$ ipcrm -s 768
세마포어 죽이기(오래된 리눅스)
$ ipcrm sem 768
공유 메모리 상태 보기 명령
$ ipcs -m
공유 메모리 죽이기
$ ipcrm -m <ID>
메시지 대기열 상태 보기 명령
$ ipcs -q
메시지 대기열 죽이기
$ ipcrm -q <ID>
================================================================================================================================================================
16Day Study
[[[[[소켓(Socket)]]]]]
소켓은 소켓 이름으로 /tmp나 /usr/tmp 에 저장이 된다
$ ls -lF
'기타 > 프로그래밍 관련' 카테고리의 다른 글
이클립스 overlaps the location of another project 에러 (309) | 2012.07.30 |
---|---|
JQuery, JQuery Moblie, JQTouch 차이 (0) | 2012.06.08 |
HTTP Header 분석 (0) | 2009.05.27 |
ctags & cscope 설치 및 사용 (1) | 2009.05.27 |
ctags를 이용한 VI에서 Go to Definition (0) | 2009.05.27 |