티스토리 뷰
http://bbs.kldp.org/viewtopic.php?t=768
여기에 썼던글이다. (drupal로 이관하면서 이관된 문서를 찾으려 했으나 역부족.)
본 글은 IP 주소를 얻는 방법에 대해 쓴 것이 아니라, 그 이면에 있는 드라이버와의 통신에 대해 다룬다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stropts.h>
#if defined(sun)
#include <sys/sockio.h>
#endif
#include <net/if.h>
#if defined(linux)
#include <linux/sockios.h>
#endif
#define BUFFERSIZE 1024
const char * localip = "0.0.0.0";
const char * myip()
{
const int MAX_NIC = 10;
struct ifconf ifc;
struct ifreq ifr[MAX_NIC];
int s;
int nNumIFs;
int i;
int count;
int max=2;
static char ip[BUFFERSIZE];
int cmd = SIOCGIFCONF;
max++;
ifc.ifc_len = sizeof ifr;
ifc.ifc_ifcu.ifcu_req = ifr;
if( (s=socket(AF_INET,SOCK_STREAM,0)) < 0)
{
perror("socket");
exit(1);
}
#if defined(_AIX)
cmd = CSIOCGIFCONF;
#endif
if( ioctl(s, cmd, &ifc) < 0)
{
perror("ioctl");
exit(1);
}
close(s);
nNumIFs = ifc.ifc_len / sizeof ( struct ifreq );
count = 0;
strcpy( ip, localip );
for( i=0; i<nNumIFs; i++ )
{
struct in_addr addr;
if( ifc.ifc_ifcu.ifcu_req[i].ifr_ifru.ifru_addr.sa_family != AF_INET)
{
continue;
}
addr = ((struct sockaddr_in *) & ifc.ifc_ifcu.ifcu_req[i].ifr_ifru.ifru_addr)->sin_addr;
if( addr.s_addr == htonl( 0x7f000001 ) )
{
continue;
}
strcpy( ip, inet_ntoa( addr ) );
printf( "IP: %s\n", ip );
}
return ip;
}
int main()
{
printf("One of my IP is %s\n", myip() );
return 0;
}
이 함수를 인용하는 이유는, 원리가 특이하다 생각할 수 있기 때문이다. 자세히 들여다보면, myip 함수에서 socket 함수를 사용하여 소켓하나를 만들고 정작 우리가 흔히 이용하는 대로 bind하거나 connect하지 않는다.
위 함수가 Windows에서 돌아가는지조차 테스트 해보지 않아서 더더욱 이식성이라도 있는지 모르겠다.
Windows 같으면 Registry를 뒤져가며, 네트웍 인터페이스 카드(NIC)에 할당되어 있는 DHCP IP건 Auto IP건 말그대로 Static IP건 찾는대로 보여줄텐데, 이 녀석은 그렇지 않다.
IP 주소는 무엇인가? 커널의 어떤 녀석이 그 주소 정보를 가지고 있는것인가? SIOCGIFCONF 라는 옵션은 인터페이스 구성에 대한 것을 되돌려 받는 것 같은데, 그것이 커널내의 어떤 녀석에게 물어 본다는 것인가? 상상을 하자면 끝이 없다.
모든 I/O 관련 시스템콜이 그렇지만, 간과해서는 안 될 것이, I/O 관련 시스템콜은 사실 파일 기술자 혹은 소켓이 어디 소속인지를 보고 소속 드라이버의 실제 시스템콜을 호출하는 것에 불과하다는 것이다. 드라이버를 제작하다보면, 그 드라이버와 통신하기 위해 몇가지 방법이 존재하는데 그 중 한 방법이 ioctl이다. (디바이스 드라이버나 가상 파일 시스템을 만들수도 있고, 시스템 콜을 추가할 수도 있다.)
위의 예제는 네트웍 인터페이스 카드의 주소를 설정하기 위해, 해당 드라이버와 통신하기 위한 소켓을 만들었을 뿐, 그 이상도 이하도 아니다. 그 소켓은 실제 통신용이 아니라는 얘기이다. 만일, 실제 통신용이 존재한다면, 그것을 그대로 이용해도 무방하다. 즉 따로 IP를 구하기 위해 소켓을 만들지 말라는 얘기이다.
아니 정말, 소켓을 만든이유가 단지 그 드라이버와의 통신을 위한 것이란 말이오? 라고 반문할 수 있겠지만, 요즈음에 사용되는 /proc 파일 시스템같은 것들이 소개되기 훨씬이전부터 있어 왔던 방식이다라고 말할 수 밖에 없다.
좀더 생각해 볼 것은, read가 recv와 같은 역할을 하는 이유가 read, recv 들은 사실 wrapper일 뿐 실제적인 녀석은 따로 있기 때문이다. 둘 다 소켓을 보고 해당 드라이버의 recv 용 함수를 부르게된다.
반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- SSO
- 클레로덴드럼
- 퀴즈
- Linux
- macosx
- writely
- perl
- 덴드롱
- 구근
- nodejs
- 식물
- 오픈소스
- TCP/IP
- VIM
- 수선화
- SVN
- 킹벤자민
- 디버깅
- 커피
- 벤자민
- url
- JavaScript
- tattertools
- OpenID
- Subversion
- Tattertools plugin
- MySQL
- ssh
- 대화
- BlogAPI
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
글 보관함