반응형

http://mycpp.blog.me/120095872757

'language > C' 카테고리의 다른 글

소스 정적분석 툴  (0) 2018.06.29
형식지정자 (printf, sprintf 숫자, 문자 출력)  (0) 2016.08.09
time 함수  (0) 2015.04.21
C 언어와 C++ 언어에서 const 처리  (0) 2015.03.16
long long 입출력 관련  (0) 2015.01.28
반응형

http://itguru.tistory.com/113

http://s2kiess.blog.me/220147400129

'language > C' 카테고리의 다른 글

형식지정자 (printf, sprintf 숫자, 문자 출력)  (0) 2016.08.09
[C언어] open flag  (0) 2015.07.14
C 언어와 C++ 언어에서 const 처리  (0) 2015.03.16
long long 입출력 관련  (0) 2015.01.28
2차원 배열 크기 구하기  (0) 2013.01.15
반응형
http://iamaman.tistory.com/trackback/1175

 

반응형
https://kldp.org/node/68231

 

'language > C' 카테고리의 다른 글

[C언어] open flag  (0) 2015.07.14
time 함수  (0) 2015.04.21
long long 입출력 관련  (0) 2015.01.28
2차원 배열 크기 구하기  (0) 2013.01.15
printf format string  (0) 2012.01.18
반응형

.bashrc에 아래와 같은 방법으로 원하는 내용을 추가한다.(ubuntu에서 했음)

LS_COLORS='d1=01;33'

 

출처:

http://blog.naver.com/kamakaru?Redirect=Log&logNo=50020998094

http://tuwlab.com/ece/10547

http://egloos.zum.com/sunyzero/v/4282610

반응형

출처: http://ko.m.wikibooks.org/wiki/C_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D_%EC%9E%85%EB%AC%B8/%EC%A0%95%EC%88%98%ED%98%95_%EB%8D%B0%EC%9D%B4%ED%84%B0

 

 

C 프로그래밍 입문/정수형 데이터

  • 이 문서 주시

 

정수형 데이터편집

C 에서 가장 많이 다루는 데이터 형태는 정수형이고, 그만큼 데이터 타입도 다양하다. 먼저 C 정수형 데이터의 기본 데이터를 확인해 보도록 하자:

타입 바이트수 최소값/최대값 limits.h 상수 접미사 비고
(signed) short (int)
unsigned short (int)
2 -32768 - 32767
0 - 65535
SHRT_MIN, SHRT_MAX
USHRT_MAX
(signed) int
unsigned (int)
4* -2147483648 - 2147483647
0 - 4294967295
INT_MIN, INT_MAX
UINT_MAX

U
(signed) long (int)
unsigned long (int)
4** -2147483648 - 2147483647
0 - 4294967295
LONG_MIN, LONG_MAX
ULONG_MAX
L
UL
(signed) long long (int)
unsigned long long (int)
8 -9223372036854775808 - 9223372036854775807
0 - 18446744073709551615
LONG_LONG_MIN, LONG_LONG_MAX
ULONG_LONG_MAX
LL
ULL

*, **: 이 크기는 컴파일러에 따라 달라집니다. 이 아래에 자세한 내용을 설명하였습니다.
표의 타입에 괄호가 쳐진 것은 원래 있어야 하는 내용이지만 생략이 가능하고 보통은 생략하여 사용한다는 뜻 입니다. 예를 들어 unsinged int 타입은 그냥 unsinged 로 사용할 수 있습니다.


정수 타입의 데이터는 많은 변화를 거쳐왔기 때문에 약간의 혼동의 여지가 있다. 먼저 int 타입이 있는데, 이 int 타입은 가장 효율적으로 처리될 수 있는 정수타입이라는 의미이다. 문제는 효율적으로 처리라는 문구에서 시작되는데, 이 이야기를 하기 전에 먼저 해야할 이야기가 하나 있다.

위에서 설명했듯이 컴퓨터를 분류하는 방법 중에는 n 비트 컴퓨터 - 8비트 컴퓨터, 16비트 컴퓨터 등등 - 라는 표현이 있고, 이 n 비트 컴퓨터라는 말의 기본적인 정의는 n 비트 단위로 데이터를 처리하는 컴퓨터라는 뜻이다. 다른 표현을 사용 한다면 8비트 컴퓨터는 데이터를 처리할 때 8비트씩 읽어들여서 처리 하고, 16비트 컴퓨터는 16비트씩 읽어서 처리 한다는 뜻이다. 의미 상으로는 16비트 데이터를 처리할 때 8비트 컴퓨터는 두 번 일을 해야 하고, 16비트 컴퓨터는 한 번만 해도 된다는 의미로, 수치적으로는 16비트 컴퓨터의 속도가 8비트 컴퓨터의 두 배 빠른 컴퓨터 라는 의미 이다[1].

