http://www.codedream.net/blog/

 

출처 : Internet 에서 구한 문서입니다.
================================================================================================

3.7 소켓 함수 처리시간 측정

3.7.1 유닉스의 시간측정 함수
▶ time() 함수는 1970년 1월 1일 0시부터(이를 Epoch라고 한다) 현재까지 경과된 시간을 초단위로 정수값으로 리턴한다.
▶ ctime()은 time_t 타입의 포인터를 인자로 받아, 날짜와 시간을 나타내는 문자열로 변환해 준다. 아래 프로그램 코드는 현재의 날짜와 시간을 화면에 출력한다.

#include <time.h>
void main(void) {
   time_t now;
   time(&now);
   printf("Now : %s", ctime(&now));
}

▶ 위 코드의 실행 결과 예는 다음과 같다.

Now : Wed Dec  8 12:43:39 1999

▶ nano second 단위의 시간을 측정하기 위해서는 clock_gettime()을 사용한다.

#include <time.h>
int clock_gettime(clockid_t clock_id, struct timespec *tp);

typedef struct  timespec {
        time_t  tv_sec;         /* second (초) 단위 */
  long    tv_nsec;        /* nano second 단위 */
} timespec_t;

▶ 첫번째 인자 clock_id로 CLOCK_REALTIME을 선택하면 두번째 인자인 구조체 timespec에 January 1, 1970 00:00시 이후의 시간이 초단위와 nano second 단위로 리턴된다.
3.7.2 소켓 함수 처리시간 측정 프로그램
■ socket_delay.c

∙ 소켓 관련 함수들을 실행하는데 소요되는 시간을 clock_gettime()을 이용하여 측정한다.

∙ 실행예

> socket_delay
For 'socket' call :        8045500 nsec
For 'connect' call :       3622500 nsec
For 'write' call :           222000 nsec
For 'read' call :         23732000 nsec
For 'close' call :          657500 nsec

∙ 시간을 측정하기 위하여 timespec 타입 변수의 배열 myclock[2]를 사용하는데 myclock[0]에는 어떤 소켓 함수를 호출하기 직전의 시각을 기록하고 myclock[1]에는 그 소켓 함수를 수행한 직후의 시각을 기록한 다음 이들의 시간차이를 계산해 주는 사용자 정의 함수 calclock()을 호출한다.

struct         timespec myclock[2];
long                nano_time;

clock_gettime(CLOCK_REALTIME, &myclock[0]);
s = socket(PF_INET, SOCK_STREAM, 0);
clock_gettime(CLOCK_REALTIME, &myclock[1]);
nano_time = calclock( myclock );
printf("For 'socket' call :        %10ld nsec \n", nano_time);

∙ 프로그램 리스트

/*--------------------------------------------------------------------------------------------------------
파일명 : socket_delay.c
기  능 : 소켓 함수 처리 소요 시간을 [nsec] 단위로 측정
컴파일 : cc -o socket_delay socket_delay.c -lsocket -lnsl -lposix4
사용법 : socket_delay IP_addr
--------------------------------------------------------------------------------------------------------*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/times.h>
#include <netinet/in.h>
#include <time.h>
#include <stdio.h>
#define port_number    7                                                        /* echo 서비스 포트 번호 */

long calclock (struct timespec *myclock);                /* 시간 차이를 계산하는 함수 */
void insertnull (char *ps, int len);                                /* 초기화 함수*/

