2011. 7. 29. 14:58
도메인 이름을 이용해서 IP 주소 얻어오기
다음 함수를 이용하면 문자열 형태의 도메인 이름으로부터 IP주소정보를 얻어올 수 있다.

#include <netdb.h>

struct hostent * gethostbyname(const char * hostname);
    =>성공시 hostent 구조체 변수의 주소 값, 실패 시 NULL 포인터 반환

struct hostent //hostent구조체
{
      char * h_name;         // official name
      char ** h_aliases;     // alias list
      int h_addrtype;          // host address type
      int h_length;              // address length
      char ** h_addr_list;    // address list
h_name
이 멤버에는 '공식 도메인 이름(Official domain name)'이 저장된다.
h_aliases
하나의 IP에 둘 이상의 도메인 이름을 지정하는 것이 가능하기 때문에, 공식 도메인 이외에 해당 메인 페이지를 접속할 수 있는 다른 도메인 이름의 지정이 가능.(h_aliases를 통해 얻을 수있음)
h_addrtype
gethostbyname은 IPv4뿐만 아니라 IPv6도 지원. 때문에 h_addr_list로 반환된 IP주소체계에 대한 정보를 이 멤버를 통해 반환
(IPv4경우 AF_INET반환)
h_length
함수 호출의 결과로 반환된 IP주소의 크기.(IPv4경우 4바이트)
h_addr_list
이 멤버를 통해서 도메인 이름에 대한 IP주소가 정수의 형태로 반환
(참로 : 접속자수가 많은 서버는 하나의 도메인 이름에 대응하는 IP를 여러개 둬서, 둘 이상의 서버로 분산시킬 수 있는데, 이러한 경우에도 이 멤버를 통해서 모든 IP의 주소를 얻어올 수 있다.)



예제소스_ gethostbyname.c




예제결과_gethostbyname www.google.com






IP주소를 이용해서 도메인 정보 가져오기
 #include <netdb.h>

struct hostent * gethostbyaddr(const char * addr, socklen_t len, int family);
     => 성공시 hostent 구조체 변수의 주소값, 실패시 NULL포인터 반환
인자설명
addr : IP주소를 지니는 in_addr 구조체 변수의 포인터 전달, IPv4이외의 다양한 정보를 전달받을 수 있도록 일반화하기 위해서 매개변수 char형 포인터로 선언
len : 첫 번째 인자로 전달된 주소정보의 길이, IPv4의 경우 4, IPv6의 경우 16전달.
family : 주소체계 정보 전달. IPv4의 경우 AF_INET, IPv6의 경우 AF_INET6전달
ex) host = gethostbyaddr((char*)&addr.sin_addr, 4, AF_INET);

예제: gethostbyaddr.c




출처 : 열혈강의tcp/ip 소켓 프로그래밍_윤성우

Posted by Triany
2011. 7. 29. 02:01
Q.

p.130~131 op_client.c 부분에서 막혀서 이렇게 글을 씁니다.

학교 서버 리눅스 환경에서 이 소스를 돌려보았습니다.. 그런데..

클라이언트 쪽에서 연결도 됐고, Operand conunt 까지 입력이 되는데

Operand 1 부터 입력을 하면 버스 오류 (core dumped)라는 게 뜨네요..

아무리 찾아봐도 잘 모르겠어서 올립니다.. ㅠㅠ

아무래도 39행인 scanf("%d", (int*)&opmsg[i*OPSZ+1]); 에서 오류가 나는 것 같은데요.

왜 그럴까요 ? ㅠㅠ

미심적어서 소스를 scanf("%d", (int*)&opmsg[i*OPSZ+4]);

이렇게 고쳐보면, 그 뒤 값들은 받아지긴 하지만, 전체적인 로직과, 구현 목적(char 문자에 계산할만큼 숫자를 담아라)이

달라지기에...

34라인의 opmsg[0] = (char)opnd_cnt; 여기서 char형인 1바이트만큼만 기록되야 맞는게 아닌가요?

인터넷에서 대략 찾아보니 메모리가 덤프되는게.. 뭐 겹쳐써지고.. 이런 말도 있고..... ㅠㅠ

알려주세요!!!!!! ㅠㅠㅠㅠㅠ



A.

안녕하세요 해결하지 못해 답변이라 하긴 뭐하지만...

빅엔디안 시스템이 원래 이런 것인지는 잘 모르겠습니다.

op_client.c에서,
문제가 발생하는 부분만 요약했습니다.

1 #include <stdio.h>
2 #include <string.h>
3
4 #define BUFMAX 9
5
6
7 int main(void){
8 int i;
9 char buf[BUFMAX];
10
11 memset(buf, 0, BUFMAX);
12 scanf("%d", (int *)&buf[1]);
13
14 for(i=0; i<BUFMAX; i++)
15 printf("buf[%d]=%0x , %p\n",i, buf[i], &buf[i]);
16
17 return 0;
18
19 }



12번 줄이 문제가 되는 부분인데,
리틀엔디안 시스템의 리눅스에서는 (int *)&buf[숫자]의 숫자 부분을
범위 내에서 마음대로 줄 수가 있었습니다. 원하는 대로 포인터가 갑니다.

