AcceptEx 関数 (mswsock.h)

AcceptEx 関数は、新しい接続を受け入れ、ローカル アドレスとリモート アドレスを返し、クライアント アプリケーションによって送信されたデータの最初のブロックを受信します。

メモ この関数は、Windows ソケット仕様に対する Microsoft 固有の拡張機能です。

 

構文

BOOL AcceptEx(
  [in]  SOCKET       sListenSocket,
  [in]  SOCKET       sAcceptSocket,
  [in]  PVOID        lpOutputBuffer,
  [in]  DWORD        dwReceiveDataLength,
  [in]  DWORD        dwLocalAddressLength,
  [in]  DWORD        dwRemoteAddressLength,
  [out] LPDWORD      lpdwBytesReceived,
  [in]  LPOVERLAPPED lpOverlapped
);

パラメーター

[in] sListenSocket

listen 関数で既に呼び出されているソケットを識別する記述子。 サーバー アプリケーションは、このソケットでの接続の試行を待機します。

[in] sAcceptSocket

受信接続を受け入れるソケットを識別する記述子。 このソケットをバインドしたり接続したりすることはできません。

[in] lpOutputBuffer

新しい接続で送信されるデータの最初のブロック、サーバーのローカル アドレス、およびクライアントのリモート アドレスを受け取るバッファーへのポインター。 受信データは、オフセット 0 から始まるバッファーの最初の部分に書き込まれ、アドレスはバッファーの後半の部分に書き込まれます。 このパラメーターを指定する必要があります。

[in] dwReceiveDataLength

バッファーの先頭にある実際の受信データに使用される lpOutputBuffer のバイト数。 このサイズには、サーバーのローカル アドレスのサイズやクライアントのリモート アドレスを含めてはなりません。これらは出力バッファーに追加されます。 dwReceiveDataLength が 0 の場合、接続を受け入れると受信操作は行われません。 代わりに、 AcceptEx は接続が到着するとすぐに完了し、データを待つ必要はありません。

[in] dwLocalAddressLength

ローカル アドレス情報用に予約されているバイト数。 この値は、使用中のトランスポート プロトコルの最大アドレス長より 16 バイト以上長くする必要があります。

[in] dwRemoteAddressLength

リモート アドレス情報用に予約されているバイト数。 この値は、使用中のトランスポート プロトコルの最大アドレス長より 16 バイト以上長くする必要があります。 0 にすることはできません。

[out] lpdwBytesReceived

受信したバイト数を受け取る DWORD へのポインター。 このパラメーターは、操作が同期的に完了した場合にのみ設定されます。 ERROR_IO_PENDINGを返し、後で完了した場合、この DWORD は設定されません。完了通知メカニズムから読み取ったバイト数を取得する必要があります。

[in] lpOverlapped

要求の処理に使用される OVERLAPPED 構造体。 このパラメーターは指定する必要があります。 NULL にすることはできません。

戻り値

エラーが発生しない場合、 AcceptEx 関数は正常に完了し、 TRUE の値が返されます。

関数が失敗した場合、 AcceptEx はFALSE を返しますWSAGetLastError 関数を呼び出して、拡張エラー情報を返すことができます。 WSAGetLastError がERROR_IO_PENDINGを返した場合、操作は正常に開始され、まだ進行中です。 エラーが WSAECONNRESET の場合は、着信接続が示されましたが、その後、呼び出しを受け入れる前にリモート ピアによって終了されました。

注釈

AcceptEx 関数は、複数のソケット関数を 1 つの API/カーネル遷移に結合します。 AcceptEx 関数は、成功すると、次の 3 つのタスクを実行します。

  • 新しい接続が受け入れられます。
  • 接続のローカル アドレスとリモート アドレスの両方が返されます。
  • リモートから送信されたデータの最初のブロックが受信されます。