int main(int argc, char *argv[]) {
   int s;                                /* 소켓번호 */
   int cd, wd, rd;
   struct sockaddr_in serv_addr;
   struct timespec myclock[2];
   long        timedelay;
   char         wmsg[] = " To be or not to be, that is the problem...";
   char         rbuf[100];
  
   if (argc != 2) {
                printf("사용법 : %s server_IP\n", argv[0]);
                exit(0);
   }
   bzero((char *)&serv_addr, sizeof(serv_addr));
   serv_addr.sin_family = AF_INET;
   serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
   serv_addr.sin_port = htons(port_number);

   /* ----------------------------- socket() 처리시간 측정 ------------------------------ */
   clock_gettime(CLOCK_REALTIME, &myclock[0]);
   s = socket(PF_INET, SOCK_STREAM, 0);
   clock_gettime(CLOCK_REALTIME, &myclock[1]);
  
   timedelay = calclock( myclock );
   printf("For 'socket' call :        %10ld nsec \n", timedelay);

   /* ----------------------------- connect() 처리시간 측정 --------------------------- */
   clock_gettime(CLOCK_REALTIME, &myclock[0]);
   cd = connect(s, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
   clock_gettime(CLOCK_REALTIME, &myclock[1]);
  
   timedelay = calclock(myclock);
   printf("For 'connect' call :        %10ld nsec \n", timedelay);

   /* ------------------------- write() 처리시간 측정 ---------------------------------- */
   clock_gettime(CLOCK_REALTIME, &myclock[0]);
   wd = write(s, wmsg, sizeof(wmsg));
   clock_gettime(CLOCK_REALTIME, &myclock[1]);

   timedelay = calclock( myclock );
   printf("For 'write' call :        %10ld nsec \n", timedelay);
  
   /* -------------------------- read() 처리시간 측정 ---------------------------------- */
   clock_gettime(CLOCK_REALTIME, &myclock[0]);
   rd = read(s, rbuf, sizeof(rbuf));
   clock_gettime(CLOCK_REALTIME, &myclock[1]);
  
   timedelay = calclock( myclock );
   printf("For 'read' call :        %10ld nsec \n", timedelay);
  
   /* -------------------------- close() 처리시간 측정 --------------------------------- */
   clock_gettime(CLOCK_REALTIME, &myclock[0]);
   close(s);
   clock_gettime(CLOCK_REALTIME, &myclock[1]);
   timedelay = calclock( myclock );
   printf("For 'close' call :        %10ld nsec \n", timedelay);
}
/* 배열 myclock[] 내의 시간차를 리턴하는 함수 */
long calclock( struct timespec *myclock ) {
   long timedelay, temp, temp_n;
   if (myclock[1].tv_nsec >= myclock[0].tv_nsec) {
      temp = myclock[1].tv_sec - myclock[0].tv_sec;
      temp_n = myclock[1].tv_nsec - myclock[0].tv_nsec;
      timedelay = 1000000000 * temp + temp_n;
   } else {
      temp = myclock[1].tv_sec - myclock[0].tv_sec - 1;
      temp_n = 1000000000 + myclock[1].tv_nsec - myclock[0].tv_nsec;
      timedelay = 1000000000 * temp + temp_n;
   }
   return timedelay;
}

안정적인 DNS서비스 DNSEver DNS server, DNS service
Posted by 키르히아이스
,

버퍼 오버플로우(buffer overflow)
버퍼 오버플로우는 프로그램이 고정폭을 가진 버퍼로 복사될때 발생합니다.
정보가 버퍼보다 크다면, 표준 C 메모리 및 문자열 루틴은 알아차리지못하고, 버퍼 외부의 쓰레기정보가 되는것입니다.
이것은 시스템을 공격하는 사람이 잘못된 코드를 실행함으로서, 호출하는 함수에 대한 정보를 겹쳐쓰기위해 사용될수있습니다.

이것은 여러가지방법으로 사용될수있습니다.
예를 들면, 인텔 기반의 시스템에서 버퍼오버플로우가 발생하면 어떤일이 발생할지 상상해봅시다.
일반적으로, 이런상황이 발생하면 UNIX 시스템에서 SIGSEGV로 인해 프로그램이 영향을 받게됩니다.
Windows사용자는 GPF(General Protection Fault)대화상자 또는 블루스크린으로 인해 프로그램이 정상적으로 실행되지않는
경우가 발생합니다.

인텔기반 시스템에서 C언어로 작성한 프로그램에서 함수를 호출하기위해 어느정도의 메모리를 할당해야 하는지 생각해봅시다.
일반적으로, 함수의 매개변수및 모든 변수는 일시적인 저장공간을 위해 임시적인 장소에 보관되는 Stack에 저장됩니다.
Stack은 CPU가 직접관리하며, LIFO(Last-In-First-Out) 큐(queue)로서 정렬됩니다. 즉, 메모리 블록의 최상위 부분이
가장 먼저 사용되며, 정보가 추가될때 아래로 내려가는 구조입니다.

함수가 호출될때, 각 매개 변수는 우선 Stack에 저장된후, 함수가 호출됩니다.
CPU 실행함수는 Stack에서 명령어 지시자(Instruction pointer)의 현재 위치를 저장함으로서 호출됩니다.
함수의 첫번째 Stack은 지역변수에 대한 Stack의 크기보다 많이 할당됩니다.
그러므로, 함수는 다음과 같이 호출됩니다.

void foo(char *bar)
{
  char baz[16] = "quux";
  ...
}

호출된후 다음과 같이 Stack에 저장됩니다.

baz--------->return addr------->bar----->
quux\0-------[void *]-----------[char *]

이제 문제점이 어디서 발생하는지 파악했을겁니다.
위의 예제에서, 16바이트보다 큰 데이터가 baz버퍼로 복사된다면, 오버플로우는 함수가 값을 되돌려줄때 코드주소로서
해석하는 루틴을 호출하기 위해 포인터를 겹쳐쓰게 됩니다.
이것은 SIGSEGV를 발생시킵니다. 즉, 포인터는 사용할수없는 메모리 범위를 카리키는 쓰레기값으로 겹쳐쓰기가됩니다.

시스템을 공격하는 사람에 의해 데이터가 복사된다면 어떤일이 벌어질지 생각해봅시다.
문자열이 버퍼에 기록되면 사용할수없는 주소가 저장될것입니다.
또한, 프로그램은 정상적으로 실행되지않고 잘못된 주소로 이동한후, 실행될것입니다.
버퍼자체는 메모리 상의 사용가능한 주소에 저장되므로, 버퍼의 주소는 버퍼의 시작부분을 가리키게됩니다.

버퍼에 사용 가능한 코드가 포함되어있다면, 프로그램이 가지고있는 모든권한으로 코드를 무의식적으로 실행합니다.
공통적으로 쉘을 실행하기위해 exec(2) 함수를 호출하는 코드를 포함합니다. 루트권한으로 프로그램을 실행했다면,
쉘은 루트의 모든권한을 가지게되겠지요.

인텔 기반의 시스템에서 Stack을 사용하는 버퍼오버플로우는 기본 매커니즘을 가지고있습니다.
거의 동일한 매커니즘이 여러 하드웨어 플랫폼에서 사용되고있습니다. 또한 시스템을 공격하는 사람은 이와 유사하게
Heap buffer를 사용할수있습니다.

버퍼오버플로우 문제해결

버퍼오버플로우는 보안성이 없는 데이터를 무작정 복사하기때문에 발생합니다.
즉, 보안성 있는 정보에서 파생되지않은 데이터를 사용하기때문입니다. 따라서, 이런 문제점을 해결하려면
보안성이 없는 데이터를 사용하여 버퍼로 복사하지말아야겠죠.

이런 문제점을 해결하는 가장 쉬운방법은 최대 길이를 가지는 인수를 허용하지않는 데이터를 받아들이는
라이브러리 루틴을 사용하지않는것입니다. 예를 들면, strcpy대신에 strncpy를 사용하는거죠.


위험         안전
strcpy --> strncpy
strcat --> strncat
sprintf --> snprintf
gets --> fgets

scanf함수는 입력시 공백제거문자열을 가리키는 %s 형식을 제공합니다.
문자열이 버퍼로 복사되므로, 보안성이 없는 입력으로 처리할때 최대 필드길이가 항상제공됩니다.
이런 정보를 입력하면 시스템을 공격하는 사람은 공백 및 오버플로우가 없이 긴 문자열을 입력할수있겠죠.

내용출처 : [기타] 인터넷 : http://udanax.org/ 원문 : Neil Matthew
안정적인 DNS서비스 DNSEver DNS server, DNS service
Posted by 키르히아이스
,

출처 : 네이X 지식즐

 

 

2005(2008)에서 Windows98계열을 더이상 공식적으로 개발환경 지원을 하지않으므로

모든 프로젝트는 기본으로 유니코드를 기본값으로 설정되어있습니다.

 

그리고 유니코드 사용과 멀티 바이트 사용시의 차이점이 뭐길래 컴파일시 에러가 나는지에 대해

설명 해주시면 감사하겠습니다~^^

1.

유니코드는 문자열을 2Byte로 인식해서 처리합니다.

멀티바이트는 문자열을 상황에 따라서 여러Byte로 인식해서 처리합니다.

(영문의 경우 ANSI와 동일하게 항상 1Byte(256자)이지만 한국어의 경우  모자라기 때문에

앞에 Byte의 값을 봐서 그 내용에 따라 다음 몇Byte(1~3Byte)를 모아서 하나의 글자로

표시하는 방식입니다.)

일단, 영어권에서는 1Byte로 모든 문자가 표시가능했지만 다른 언어권에서는 1Byte가 모자라서

멀티바이트방식으로 확장되었는데 이것이 일반적으로 처리하기도 복잡하고 여러가지 문제가

발생해서 그냥 국가 언어별로 2Byte로 통일을 해버린 것이 유니코드입니다.

(유니코드의 경우 영어권에서는 1Byte로 가능한 문자도 2Byte로 처리되므로 메모리상 2배씩

사용하므로 손해이지만 다국어를 지원하기 위해 선택하게 된것이죠. 항상 2Byte이므로 처리하기도 쉽고...)

VC에서 멀티바이트는 char (1Byte), 유니코드는 unsigned short (2Byte) 타입을 이용해 처리합니다.

 

2.

모든 win32 api들은 내부적으로 문자를 유니코드로 처리합니다.

그래서 문자열 입력을 유니코드로 받는데 하위호환성(win9x)을 위해서 멀티바이트도 입력을

받을 수 있게 API를 제공합니다. ( SendMessageW (유니코드), SendMessagA (멀티바이트) )

단지 개발환경에서 SendMessage를 사용하면 컴파일전에 유니코드 사용여부에 맞게

해당되는 형태로 스위칭되는 것이죠.

ex)

