티스토리 뷰
일반적인 FD 닫기를 구현 할 때 아래와 같이 구현 한다.
하지만 개발 할 때 우리가 지속적으로 생각해 봐야 할 부분에 대해서 작성해 보았습니다.
void CloseSockFD()
{
struct rlimit rlim;
// 현재 프로세스에 대해 열 수 있는 파일 디스크립터의 최대 개수를 조회합니다.
if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
return; // 조회에 실패하면 함수를 종료합니다.
for (rlim_t idxFD = 0; idxFD < rlim.rlim_cur; ++idxFD)
{
struct stat statbuf;
// 각 파일 디스크립터에 대한 정보를 얻기 위해 fstat 함수를 호출합니다.
if (fstat(idxFD, &statbuf) == -1)
{
if (errno == EBADF) // 유효하지 않은 파일 디스크립터인 경우 계속 진행합니다.
continue;
else
return; // 그 외의 오류가 발생한 경우 함수를 종료합니다.
}
// fstat 호출이 성공하면, 해당 파일 디스크립터가 소켓인지 확인합니다.
if (S_ISSOCK(statbuf.st_mode))
close(idxFD); // 소켓이면 해당 파일 디스크립터를 닫습니다.
}
}
1. 불필요한 검사 최소화
현재 구현에서는 유효하지 않은 파일 디스크립터에 대한 fstat 호출을 시도한 후 오류를 확인합니다. 대신, 열린 파일 디스크립터의 집합을 관리하고, 이 집합에 대해서만 fstat를 호출하는 방식으로 불필요한 시스템 호출을 줄일 수 있습니다.
2. /proc/self/fd/ 활용
리눅스 시스템에서는 /proc/self/fd/ 디렉토리를 통해 현재 프로세스의 모든 열린 파일 디스크립터를 확인할 수 있습니다. 이 방법을 사용하면 시스템이 관리하는 실제 열린 파일 디스크립터 목록을 직접 얻을 수 있어, 불필요한 반복과 검사를 피할 수 있습니다.
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
void CloseSockFD()
{
DIR *dp;
struct dirent *dirp;
if ((dp = opendir("/proc/self/fd")) == NULL)
return;
while ((dirp = readdir(dp)) != NULL) {
int fd = atoi(dirp->d_name);
if (fd > STDERR_FILENO) { // 표준 입출력을 제외
struct stat statbuf;
if (fstat(fd, &statbuf) != -1 && S_ISSOCK(statbuf.st_mode)) {
close(fd);
}
}
}
closedir(dp);
}
3. 동시성 고려
만약 이 함수가 멀티스레드 환경에서 호출될 수 있다면, 동시성에 대한 고려가 필요합니다. 여러 스레드가 동시에 파일 디스크립터를 닫을 때 생길 수 있는 문제를 방지하기 위해, 해당 작업을 수행하는 동안 다른 스레드에서의 파일 디스크립터 변경을 제한할 수 있는 동기화 메커니즘이 필요합니다.
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t fd_lock = PTHREAD_MUTEX_INITIALIZER;
void CloseSockFD()
{
DIR *dp;
struct dirent *dirp;
// /proc/self/fd를 열어 현재 프로세스의 열린 파일 디스크립터를 얻습니다.
if ((dp = opendir("/proc/self/fd")) == NULL)
return;
while ((dirp = readdir(dp)) != NULL) {
int fd = atoi(dirp->d_name);
// 표준 입출력 파일 디스크립터를 건너뜁니다.
if (fd <= STDERR_FILENO)
continue;
// 파일 디스크립터 닫기 전에 락을 걸어 동시성 문제를 방지합니다.
pthread_mutex_lock(&fd_lock);
struct stat statbuf;
if (fstat(fd, &statbuf) != -1 && S_ISSOCK(statbuf.st_mode)) {
close(fd);
}
// 작업이 끝나면 락을 해제합니다.
pthread_mutex_unlock(&fd_lock);
}
closedir(dp);
}
4. 성능 테스트
최적화를 진행한 후에는 반드시 성능 테스트를 진행해야 합니다. 최적화가 실제로 성능 개선을 가져왔는지, 그리고 부작용이 없는지 확인해야 합니다. 특히, /proc/self/fd/를 사용하는 방식은 파일 시스템 접근을 필요로 하므로, 해당 접근이 성능에 미치는 영향을 평가해야 합니다.
5. 리소스 누수 방지
파일 디스크립터를 닫는 과정에서 발생할 수 있는 리소스 누수를 방지하기 위해, 닫힌 파일 디스크립터에 대한 참조를 제거하고, 필요한 경우에는 추가적인 정리 작업을 수행해야 합니다. 예를 들어, 소켓을 닫은 후에는 관련 자료구조를 정리하는 등의 작업이 필요할 수 있습니다.
- Total
- Today
- Yesterday
- Windows
- DLL
- 스쿠버 다이빙
- C
- 네트워크 정보
- 서귀포블루버블
- 제주도
- 패턴
- 스쿠버다이빙
- CMake
- 울릉도
- 블루버블다이빙팀
- PowerShell
- OpenSource
- 외돌개
- C#
- C#.NET
- effective
- C# 고급 기술
- 서귀포
- Effective c++
- 현포다이브
- 블루버블다이브팀
- script
- 암호화
- C++
- Linux
- 블루버블
- Build
- 성산블루버블
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |