Как именно работает fopen (), fclose ()? - PullRequest
11 голосов
/ 27 февраля 2011

Мне было просто интересно узнать о функциях fopen, fclose, socket и closesocket. Что происходит при вызове fopen или открытии сокета (особенно в отношении памяти)?

Может ли открытие файлов / сокетов без их закрытия вызвать утечки памяти?

И в-третьих, как создаются сокеты и как они выглядят в памяти?

Меня также интересует роль операционной системы (Windows) в чтении сокетов и отправке данных.

Ответы [ 2 ]

20 голосов
/ 27 февраля 2011

Отказ от ответственности: я в основном неквалифицирован, чтобы говорить об этом.Было бы замечательно, если бы кто-то более знающий тоже опубликовал.

Файлы

Детали того, как реализованы такие вещи, как fopen (), будут сильно зависеть от операционной системы (UNIX имеет fopen ()тоже например).Даже версии Windows могут сильно отличаться друг от друга.

Я дам вам свое представление о том, как это работает, но в основном это предположение.

  • При вызове fopen выделяет FILE объект в куче.Обратите внимание, что данные в объекте FILE не документированы - FILE является непрозрачной структурой , вы можете использовать только указатели на FILE из вашего кода.
  • Объект FILE инициализируется.Например, что-то вроде fillLevel = 0, где fillLevel - это количество буферизованных данных, которые еще не были сброшены.
  • Вызов драйвера файловой системы (драйвера FS) открывает файл и предоставляет ему дескриптор,который находится где-то в структуре FILE.
    • Для этого драйвер FS вычисляет адрес жесткого диска, соответствующий запрошенному пути, и внутренне запоминает этот адрес жесткого диска, чтобы впоследствии он мог выполнять вызовы к фреду и т. Д.
      • Драйвер FSиспользует своего рода таблицу индексации (хранится на жестком диске) для определения адреса жесткого диска, соответствующего запрошенному пути.Это может сильно отличаться в зависимости от типа файловой системы - FAT32, NTFS и т. Д.
      • Драйвер FS использует драйвер жесткого диска для выполнения фактических операций чтения и записи на жесткий диск.
  • Кэш-память может быть выделена в ОЗУ для файла.Таким образом, если пользователь запрашивает чтение 1 байта, C ++ может прочитать КБ на всякий случай, поэтому последующие чтения будут происходить мгновенно.
  • Указатель на выделенный FILE возвращается из fopen.

Если вы откроете файл и никогда не закроете его, некоторые вещи будут вытекать, да.Утечка структуры FILE, утечка внутренних данных драйвера FS, утечка и кеша (если есть).

Но утечка памяти - не единственная вещь.Сам файл будет иметь утечку, потому что ОС будет думать, что он открыт, а когда нет.Это может стать проблемой, например, в Windows, где файл, открытый в режиме записи, нельзя открыть снова в режиме записи, пока он не будет закрыт.

Если ваше приложение завершает работу, не закрывая какой-либо файл, большинство ОС будут очищатьпосле этого.Но это не очень полезно, потому что ваше приложение, вероятно, будет работать долгое время перед выходом, и в течение этого времени ему все равно придется правильно закрыть все файлы.Кроме того, вы не можете полностью полагаться на то, что ОС выполнит очистку после вас - это не гарантируется в стандарте C.

Сокеты

Реализация сокета будет зависеть от типа сокета - сетипрослушивающий сокет, сетевой клиентский сокет, межпроцессный сокет и т. д.

Полное обсуждение всех типов сокетов и их возможных реализаций здесь не подходит.

Короче:

  • Как и файл, сокет хранит некоторую информацию в ОЗУ, описывая вещи, относящиеся к его работе, такие как IP-адрес удаленного хоста.
  • он также может иметь кэш-память в ОЗУ для производительностипричины
  • он может удерживать ограниченные ресурсы ОС, такие как открытые порты, что делает их недоступными для использования другими приложениями

Все это может протечь, если вы не закроете сокет.

Роль ОС в сокетах

ОС реализует стандарт TCP / IP, Ethernet и другие протоколы, необходимые для планирования / отправки / приема соединений и обеспечения их доступности.к пользовательскому коду через API, например, Berkeley Sockets.

ОС будет делегировать сетевой ввод-вывод (связь с сетевой картой) сетевому драйверу.