#ifdef UNICODE
#define SendMessage  SendMessageW
#else
#define SendMessage  SendMessageA
#endif // !UNICODE

 

그래서 문자나 문자열을 처리 할 때도 char를 사용하지 않고 TCHAR를 사용하는 습관을 주세요

TCHAR도 유니코드에서는 unsigned short으로 멀티바이트에서는 char로 스위칭됩니다.

그냥 무작정 char로 코딩하고 유니코드로 빌드하면 함수호출이나 문자열 사용하는 부분에서

타입에러가 나는 것이죠.

(사족이지만 이밖에도 WinMain이 호출되기 전에 VC에서는 CRTStartup이라는 C/C++ 런타임라이브러리의

스텁코드를 호출하는데 이때도 type때문에 문제가 발생할 수 있습니다...)

 

 

또 하나.. 혹시 이런식으로 6.0과 2005 사이의 알려진 설정 변경 사항이나 2005 사용시 주의 할점

알고 계신 tip이 있으시면 알려 주세요~^^

기본적으로 컴파일러가 케스팅에 엄격해져서 애매모호한 형변환들을 에러로 표시합니다.

그리고 위험한 crt함수 strcpy류등을 사용하면 경고를 출력합니다.(strsafe또는 secure crt를 사용하라고 함)