다시 int 타입에 대해서 이야기 하자면, int 타입은 '가장 효율적으로 처리될 수 있는 정수 타입'이기 때문에 16비트 컴퓨터에서는 16비트, 그러니까 2바이트일 때 가장 효율적이므로 int 타입의 크기는 2바이트 이다. 그리고 32 비트 컴퓨터 일 땐 32비트 즉, 4 바이트일 때 가장 효율적으로 32비트 컴퓨터에서는 int 타입의 크기는 4 바이트가 된다. 그래서 8 비트 컴퓨터나 16비트 컴퓨터의 int 타입은 short int 와 동일한 데이터 타입이 되고, 32비트 컴퓨터의 int 타입은 long int와 동일한 데이터 타입이 된다.

문제는 64비트 컴퓨터가 대두 되었을 때 발생 하였는데, int 타입을 64비트로 잡아주면 long int가 int 보다 다룰 수 있는 데이터의 크기가 적어지는 모순이 생기게 되었다. 그래서 64비트 컴퓨터에서는 int를 32비트로 쓰고 long int를 64비트를 쓰는 경우와, int와 long int 모두를 32비트 컴퓨터와 동일하게 32비트를 쓰고, long long int 라는 새로운 64비트 타입을 도입한 경우가 있다.

일단 위의 표는 C99에서 제시한 표준에 따라 작성되었으며, 상황에 따라서는 위의 표와 다른 경우가 있을 수 도 있다는 것을 알려두기 위해서 위의 내용을 기술하였다.

정수형 상수는 기본적으로 int 타입으로 간주되며 short 타입을 강제하는 접미사는 없다. unsigned 타입의 상수임을 명기 하기 위해서는 u나 U를 사용하면 된다. 예를 들어 그냥 '1'이라고 상수를 사용하면 signed int 타입이 되지만, '1U'혹은 '1u'라 표기하면 unsigned int 타입의 상수가 되고, '1ul' 혹은 '1UL'이라 표기하면 unsigned long int 타입의 상수로 다루어 진다.

정수형 상수를 표기할때 사용할 수 있는 진법은 8진법, 10진법, 16진법이다. 8진법 상수를 표기 할때는 0을 시작으로 8진 숫자를 사용한다. 예를들어 8진수 72를 표기하기위해서는 '072'라 표기해 주면 된다. 16진법을 표기하기 위해 사용되는 접두어는 0x 혹은 0X이고, 16진 숫자를 쓰면 된다. 예를 들어 16진수 ae4f를 표기하기 위해서는 '0xae4f'라 쓰면 된다. 8진수나 16진수 상수를 사용하는 경우에도 10진수에서 사용하는 타입지정 접미사는 그대로 사용할 수 있다.

고정폭 정수 타입편집

이렇듯 데이터의 크기가 환경에 따라 조금씩 달라지기 때문에, 데이터를 쓸 수 있는 값의 차이가 아닌 데이터가 차지하는 메모리 공간이라는 입장에서 봐야 할 땐 이런 일괄적이지 못한 데이터 타입은 프로그래머의 혼란을 야기할 뿐 아니라, 프로그램 코드가 컴파일되는 환경에 따라 다른 코드를 사용해야 하는 문제가 발생한다. 그래서 새로 제시된 타입이 다음과 같은 것 들이 있다.

타입 바이트수 최소값/최대값 stdint.h 상수 비고
int8_t
uint8_t
1 -128 - 127
0 - 255
INT8_MIN, INT8_MAX
UINT8_MAX
int16_t
uint16_t
2 -32768 - 32767
0 - 65535
INT16_MIN, INT16_MAX
UINT16_MAX
int32_t
uint32_t
4 -2147483648 - 2147483647
0 - 4294967295
INT32_MIN, INT32_MAX
UINT32_MAX
int64_t
uint64_t
8 -9223372036854775808 - 9223372036854775807
0 - 18446744073709551615
INT64_MIN, INT64_MAX
UINT64_MAX

데이터 폭이 정해져 있는 타입들과 관련된 상수는 <limits.h> 파일이 아닌 <stdint.h> 파일에 정의되어 있다. 위에 언급된 타입들 외에도 최소 n 비트 이상의 정수 데이터를 저장할 수 있는 타입을 의미하는 int_leastn_t, uint_leastn_t (이때 n은 8, 16, 32, 64)타입과 n비트 이상의 데이터 타입중 가장 빠른 타입이라는 의미의 int_fastn_t, uint_fastn_t 타입, 현 시스템에서 사용할 수 있는 가장 큰 정수형 데이터 타입을 의미하는 intmax_t와 uintmax_t 타입도 표준에는 정의 되어있다.

