14

関数fopen、fclose、socket、closesocketについて疑問に思っていました。fopenを呼び出したり、ソケットを開いたりするとき、正確には何が起こっていますか(特にメモリに関して)?

ファイル/ソケットを閉じずに開くと、メモリリークが発生する可能性がありますか?

そして第三に、ソケットはどのように作成され、メモリに関してはどのように見えますか?

また、ソケットの読み取りとデータの送信におけるオペレーティングシステム(Windows)の役割にも関心があります。

4

2 に答える 2

23

免責事項:私はこれについて話す資格がほとんどありません。もっと知識のある人も投稿してくれたら嬉しいです。

ファイル

fopen()のようなものがどのように実装されるかの詳細は、オペレーティングシステムに大きく依存します(たとえば、UNIXにはfopen()もあります)。Windowsのバージョンでさえ、互いに大きく異なる可能性があります。

それがどのように機能するかについての私の考えをあなたに与えるでしょう、しかしそれは基本的に推測です。

  • 呼び出されると、fopenはファイルオブジェクトをヒープに割り当てます。FILEオブジェクトのデータは文書化されていないことに注意してください-FILEは不透明な構造体であり、コードからFILEへのポインタのみを使用できます。
  • FILEオブジェクトが初期化されます。たとえば、fillLevel = 0fillLevelは、まだフラッシュされていないバッファリングされたデータの量です。
  • ファイルシステムドライバー(FSドライバー)を呼び出すと、ファイルが開き、ファイルへのハンドルが提供されます。このハンドルは、FILE構造体のどこかに配置されます。
    • これを行うために、FSドライバーは要求されたパスに対応するHDDアドレスを把握し、このHDDアドレスを内部で記憶するため、後でfreadなどへの呼び出しを実行できます。
      • FSドライバーは、一種のインデックステーブル(HDDに格納されている)を使用して、要求されたパスに対応するHDDアドレスを把握します。これは、ファイルシステムの種類(FAT32、NTFSなど)によって大きく異なります。
      • FSドライバーは、HDDドライバーに依存して、HDDへの実際の読み取りと書き込みを実行します。
  • ファイルのRAMにキャッシュが割り当てられる場合があります。このように、ユーザーが1バイトの読み取りを要求した場合、C ++は万が一に備えてKBを読み取る可能性があるため、後の読み取りは瞬時に行われます。
  • 割り当てられたFILEへのポインタがfopenから返されます。

ファイルを開いて決して閉じないと、いくつかのことがリークします。FILE構造体がリークし、FSドライバーの内部データがリークし、キャッシュ(存在する場合)もリークします。

しかし、リークするのはメモリだけではありません。OSは開いていないときに開いていると見なすため、ファイル自体がリークしますこれは、たとえばWindowsで問題になる可能性があります。この場合、書き込みモードで開いたファイルは、閉じるまで書き込みモードで再び開くことができません。

一部のファイルを閉じずにアプリを終了すると、ほとんどのOSはその後クリーンアップします。ただし、アプリは終了する前に長時間実行される可能性があり、その間もすべてのファイルを適切に閉じる必要があるため、あまり役に立ちません。また、後のクリーンアップをOSに完全に依存することはできません。これは、C標準では保証されていません。

ソケット

ソケットの実装は、ソケットのタイプ(ネットワークリッスンソケット、ネットワーククライアントソケット、プロセス間ソケットなど)によって異なります。

すべてのタイプのソケットとそれらの可能な実装の完全な説明は、ここには当てはまりません。

要するに:

  • ファイルと同じように、ソケットは、リモートホストのIPなど、その操作に関連する情報を記述した情報をRAMに保持します。
  • パフォーマンス上の理由から、RAMにキャッシュを含めることもできます
  • 開いているポートなどの有限のOSリソースを保持できるため、他のアプリで使用できなくなります

ソケットを閉じないと、これらすべてのものがリークします。

ソケットにおけるOSの役割

OSは、TCP / IP標準、イーサネット、および接続のスケジュール/ディスパッチ/受け入れに必要なその他のプロトコルを実装し、バークレーソケットなどのAPIを介してユーザーコードでそれらを利用できるようにします。

OSは、ネットワーク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();

最後に、アセンブリコードが次の非表示API「NtCreateFile」を呼び出すWindowsAPICreateFileWを呼び出します。

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命令を実行します。

于 2019-04-25T08:00:19.180 に答える