VC++ の共通機能開発の概要 (コラム記事のリスト、購読歓迎、継続的な更新...) https://blog.csdn.net/chenlycly/article/details/124272585 C++ ソフトウェア異常トラブルシューティング チュートリアル シリーズ入門から習熟まで(コラム記事一覧)、ぜひ購読して更新を続けてください...)https://blog.csdn.net/chenlycly/article/details/125529931入門から習熟までのC++ソフトウェア解析ツール事例集(コラム)記事は更新中...) https://blog.csdn.net/chenlycly/article/details/131405795 C/C++ の基礎と応用 (コラム記事、継続的に更新中...) https://blog.csdn.net /chenlycly/category_11931267.html ソケットの使用 ソケットを使用してリモート サーバーに接続する場合、IP を使用してリモート サーバーとのリンクを確立する必要があります。ドメイン名を直接使用することはできません。ただし、サーバー アドレスを設定するときに、場合によっては、ドメイン名を設定する必要があります。これには、コードにドメイン名解決モジュールを追加する必要があります。サーバーに接続する前に、ドメイン名を IP アドレスに解決します。
1. ドメイン名解決の完全なプロセス
DNS システムを使用して IP をクエリする完全なプロセスについてよく友人に尋ねられますが、ここではこのプロセスを普及させていきます。DNSサーバーはルートDNSサーバー、トップレベルドメインDNSサーバー、権威DNSサーバーの3種類に大別され、トップレベルドメインDNSサーバーは主にcom、org、net、edu、などのトップレベルドメイン名を担当します。政府など
ルート DNS サーバーには、すべてのトップレベル ドメイン DNS サーバーの IP アドレスが保存されます。トップレベル ドメイン サーバーは、ルート サーバーを通じて見つけることができます。たとえば、Baidu のドメイン名 www.baidu.com の場合、ルート サーバーは IP を返します。 com トップレベル ドメインを維持するすべてのサーバーのアドレス。次に、リクエストを送信するトップレベル ドメイン サーバーの 1 つを選択すると、ドメイン名を取得した後、トップレベル ドメイン サーバーは、現在のドメインを担当する権限のあるサーバー アドレスを与えることができます。Baidu のドメイン名を例にとると、トップレベル ドメイン サーバーは、Baidu のドメインを担当するすべての権威サーバー アドレスを返します。次に、権威サーバー アドレスの 1 つを選択して、「www.baidu.com」の特定の IP アドレスをクエリすると、最終的に権威サーバーから特定の IP アドレスが返されます。また、ローカルDNSサーバーにはキャッシュ機能があり、通常2日以内のレコードがキャッシュされます。
したがって、DNS システムを通じてドメイン名に対応する IP を照会するための具体的な手順は次のように要約できます。
- ① オペレーティングシステムは、まずローカルホストファイルにレコードがあるかどうかを確認し、レコードがあれば、対応するマッピングされた IP アドレスを直接返します。
- ② ローカルホストファイルに設定がない場合、ホストはローカル DNS サーバーにクエリメッセージを送信し、ローカル DNS サーバーのキャッシュに設定があれば、結果を直接返します。
- ③ ローカルサーバーキャッシュに見つからない場合は、内蔵ルートDNSサーバーリスト(世界13、固定IPアドレス)から1つを選択してクエリメッセージを送信します。
- ④ ルート サーバーはドメイン名のサフィックス名を解決し、そのサフィックス名を担当するすべてのトップレベル サーバーのリストをローカル サーバーに伝えます。
- ⑤ ローカル サーバーは、クエリ要求を送信するトップレベル ドメイン サーバーの 1 つを選択し、ドメイン名を取得した後、トップレベル ドメイン サーバーは解析を続け、対応するドメイン内のすべての権限のあるサーバーのリストを返します。
- ⑥ ローカルサーバーは、返された権威サーバーにクエリメッセージを送信し、最終的に権威サーバーから特定の IP アドレスを取得します。
- ⑦ ホストは結果の IP を返します。
2. gethostbyname を呼び出してドメイン名解決を開始します。
では、ドメイン名を IP アドレスに解決するにはどうすればよいでしょうか? 実際、これは非常に簡単で、システム API 関数 gethostbyname を呼び出すだけで実現できます。gethostbyname 関数は、短期間の輻輳を引き起こす可能性があることに注意してください。この関数は、まずネットワーク カードに設定されている DNS サーバーにアクセスして、ドメイン名に対応する IP アドレスをクエリします。ローカル DNS にクエリできない場合は、リモート DNS サーバーにクエリを実行するため、より時間がかかる場合があります。
したがって、gethostbyname 関数を呼び出すコードを新しいスレッドに配置し、解析された IP 情報をメインスレッドに渡す必要があります。関連するコードは次のとおりです。
// 域名解析线程函数
UINT __stdcall QueryDomainThread( LPVOID pParam )
{
char* lpszDomainName = (char*)pParam;
struct hostent *pHost = gethostbyname( lpszDomainName );
if( NULL == pHost )
{
// ::PostMessage // 通知主线程域名解析失败
return 0;
}
if ( pHost->h_addr_list[0] != NULL )
{
u32 dwIP = (*(in_addr*)pHost->h_addr_list[0]).S_un.S_addr;
// ::PostMessage // 通知主线程域名解析成功,将解析出来的IP投递过去
}
return 0;
}
// 发起域名解析,创建新的线程去解析
LRESULT StartQueryDomain( char* lpszDomainName )
{
// 此处不能直接将局部变量lpszDomainName传到线程函数中,因为启动线程的_beginthreadex返回时,线程函数不一定跑起来了
// 所以最好搞一个成员变量或者全局变量,将lpszDomainName中的字符串拷贝下来,然后给_beginthreadex传递这个声明周期
// 更长的变量
strcpy( g_szMDomainName, lpszDomainName );
// 线程函数QueryDomainThread的实现,上面已经给出
HANDLE hThread= (HANDLE)_beginthreadex( NULL, 0, QueryDomainThread, (void*)g_szMDomainName, 0, NULL );
if( hThread != NULL )
{
CloseHandle( hThread );
return S_OK;
}
return S_FALSE;
}