또한 C언어 표준을 엄격하게 준수합니다.

ex) for(int i = 0 ; ...) 의 예제에서 int i가 for루프 밖에서도 사용가능했는데 표준에서는 for루프 에서만

사용하도록 한정하고 있습니다. for루프 밖에서 i값에 접근하는 코드들을 2005에서 에러납니다.

for루프 이전에 int i를 따로 정의해야지 접근가능합니다.

이 외에도 프로젝트에 따라서 다양한 문제가 발생하겠죠 ^^;

'Development > C/C++' 카테고리의 다른 글

소켓 함수 처리시간 측정  (0) 2011.08.13
버퍼 오버플로우(buffer overflow)  (0) 2011.08.13
랜덤함수  (0) 2011.08.13
랜덤함수 C Source  (0) 2011.08.13
디버깅용 콘솔창을 띄우자.(자바 콘솔 맹키로...)  (0) 2011.08.13
안정적인 DNS서비스 DNSEver DNS server, DNS service
Posted by 키르히아이스
,

랜덤함수

Development/C/C++ 2011. 8. 13. 15:03

int Rand_Cur()
{
     static int nRand;

 

     if(nRand == 0)
     {
         nRand= time(NULL);
     }

     nRand= 69069 * nRand+ 1;

    

     return nRand
}

안정적인 DNS서비스 DNSEver DNS server, DNS service
Posted by 키르히아이스
,