2011.06.30. 목
얼마 전에 알고 지내던 사람의 도움 요청이 있어서, 해당 회사의 서버 프로그램을 볼 기회가 있었습니다. 프로그램의 내용을 보고서, 이렇게 프로그램을 하면 안 되지 않을까, 자꾸 서버가 문제를 일으키는 원인이 있었네하는 생각을 가졌습니다.
모든 소스를 살펴보는 것은 시간적인 문제도 있었지만, 서비스하는 다른 회사의 소스를 마음대로 보는 것도 문제가 있겠지요. 그래서 문제가 일어난 소스만 살펴보았는데요, 그 중 하나 눈에 띈 것이 바로 strcpy 함수를 쓴 내용이었습니다. 길드 이름을 매번 사용자 프로필 구조체에 있는 친구 리스트에 strcpy 함수로 복사해서 넣는 것을 보고서, 나라면, 길드 프로필 구조체를 만들고 길드 데이터베이스에서 길드 프로필을 미리 복사를 하고, 플레이어 프로필 친구 리스트에는 단순하게 링크만 했을텐데 하고 생각하였습니다. 그렇지만 제가 생각한 방식으로 수정을 하기 위해서는 상당부분의 프로그램 소스 코드를 고쳐야 하는 일인 관계로 언급하지 않았습니다.
strcpy 함수가 첫 번째로 문제가 될 수 있는 것은 심각한 프로그램 오류를 일으킬 수 있다는 것입니다. strcpy 함수보다는 당연히 strncpy 함수나 strcpy_s 함수를 사용해야 합니다. 프로그램 어디인가, 또는 데이터베이스 필드가 복사하려는 배열 공간보다 더 큰 공간의 문자열을 가졌거나 또는 null 문자를 소실한 상태였다면, strcpy는 아주 심각한 문제를 발생시킵니다. strncpy 함수를 사용했다면, 이상하게 보여주는 정도로 끝날 오류입니다.
두 번째로는 바로 성능의 문제입니다. strcpy 함수는 계속 null 문자인가를 검사하는 로직을 가질 수밖에 없습니다. 항상 매 문자를 읽을 때보다 if 문에 의해서 null 문자 검사를 하기 때문에, 수행되는 명령어 숫자의 증가와 파이프라인이 깨지는 문제가 발생합니다.
문자열은 다음과 같은 구조로 이루어집니다.
s | t | r | i | n | g | \0 |
"string"이란 여섯 글자 이후에 있는 '\0' 문자는 아주 중요한 역할을 합니다. '\0' 문자는 문자열의 끝을 나타내줍니다. 이 때문에 많은 프로그래머는 문자열 배열을 정의할 때 다음과 같은 형태로 문자열을 정의합니다.
char str[MAX_CHAR+1];
제 경우에는 +1을 붙이지 않습니다. 구조체 등에 들어갈 때 무의미한 패딩(padding)을 발생시키고, +1을 붙이지 않더라도 보다 안전하면서 효율적으로 처리할 수 있기 때문입니다. 문자열 복사할 때에는 strcpy 대신 strncpy 또는 memcpy를 사용합니다. 포맷 형태의 문자열 출력할 때에는 "%.16s" 형태로 부분문자열 출력 형태를 사용합니다.
문자열의 '\0' 문자 이후에 있는 나머지 배열값들은 쓰레기 값들입니다. 즉 프로그램 수행에 아무런 의미가 없는 데이터입니다. strcpy 함수나 strncpy 함수를 쓰더라도 결국 목적지가 되는 배열에는 의미가 없는 쓰레기값이 있을 뿐입니다. 그렇기 때문에 memcpy 함수를 써도 하등의 문제가 되지 않을뿐더러, 오히려 많은 경우에 보안에 더 안전합니다. 많은 프로그래머는 보안을 위해서 배열을 선언한 후 배열의 내용을 0으로 지워줍니다. 그렇지만 memcpy를 사용할 경우에는 소스 문자열의 내용만 0으로 지워주면 됩니다.
주의할 것이라면 소스가 되는 배열의 크기가 목적지가 되는 배열의 크기보다 크거나 같아야 합니다. 작더라도 사실 대부분의 프로그램에서는 크게 문제가 되지 않겠지만, 그렇게 사용하지 않는 것이 바람직합니다.
서버 프로그램에서 성능상 가장 문제가 되는 것은 메모리 병목(Bottlenect) 현상입니다. 메모리 복사를 가능하면 하지 않도록 설계하는 것이 좋은 프로그램 방법일 것입니다. 때로는 구조화 형태를 무너뜨릴 수도 있겠지만, 늘 염두에 두고서 프로그램을 해야 하겠죠.
다음은 간단하게 테스트해 본 strncpy 함수와 memcpy 함수의 성능 테스트 결과입니다.
memcpy 함수는 복사할 크기가 늘어나도 서서히 수행시간이 늘어나는데, 이는 메모리 블록 복사를 하기 위한 설정 비용에 비해서 상대적으로 복사비용이 싸기 때문입니다. 그에 비해서 strncpy 함수는 계속 늘어나는 것을 볼 수 있습니다. 일반적으로 게임에서 이름은 16바이트 또는 32바이트를 사용하는데, 요즘과 같이 유니코드를 이용하는 추세라면 32바이트를 많이 사용할 것입니다. 이 경우 memcpy 함수의 이용은 strncpy 사용 대비 약 2배의 속도 개선 효과가 나옵니다. 채팅 메시지와 같은 경우라면 무려 5배정도의 속도 차이가 발생합니다. 무엇을 사용해야 할지는 이 결과를 보면 당연하다고 볼 수 있겠죠.
'Programming > Server' 카테고리의 다른 글
캐시에 의한 효율성 (6) | 2012.01.25 |
---|
댓글