Fungsi AcceptEx (mswsock.h)

Fungsi AcceptEx menerima koneksi baru, mengembalikan alamat lokal dan jarak jauh, dan menerima blok data pertama yang dikirim oleh aplikasi klien.

Catatan Fungsi ini adalah ekstensi khusus Microsoft untuk spesifikasi Windows Sockets.

 

Sintaks

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
);

Parameter

[in] sListenSocket

Deskriptor yang mengidentifikasi soket yang telah dipanggil dengan fungsi dengar . Aplikasi server menunggu upaya untuk terhubung pada soket ini.

[in] sAcceptSocket

Deskriptor yang mengidentifikasi soket untuk menerima koneksi masuk. Soket ini tidak boleh terikat atau tersambung.

[in] lpOutputBuffer

Penunjuk ke buffer yang menerima blok pertama data yang dikirim pada koneksi baru, alamat lokal server, dan alamat jarak jauh klien. Data penerima ditulis ke bagian pertama buffer mulai dari offset nol, sementara alamat ditulis ke bagian buffer terakhir. Parameter ini harus ditentukan.

[in] dwReceiveDataLength

Jumlah byte dalam lpOutputBuffer yang akan digunakan untuk data penerimaan aktual di awal buffer. Ukuran ini tidak boleh mencakup ukuran alamat lokal server, atau alamat jarak jauh klien; mereka ditambahkan ke buffer output. Jika dwReceiveDataLength adalah nol, menerima koneksi tidak akan menghasilkan operasi penerimaan. Sebaliknya, AcceptEx selesai segera setelah koneksi tiba, tanpa menunggu data apa pun.

[in] dwLocalAddressLength

Jumlah byte yang dicadangkan untuk informasi alamat lokal. Nilai ini harus minimal 16 byte lebih dari panjang alamat maksimum untuk protokol transportasi yang digunakan.

[in] dwRemoteAddressLength

Jumlah byte yang dicadangkan untuk informasi alamat jarak jauh. Nilai ini harus minimal 16 byte lebih dari panjang alamat maksimum untuk protokol transportasi yang digunakan. Tidak boleh nol.

[out] lpdwBytesReceived

Pointer ke DWORD yang menerima jumlah byte yang diterima. Parameter ini diatur hanya jika operasi selesai secara sinkron. Jika mengembalikan ERROR_IO_PENDING dan selesai nanti, maka DWORD ini tidak pernah diatur dan Anda harus mendapatkan jumlah byte yang dibaca dari mekanisme pemberitahuan penyelesaian.

[in] lpOverlapped

Struktur TUMPANG TINDIH yang digunakan untuk memproses permintaan. Parameter ini harus ditentukan; tidak boleh NULL.

Nilai kembali

Jika tidak ada kesalahan yang terjadi, fungsi AcceptEx berhasil diselesaikan dan nilai TRUE dikembalikan.

Jika fungsi gagal, AcceptEx mengembalikan FALSE. Fungsi WSAGetLastError kemudian dapat dipanggil untuk mengembalikan informasi kesalahan yang diperluas. Jika WSAGetLastError mengembalikan ERROR_IO_PENDING, maka operasi berhasil dimulai dan masih berlangsung. Jika kesalahannya adalah WSAECONNRESET, koneksi masuk ditunjukkan, tetapi kemudian dihentikan oleh peer jarak jauh sebelum menerima panggilan.

Keterangan

Fungsi AcceptEx menggabungkan beberapa fungsi soket ke dalam satu transisi API/kernel. Fungsi AcceptEx , jika berhasil, melakukan tiga tugas:

  • Koneksi baru diterima.
  • Alamat lokal dan jarak jauh untuk koneksi dikembalikan.
  • Blok pertama data yang dikirim oleh jarak jauh diterima.