위 표에 나열 되어있는 데이터 타입들은 사용되는 메모리의 양이 분명해야 하는 경우에 사용되며 산술연산을 위해서는 거의 사용되지 않는다. 주로 네트워크 패킷을 처리하는 프로그램 코드에서 자주 볼 수 있다.

조금 어려운 이야기 -- 바이트 오더 혹은 엔디언편집

위에서 8비트 컴퓨터는 데이터를 8비트 단위로 처리한다는 이야길 했었다. 그러나 8비트로 표현할 수 있는 정수 값은 0 ~ 255 사이의 256개의 숫자 뿐이다. 그러나 실제 프로그램을 작성할 때에는 255보다 큰 값을 처리 해야 할 상황이 발생하기 마련이다. 그런 경우에 2개의 8비트 데이터를 합쳐서 16비트 데이터로 처리 하거나 4개의 8비트 데이터를 합쳐서 32비트 데이터를 처리 해야만 한다.

2개의 8비트 데이터를 합쳐서 덧셈을 하는 경우에는 먼저 2개의 8비트 데이터를 더한 다음에 자리 올림을 해서 다음번 8비트 데이터를 덧셈 하는 방식을 사용하게 된다. 좀더 간단하게 설명하자면 19 + 27을 계산할 때 먼저 9 + 7을 한 다음에 자리 올림 1과 6이라고 계산하고 다시 1 + 2 + 1 (자리올림)을 계산해서 46이라는 값을 얻게 된다.

10진 덧셈 2바이트 덧셈
올림 1 1
1 9 1E 2F
+ 2 7 + 3A E0
4 6 59 0F

위의 표에서와 같이 10진 덧셈이나 바이트 단위의 덧셈 모두 첫번째 자리에서 먼저 덧셈을 한 다음에 올림 값을 포함해서 윗자리의 덧셈을 하게 된다. 문제는 이 덧셈방식이 사람의 감각을 기준으로 해서 진행되는 것 이다. 실제 8비트 컴퓨터에서 16비트 - 2바이트 덧셈을 한다면 방법이 복잡해 진다. 변수는 메모리 공간 이라고 했던 것을 기억 할 것이다. 그렇기 때문에 실제로 8비트 컴퓨터가 하는 덧셈 이라는 것은 먼저 메모리에서 덧셈을 할 데이터를 두개 꺼내서 덧셈을 하고 두 값을 더한 다음에 다시 메모리에 넣는 세 단계 작업을 의미한다. 그림으로 그린다면 다음과 같다.

1 바이트 덧셈
1 바이트 덧셈

8비트 컴퓨터에서 16비트 덧셈을 수행하는 것은 조금 더 복잡하다. 먼저 아랫자리 1바이트 두개를 읽어 더한 다음 자리 올림을 확인하고, 더한 결과를 아랫자리 1바이트 영역에 저장해 둔다. 그 다음 윗자리 1바이트 두개를 읽고 자리 올림과 함께 더해 윗자리 1바이트 영역에 넣어 줘야 한다. 문제는 변수의 메모리 영역을 표시할 때 아랫자리의 위치를 표시하는 것이 아니라 윗자리의 위치를 기준으로 한다는 것이다. 그렇기 때문에 윗자리의 메모리 위치를 얻어낸 다음에 아랫자리 위치를 구하기 위해 메모리 위치 계산을 한번 해야 한다는 것이다. 그리고 위치 계산을 한 값을 가지고 더할 값을 꺼내서 더한 다음 비슷한 과정을 거쳐 저장할 위치를 계산해 내서 값을 저장한다. 아랫자리를 계산하기 위해 덧셈을 세번이나 더 해야 하고, 기준값을 유지하는 작업을 해야 하기 때문에 메모리를 더 필요로 하거나 복잡한 절차를 거처야 한다.

2 바이트 덧셈
2 바이트 덧셈

하지만 위의 그림에서 윗자리에 해당되는 바이트와 아랫자리에 해당되는 바이트를 바꾸면 위와 같은 복잡한 절차를 거치지 않더라도 아랫자리를 더한 다음에 결과를 넣고, 메모리 위치를 1증가 시킨 다음에 윗자리를 더하면 되므로 연산의 수가 줄어들고 연산의 복잡도 역시 줄어들게 된다. 실상 대부분의 CPU에는 인덱스드 모드(indexed mode)라는 연산 방식이 있어 여러자리의 연산을 쉽게 할 수 있도록 하는 어셈블리 명령이 별도로 존재하지만 아무래도 상대적으로 오래된 CPU들은 위에 설명한 방식으로 연산을 수행해야 했기 때문에 연산의 복잡도를 낮추기 위해 아랫자리와 윗자리를 바꿔서 저장을 했다.

