我只是想知道函数fopen,fclose,socket和closesocket。当调用fopen或打开套接字时,到底发生了什么(尤其是内存方式)?
打开文件/套接字而不关闭它们会导致内存泄漏吗?
第三,如何创建套接字,它们看起来像内存一样明智?
我也对操作系统(Windows)在读取套接字和发送数据方面的作用感兴趣。
答案 0 :(得分:20)
免责声明:我几乎没有资格谈论此事。如果有更多知识渊博的人发布,那就太棒了。
fopen()的实现细节将在很大程度上取决于操作系统(例如,UNIX也有fopen())。甚至Windows的版本也可能彼此不同。
我会告诉你它是如何运作的,但它基本上是猜测。
fillLevel = 0
之类的内容,其中fillLevel是尚未刷新的缓冲数据量。如果你打开一个文件并且从不关闭它,有些东西会泄漏,是的。 FILE结构将泄漏,FS驱动程序的内部数据将泄漏,缓存(如果有)也将泄漏。
但记忆不是唯一会泄漏的东西。 文件本身会泄漏,因为操作系统会认为它不会打开。这可能会成为一个问题,例如在Windows中,在写入模式下打开的文件在关闭之前无法再以写入模式打开。
如果你的应用程序在没有关闭某个文件的情况下退出,大多数操作系统都会在它之后清理。但这并没有多大用处,因为您的应用可能会在退出之前运行很长时间,在此期间,它仍然需要正确关闭所有文件。此外,您不能完全依赖操作系统来清理 - 在C标准中无法保证。
套接字的实现将取决于套接字的类型 - 网络侦听套接字,网络客户端套接字,进程间套接字等。
对所有类型的套接字及其可能的实现的完整讨论都不适合这里。
简而言之:
如果你不关闭插座,所有这些东西都会泄漏。
操作系统实施TCP / IP标准,以太网和其他协议,用于调度/分派/接受连接,并通过Berkeley套接字等API将其提供给用户代码。
操作系统会将网络I / O(与网卡通信)委派给网络驱动程序。
答案 1 :(得分:2)
在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,该Windows API将调用隐藏的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指令。