Catatan Penunjuk fungsi untuk fungsi AcceptEx harus diperoleh pada durasi dengan melakukan panggilan ke fungsi WSAIoctl dengan opcode SIO_GET_EXTENSION_FUNCTION_POINTER yang ditentukan. Buffer input yang diteruskan ke fungsi WSAIoctl harus berisi WSAID_ACCEPTEX, pengidentifikasi unik global (GUID) yang nilainya mengidentifikasi fungsi ekstensi AcceptEx . Setelah berhasil, output yang dikembalikan oleh fungsi WSAIoctl berisi penunjuk ke fungsi AcceptEx . GUID WSAID_ACCEPTEX didefinisikan dalam file header Mswsock.h .
 

Program dapat membuat koneksi ke soket lebih cepat menggunakan AcceptEx alih-alih fungsi terima .

Buffer output tunggal menerima data, alamat soket lokal (server), dan alamat soket jarak jauh (klien).

Menggunakan buffer tunggal meningkatkan performa. Saat menggunakan AcceptEx, fungsi GetAcceptExSockaddrs harus dipanggil untuk mengurai buffer ke dalam tiga bagian yang berbeda (data, alamat soket lokal, dan alamat soket jarak jauh). Pada Windows XP dan yang lebih baru, setelah fungsi AcceptEx selesai dan opsi SO_UPDATE_ACCEPT_CONTEXT diatur pada soket yang diterima, alamat lokal yang terkait dengan soket yang diterima juga dapat diambil menggunakan fungsi getsockname . Demikian juga, alamat jarak jauh yang terkait dengan soket yang diterima dapat diambil menggunakan fungsi getpeername .

Ukuran buffer untuk alamat lokal dan jarak jauh harus 16 byte lebih dari ukuran struktur sockaddr untuk protokol transportasi yang digunakan karena alamat ditulis dalam format internal. Misalnya, ukuran sockaddr_in (struktur alamat untuk TCP/IP) adalah 16 byte. Oleh karena itu, ukuran buffer setidaknya 32 byte harus ditentukan untuk alamat lokal dan jarak jauh.

Fungsi AcceptEx menggunakan I/O yang tumpang tindih, tidak seperti fungsi terima . Jika aplikasi Anda menggunakan AcceptEx, aplikasi dapat melayani sejumlah besar klien dengan jumlah utas yang relatif kecil. Seperti semua fungsi Windows yang tumpang tindih, peristiwa Windows atau port penyelesaian dapat digunakan sebagai mekanisme pemberitahuan penyelesaian.

Perbedaan utama lain antara fungsi AcceptEx dan fungsi terima adalah bahwa AcceptEx mengharuskan penelepon sudah memiliki dua soket:

  • Salah satu yang menentukan soket untuk mendengarkan.
  • Salah satu yang menentukan soket untuk menerima koneksi.

Parameter sAcceptSocket harus berupa soket terbuka yang tidak terikat atau terhubung.

Parameter lpNumberOfBytesTransferred dari fungsi GetQueuedCompletionStatus atau fungsi GetOverlappedResult menunjukkan jumlah byte yang diterima dalam permintaan.

Ketika operasi ini berhasil diselesaikan, sAcceptSocket dapat diteruskan, tetapi ke fungsi berikut saja:

ReadFile
WriteFile
Mengirim
WSASend
recv
WSARecv
TransmitFile
closesocket
setsockopt(hanya untuk SO_UPDATE_ACCEPT_CONTEXT)
Catatan Jika fungsi TransmitFile dipanggil dengan bendera TF_DISCONNECT dan TF_REUSE_SOCKET, soket yang ditentukan telah dikembalikan ke status di mana tidak terikat atau tersambung. Handel soket kemudian dapat diteruskan ke fungsi AcceptEx dalam parameter sAcceptSocket , tetapi soket tidak dapat diteruskan ke fungsi ConnectEx .
 