아랫 자리와 윗 자리를 바꿔넣는 형태의 데이터 저장방식을 리틀 엔디언(little-endian)이라 하며, 이 방식을 사용하는 가장 대표적인 CPU로는 Intel의 x86 계열의 CPU들이 있다. 반대로 아랫 자리와 윗자리를 바꾸지 않고 그대로 저장하는 방식을 빅 엔디언(big-endian)이라 하며 네트워크를 통해 전송할 때에는 이 형태로 전송 하도록 약속되어 있다. 또한 빅 엔디언을 사용하는 CPU중에 가장 알기 쉬운 것은 매킨토시에서 사용되는 모토롤라의 68계열의 CPU들이다.

빅 엔디언과 리틀 엔디언을 통틀어 엔디언혹은 바이트오더 라고 하며 한 시스템이 아닌 여러 시스템에서 공통적으로 사용되는 데이터를 다룰 때, 특히 네트워크를 통해 데이터를 전송하는 경우에는 엔디언 - 바이트 오더 문제를 반드시 고려해야만 한다.[2]


주석 및 참고 자료편집

  1. 물론 실제적으로는 여러가지 이유에 의해서 두 배 정도가 아니라 몇배에서 수십배 이상의 속도 차이가 납니다. 그 위에 이 n 비트 컴퓨터라는 용어에 대한 수많은 의견이 있기 때문에 이렇게 한마디로 정의해 버리기엔 여러가지 불편한 점이 많기는 하지만, C 언어를 배우는데 있어 가장 필요한 정보만 제공한다는 의미에서 필요 이상으로 용어의 정의에 있어야 할 이야기들을 가지쳐 버렸습니다.
  2. 일반적으로 네트워크를 통해 데이터를 전송 할 때엔 빅 엔디언으로 전송을 합니다. 네트워크를 통해 전송할 때 사용해야 하는 바이트 오더라는 의미로 네트워크 프로그래밍을 할 때엔 빅 엔디언 이라는 용어 보다는 '네트워크 오더'라는 용어를 더 많이 사용합니다. 네트워크를 통해 데이터를 전송할 때엔 상대방 프로그램 외에도 중간에 거쳐야 하는 여러 네트워크 장비를 거쳐야 하기 때문에 오로지 자신이 만든 두 프로그램 사이에서 통신을 하는 경우에라도 데이터, 특히 네트워크 전송시 사용되는 패킷의 해더 정보는 반드시 네트워크 오더로 변환하는 작업을 해야만 합니다.
닫기

이 문서를 개선하는 데 도움을 주세요!

로그인

이 문서의 모든 바뀜을 추적합니다.

로그인

'language > C' 카테고리의 다른 글

time 함수  (0) 2015.04.21
C 언어와 C++ 언어에서 const 처리  (0) 2015.03.16
2차원 배열 크기 구하기  (0) 2013.01.15
printf format string  (0) 2012.01.18
gcc option  (0) 2011.10.26
반응형

pthread_attr: http://bitsoul.tistory.com/168

출처:

http://xucxo.blogspot.com/2011/03/linux-programming-thread.html: 함수에 대한 상세한 추가 설명이 좋다: 

http://underresearch.blogspot.kr/2013/05/pthread-thread.html

http://www.joinc.co.kr/w/Site/Thread/Beginning/PthreadApiReference#AEN226

http://www.morenice.kr/75

http://www.joinc.co.kr/w/Site/system_programing/Book_LSP/ch07_Thread

http://m.blog.naver.com/cky5122/80198083088

http://www.joinc.co.kr/w/Site/Thread/Beginning/PthreadApiReference#AEN226

https://kldp.org/node/93835

http://blog.naver.com/rbosc/90016327317

 

PThread - 리눅스에서 Thread 이용하기

Thread를 이용해야할 때까 있어서 공부를 했다
근데 리눅스에서 PThread를 사용하는 것이 윈도우 Visual Studio에서 지원하는 Thread를 사용하는 것보다 쉬워보였다.
그래서 PThread만 공부한 적이 있다.
처음엔 복잡한줄 알았는데 막상 공부해보니 쉬웠다.

