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