프로그래밍을 하다보면 좀 더 효율적으로 만들수 없을까 하는 생각이 든다
주로 C를 기반으로 설명해서 C언어를 알고 보는 것이 좋다.
언어 뿐이 아니라 소프트웨어의 효율적인 방법을 소개하는 것이라고 생각한다.
특히 몇몇 책은 나에게 큰 도움이 되었다.
몇몇 책은 도서관에서 빌려봤다가 소장하고 싶어서 구입한 책도 있다.
2014년 12월 15일 월요일
도서 추천 - 네트워크 편
맥/리눅스/윈도우를 다 사용했었지만 확실히 리눅스를 가장 적게 활용한 것 같다.
특히 리눅스는 그동안은 컴퓨터가 너무 느려서(듀얼코어 초창기 버전...;;)
가상 컴퓨터에 설치가 불가능 했다.(설치해도 엄청 느렸다)
듀얼부팅으로 설치도 해봤지만 확실히 윈도우에서 리눅스로 끄고 넘어간다는건 쉬운 일은 아니였다.....
이제는 컴퓨터도 최신이고(하스웰 5i)가상으로 리눅스 4개를 동시에 돌려서 실습해도 무리가 없었다.(우왕~)
그래서 이제야 네트워크 공부를 할 수 있는 기반이 마련되었다...;;
사설이 길었다. 책을 추천한다~
다 좋은 책인 것 같다. 각자 장단점이 있으니 서점에 가서 직접 보고 구입하는 것이 좋겠다.
특히 리눅스는 그동안은 컴퓨터가 너무 느려서(듀얼코어 초창기 버전...;;)
가상 컴퓨터에 설치가 불가능 했다.(설치해도 엄청 느렸다)
듀얼부팅으로 설치도 해봤지만 확실히 윈도우에서 리눅스로 끄고 넘어간다는건 쉬운 일은 아니였다.....
이제는 컴퓨터도 최신이고(하스웰 5i)가상으로 리눅스 4개를 동시에 돌려서 실습해도 무리가 없었다.(우왕~)
그래서 이제야 네트워크 공부를 할 수 있는 기반이 마련되었다...;;
사설이 길었다. 책을 추천한다~
도서 추천 - 프로그래밍에 도움이 되는 책들
프로그래밍 언어를 익히고 나니 프로그램을 효율적으로 만드는 법이 궁금했다.
내가 만든 프로그램이 너무 개판(?)이었기 때문이다.
그래서 알고리즘을 익히기 시작했다.
대딩 때 배우긴 했지만 수박 겉핣기로 배웠으니....;
아래 나열한 책들은 아직은 다 읽지는 못했다.
구입만 해논 상태다 ㅡㅡ;;(도서 정가제 시행 전에 급하게 구입 ㅋㅋ)
그래도 여기저기 커뮤니티에서 추천받은 책이다.
이중 본 책은 자료구조와 디자인 패턴 책이다.
내가 만든 프로그램이 너무 개판(?)이었기 때문이다.
그래서 알고리즘을 익히기 시작했다.
대딩 때 배우긴 했지만 수박 겉핣기로 배웠으니....;
아래 나열한 책들은 아직은 다 읽지는 못했다.
구입만 해논 상태다 ㅡㅡ;;(도서 정가제 시행 전에 급하게 구입 ㅋㅋ)
그래도 여기저기 커뮤니티에서 추천받은 책이다.
도서 추천 - 프로그램 언어 편
내가 읽어본 책 중에 괜찮았던 책을 추천해보고자 한다.
잠깐 쉬어가는 타임으로 추천하는거다 ㅡ.ㅡ;;
프로그램 언어 중 C/C++/C#/Java/델파이를 아래 책들로 공부했다.
프로그래밍 언어 책은 1권을 여러번 보는 것보다는 여러책을 보는 것을 추천한다
그 이유는 각 책마다 어떤 부분의 설명은 난해하고 어렵게 한 경우가 있다.
여러 책을 읽어보면 어려웠던 부분을 쉽게 이해하게 되었다.
물론 책값이 만만치 않아서 도서관에서 빌려서도 공부해 봤지만
2주만에 읽기엔 분량이 많아서 쉽지 않다.
개발자의 길을 걷기로 했으면 이 정도 책 투자는 해야한다고 생각한다.
이건 내 개인적인 생각이니 참고만 하길~
잠깐 쉬어가는 타임으로 추천하는거다 ㅡ.ㅡ;;
프로그램 언어 중 C/C++/C#/Java/델파이를 아래 책들로 공부했다.
그 이유는 각 책마다 어떤 부분의 설명은 난해하고 어렵게 한 경우가 있다.
여러 책을 읽어보면 어려웠던 부분을 쉽게 이해하게 되었다.
물론 책값이 만만치 않아서 도서관에서 빌려서도 공부해 봤지만
2주만에 읽기엔 분량이 많아서 쉽지 않다.
개발자의 길을 걷기로 했으면 이 정도 책 투자는 해야한다고 생각한다.
이건 내 개인적인 생각이니 참고만 하길~
2014년 12월 14일 일요일
TCP/IP 소켓 프로그래밍 10강
10-1 : 프로세스의 이해와 활용
10강은 리눅스에서 할 수 있는 멀티 프로세스 기반의 서버 구현이다.
일단 프로세스란 "메모리 공간을 차지한 상태에서 실행 중인 프로그램"이다.
단순히 하드디스크에 저장되어 있는 프로그램은 그저 파일에 불과하다
프로그램을 실행하면 하드->메모리로 올리는 과정이 로딩이고,
메모리로 올라오면 OS로부터 프로세스 ID를 부여 받는다.
이것을 Process ID = PID라고 불린다.
리눅스 상에서 pa au 명령어를 입력하면 현재 실행중인 프로세스를 확인할 수 있다.
PID는 2 이상의 정수 형태로 받는다.(1은 os에서 사용하는 프로세스에 부여된다)
그럼 이 프로세스를 복사하는 방법을 알아보자.
#include <unistd.h>
pid_t fork(void);
fork함수는 프로세스의 복사본을 생성한다. 이것을 복사하는 이유는 동일한 프로세서를 분리해서 실행시키기 위해서다.
하나는 입력을, 하나는 출력을 담당시켜서 부하를 줄이려는 것이다.
원본 프로세서는 부모 프로세서로, 복사된 프로세서는 자식 프로세스로 불리운다.
소스를 보자.
#include <stdio.h>
#include <unistd.h>
int gval=10;
int main(int argc, char *argv[])
{
pid_t pid;
int lval=20;
gval++, lval+=5;
//자식 프로세스를 생성하고 있다. 부모 프로세스의 pid에는
//자식 프로세스의 id가 저장 되며, 자식 프로세스의 pid에는 0이 저장된다.
pid=fork();
if(pid==0) // 자식 프로세스가 실행한다.
gval+=2, lval+=2;
else // 부모 프로세스가 실행한다.
gval-=2, lval-=2;
if(pid==0) //자식 프로세스가 실행한다.
printf("Child Proc: [%d, %d] \n", gval, lval);
else //부모 프로세스가 실행한다
printf("Parent Proc: [%d, %d] \n", gval, lval);
return 0;
}
10-2 : 프로세스 & 좀비 프로세스
프로세스의 복사는 위와 같고, 이제는 해제하는 법을 알아야 하는데 주의할 점이 있다.
잘못 해제하면 좀비 프로세스가 되어서 시스템의 리소스를 잡아 먹으며 죽지 않는 경우가 생긴다. (농담이 아니고 진짜 좀비 프로세서로 불리운다-_-;)
좀비 프로세스의 생성 이유
fork 함수로 생성된 자식 프로세스가 종료되는 상황은 2가지다.
-인자를 전달하면서 exit를 호출하는 경우
-main 함수에서 return 문을 실행하면서 값을 반환하는 경우
exit 함수로 전달되는 인자 값과 main함수의 return문에 의해 반환되는 값 모두
운영체제로 전달되는데, 운영체제는 이 값이 자식 프로세스를 생성한
부모 프로세스에게 전달될 때까지 자식 프로세스를 소멸시키지 않는다.
이 상황이 바로 좀비 프로세스다.
"해당 자식 프로세스를 생성한 부모 프로세스에게 exit함수의 인자 값이나 return문의 반환 값이 전달 되어야" 좀비 프로세스가 소멸 된다.
좀비 프로세스의 소멸 1 : wait 함수의 사용
#include <sys/with.h>
pid_t wait(int* statloc);
위 함수를 호출했을 때 이미 종료된 자식 프로세스가 있다면, 자식 프로세스가 종료되면서 전달한 값이 매게변수로 전달된 주소의 변수에 저장된다.
그런데 이 변수에 저장되는 값에는 자식 프로세스가 존료되면서 전달한 값 이외에도 다른 정보가 함께 포함되어 있으니, 다음 매크로 함수를 통해서 값의 분리 과정을 거쳐야 한다.
-WIFEXITED : 자식 프로세스가 정상 종료한 경우 (TRUE)를 반환한다.
-WEXITSTATUS : 자식 프로세스의 전달 값을 반환한다.
예제를 보자.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
int status;
pid_t pid=fork();
if(pid==0)
{
return 3;
}
else
{
printf("Child PID: %d \n", pid);
pid=fork();
if(pid==0)
{
exit(7);
}
else
{
printf("Child PID: %d \n", pid);
//wait 함수를 호출하고 이로 인해 종료된 프로세스 관련 정보는 status에 담기게 되고,
//해당 정보의 프로세스는 완전히 소멸된다.
wait(&status);
//WIFEXITED를 통해 자식 프로세스의 정상종료 여부를 확인한다.
//그리고 정상 종료인 경우에 한해서
//WEXITSTATUS 함수를 호출해서 자식 프로세스가 전달한 값을 출력한다.
if(WIFEXITED(status))
printf("Child send one: %d \n", WEXITSTATUS(status));
//앞서 생성한 자식 프로세스가 두 개이므로 또 한번의 wait 함수호출과 매크로 함수의 호출한다.
wait(&status);
if(WIFEXITED(status))
printf("Child send two: %d \n", WEXITSTATUS(status));
//부모 프로세스의 종료를 멈추기 위해서 삽입한 코드
sleep(30); // Sleep 30 sec.
}
}
return 0;
}
wait 함수는 호출된 시점에서 종료된 자식 프로세스가 없다면 임의의 자식 프로세스가 종료될 때까지 블로킹 상태에 놓인다는 특징이 있다. 때문에 함수의 호출에 주의해야 한다.
좀비 프로세스의 소멸2: waitpid 함수의 사용
wait함수의 블로킹이 문제가 된다면 waitpid 함수의 호출을 사용하면 된다.
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int* statloc, int options);
-pid : 종료를 확인하고자는 자식 프로세스의 id전달, 이를 대신해서 -1을 전달하면 wait함수와 마찬가지로 임의의 자식 프로세스가 종료되기를 기다린다.
-statloc : wait 함수의 매개변수 statloc와 동일한 의미로 사용된다.
-options : 헤더파일 sys/wait.h에 선언된 상수 WNOHANG을 인자로 전달, 종료된 자식 프로세스가 존재하지도 않아도 블로킹 상태에 있지 않고, 0을 반환하면서 함수를 빠져나온다.
예제를 보자.
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
int status;
pid_t pid=fork();
if(pid==0)
{
sleep(15); //자식 프로세스의 종료를 늦추기 위해 호출
return 24;
}
else
{
//while문 내에서 waitpid를 호출하고 있다. 세 번째 인자로 WNOHANG을 전달하였으니 종료된 자식 프로세스가 없으면 0을 반환한다.
while(!waitpid(-1, &status, WNOHANG))
{
sleep(3);
puts("sleep 3sec.");
}
if(WIFEXITED(status))
printf("Child send %d \n", WEXITSTATUS(status));
}
return 0;
}
10-3 시그널 핸들링
위의 예제의 문제는 자식 프로세스가 종료될 때까지 waitpid 함수를 계속 호출해야 한다.
이건 낭비다. 이 문제를 해결하는 법을 보자.
어차피 자식 프로세스가 종료 되었다는 것을 아는 건 운영체제다.
그럼 운영체제가 부모 프로세스에게 자식 프로세스가 종료되었다는 것을 알려준다면
부모 프로세스가 자식 프로세스를 죽일 것이다.(부모가 자식을 킬....)
이러한 프로그램 구현을 위해 '시그널 핸들링'이라는 것이 존재한다.
시그널은 특정 상황이 발생했음을 알리기 위해 운영체제가 프로세스에게 전달하는 메세지다.
시그널을 운영체제에게 등록하는 함수를 보자
#include <signal.h>
void (*signal(int signo, void (*func)(int)))(int);
-시그널 발생시 호출되도록 이전에 등록된 함수의 포인터 반환
위 함수는 반환형이 함수 포인터라 선언이 좀 다르다.
(void*) signal(int signo, (void*)func(int)) (int);
위와 같이 표현해도 될 것이다.
-함수 이름: signal
-매개변수 선언 : int sinno, (void*)func(int)
-반환형 : 매개변수형이 int이고 반환형이 void인 함수 포인터
signal 함수를 통해서 등록가능한 특정 상황과 그 상황에 할당된 상수를 몇개 보자
-SIGALRM : alarm 함수 호출을 통해서 등록된 시간이 된 상황
-SIGINT : 컨트롤 + C가 입력된 상황
-SIGCHLD : 자식 프로세스가 종료된 상황
//alarm함수 호출을 통해서 등록된 시간이 지나면 timeout 함수를 호출해달라.
signal(SIGALRM, timeout);
//컨트롤 +C가 입렫되면 keycontrol 함수를 호출해달라.
singnal(SIGINT, keycontrol);
alarm 함수
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
위 함수를 호출하면서 양의 정수를 인자로 전달하면, 전달한 수에 해당하는 시간이 지나서 SINALRM 시그널이 발생한다. 그리고 0을 전달하면 이전에 설정된 시그널 발생의 예약이 취소된다.
sigaction 함수를 이용한 시그널 핸들링
#include <singnal.h>
int sigaction(int signo, const struct singaction * act, struct sigaction * oldact);
-sinno : signal 함수와 마찬가지로 시그널의 정보를 인자로 전달
-act : 첫번째 인자로 전달된 상수에 해당하는 시그널 발생시 호출될 함수의 정보 전달
-oldact : 이전에 등록되었던 시그널 핸들러의 함수 포인터를 얻는데 사용되는 인자, 필요 없으면 0 전달
위 함수들을 이용해서 다중 접속 서버를 구현한 소스가 있는데
여기에 기재하기엔 길다 ㅡ.ㅡ;
그래서 역시 소스를 다운 받아서 직접 실행해보는 것이 좋다.
소스 다운 받기
희안하게 책만 읽었을 때는 이해가 안가고, 소스코드를 실행시켜 보면 조금 이해가 가고,
블로그에 정리해서 올리면 더 많이 이해가 간다.
이 블로그에 기재하는 이유가 나 스스로가 이해력을 높이기 위한 것도 있다.
여기에 동영상 강의까지 들으면 완전(?) 이해가 될 듯하다.
아직 동영상 강의를 10강까지는 듣지 못했다.
프로그래밍 공부는 직접 해보는 것이 가장 좋은 듯하다.
그래서 블로그에 기재할 때는 중요 함수만 나열하려고 한다.
전에 쓴 것을 보니 내가 봐도 난잡하다 -_-;
기억나지 않을 때 찾아보는 용도로나 할려고 한다.
10강은 리눅스에서 할 수 있는 멀티 프로세스 기반의 서버 구현이다.
일단 프로세스란 "메모리 공간을 차지한 상태에서 실행 중인 프로그램"이다.
단순히 하드디스크에 저장되어 있는 프로그램은 그저 파일에 불과하다
프로그램을 실행하면 하드->메모리로 올리는 과정이 로딩이고,
메모리로 올라오면 OS로부터 프로세스 ID를 부여 받는다.
이것을 Process ID = PID라고 불린다.
리눅스 상에서 pa au 명령어를 입력하면 현재 실행중인 프로세스를 확인할 수 있다.
PID는 2 이상의 정수 형태로 받는다.(1은 os에서 사용하는 프로세스에 부여된다)
그럼 이 프로세스를 복사하는 방법을 알아보자.
#include <unistd.h>
pid_t fork(void);
fork함수는 프로세스의 복사본을 생성한다. 이것을 복사하는 이유는 동일한 프로세서를 분리해서 실행시키기 위해서다.
하나는 입력을, 하나는 출력을 담당시켜서 부하를 줄이려는 것이다.
원본 프로세서는 부모 프로세서로, 복사된 프로세서는 자식 프로세스로 불리운다.
소스를 보자.
#include <stdio.h>
#include <unistd.h>
int gval=10;
int main(int argc, char *argv[])
{
pid_t pid;
int lval=20;
gval++, lval+=5;
//자식 프로세스를 생성하고 있다. 부모 프로세스의 pid에는
//자식 프로세스의 id가 저장 되며, 자식 프로세스의 pid에는 0이 저장된다.
pid=fork();
if(pid==0) // 자식 프로세스가 실행한다.
gval+=2, lval+=2;
else // 부모 프로세스가 실행한다.
gval-=2, lval-=2;
if(pid==0) //자식 프로세스가 실행한다.
printf("Child Proc: [%d, %d] \n", gval, lval);
else //부모 프로세스가 실행한다
printf("Parent Proc: [%d, %d] \n", gval, lval);
return 0;
}
10-2 : 프로세스 & 좀비 프로세스
프로세스의 복사는 위와 같고, 이제는 해제하는 법을 알아야 하는데 주의할 점이 있다.
잘못 해제하면 좀비 프로세스가 되어서 시스템의 리소스를 잡아 먹으며 죽지 않는 경우가 생긴다. (농담이 아니고 진짜 좀비 프로세서로 불리운다-_-;)
좀비 프로세스의 생성 이유
fork 함수로 생성된 자식 프로세스가 종료되는 상황은 2가지다.
-인자를 전달하면서 exit를 호출하는 경우
-main 함수에서 return 문을 실행하면서 값을 반환하는 경우
exit 함수로 전달되는 인자 값과 main함수의 return문에 의해 반환되는 값 모두
운영체제로 전달되는데, 운영체제는 이 값이 자식 프로세스를 생성한
부모 프로세스에게 전달될 때까지 자식 프로세스를 소멸시키지 않는다.
이 상황이 바로 좀비 프로세스다.
"해당 자식 프로세스를 생성한 부모 프로세스에게 exit함수의 인자 값이나 return문의 반환 값이 전달 되어야" 좀비 프로세스가 소멸 된다.
좀비 프로세스의 소멸 1 : wait 함수의 사용
#include <sys/with.h>
pid_t wait(int* statloc);
위 함수를 호출했을 때 이미 종료된 자식 프로세스가 있다면, 자식 프로세스가 종료되면서 전달한 값이 매게변수로 전달된 주소의 변수에 저장된다.
그런데 이 변수에 저장되는 값에는 자식 프로세스가 존료되면서 전달한 값 이외에도 다른 정보가 함께 포함되어 있으니, 다음 매크로 함수를 통해서 값의 분리 과정을 거쳐야 한다.
-WIFEXITED : 자식 프로세스가 정상 종료한 경우 (TRUE)를 반환한다.
-WEXITSTATUS : 자식 프로세스의 전달 값을 반환한다.
예제를 보자.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
int status;
pid_t pid=fork();
if(pid==0)
{
return 3;
}
else
{
printf("Child PID: %d \n", pid);
pid=fork();
if(pid==0)
{
exit(7);
}
else
{
printf("Child PID: %d \n", pid);
//wait 함수를 호출하고 이로 인해 종료된 프로세스 관련 정보는 status에 담기게 되고,
//해당 정보의 프로세스는 완전히 소멸된다.
wait(&status);
//WIFEXITED를 통해 자식 프로세스의 정상종료 여부를 확인한다.
//그리고 정상 종료인 경우에 한해서
//WEXITSTATUS 함수를 호출해서 자식 프로세스가 전달한 값을 출력한다.
if(WIFEXITED(status))
printf("Child send one: %d \n", WEXITSTATUS(status));
//앞서 생성한 자식 프로세스가 두 개이므로 또 한번의 wait 함수호출과 매크로 함수의 호출한다.
wait(&status);
if(WIFEXITED(status))
printf("Child send two: %d \n", WEXITSTATUS(status));
//부모 프로세스의 종료를 멈추기 위해서 삽입한 코드
sleep(30); // Sleep 30 sec.
}
}
return 0;
}
wait 함수는 호출된 시점에서 종료된 자식 프로세스가 없다면 임의의 자식 프로세스가 종료될 때까지 블로킹 상태에 놓인다는 특징이 있다. 때문에 함수의 호출에 주의해야 한다.
좀비 프로세스의 소멸2: waitpid 함수의 사용
wait함수의 블로킹이 문제가 된다면 waitpid 함수의 호출을 사용하면 된다.
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int* statloc, int options);
-pid : 종료를 확인하고자는 자식 프로세스의 id전달, 이를 대신해서 -1을 전달하면 wait함수와 마찬가지로 임의의 자식 프로세스가 종료되기를 기다린다.
-statloc : wait 함수의 매개변수 statloc와 동일한 의미로 사용된다.
-options : 헤더파일 sys/wait.h에 선언된 상수 WNOHANG을 인자로 전달, 종료된 자식 프로세스가 존재하지도 않아도 블로킹 상태에 있지 않고, 0을 반환하면서 함수를 빠져나온다.
예제를 보자.
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
int status;
pid_t pid=fork();
if(pid==0)
{
sleep(15); //자식 프로세스의 종료를 늦추기 위해 호출
return 24;
}
else
{
//while문 내에서 waitpid를 호출하고 있다. 세 번째 인자로 WNOHANG을 전달하였으니 종료된 자식 프로세스가 없으면 0을 반환한다.
while(!waitpid(-1, &status, WNOHANG))
{
sleep(3);
puts("sleep 3sec.");
}
if(WIFEXITED(status))
printf("Child send %d \n", WEXITSTATUS(status));
}
return 0;
}
10-3 시그널 핸들링
위의 예제의 문제는 자식 프로세스가 종료될 때까지 waitpid 함수를 계속 호출해야 한다.
이건 낭비다. 이 문제를 해결하는 법을 보자.
어차피 자식 프로세스가 종료 되었다는 것을 아는 건 운영체제다.
그럼 운영체제가 부모 프로세스에게 자식 프로세스가 종료되었다는 것을 알려준다면
부모 프로세스가 자식 프로세스를 죽일 것이다.(부모가 자식을 킬....)
이러한 프로그램 구현을 위해 '시그널 핸들링'이라는 것이 존재한다.
시그널은 특정 상황이 발생했음을 알리기 위해 운영체제가 프로세스에게 전달하는 메세지다.
시그널을 운영체제에게 등록하는 함수를 보자
#include <signal.h>
void (*signal(int signo, void (*func)(int)))(int);
-시그널 발생시 호출되도록 이전에 등록된 함수의 포인터 반환
위 함수는 반환형이 함수 포인터라 선언이 좀 다르다.
(void*) signal(int signo, (void*)func(int)) (int);
위와 같이 표현해도 될 것이다.
-함수 이름: signal
-매개변수 선언 : int sinno, (void*)func(int)
-반환형 : 매개변수형이 int이고 반환형이 void인 함수 포인터
signal 함수를 통해서 등록가능한 특정 상황과 그 상황에 할당된 상수를 몇개 보자
-SIGALRM : alarm 함수 호출을 통해서 등록된 시간이 된 상황
-SIGINT : 컨트롤 + C가 입력된 상황
-SIGCHLD : 자식 프로세스가 종료된 상황
//alarm함수 호출을 통해서 등록된 시간이 지나면 timeout 함수를 호출해달라.
signal(SIGALRM, timeout);
//컨트롤 +C가 입렫되면 keycontrol 함수를 호출해달라.
singnal(SIGINT, keycontrol);
alarm 함수
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
위 함수를 호출하면서 양의 정수를 인자로 전달하면, 전달한 수에 해당하는 시간이 지나서 SINALRM 시그널이 발생한다. 그리고 0을 전달하면 이전에 설정된 시그널 발생의 예약이 취소된다.
sigaction 함수를 이용한 시그널 핸들링
#include <singnal.h>
int sigaction(int signo, const struct singaction * act, struct sigaction * oldact);
-sinno : signal 함수와 마찬가지로 시그널의 정보를 인자로 전달
-act : 첫번째 인자로 전달된 상수에 해당하는 시그널 발생시 호출될 함수의 정보 전달
-oldact : 이전에 등록되었던 시그널 핸들러의 함수 포인터를 얻는데 사용되는 인자, 필요 없으면 0 전달
위 함수들을 이용해서 다중 접속 서버를 구현한 소스가 있는데
여기에 기재하기엔 길다 ㅡ.ㅡ;
그래서 역시 소스를 다운 받아서 직접 실행해보는 것이 좋다.
소스 다운 받기
희안하게 책만 읽었을 때는 이해가 안가고, 소스코드를 실행시켜 보면 조금 이해가 가고,
블로그에 정리해서 올리면 더 많이 이해가 간다.
이 블로그에 기재하는 이유가 나 스스로가 이해력을 높이기 위한 것도 있다.
여기에 동영상 강의까지 들으면 완전(?) 이해가 될 듯하다.
아직 동영상 강의를 10강까지는 듣지 못했다.
프로그래밍 공부는 직접 해보는 것이 가장 좋은 듯하다.
그래서 블로그에 기재할 때는 중요 함수만 나열하려고 한다.
전에 쓴 것을 보니 내가 봐도 난잡하다 -_-;
기억나지 않을 때 찾아보는 용도로나 할려고 한다.
2014년 12월 12일 금요일
TCP/IP 소켓 프로그래밍 9강
이번 강은 소켓의 다양한 옵션을 알아보자.
다음 표를 보자. 출처 : 윤성우 TCP/IP소켓 프로그래밍
표만 봐서는 뭐가 뭔지 하나도 모르겠다.
하지만 Get, Set 가 있다.
참조(Get) 및 변경(Set)에 쓰는 함수를 보자
#include <sys/socket.h>
int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen);
-sock : 옵션확인을 위한 소켓의 파일 디스크립터 전달
-level : 확인할 옵션의 프로토콜 레벨 전달.
-optname : 확인할 옵션의 이름 전달.
-optval : 확인결과의 저장을 위한 버퍼의 주소 값 전달.
-optlen : optval로 전달된 주소 값의 버퍼크기를 담고 있는 변수의 주소 값 전달
#include <sys/socket.h>
int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);
-sock : 옵션확인을 위한 소켓의 파일 디스크립터 전달
-level : 변경할 옵션의 프로토콜 레벨 전달.
-optname : 변경할 옵션의 이름 전달.
-optval : 변경할 옵션정보를 저장한 버퍼의 주소 값 전달.
-optlen : optval로 전달된 옵션정보의 바이트 단위 크기 전달.
이 강에는 여러 옵션을 설명하다보니 소스가 많이 나온다.
이걸 여기에 다 기록하기엔 양이 많으니
직접 소스를 다운 받아서 해보는게 가장 좋을 것 같다.
소스 다운 받기
Nagle 알고리즘을 알아보자.
일단 그림을 보자. 역시 출처는 "윤성우 TCP/IP 소켓 프로그래밍" 이다.
기본적으로 TCP 소켓에서는 Nagle 알고리즘을 적용해서 데이터를 송수신한다.
이 알고리즘을 적용하지 않으면 지나치게 네트워크 트래픽이 높아질 수 있다.
하지만 항상 이 알고리즘이 좋은 것은 아니다.
용량이 큰 파일데이터의 전송에는 이 알고리즘을 끄고 전송하는 것이 더 좋다.
그러니 전송할 데이터의 특성을 알고 알고리즘을 선택해야 할 것이다.
새벽에 졸음을 쫒아가며 쓰다 보니 너무 대충 쓴다는 생각이 든다 ㅡㅡ;;
10강에는 멀티프로세스를 이용한 서버 구현을 해보겠다.
다음 표를 보자. 출처 : 윤성우 TCP/IP소켓 프로그래밍
표만 봐서는 뭐가 뭔지 하나도 모르겠다.
하지만 Get, Set 가 있다.
참조(Get) 및 변경(Set)에 쓰는 함수를 보자
#include <sys/socket.h>
int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen);
-sock : 옵션확인을 위한 소켓의 파일 디스크립터 전달
-level : 확인할 옵션의 프로토콜 레벨 전달.
-optname : 확인할 옵션의 이름 전달.
-optval : 확인결과의 저장을 위한 버퍼의 주소 값 전달.
-optlen : optval로 전달된 주소 값의 버퍼크기를 담고 있는 변수의 주소 값 전달
#include <sys/socket.h>
int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);
-sock : 옵션확인을 위한 소켓의 파일 디스크립터 전달
-level : 변경할 옵션의 프로토콜 레벨 전달.
-optname : 변경할 옵션의 이름 전달.
-optval : 변경할 옵션정보를 저장한 버퍼의 주소 값 전달.
-optlen : optval로 전달된 옵션정보의 바이트 단위 크기 전달.
이 강에는 여러 옵션을 설명하다보니 소스가 많이 나온다.
이걸 여기에 다 기록하기엔 양이 많으니
직접 소스를 다운 받아서 해보는게 가장 좋을 것 같다.
소스 다운 받기
Nagle 알고리즘을 알아보자.
일단 그림을 보자. 역시 출처는 "윤성우 TCP/IP 소켓 프로그래밍" 이다.
기본적으로 TCP 소켓에서는 Nagle 알고리즘을 적용해서 데이터를 송수신한다.
이 알고리즘을 적용하지 않으면 지나치게 네트워크 트래픽이 높아질 수 있다.
하지만 항상 이 알고리즘이 좋은 것은 아니다.
용량이 큰 파일데이터의 전송에는 이 알고리즘을 끄고 전송하는 것이 더 좋다.
그러니 전송할 데이터의 특성을 알고 알고리즘을 선택해야 할 것이다.
새벽에 졸음을 쫒아가며 쓰다 보니 너무 대충 쓴다는 생각이 든다 ㅡㅡ;;
10강에는 멀티프로세스를 이용한 서버 구현을 해보겠다.
2014년 12월 11일 목요일
TCP/IP 소켓 프로그래밍 8강
목표가 올해안에 22강까지 공부하는 건데.
7강이 짧아서 8강까지 공부했다 ㅎㅎ
8강은 DNS에 대해 알아본다
DNS는 (Domain Name System)이다.
도메인 이름 <-> IP주소 를 변환 시켜주는 시스템이다.
모든 컴퓨터에는 디폴트 DNS 서버의 주소가 등록되어 있는데,
먼저 이 디폴트 DNS서버를 통해 IP주소를 받고,
여기에 없으면 상위 DNS 서버로 올라가서 다른 DNS 서버에서 IP주소를 받아와서 알려준다.
소켓 프로그래밍을 하기 위해서는 IP주소와 포트 번호를 알아야 하는데
문제는 이 IP주소가 자주 바뀐다는 것이다.
이 바뀌는 IP를 계속 찾아서 프로그램에 넣을 수도 없는 노릇이니
서비스가 망하지 않는한 바뀌지 않는 도메인 주소를 가지고 프로그래밍을 하는 것이 합당할 것이다.
그럴려면 도메인 이름 -> IP주소로 변환시켜주는 함수가 필요하다.
#include <netdb.h>
struct hosttent *gethostbyname(const char* hostname);
변환하고자 하는 도메인의 이름을 문자열 형태로 전달하면 해당 도메인의 IP주소를 반환한다
단, 구조체에 담겨서 반환이 되니 구조체를 알아보자.
struct hostnet
{
char* h_name; //공식 도메인 이름
char** h_aliases; //하나의 IP로 접속 가능한 다른 도메인의 이름
int h_addrtype; //IPv4, IPv6 같은 주소 체계를 저장
int h_length; //IP 주소의 크기 정보
char** h_addr_list; //도메인 이름에 대한 IP주소 저장
}
소스를 보자
int main(int argc, char *argv[])
{
int i;
struct hostent *host;
if(argc!=2) {
printf("Usage : %s <addr>\n", argv[0]);
exit(1);
}
//main 함수를 통해서 전달 된 문자열을 인자로 gethostbyname함수 호출
host=gethostbyname(argv[1]);
if(!host)
error_handling("gethost... error");
//공식 도메인을 출력한다.
printf("Official name: %s \n", host->h_name);
for(i=0; host->h_aliases[i]; i++)
printf("Aliases %d: %s \n", i+1, host->h_aliases[i]);
//ip주소 타입
printf("Address type: %s \n",
(host->h_addrtype==AF_INET)?"AF_INET":"AF_INET6");
//ip주소 정보 출력
for(i=0; host->h_addr_list[i]; i++)
printf("IP addr %d: %s \n", i+1,
inet_ntoa(*(struct in_addr*)host->h_addr_list[i]));
return 0;
}
이번에는 반대로 IP주소 -> 도메인 주소를 알려주는 함수다.
#include <netdb.h>
struct hostent* gethostbyaddr(const char* addr, socklen_t len, int family);
-addr : ip주소를 지나는 in_addr 구조체 변수의 포인터 전달, IPv4 이외의 다양한 정보를 전달 받을 수 있도록 일반화 하기 위해서 매개변수를 char형 포인터로 선언
-len : 첫 번째 인자로 전달된 주소 정보의 길이, IPv4의 경우 4, IPv6의 경우 16을 전달.
-family : 주소체계 정보 전달, IPv4의 경우 AF_INET, IPv6의 경우 AF_INET6 전달.
소스를 보자.
int main(int argc, char *argv[])
{
int i;
struct hostent *host;
struct sockaddr_in addr;
if(argc!=2) {
printf("Usage : %s <IP>\n", argv[0]);
exit(1);
}
memset(&addr, 0, sizeof(addr));
addr.sin_addr.s_addr=inet_addr(argv[1]);
//IP -> 도메인으로 변환하는 함수
host=gethostbyaddr((char*)&addr.sin_addr, 4, AF_INET);
if(!host)
error_handling("gethost... error");
printf("Official name: %s \n", host->h_name);
for(i=0; host->h_aliases[i]; i++)
printf("Aliases %d: %s \n", i+1, host->h_aliases[i]);
printf("Address type: %s \n",
(host->h_addrtype==AF_INET)?"AF_INET":"AF_INET6");
for(i=0; host->h_addr_list[i]; i++)
printf("IP addr %d: %s \n", i+1,
inet_ntoa(*(struct in_addr*)host->h_addr_list[i]));
return 0;
}
위 2개 함수는 윈도우에서도 동일하다.
역시 소스 코드를 받아서 확인해보자.
소스 코드 받기
다음 강에는 소켓의 다양한 옵션에 대해 알아볼 것이다~
7강이 짧아서 8강까지 공부했다 ㅎㅎ
8강은 DNS에 대해 알아본다
DNS는 (Domain Name System)이다.
도메인 이름 <-> IP주소 를 변환 시켜주는 시스템이다.
모든 컴퓨터에는 디폴트 DNS 서버의 주소가 등록되어 있는데,
먼저 이 디폴트 DNS서버를 통해 IP주소를 받고,
여기에 없으면 상위 DNS 서버로 올라가서 다른 DNS 서버에서 IP주소를 받아와서 알려준다.
소켓 프로그래밍을 하기 위해서는 IP주소와 포트 번호를 알아야 하는데
문제는 이 IP주소가 자주 바뀐다는 것이다.
이 바뀌는 IP를 계속 찾아서 프로그램에 넣을 수도 없는 노릇이니
서비스가 망하지 않는한 바뀌지 않는 도메인 주소를 가지고 프로그래밍을 하는 것이 합당할 것이다.
그럴려면 도메인 이름 -> IP주소로 변환시켜주는 함수가 필요하다.
#include <netdb.h>
struct hosttent *gethostbyname(const char* hostname);
변환하고자 하는 도메인의 이름을 문자열 형태로 전달하면 해당 도메인의 IP주소를 반환한다
단, 구조체에 담겨서 반환이 되니 구조체를 알아보자.
struct hostnet
{
char* h_name; //공식 도메인 이름
char** h_aliases; //하나의 IP로 접속 가능한 다른 도메인의 이름
int h_addrtype; //IPv4, IPv6 같은 주소 체계를 저장
int h_length; //IP 주소의 크기 정보
char** h_addr_list; //도메인 이름에 대한 IP주소 저장
}
소스를 보자
int main(int argc, char *argv[])
{
int i;
struct hostent *host;
if(argc!=2) {
printf("Usage : %s <addr>\n", argv[0]);
exit(1);
}
//main 함수를 통해서 전달 된 문자열을 인자로 gethostbyname함수 호출
host=gethostbyname(argv[1]);
if(!host)
error_handling("gethost... error");
//공식 도메인을 출력한다.
printf("Official name: %s \n", host->h_name);
for(i=0; host->h_aliases[i]; i++)
printf("Aliases %d: %s \n", i+1, host->h_aliases[i]);
//ip주소 타입
printf("Address type: %s \n",
(host->h_addrtype==AF_INET)?"AF_INET":"AF_INET6");
//ip주소 정보 출력
for(i=0; host->h_addr_list[i]; i++)
printf("IP addr %d: %s \n", i+1,
inet_ntoa(*(struct in_addr*)host->h_addr_list[i]));
return 0;
}
이번에는 반대로 IP주소 -> 도메인 주소를 알려주는 함수다.
#include <netdb.h>
struct hostent* gethostbyaddr(const char* addr, socklen_t len, int family);
-addr : ip주소를 지나는 in_addr 구조체 변수의 포인터 전달, IPv4 이외의 다양한 정보를 전달 받을 수 있도록 일반화 하기 위해서 매개변수를 char형 포인터로 선언
-len : 첫 번째 인자로 전달된 주소 정보의 길이, IPv4의 경우 4, IPv6의 경우 16을 전달.
-family : 주소체계 정보 전달, IPv4의 경우 AF_INET, IPv6의 경우 AF_INET6 전달.
소스를 보자.
int main(int argc, char *argv[])
{
int i;
struct hostent *host;
struct sockaddr_in addr;
if(argc!=2) {
printf("Usage : %s <IP>\n", argv[0]);
exit(1);
}
memset(&addr, 0, sizeof(addr));
addr.sin_addr.s_addr=inet_addr(argv[1]);
//IP -> 도메인으로 변환하는 함수
host=gethostbyaddr((char*)&addr.sin_addr, 4, AF_INET);
if(!host)
error_handling("gethost... error");
printf("Official name: %s \n", host->h_name);
for(i=0; host->h_aliases[i]; i++)
printf("Aliases %d: %s \n", i+1, host->h_aliases[i]);
printf("Address type: %s \n",
(host->h_addrtype==AF_INET)?"AF_INET":"AF_INET6");
for(i=0; host->h_addr_list[i]; i++)
printf("IP addr %d: %s \n", i+1,
inet_ntoa(*(struct in_addr*)host->h_addr_list[i]));
return 0;
}
위 2개 함수는 윈도우에서도 동일하다.
역시 소스 코드를 받아서 확인해보자.
소스 코드 받기
다음 강에는 소켓의 다양한 옵션에 대해 알아볼 것이다~
피드 구독하기:
덧글 (Atom)

