그러나, 솔라리스만 이런 것인지 빅엔디안 시스템이 다 이런 것인지는 모르겠지만,
솔라리스 빅엔디안 시스템에서는 반드시 (int *)&buf[숫자]부분의 숫자가 0, 4, 8 이런 식으로
int의 크기에 맞춰서 써줘야 했고, 중간 숫자 1, 2, 3, 5, 6, 7 같은 숫자를 넣는다면
반드시 Core Dump가 일어났습니다.


** 숫자를 0을 주었을 때...
$./a.out
9
buf[0]=0 , ffbff9a8
buf[1]=0 , ffbff9a9
buf[2]=0 , ffbff9aa
buf[3]=9 , ffbff9ab <-- 하위 바이트의 값을 높은 번지 주소에 저장.
buf[4]=0 , ffbff9ac
buf[5]=0 , ffbff9ad
buf[6]=0 , ffbff9ae
buf[7]=0 , ffbff9af
buf[8]=0 , ffbff9b0
$


** 숫자를 1을 주었을 때...
$./a.out
3
Bus error (core dumped)
$



*** 리틀엔디안 시스템의 리눅스에서 숫자 1주고 실행했을 때
$ ./a.out
3
buf[0]=0 , 0xbfb10b83
buf[1]=3 , 0xbfb10b84 <--- buf의 1번 주소에 바로 들어갑니다.
buf[2]=0 , 0xbfb10b85 하위 바이트의 값을 낮은 번지 주소에 저장.
buf[3]=0 , 0xbfb10b86
buf[4]=0 , 0xbfb10b87
buf[5]=0 , 0xbfb10b88
buf[6]=0 , 0xbfb10b89
buf[7]=0 , 0xbfb10b8a
buf[8]=0 , 0xbfb10b8b
$


솔라리스 빅엔디안 시스템에서
op_client.c, op_server.c의 소스를 그대로 쓸 수 없는 것은
맞는 것 같습니다.


A2.

그냥 되도록 바꿨습니다.

서버 프로그램 쪽에서는 바꿀 코드가
int형으로 선언된 opnd_cnt를
char형으로 바꿔주고,


클라이언트 프로그램 쪽에서는

typedef union charInt{
char intByte[4];
int cInt;
}UsrInt;

위와 같이 scanf()를 통해 받을 정보를
임시저장할 공용체 형을 정의하고 후에 선언한 뒤,
이것을 사용해서 클라이언트에서
피 연산자 값을 입력 받는 부분을 아래와 같이 고쳐서

for(i=0; i<opnd_cnt; i++)
{
printf("Operand %d: ", i+1);
scanf("%d", &usrInt.cInt);

opmsg[i*OPSZ+1]=usrInt.intByte[0];
opmsg[i*OPSZ+2]=usrInt.intByte[1];
opmsg[i*OPSZ+3]=usrInt.intByte[2];
opmsg[i*OPSZ+4]=usrInt.intByte[3];
}

opmsg[]에 수동으로 값을 맞춰 넣어주니..

솔라리스에서도 잘되네요..


출처: http://cafe.naver.com/cstudyjava.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=20401&

초보01님의 답변^^ 친절한 답변 감사드립니다 - 소켓 공부ing...

Posted by Triany
2011. 7. 25. 13:59
[C표준함수] memset() 함수
글쓴이 : 정민구 날짜 : 09-03-26 21:19 조회 : 6046 
memset 
메모리를 지정한 문자로 채웁니다. 

Declaration 
void *memset( void *dest, int c, size_t count ) 

Return value 
성공 - 채워진 메모리 주소(dest 매개 변수) 반환 
실패 - 없음 


Parameters 
dest  - 채울 메모리의 주소 
c    - 채울 문자 
count - 채우려고 하는 문자 개수 


Detail descriptions 
memset()는 버퍼를 똑같은 "문자"로 채울 때 사용합니다. 명확하게 문자라고 표현했듯이 단위는 바이트입니다. memset()는 문자를 저장하는 char 배열뿐만 아니라 모든 종류의 배열에 대해서 사용할 수 있습니다. 그러나, 단위가 바이트이기 때문에 배열 요소의 자료형에 따라 세심한 주의가 필요합니다. 

대부분의 배열은 초기 상태로 0을 갖습니다. 그래서, {} 초기화를 사용해서 모든 요소에 대해 0을 지정하도록 합니다. 그러나, {} 초기화는 배열을 선언할 때 한번만 사용할 수 있고, 이후에는 일일이 모든 요소에 대해 0을 넣어줘야 합니다. 이와 같이 모든 요소를 0으로 채울 때, 배열 종류에 상관없이 사용하는 함수가 memset()입니다. 




출처 : 
http://www.itdi.co.kr/onuri/bbs/board.php?bo_table=02_1&wr_id=9

소켓 프로그래밍 당시 이 함수가 계속하여 쓰이기에 알아보았다.
주로

memset(&addr, 0 sizeof(addr));
이런식으로 sockaddr_in addr;로 선언한 주소체계를 addr의 size만큼 0으로 채우는 것을 볼 수 있다. 
Posted by Triany