처음 포스트인데 이번에는 PThread를 사용해서 간단한 프로그램을 작성할 것이다.
PThread는 리눅스에서만 되는것이 아니라 윈도우에서 MinGW를 설치하면 사용할 수 있다.

프로그램이 동작하는것은 이러하다.main에서 사용자에게 숫자 num을 입력받고 Thread 2개를 생성한다.하나의 Thread에서는 1부터 num까지 숫자를 카운트 하고 다른 하나의 Thread는 1부터 num까지 합한다.



또한 1부터 num까지 세는 Thread는 하나씩 셀 때마다 1000마이크로 초(1ms)를 쉰다
쉬지 않으면 SumThread가 끝나기 전에 CountThread가 끝나버려서 Thread가 제대로 돌아갔는지 알 수 없기 때문이다.

PThread를 사용하려면 pthread.h를 인클루드 시켜줘야 한다.
또한 pthread_t 라는 자료형의 변수와 함수들을 사용해 thread를 제어한다.

pthread_t라는 변수형은 thread의 id를 저장한다.

이 프로그램에서 사용한 함수들은 이렇다.

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);

이 함수는 thread를 생성하는 함수이다.
첫번째 인자는 생성할 thread의 id
두번째 인자는 thread의 특성인데, 보통 NULL을 집어넣는다.
세번째 인자는 thread를 실행할 함수가 온다. thread를 실행할 함수는 포인터 함수이므로 인자값으로 올 수 있다.
네번째 인자는 thread를 실행할 함수에 넣어줄 인자값이 온다. 인자값은 하나지만 여러개의 인자값을 넣어주는 꼼수도 존재한다.(이건 다음에 포스팅)

int pthread_join(pthread_t thread, void **rval_ptr);

이 함수는 main이나 부모 thread에서 자식 thread가 종료할 때까지 대기하는 함수이다. main이나 부모thread가 끝나버리면 자식 thread 또한 종료되기 때문이다.
첫번째 인자는 생성한 thread의 id
두번째 인자는 해당 thread가 종료되면 return받을 변수. 리턴받을 값이 없으면 NULL을 넣으면 된다.
추가설명: https://www.joinc.co.kr/w/man/3/pthread_join

void pthread_exit(void *rval_ptr);


이 함수는 thread를 종료할 때 사용한다.
첫번째 인자는 thread를 종료하고 pthread_join() 함수 두번째 인자에 리턴할 변수. 리턴할 값이 없으면 NULL을 넣으면 된다.

pthread_t pthread_self(void)

이 함수는 실행하고 있는 thread의 id를 리턴한다.


또한 gcc에서 PThread를 사용할 소스를 컴파일 할때 맨 뒤에 -lpthread 명령어를 붙여줘야 한다.



이런식으로
MinGW로 컴파일 할때도 마찬가지.

아래는 소스.


  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <pthread.h>
  4. void *CountThread(void *);
  5. void *SumThread(void *);
  6. int main(void)
  7. {
  8. int num;
  9. int result[2];
  10. int i, rc;
  11. pthread_t threads[2];
  12. printf("input number : ");
  13. scanf("%d", &num);
  14. pthread_create(&threads[0], NULL, &CountThread, (void *)&num); //Count를 할 Thread함수를 threads[0]에서 실행(인자값은 num)
  15. pthread_create(&threads[1], NULL, &SumThread, (void *)&num); //Sum을 구할 Thread함수를 threads[1]에서 실행(인자값은 num)
  16. for(i = 0; i < 2; i++)
  17. {
  18. rc = pthread_join(threads[i], (void **)&result[i]);
  19. if(rc != 0) //rc가 0이 아니면 오류 발생
  20. {
  21. printf("Error in thread[%d] : %d\n", i, rc);
  22. exit(1);
  23. }
  24. }
  25. printf("Result of CountThread : %d\n", result[0]);
  26. printf("Result of SumThread : %d\n", result[1]);
  27. return 0;
  28. }
  29. void *CountThread(void *arg)
  30. {
  31. int i;
  32. int num = *(int *)arg; //인자값을 사용해야할 때마다 일일이 void* 포인터에서 int* 포인터로 바꿔줘야 해서 귀찮아지므로 그냥 변수를 하나 만들어서 인자값을 넣어줌
  33. for(i = 1; i <= num; i++)
  34. {
  35. printf("In CountThread(0x%lx) : %d\n", pthread_self(), i);
  36. usleep(1000);
  37. }
  38. printf("CountThread End\n");
  39. pthread_exit(NULL); //인자값을 return하고 Thread함수 종료
  40. }
  41. void *SumThread(void *arg)
  42. {
  43. int result, i;
  44. int num = *(int *)arg;
  45. for(result = 0, i = 1; i <= num; i++)
  46. result += i;
  47. printf("SumThread End\n");
  48. pthread_exit((void *)result); //인자값을 return하고 Thread함수 종료(인자값이 void형 포인터로 들어가므로 void형 포인터로 형변환)
  49. }


앞에서 언급했듯이 pthread를 사용할 때 인자를 하나만 넣을 수 있는데 여러개를 넣는 꼼수가 존재한다. 구조체를 사용하는 방법이 있는데, 이것은 다음에 포스팅 하겠다.


반응형

인터넷에 돌아다니는 코드 막 붙여 넣었음. 코드 정리가 필요함;;;

 

출처: https://kldp.org/node/42683

        http://www.qnx.com/developers/docs/6.5.0/index.jsp?topic=%2Fcom.qnx.doc.neutrino_lib_ref%2Fi%2Fifaddrs.html

        http://pencil1031.tistory.com/69

        http://stackoverflow.com/questions/1779715/how-to-get-mac-address-of-your-machine-using-a-c-program

 

 

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <netdb.h>
#include <netinet/in.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>

#define dpt()        printf( "[dmsg] [file:%s, line:%d] \n", __FILE__, __LINE__ )


#include <stdlib.h>
#include <arpa/inet.h>


#include <sys/ioctl.h>


#define BUFSIZE 8192

struct route_info
{
  struct in_addr dstAddr;
  struct in_addr srcAddr;
  struct in_addr gateWay;
  char ifName[IF_NAMESIZE];
};


int readNlSock(int sockFd, char *bufPtr, size_t buf_size, int seqNum, int pId)
{
  struct nlmsghdr *nlHdr;
  int readLen = 0, msgLen = 0;

  do
  {
    /* Recieve response from the kernel */
    if((readLen = recv(sockFd, bufPtr, buf_size - msgLen, 0)) < 0)
    {
      perror("SOCK READ: ");
      return -1;
    }

    nlHdr = (struct nlmsghdr *)bufPtr;

    /* Check if the header is valid */
    if((NLMSG_OK(nlHdr, readLen) == 0) || (nlHdr->nlmsg_type == NLMSG_ERROR))
    {
      perror("Error in recieved packet");
      return -1;
    }

    /* Check if the its the last message */
    if(nlHdr->nlmsg_type == NLMSG_DONE)
    {
      break;
    }
    else
    {
      /* Else move the pointer to buffer appropriately */
      bufPtr += readLen;
      msgLen += readLen;
    }

    /* Check if its a multi part message */
    if((nlHdr->nlmsg_flags & NLM_F_MULTI) == 0)
    {
      /* return if its not */
      break;
    }
  }
  while((nlHdr->nlmsg_seq != seqNum) || (nlHdr->nlmsg_pid != pId));

  return msgLen;
}

/* parse the route info returned */
int parseRoutes(struct nlmsghdr *nlHdr, struct route_info *rtInfo)
{
  struct rtmsg *rtMsg;
  struct rtattr *rtAttr;
  int rtLen;

  rtMsg = (struct rtmsg *)NLMSG_DATA(nlHdr);

  /* If the route is not for AF_INET or does not belong to main routing table then return. */
  if((rtMsg->rtm_family != AF_INET) || (rtMsg->rtm_table != RT_TABLE_MAIN))
    return -1;

  /* get the rtattr field */
  rtAttr = (struct rtattr *)RTM_RTA(rtMsg);
  rtLen = RTM_PAYLOAD(nlHdr);

  for(; RTA_OK(rtAttr,rtLen); rtAttr = RTA_NEXT(rtAttr,rtLen))
  {
    switch(rtAttr->rta_type)
    {
    case RTA_OIF:
      if_indextoname(*(int *)RTA_DATA(rtAttr), rtInfo->ifName);
      break;

    case RTA_GATEWAY:
      memcpy(&rtInfo->gateWay, RTA_DATA(rtAttr), sizeof(rtInfo->gateWay));
      break;

    case RTA_PREFSRC:
      memcpy(&rtInfo->srcAddr, RTA_DATA(rtAttr), sizeof(rtInfo->srcAddr));
      break;

    case RTA_DST:
      memcpy(&rtInfo->dstAddr, RTA_DATA(rtAttr), sizeof(rtInfo->dstAddr));
      break;
    }
  }

  return 0;
}