メモAcceptEx 関数の関数ポインターは、実行時に、SIO_GET_EXTENSION_FUNCTION_POINTERオペコードを指定して WSAIoctl 関数を呼び出すことによって取得する必要があります。 WSAIoctl 関数に渡される入力バッファーには、AcceptEx 拡張関数を識別する値持つグローバル一意識別子 (GUID) WSAID_ACCEPTEXが含まれている必要があります。 成功した場合、 WSAIoctl 関数によって返される出力には 、AcceptEx 関数へのポインターが含まれます。 WSAID_ACCEPTEX GUID は Mswsock.h ヘッダー ファイルで定義されています。
 

プログラムでは、accept 関数の代わりに AcceptEx を使用して、ソケットへの接続をより迅速に行うことができます。

1 つの出力バッファーは、データ、ローカル ソケット アドレス (サーバー)、およびリモート ソケット アドレス (クライアント) を受け取ります。

1 つのバッファーを使用すると、パフォーマンスが向上します。 AcceptEx を使用する場合、GetAcceptExSockaddrs 関数を呼び出して、バッファーを 3 つの異なる部分 (データ、ローカル ソケット アドレス、リモート ソケット アドレス) に解析する必要があります。 Windows XP 以降では、 AcceptEx 関数が完了し、受け入れられたソケットで SO_UPDATE_ACCEPT_CONTEXT オプションが設定されると、受け入れ可能なソケットに関連付けられているローカル アドレスも getsockname 関数を使用して取得できます。 同様に、受け入れられたソケットに関連付けられているリモート アドレスは 、getpeername 関数を使用して取得できます。

ローカル アドレスとリモート アドレスのバッファー サイズは、アドレスが内部形式で書き込まれるため、使用中のトランスポート プロトコルの sockaddr 構造体のサイズより 16 バイト大きくする必要があります。 たとえば、 sockaddr_in のサイズ (TCP/IP のアドレス構造) は 16 バイトです。 そのため、ローカル アドレスとリモート アドレスには、少なくとも 32 バイトのバッファー サイズを指定する必要があります。

AcceptEx 関数は、accept 関数とは異なり、重複した I/O を使用します。 アプリケーションで AcceptEx を使用している場合は、比較的少数のスレッドで多数のクライアントにサービスを提供できます。 すべての重複する Windows 関数と同様に、Windows イベントまたは完了ポートのいずれかを完了通知メカニズムとして使用できます。

AcceptEx 関数と accept 関数のもう 1 つの主な違いは、AcceptEx で呼び出し元に既に 2 つのソケットが必要であることです。

  • リッスンするソケットを指定する 1 つ。
  • 接続を受け入れるソケットを指定する 1 つ。

sAcceptSocket パラメーターは、バインドも接続もされていないオープン ソケットである必要があります。

GetQueuedCompletionStatus 関数または GetOverlappedResult 関数の lpNumberOfBytesTransferred パラメーターは、要求で受信したバイト数を示します。

この操作が正常に完了すると、 sAcceptSocket を渡すことができますが、次の関数にのみ渡すことができます。

ReadFile
WriteFile
送信
WSASend
Recv
WSARecv
TransmitFile
closesocket
setsockopt(SO_UPDATE_ACCEPT_CONTEXTの場合のみ)
メモTransmitFile 関数が TF_DISCONNECT フラグとTF_REUSE_SOCKET フラグの両方で呼び出された場合、指定されたソケットはバインドも接続もされていない状態に戻されます。 その後、ソケット ハンドルを sAcceptSocket パラメーターの AcceptEx 関数に渡すことができますが、ソケットを ConnectEx 関数に渡すことはできません。
 

AcceptEx 関数が戻ると、ソケット sAcceptSocket は、接続されているソケットの既定の状態になります。 ソケット sAcceptSocket は、ソケットで SO_UPDATE_ACCEPT_CONTEXTが設定されるまで 、sListenSocket パラメーターに関連付けられているソケットのプロパティを継承しません。 setsockopt 関数を使用してSO_UPDATE_ACCEPT_CONTEXT オプションを設定し、ソケット ハンドルとして sAcceptSocket を、オプション値として sListenSocket を指定します。

例:

//Need to #include <mswsock.h> for SO_UPDATE_ACCEPT_CONTEXT

int iResult = 0;

iResult =  setsockopt( sAcceptSocket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, 
    (char *)&sListenSocket, sizeof(sListenSocket) );
   

