14

我只是想知道函数 fopen、fclose、socket 和 closesocket。调用 fopen 或打开套接字时,到底发生了什么(尤其是内存方面)?

打开文件/套接字而不关闭它们会导致内存泄漏吗?

第三,套接字是如何创建的,它们在内存方面看起来如何?

我还对操作系统(Windows)在读取套接字和发送数据方面的作用感兴趣。

4

2 回答 2

23

免责声明:我基本上没有资格谈论这个。如果有知识渊博的人也发帖,那就太好了。

文件

fopen() 之类的实现细节很大程度上取决于操作系统(例如,UNIX 也有 fopen())。甚至 Windows 的不同版本也可能存在很大差异。

我会告诉你它是如何工作的,但这基本上是猜测。

  • 调用时,fopen 在堆上分配一个FILE对象。请注意,FILE 对象中的数据是未记录的 - FILE 是一个不透明的结构,您只能使用代码中的指向文件的指针。
  • FILE 对象被初始化。例如,类似fillLevel = 0where fillLevel 是尚未刷新的缓冲数据量。
  • 对文件系统驱动程序(FS 驱动程序)的调用会打开文件并为其提供句柄,该句柄位于 FILE 结构中的某个位置。
    • 为此,FS 驱动程序计算出与请求路径对应的 HDD 地址,并在内部记住该 HDD 地址,以便稍后执行对 fread 等的调用。
      • FS 驱动程序使用一种索引表(存储在 HDD 上)来计算出与请求路径对应的 HDD 地址。这将根据文件系统类型(FAT32、NTFS 等)有很大不同。
      • FS 驱动程序依赖 HDD 驱动程序来执行对 HDD 的实际读取和写入。
  • 可能会在 RAM 中为文件分配缓存。这样,如果用户请求读取 1 个字节,C++ 可能会读取一个 KB 以防万一,因此以后的读取将是瞬时的。
  • 从 fopen 返回指向已分配 FILE 的指针。

如果你打开一个文件并且从不关闭它,有些东西会泄漏,是的。FILE 结构会泄漏,FS 驱动程序的内部数据会泄漏,缓存(如果有)也会泄漏。

但内存并不是唯一会泄漏的东西。文件本身会泄漏,因为操作系统会认为它不是打开的。这可能会成为一个问题,例如在 Windows 中,以写入模式打开的文件在关闭之前无法再次以写入模式打开。

如果您的应用程序在没有关闭某些文件的情况下退出,大多数操作系统都会在它之后进行清理。但这并没有多大用处,因为您的应用程序可能会在退出之前运行很长时间,并且在此期间,它仍然需要正确关闭所有文件。此外,您不能完全依赖操作系统进行清理——C 标准不保证这一点。

插座

套接字的实现将取决于套接字的类型——网络侦听套接字、网络客户端套接字、进程间套接字等。

这里不适合对所有类型的套接字及其可能的实现进行全面讨论。

简而言之:

  • 就像文件一样,套接字在 RAM 中保存一些信息,描述与其操作相关的内容,例如远程主机的 IP。
  • 出于性能原因,它还可以在 RAM 中缓存
  • 它可以保留有限的操作系统资源,例如开放端口,使它们无法被其他应用程序使用

如果您不关闭套接字,所有这些东西都会泄漏。

操作系统在套接字中的作用

操作系统实现了 TCP/IP 标准、以太网和其他协议,这些协议需要调度/调度/接受连接,并通过像伯克利套接字这样的 API 使用户代码可以使用它们。

操作系统会将网络 I/O(与网卡的通信)委托给网络驱动程序。

于 2011-02-27T00:07:09.377 回答
7

在 Windows 10 上使用 VS2017,您可以通过调用堆栈查看内部:

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

在 open.cpp 的 _wsopen_nolock 中,有:

// 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]

所以最后它执行进入内核代码的系统调用指令。

于 2019-04-25T08:00:19.180 回答