// meat
int get_gatewayip(char *gatewayip, socklen_t size)
{
  int found_gatewayip = 0;

  struct nlmsghdr *nlMsg;
  struct rtmsg *rtMsg;
  struct route_info route_info;
  char msgBuf[BUFSIZE]; // pretty large buffer

  int sock, len, msgSeq = 0;

  /* Create Socket */
  if((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)
  {
    perror("Socket Creation: ");
    return(-1);
  }

  /* Initialize the buffer */
  memset(msgBuf, 0, sizeof(msgBuf));

  /* point the header and the msg structure pointers into the buffer */
  nlMsg = (struct nlmsghdr *)msgBuf;
  rtMsg = (struct rtmsg *)NLMSG_DATA(nlMsg);

  /* Fill in the nlmsg header*/
  nlMsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); // Length of message.
  nlMsg->nlmsg_type = RTM_GETROUTE; // Get the routes from kernel routing table .

  nlMsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; // The message is a request for dump.
  nlMsg->nlmsg_seq = msgSeq++; // Sequence of the message packet.
  nlMsg->nlmsg_pid = getpid(); // PID of process sending the request.

  /* Send the request */
  if(send(sock, nlMsg, nlMsg->nlmsg_len, 0) < 0)
  {
    printf("Write To Socket Failed...\n");
    return -1;
  }

  /* Read the response */
  if((len = readNlSock(sock, msgBuf, sizeof(msgBuf), msgSeq, getpid())) < 0)
  {
    printf("Read From Socket Failed...\n");
    return -1;
  }

  /* Parse and print the response */
  for(; NLMSG_OK(nlMsg,len); nlMsg = NLMSG_NEXT(nlMsg,len))
  {
    memset(&route_info, 0, sizeof(route_info));
    if ( parseRoutes(nlMsg, &route_info) < 0 )
      continue;  // don't check route_info if it has not been set up

    // Check if default gateway
    if (strstr((char *)inet_ntoa(route_info.dstAddr), "0.0.0.0"))
    {
      // copy it over
      inet_ntop(AF_INET, &route_info.gateWay, gatewayip, size);
      found_gatewayip = 1;
      break;
    }
  }

  close(sock);

  return found_gatewayip;
}