受信バッファーが指定されている場合、重複した操作は、接続が受け入れられ、データが読み取られるまで完了しません。 接続が受け入れられたかどうかをチェックするには、SO_CONNECT_TIME オプションと共に getsockopt 関数を使用します。 それが受け入れられた場合は、接続が確立された期間を決定できます。 戻り値は、ソケットが接続された秒数です。 ソケットが接続されていない場合、 getsockopt は0xFFFFFFFFを返します。 重複した操作が完了したかどうかをチェックするアプリケーションは、SO_CONNECT_TIME オプションと組み合わせて、接続が受け入れられたがデータが受信されていないことを判断できます。 この方法で接続を確認すると、アプリケーションは、しばらくの間確立された接続がデータを受信していないかどうかを判断できます。 このような接続は、受け入れられたソケットを閉じて終了することをお勧めします。これにより、 AcceptEx 関数の呼び出しが強制的にエラーで完了します。

例:


INT seconds;
INT bytes = sizeof(seconds);
int iResult = 0;

iResult = getsockopt( sAcceptSocket, SOL_SOCKET, SO_CONNECT_TIME,
                      (char *)&seconds, (PINT)&bytes );

if ( iResult != NO_ERROR ) {
    printf( "getsockopt(SO_CONNECT_TIME) failed: %u\n", WSAGetLastError( ) );
    exit(1);
}

メモ 特定のスレッドによって開始されたすべての I/O は、そのスレッドが終了すると取り消されます。 重複するソケットの場合、操作が完了する前にスレッドが閉じられた場合、保留中の非同期操作が失敗する可能性があります。 詳細については、「 ExitThread 」を参照してください。
 

Windows Phone 8: この関数は、Windows Phone 8 以降のWindows Phone ストア アプリでサポートされています。

Windows 8.1Windows Server 2012 R2: この関数は、Windows 8.1、Windows Server 2012 R2 以降の Windows ストア アプリでサポートされています。

コード例

次の例では、重複した I/O ポートと完了ポートを使用して AcceptEx 関数を使用します。
#ifndef UNICODE
#define UNICODE
#endif

#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <ws2tcpip.h>
#include <mswsock.h>
#include <stdio.h>

// Need to link with Ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")

