LPFN_CONNECTEX
コールバックシグネチャ
BOOL LPFN_CONNECTEX(
SOCKET s,
SOCKADDR* name,
INT namelen,
void* lpSendBuffer,
DWORD dwSendDataLength,
DWORD* lpdwBytesSent,
OVERLAPPED* lpOverlapped
);パラメーター
| フィールド | 型 | 説明 |
|---|---|---|
| s | SOCKET | 接続されていない、事前にバインドされたソケットを識別する記述子。詳細については「解説」を参照してください。 |
| name | SOCKADDR* | 接続先のアドレスを指定する sockaddr 構造体へのポインター。IPv4 の場合、sockaddr にはアドレスファミリとして AF_INET、接続先の IPv4 アドレス、接続先のポートが格納されます。IPv6 の場合、sockaddr 構造体にはアドレスファミリとして AF_INET6、接続先の IPv6 アドレス、接続先のポートが格納され、さらに IPv6 のフロー情報およびスコープ ID 情報が含まれることがあります。 |
| namelen | INT | name パラメーターが指す sockaddr 構造体の長さ (バイト単位)。 |
| lpSendBuffer | void* | 接続の確立後に転送されるバッファーへのポインター。このパラメーターは省略可能です。ConnectEx を呼び出す前に s に対して TCP_FASTOPEN オプションが有効になっている場合、このデータの一部は接続の確立中に送信されることがあります。 |
| dwSendDataLength | DWORD | lpSendBuffer パラメーターが指すデータの長さ (バイト単位)。lpSendBuffer パラメーターが NULL の場合、このパラメーターは無視されます。 |
| lpdwBytesSent | DWORD* | 正常に復帰した場合、このパラメーターは、接続の確立後に送信されたバイト数を示す DWORD 値を指します。送信されたバイトは、lpSendBuffer パラメーターが指すバッファーの内容です。lpSendBuffer パラメーターが NULL の場合、このパラメーターは無視されます。 |
| lpOverlapped | OVERLAPPED* | 要求の処理に使用される OVERLAPPED 構造体。lpOverlapped パラメーターは必ず指定する必要があり、NULL にすることはできません。 |
公式ドキュメント
ConnectEx 関数は、指定されたソケットへの接続を確立し、接続の確立後に必要に応じてデータを送信します。 ConnectEx 関数は、コネクション指向のソケットでのみサポートされます。
戻り値
成功した場合、ConnectEx 関数は TRUE を返します。失敗した場合、この関数は FALSE を返します。拡張エラー情報を取得するには、 WSAGetLastError 関数を使用します。 WSAGetLastError 関数の呼び出しが ERROR_IO_PENDING を返した場合、操作は正常に開始され、進行中です。この場合でも、オーバーラップ操作の完了時に呼び出しが失敗することがあります。
返されたエラーコードが WSAECONNREFUSED、WSAENETUNREACH、または WSAETIMEDOUT の場合、アプリケーションは同じソケットに対して ConnectEx、 WSAConnect、または connect を再度呼び出すことができます。
| エラーコード | 説明 |
|---|---|
| ConnectEx を使用する前に、 WSAStartup 関数の呼び出しが成功している必要があります。 | |
| ネットワークサブシステムで障害が発生しました。 | |
| ソケットのローカルアドレスが既に使用されており、そのソケットには SO_REUSEADDR によるアドレスの再利用が設定されていません。このエラーは通常 bind 操作中に発生しますが、ローカル IP アドレスにワイルドカードアドレス (INADDR_ANY または in6addr_any) を指定して bind 関数を呼び出した場合は、 ConnectEx 関数の呼び出しまでエラーが遅延することがあります。この場合、ConnectEx 関数によって特定の IP アドレスが暗黙的にバインドされる必要があります。 | |
| 指定されたソケットで、非ブロッキングの connect、 WSAConnect、または ConnectEx 関数の呼び出しが進行中です。 | |
| リモートアドレスが ADDR_ANY などの無効なアドレスです ( ConnectEx 関数は、コネクション指向のソケットでのみサポートされます)。 | |
| 指定されたファミリのアドレスは、このソケットでは使用できません。 | |
| 接続の試行が拒否されました。 | |
| name、lpSendBuffer、または lpOverlapped パラメーターがユーザーアドレス空間の有効な部分を指していないか、namelen が小さすぎます。 | |
| パラメーター s が、バインドされていないソケットまたはリッスン中のソケットです。 | |
| ソケットは既に接続されています。 | |
| 現時点では、このホストからネットワークに到達できません。 | |
| 到達できないホストに対してソケット操作が試行されました。 | |
| 利用可能なバッファー領域がないため、ソケットを接続できません。 | |
| 記述子がソケットではありません。 | |
| 接続を確立できないまま、接続の試行がタイムアウトしました。 |
解説(Remarks)
ConnectEx 関数は、複数のソケット関数を 1 回の API/カーネル遷移にまとめたものです。 ConnectEx 関数の呼び出しが正常に完了すると、次の操作が実行されます。
- 新しい接続が確立されます。
- 接続の確立後に、省略可能なデータブロックが送信されます。
Windows Vista 以降を対象とするアプリケーションでは、クライアントアプリケーションの設計を大幅に簡素化できる WSAConnectByList 関数または WSAConnectByName 関数の使用を検討してください。
ConnectEx 関数は、コネクション指向のソケットでのみ使用できます。s パラメーターに渡すソケットは、ソケットの種類として SOCK_STREAM、SOCK_RDM、または SOCK_SEQPACKET を指定して作成する必要があります。
lpSendBuffer パラメーターは、接続の確立後に送信するデータのバッファーを指します。dwSendDataLength パラメーターは、送信するこのデータの長さをバイト単位で指定します。アプリケーションは、send 関数や WSASend 関数と同じように、ConnectEx を使用して大きなデータバッファーの送信を要求できます。ただし、ConnectEx の 1 回の呼び出しで巨大なバッファーを送信することは強く推奨されません。この操作では、バッファー全体が送信されるまで大量のシステムメモリリソースが使用されるためです。
ConnectEx 関数が成功した場合、接続が確立され、lpSendBuffer パラメーターが指すデータはすべて、name パラメーターが指す sockaddr 構造体で指定されたアドレスに送信されています。
ConnectEx 関数はオーバーラップ I/O を使用します。そのため、ConnectEx 関数を使用すると、アプリケーションは比較的少数のスレッドで多数のクライアントを処理できます。これに対し、オーバーラップ I/O を使用しない WSAConnect 関数では、複数の要求を同時に受け取る場合、通常は接続要求ごとに個別のスレッドが必要になります。
コネクション指向のソケットでは、接続を直ちに完了できないことが多いため、操作が開始された時点で関数はすぐに ERROR_IO_PENDING または WSA_IO_PENDING エラーで復帰します。接続操作が完了して成功または失敗が確定すると、lpOverlapped で指定された完了通知メカニズムを使用して状態が報告されます。他のすべてのオーバーラップ関数の呼び出しと同様に、完了通知メカニズムとしてイベントまたは完了ポートを使用できます。 GetQueuedCompletionStatus、 GetOverlappedResult、または WSAGetOverlappedResult 関数の lpNumberOfBytesTransferred パラメーターは、要求で送信されたバイト数を示します。
ConnectEx 関数が正常に完了した場合、ソケットハンドル s は次の関数にのみ渡すことができます。
既に接続されているソケットに対して TF_DISCONNECT フラグと TF_REUSE_SOCKET フラグの両方を指定して TransmitFile 関数を呼び出すと、指定したソケットは、接続されていないがバインドされたままの状態に戻ります。この場合、そのソケットのハンドルを ConnectEx 関数の s パラメーターに渡すことはできますが、そのソケットを AcceptEx 関数の呼び出しで再利用することはできません。同様に、TransmitFile 関数を使用して再利用した受け入れ済みソケットを、ConnectEx の呼び出しで使用することもできません。なお、再利用したソケットの場合、ConnectEx は下位のトランスポートの動作の影響を受けます。たとえば、TCP ソケットは TCP の TIME_WAIT 状態の影響を受けることがあり、その結果 ConnectEx の呼び出しが遅延することがあります。
ConnectEx 関数が TRUE を返した時点で、ソケット s は接続済みソケットの既定の状態になっています。ソケット s では、SO_UPDATE_CONNECT_CONTEXT がソケットに設定されるまで、以前に設定したプロパティやオプションは有効になりません。SO_UPDATE_CONNECT_CONTEXT オプションを設定するには、 setsockopt 関数を使用します。
例:
//Need to #include <mswsock.h> for SO_UPDATE_CONNECT_CONTEXT
int iResult = 0;
iResult = setsockopt( s, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0 );
ConnectEx の実行中に接続が確立されたかどうかを確認するには、SO_CONNECT_TIME ソケットオプションを指定して getsockopt 関数を使用します。接続が確立されている場合、getsockopt 関数に渡した optval パラメーターに返される値は、そのソケットが接続されてからの秒数です。ソケットが接続されていない場合、返される optval パラメーターには 0xFFFFFFFF が格納されます。この方法で接続を確認することは、データをまったく送信しないまま一定時間接続が確立されたままになっていないかを判断するために必要です。そのような接続は終了することが推奨されます。
例:
//Need to #include <mswsock.h> for SO_CONNECT_TIME
int seconds;
int bytes = sizeof(seconds);
int iResult = 0;
iResult = getsockopt( s, SOL_SOCKET, SO_CONNECT_TIME,
(char *)&seconds, (PINT)&bytes );
if ( iResult != NO_ERROR ) {
printf( "getsockopt(SO_CONNECT_TIME) failed with error: %u\n",
WSAGetLastError() );
}
else {
if (seconds == 0xFFFFFFFF)
printf("Connection not established yet\n");
else
printf("Connection has been established %ld seconds\n",
seconds);
}
name パラメーターが指す sockaddr 構造体のアドレスパラメーターがすべて 0 の場合、ConnectEx はエラー WSAEADDRNOTAVAIL を返します。アクティブな接続を再接続しようとすると、エラーコード WSAEISCONN で失敗します。
接続済みのソケットが何らかの理由で閉じられた場合は、そのソケットを破棄して新しいソケットを作成することが推奨されます。これは、接続済みソケットで何らかの問題が発生した場合、安定した状態に戻すためには、アプリケーションはそのソケットを破棄して必要なソケットを作成し直す必要があると想定するのが最も安全なためです。
DisconnectEx 関数を TF_REUSE_SOCKET フラグ付きで呼び出すと、指定したソケットは、接続されていないがバインドされたままの状態に戻ります。この場合、そのソケットのハンドルを ConnectEx 関数の s パラメーターに渡すことができます。
TCP が閉じた接続を解放してそのリソースを再利用できるようになるまでに経過する必要がある時間の間隔は、TIME_WAIT 状態または 2MSL 状態と呼ばれます。この間、接続は、新しい接続を確立する場合よりもはるかに低いコストでクライアントとサーバーの双方で再び開くことができます。
TIME_WAIT の動作は RFC 793 で規定されており、TCP はネットワークの最大セグメント有効期間 (MSL) の 2 倍以上の間、閉じた接続を保持する必要があります。接続が解放されると、そのソケットペアおよびソケットで使用されていた内部リソースを別の接続に使用できるようになります。
Windows の TCP は、接続の終了後に TIME_WAIT 状態になります。TIME_WAIT 状態の間は、ソケットペアを再利用できません。TIME_WAIT の期間は、TIME_WAIT の期間を秒単位で表す次の DWORD レジストリ設定を変更することで構成できます。
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters\TcpTimedWaitDelay
既定では、MSL は 120 秒と定義されています。TcpTimedWaitDelay レジストリ設定の既定値は 240 秒で、これは最大セグメント有効期間 120 秒の 2 倍、つまり 4 分に相当します。ただし、このエントリを使用して間隔をカスタマイズできます。
このエントリの値を小さくすると、TCP は閉じた接続をより早く解放し、新しい接続により多くのリソースを提供できます。ただし、値が小さすぎると、接続が完了する前に TCP が接続リソースを解放してしまい、サーバーが接続を再確立するために追加のリソースを使用する必要が生じる場合があります。
このレジストリ設定には 0 から 300 秒までの値を設定できます。
Windows Phone 8: この関数は、Windows Phone 8 以降の Windows Phone ストアアプリでサポートされます。
Windows 8.1 および Windows Server 2012 R2: この関数は、Windows 8.1、Windows Server 2012 R2 以降の Windows ストアアプリでサポートされます。
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)