2 голосов
/ 25 апреля 2019

С VS2017 на Windows 10 вы можете увидеть внутреннюю по callstack:

ntdll.dll!NtCreateFile()   Unknown
KernelBase.dll!CreateFileInternal() Unknown
KernelBase.dll!CreateFileW()   Unknown
ucrtbased.dll!create_file(const wchar_t * const path, _SECURITY_ATTRIBUTES * const security_attributes, const `anonymous-namespace'::file_options options) Line 234 C++
ucrtbased.dll!_wsopen_nolock(int * punlock_flag, int * pfh, const wchar_t * path, int oflag, int shflag, int pmode, int secure) Line 702    C++
ucrtbased.dll!_sopen_nolock(int * punlock_flag, int * pfh, const char * path, int oflag, int shflag, int pmode, int secure) Line 852    C++
ucrtbased.dll!__crt_char_traits<char>::tsopen_nolock<int * __ptr64,int * __ptr64,char const * __ptr64 const & __ptr64,int const & __ptr64,int,int const & __ptr64,int>(int * && <args_0>, int * && <args_1>, const char * const & <args_2>, const int & <args_3>, int && <args_4>, const int & <args_5>, int && <args_6>) Line 109  C++
ucrtbased.dll!common_sopen_dispatch<char>(const char * const path, const int oflag, const int shflag, const int pmode, int * const pfh, const int secure) Line 172  C++
ucrtbased.dll!_sopen_dispatch(const char * path, int oflag, int shflag, int pmode, int * pfh, int secure) Line 204  C++
ucrtbased.dll!_sopen_s(int * pfh, const char * path, int oflag, int shflag, int pmode) Line 895 C++
ucrtbased.dll!__crt_char_traits<char>::tsopen_s<int * __ptr64,char const * __ptr64 const & __ptr64,int const & __ptr64,int const & __ptr64,int>(int * && <args_0>, const char * const & <args_1>, const int & <args_2>, const int & <args_3>, int && <args_4>) Line 109 C++
ucrtbased.dll!common_openfile<char>(const char * const file_name, const char * const mode, const int share_flag, const __crt_stdio_stream stream) Line 38   C++
ucrtbased.dll!_openfile(const char * file_name, const char * mode, int share_flag, _iobuf * public_stream) Line 67  C++
ucrtbased.dll!__crt_char_traits<char>::open_file<char const * __ptr64 const & __ptr64,char const * __ptr64 const & __ptr64,int const & __ptr64,_iobuf * __ptr64>(const char * const & <args_0>, const char * const & <args_1>, const int & <args_2>, _iobuf * && <args_3>) Line 109 C++
ucrtbased.dll!common_fsopen<char>(const char * const file_name, const char * const mode, const int share_flag) Line 54  C++
ucrtbased.dll!fopen(const char * file, const char * mode) Line 104  C++

Большинство кодов:

C:\Program Files (x86)\Windows Kits\10\Source\10.0.17763.0\ucrt\stdio\fopen.cpp
C:\Program Files (x86)\Windows Kits\10\Source\10.0.17763.0\ucrt\stdio\openfile.cpp
C:\Program Files (x86)\Windows Kits\10\Source\10.0.17763.0\ucrt\lowio\open.cpp

В _wsopen_nolock в open.cpp есть:

// Allocate the CRT file handle.  Note that if a handle is allocated, it is
// locked when it is returned by the allocation function.  It is our caller's
// responsibility to unlock the file handle (we do not unlock it before
// returning).
*pfh = _alloc_osfhnd();

Наконец, он вызывает Windows API CreateFileW, который вызывает скрытый API «NtCreateFile», код сборки которого:

NtCreateFile:
00007FFFD81A0120 mov         r10,rcx  
00007FFFD81A0123 mov         eax,55h  
00007FFFD81A0128 test        byte ptr[7FFE0308h],1  
00007FFFD81A0130 jne         NtCreateFile+15h(07FFFD81A0135h)
00007FFFD81A0132 syscall
00007FFFD81A0134 ret
00007FFFD81A0135 int         2Eh  
00007FFFD81A0137 ret
00007FFFD81A0138 nop         dword ptr[rax + rax]

Итак, наконец, он выполняет инструкцию syscall, которая входит в код ядра.

...