Saat fungsi AcceptEx kembali, soket sAcceptSocket berada dalam status default untuk soket yang terhubung. Soket sAcceptSocket tidak mewarisi properti soket yang terkait dengan parameter sListenSocket hingga SO_UPDATE_ACCEPT_CONTEXT diatur pada soket. Gunakan fungsi setsockopt untuk mengatur opsi SO_UPDATE_ACCEPT_CONTEXT, menentukan sAcceptSocket sebagai handel soket dan sListenSocket sebagai nilai opsi.

Contohnya:

//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) );
   

Jika buffer penerima disediakan, operasi yang tumpang tindih tidak akan selesai sampai koneksi diterima dan data dibaca. Gunakan fungsi getsockopt dengan opsi SO_CONNECT_TIME untuk memeriksa apakah koneksi telah diterima. Jika telah diterima, Anda dapat menentukan berapa lama koneksi telah dibuat. Nilai yang dikembalikan adalah jumlah detik soket telah tersambung. Jika soket tidak tersambung, getsockopt akan mengembalikan 0xFFFFFFFF. Aplikasi yang memeriksa apakah operasi yang tumpang tindih telah selesai, dalam kombinasi dengan opsi SO_CONNECT_TIME, dapat menentukan bahwa koneksi telah diterima tetapi tidak ada data yang diterima. Meneliti koneksi dengan cara ini memungkinkan aplikasi untuk menentukan apakah koneksi yang telah dibuat untuk sementara waktu tidak menerima data. Disarankan agar koneksi tersebut dihentikan dengan menutup soket yang diterima, yang memaksa panggilan fungsi AcceptEx selesai dengan kesalahan.

Contohnya:


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);
}

Catatan Semua I/O yang dimulai oleh utas tertentu dibatalkan ketika utas tersebut keluar. Untuk soket yang tumpang tindih, operasi asinkron yang tertunda dapat gagal jika utas ditutup sebelum operasi selesai. Lihat ExitThread untuk informasi selengkapnya.
 

Windows Phone 8: Fungsi ini didukung untuk aplikasi Windows Phone Store di Windows Phone 8 dan yang lebih baru.

Windows 8.1 dan Windows Server 2012 R2: Fungsi ini didukung untuk aplikasi Windows Store di Windows 8.1, Windows Server 2012 R2, dan yang lebih baru.

Contoh Kode

Contoh berikut menggunakan fungsi AcceptEx menggunakan I/O yang tumpang tindih dan port penyelesaian.
#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;
}


Catatan untuk QoS

Fungsi TransmitFile memungkinkan pengaturan dua bendera, TF_DISCONNECT atau TF_REUSE_SOCKET, yang mengembalikan soket ke status "terputus, dapat digunakan kembali" setelah file ditransmisikan. Bendera ini tidak boleh digunakan pada soket di mana kualitas layanan telah diminta, karena penyedia layanan dapat segera menghapus kualitas layanan yang terkait dengan soket sebelum transfer file selesai. Pendekatan terbaik untuk soket berkemampuan QoS adalah dengan hanya memanggil fungsi closesocket ketika transfer file telah selesai, daripada mengandalkan bendera ini.

Catatan untuk ATM

Ada masalah penting yang terkait dengan penyiapan koneksi saat menggunakan Mode Transfer Asinkron (ATM) dengan Windows Sockets 2. Silakan lihat bagian Keterangan dalam dokumentasi fungsi terima untuk informasi penyiapan koneksi ATM penting.

Persyaratan

Persyaratan Nilai
Klien minimum yang didukung Windows 8.1, Windows Vista [aplikasi desktop | Aplikasi UWP]
Server minimum yang didukung Windows Server 2003 [aplikasi desktop | Aplikasi UWP]
Target Platform Windows
Header mswsock.h (termasuk Mswsock.h)
Pustaka Mswsock.lib
DLL Mswsock.dll

Lihat juga

GetAcceptExSockaddrs

GetOverlappedResult

GetQueuedCompletionStatus

TUMPANG TINDIH

TransmitFile

Fungsi Winsock

Referensi Winsock

Menerima

closesocket

getsockopt

Mendengarkan

sockaddr