int main()
{
    //----------------------------------------
    // Declare and initialize variables
    WSADATA wsaData;
    int iResult = 0;
    BOOL bRetVal = FALSE;

    HANDLE hCompPort;
    HANDLE hCompPort2;
    
    LPFN_ACCEPTEX lpfnAcceptEx = NULL;
    GUID GuidAcceptEx = WSAID_ACCEPTEX;
    WSAOVERLAPPED olOverlap;

    SOCKET ListenSocket = INVALID_SOCKET;
    SOCKET AcceptSocket = INVALID_SOCKET;
    sockaddr_in service;
    char lpOutputBuf[1024];
    int outBufLen = 1024;
    DWORD dwBytes;

    hostent *thisHost;
    char *ip;
    u_short port;

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != NO_ERROR) {
        wprintf(L"Error at WSAStartup\n");
        return 1;
    }    

    // Create a handle for the completion port
    hCompPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (u_long) 0, 0);
    if (hCompPort == NULL) {
        wprintf(L"CreateIoCompletionPort failed with error: %u\n",
            GetLastError() );
        WSACleanup();
        return 1;
    }
            
    // Create a listening socket
    ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (ListenSocket == INVALID_SOCKET) {
        wprintf(L"Create of ListenSocket socket failed with error: %u\n",
            WSAGetLastError() );
        WSACleanup();
        return 1;
    }

    // Associate the listening socket with the completion port
    CreateIoCompletionPort((HANDLE) ListenSocket, hCompPort, (u_long) 0, 0);

    //----------------------------------------
    // Bind the listening socket to the local IP address
    // and port 27015
    port = 27015;
    thisHost = gethostbyname("");
    ip = inet_ntoa(*(struct in_addr *) *thisHost->h_addr_list);

    service.sin_family = AF_INET;
    service.sin_addr.s_addr = inet_addr(ip);
    service.sin_port = htons(port);

    if (bind(ListenSocket, (SOCKADDR *) & service, sizeof (service)) == SOCKET_ERROR) {
        wprintf(L"bind failed with error: %u\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    //----------------------------------------
    // Start listening on the listening socket
    iResult = listen(ListenSocket, 100);
    if (iResult == SOCKET_ERROR) {
        wprintf(L"listen failed with error: %u\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    wprintf(L"Listening on address: %s:%d\n", ip, port);

    // Load the AcceptEx function into memory using WSAIoctl.
    // The WSAIoctl function is an extension of the ioctlsocket()
    // function that can use overlapped I/O. The function's 3rd
    // through 6th parameters are input and output buffers where
    // we pass the pointer to our AcceptEx function. This is used
    // so that we can call the AcceptEx function directly, rather
    // than refer to the Mswsock.lib library.
    iResult = WSAIoctl(ListenSocket, SIO_GET_EXTENSION_FUNCTION_POINTER,
             &GuidAcceptEx, sizeof (GuidAcceptEx), 
             &lpfnAcceptEx, sizeof (lpfnAcceptEx), 
             &dwBytes, NULL, NULL);
    if (iResult == SOCKET_ERROR) {
        wprintf(L"WSAIoctl failed with error: %u\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    // Create an accepting socket
    AcceptSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (AcceptSocket == INVALID_SOCKET) {
        wprintf(L"Create accept socket failed with error: %u\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    // Empty our overlapped structure and accept connections.
    memset(&olOverlap, 0, sizeof (olOverlap));

    bRetVal = lpfnAcceptEx(ListenSocket, AcceptSocket, lpOutputBuf,
                 outBufLen - ((sizeof (sockaddr_in) + 16) * 2),
                 sizeof (sockaddr_in) + 16, sizeof (sockaddr_in) + 16, 
                 &dwBytes, &olOverlap);
    if (bRetVal == FALSE) {
        wprintf(L"AcceptEx failed with error: %u\n", WSAGetLastError());
        closesocket(AcceptSocket);
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    // Associate the accept socket with the completion port
    hCompPort2 = CreateIoCompletionPort((HANDLE) AcceptSocket, hCompPort, (u_long) 0, 0); 
    // hCompPort2 should be hCompPort if this succeeds
    if (hCompPort2 == NULL) {
        wprintf(L"CreateIoCompletionPort associate failed with error: %u\n",
            GetLastError() );
        closesocket(AcceptSocket);
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
    
    // Continue on to use send, recv, TransmitFile(), etc.,.
    //...

    return 0;
}


QoS に関する注意事項

TransmitFile 関数を使用すると、TF_DISCONNECTまたはTF_REUSE_SOCKETの 2 つのフラグを設定して、ファイルの送信後にソケットを "切断された再利用可能な" 状態に戻すことができます。 サービス プロバイダーは、ファイル転送が完了する前にソケットに関連付けられているサービス品質を直ちに削除できるため、サービス品質が要求されているソケットでは、これらのフラグを使用しないでください。 QoS 対応ソケットの最適な方法は、これらのフラグに依存するのではなく、ファイル転送が完了したときに closesocket 関数を呼び出すだけです。

ATMに関する注意事項

Windows ソケット 2 で非同期転送モード (ATM) を使用する場合、接続のセットアップに関連する重要な問題があります。 ATM 接続の設定に関する重要な情報については、 受け入れ 機能に関するドキュメントの「備考」セクションを参照してください。

要件

要件
サポートされている最小のクライアント Windows 8.1、 Windows Vista [デスクトップ アプリ |UWP アプリ]
サポートされている最小のサーバー Windows Server 2003 [デスクトップ アプリのみ | UWP アプリ]
対象プラットフォーム Windows
ヘッダー mswsock.h (Mswsock.h を含む)
Library Mswsock.lib
[DLL] Mswsock.dll

こちらもご覧ください

GetAcceptExSockaddrs

GetOverlappedResult

GetQueuedCompletionStatus

OVERLAPPED

TransmitFile

Winsock 関数

Winsock リファレンス

accept

closesocket

getsockopt

listen

Sockaddr