static int
create_sock (const char *nic)
{
  struct sockaddr_nl addr;
  int                sock;

  memset (&addr, 0, sizeof (addr));
  addr.nl_family = AF_NETLINK;
  addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;

  sock = socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  if (sock < 0)
    {
      printf ("failed to open NETLINK_ROUTE socket for %s - %s(%d)",
               nic, strerror (errno), errno);
      return -1;
    }

  if (bind (sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
      printf ( "failed to bind NETLINK_ROUTE socket for %s - %s(%d)",
                 nic, strerror (errno), errno);
      close (sock);
      return -1;
    }

  return sock;
}

static int
ip_changed (int         sock,
            const char *nic)
{
  struct nlmsghdr   *nlh;
  char               buffer[4096];
  int                len;
  int                idx;
  int                found;

  len = recv (sock, buffer, sizeof (buffer), 0);
  if (len <= 0)
    {
      printf ( "NETLINK_ROUTE socket recv() failedn");
      return -1;
    }

  found = 0;
  idx = if_nametoindex (nic);

  for (nlh = (struct nlmsghdr *)buffer;
       NLMSG_OK (nlh, len);
       nlh = NLMSG_NEXT (nlh, len))
    {
      if (nlh->nlmsg_type == NLMSG_DONE)
        break;
      if (nlh->nlmsg_type == NLMSG_ERROR)
        continue;
      if (!(NLMSG_OK (nlh, len)))
        continue;

      switch (nlh->nlmsg_type)
        {
        case RTM_NEWADDR:
          {
            struct ifaddrmsg *ifa = (struct ifaddrmsg *)NLMSG_DATA (nlh);

            if (ifa->ifa_index == idx)
              found = 1;
          }
          break;
        case RTM_NEWLINK:
          {
            struct ifinfomsg *ifi = (struct ifinfomsg *)NLMSG_DATA (nlh);

            if (ifi->ifi_index == idx)
              found = 1;
          }
          break;
        default:
          break;
        }
    }

  return found;
}

static int
get_nic_addr (const char     *nic,
              struct ifaddrs *ifaddr,
              int             wanted_family,
              char           *host,
              int             host_len,
              int            *active)
{
  struct ifaddrs *ifa;

  char test[100];


  for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
    {
      int family;
      int s;

      if (ifa->ifa_addr == NULL)
        continue;

      if (strcmp (ifa->ifa_name, nic))
        continue;

      /* Skip unwanted families. */
      family = ifa->ifa_addr->sa_family;
      if (family != wanted_family)
        continue;

      *active = (ifa->ifa_flags & IFF_RUNNING) ? 1 : 0;

      s = getnameinfo (ifa->ifa_addr,
                       family == AF_INET ? sizeof (struct sockaddr_in) :
                                           sizeof (struct sockaddr_in6),
                       host,
                       host_len,
                       NULL,
                       0,
                       NI_NUMERICHOST);
      if (s != 0)
        {
          printf ( "failed to getnameinfo() for '%s - %s(%d)",
                   ifa->ifa_name, strerror (errno), errno);
          continue;
        }


  memset(test, 0, 100);
      s = getnameinfo (ifa->ifa_netmask,
                       family == AF_INET ? sizeof (struct sockaddr_in) :
                                           sizeof (struct sockaddr_in6),
                       test,
                       100,
                       NULL,
                       0,
                       NI_NUMERICHOST);
  printf("netmask:%s\n",test);

  memset(test, 0, 100);
      s = getnameinfo (ifa->ifa_dstaddr,
                       family == AF_INET ? sizeof (struct sockaddr_in) :
                                           sizeof (struct sockaddr_in6),
                       test,
                       100,
                       NULL,
                       0,
                       NI_NUMERICHOST);
  printf("ifa_dstaddr:%s\n",test);

      /* Get the address of only the first network interface card. */
      return 1;
    }

  return 0;
}

static void
print_ip (const char *nic)
{
  struct ifaddrs *ifaddr;
  char            addr[NI_MAXHOST];
  int             active;

  if (getifaddrs (&ifaddr) == -1)
    {
      printf ( "failed to getifaddrs() - %s(%d)", strerror (errno), errno);
      return;
    }

  if (!get_nic_addr (nic, ifaddr, AF_INET, addr, sizeof (addr), &active))
    if (!get_nic_addr (nic, ifaddr, AF_INET6, addr, sizeof (addr), &active))
      {
        strcpy (addr, "127.0.0.1");
        active = 0;
      }

  freeifaddrs (ifaddr);

  printf ( "%s is %s (link %s)n", nic, addr, active ? "active" : "inactive");
}

 


int
main (void)
{
  char *nic = "eth0";
  int   sock;
 char gw[100];

    struct ifreq ifr;
    struct ifconf ifc;
    char buf[1024];
    int success = 0;

    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
    if (sock == -1) { /* handle error*/ };

    ifc.ifc_len = sizeof(buf);
    ifc.ifc_buf = buf;
    if (ioctl(sock, SIOCGIFCONF, &ifc) == -1) { /* handle error */ }

    struct ifreq* it = ifc.ifc_req;
    const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq));

    for (; it != end; ++it) {
        strcpy(ifr.ifr_name, it->ifr_name);
        if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) {
            if (! (ifr.ifr_flags & IFF_LOOPBACK)) { // don't count loopback
                if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) {
                    success = 1;
                    break;
                }
            }
        }
        else { /* handle error */ }
    }

    unsigned char mac_address[6];

    if (success) memcpy(mac_address, ifr.ifr_hwaddr.sa_data, 6);
 printf("mac_address:%02x\n",mac_address[0]);
 printf("mac_address:%02x\n",mac_address[1]);
 printf("mac_address:%02x\n",mac_address[2]);
 printf("mac_address:%02x\n",mac_address[3]);
 printf("mac_address:%02x\n",mac_address[4]);
 printf("mac_address:%02x\n",mac_address[5]);
 


 
  print_ip (nic);

dpt();
  sock = create_sock (nic);
  if (sock < 0)
    return -1;

  memset(gw, 0, 100);

 get_gatewayip(gw,100);
 printf("gw:%s\n",gw);

dpt();
  while (1)
    {
      int ret;

      ret = ip_changed (sock, nic);
      if (ret < 0)
        return -1;

      if (ret)
        print_ip (nic);
    }

  close (sock);

  return 0;
}

 

 

반응형

출처: http://sunjinyang.wordpress.com/2012/03/19/detect-change-of-ip-address-and-link-status-in-linux/

반응형

출처: https://kldp.org/node/71205

 

dns 서비스 사용하기

-> wowdns dyndns 등등 다양하고 공짜도 많음

'통신 > LAN' 카테고리의 다른 글

TCP 제어플래그  (0) 2024.08.07
tftp로 파일 복사  (0) 2019.09.06
TCP 테스트 프로그램  (0) 2018.03.20
socket 통신  (0) 2016.10.28
무선랜 WPA-PSK와 WPA2-PSK 방식에서 TKIP와 AES 암호화 방식 사용의 혼동  (0) 2010.06.03

+ Recent posts