AcceptEx-Funktion (winsock.h)
Die AcceptEx-Funktion akzeptiert eine neue Verbindung, gibt die lokale adresse und die Remoteadresse zurück und empfängt den ersten Datenblock, der von der Clientanwendung gesendet wird.
Syntax
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
Ein Deskriptor, der einen Socket identifiziert, der bereits mit der Listenfunktion aufgerufen wurde. Eine Serveranwendung wartet auf Verbindungsversuche mit diesem Socket.
[in] sAcceptSocket
Ein Deskriptor, der einen Socket identifiziert, für den eine eingehende Verbindung akzeptiert werden soll. Dieser Socket darf nicht gebunden oder verbunden sein.
[in] lpOutputBuffer
Ein Zeiger auf einen Puffer, der den ersten Datenblock empfängt, der für eine neue Verbindung gesendet wird, die lokale Adresse des Servers und die Remoteadresse des Clients. Die Empfangsdaten werden ab Offset null in den ersten Teil des Puffers geschrieben, während die Adressen in den letzten Teil des Puffers geschrieben werden. Dieser Parameter muss angegeben werden.
[in] dwReceiveDataLength
Die Anzahl der Bytes in lpOutputBuffer , die für tatsächliche Empfangsdaten am Anfang des Puffers verwendet werden. Diese Größe sollte weder die Größe der lokalen Adresse des Servers noch die Remoteadresse des Clients enthalten. sie werden an den Ausgabepuffer angefügt. Wenn dwReceiveDataLength null ist, führt die Annahme der Verbindung nicht zu einem Empfangsvorgang. Stattdessen wird AcceptEx abgeschlossen, sobald eine Verbindung eingeht, ohne auf Daten zu warten.
[in] dwLocalAddressLength
Die Anzahl der für die lokalen Adressinformationen reservierten Bytes. Dieser Wert muss mindestens 16 Bytes mehr als die maximale Adresslänge für das verwendete Transportprotokoll betragen.
[in] dwRemoteAddressLength
Die Anzahl der für die Remoteadresseninformationen reservierten Bytes. Dieser Wert muss mindestens 16 Bytes mehr als die maximale Adresslänge für das verwendete Transportprotokoll betragen. Darf nicht 0 sein.
[out] lpdwBytesReceived
Ein Zeiger auf ein DWORD , das die Anzahl der empfangenen Bytes empfängt. Dieser Parameter wird nur festgelegt, wenn der Vorgang synchron abgeschlossen wird. Wenn es ERROR_IO_PENDING zurückgibt und später abgeschlossen wird, wird diese DWORD nie festgelegt, und Sie müssen die Anzahl der vom Vervollständigungsbenachrichtigungsmechanismus gelesenen Bytes abrufen.
[in] lpOverlapped
Eine OVERLAPPED-Struktur , die zum Verarbeiten der Anforderung verwendet wird. Dieser Parameter muss angegeben werden. Es darf nicht NULL sein.
Rückgabewert
Wenn kein Fehler auftritt, wurde die AcceptEx-Funktion erfolgreich abgeschlossen, und der Wert TRUE wird zurückgegeben.
Wenn die Funktion fehlschlägt, gibt AcceptExFALSE zurück. Die WSAGetLastError-Funktion kann dann aufgerufen werden, um erweiterte Fehlerinformationen zurückzugeben. Wenn WSAGetLastErrorERROR_IO_PENDING zurückgibt, wurde der Vorgang erfolgreich initiiert und wird weiterhin ausgeführt. Wenn der Fehler WSAECONNRESET lautet, wurde eine eingehende Verbindung angezeigt, die anschließend vom Remotepeer beendet wurde, bevor der Anruf angenommen wurde.
Hinweise
Die AcceptEx-Funktion kombiniert mehrere Socketfunktionen zu einem einzigen API/Kernel-Übergang. Die AcceptEx-Funktion führt bei erfolgreicher Ausführung drei Aufgaben aus:
- Eine neue Verbindung wird akzeptiert.
- Sowohl die lokale als auch die Remoteadresse für die Verbindung werden zurückgegeben.
- Der erste Block von Daten, die von der Remotedaten gesendet werden, wird empfangen.
Ein Programm kann mithilfe von AcceptEx anstelle der Accept-Funktion schneller eine Verbindung mit einem Socket herstellen.
Ein einzelner Ausgabepuffer empfängt die Daten, die lokale Socketadresse (der Server) und die Remote-Socketadresse (der Client).
Die Verwendung eines einzelnen Puffers verbessert die Leistung. Bei Verwendung von AcceptEx muss die GetAcceptExSockaddrs-Funktion aufgerufen werden, um den Puffer in seine drei verschiedenen Teile (Daten, lokale Socketadresse und Remotesocketsadresse) zu analysieren. Wenn die AcceptEx-Funktion unter Windows XP und höher abgeschlossen ist und die Option SO_UPDATE_ACCEPT_CONTEXT für den akzeptierten Socket festgelegt ist, kann die dem akzeptierten Socket zugeordnete lokale Adresse auch mithilfe der getockname-Funktion abgerufen werden. Ebenso kann die Remoteadresse, die dem akzeptierten Socket zugeordnet ist, mithilfe der getpeername-Funktion abgerufen werden.
Die Puffergröße für die lokale Adresse und die Remoteadresse muss 16 Bytes höher sein als die Größe der sockaddr-Struktur für das verwendete Transportprotokoll, da die Adressen in einem internen Format geschrieben werden. Beispielsweise beträgt die Größe eines sockaddr_in (die Adressstruktur für TCP/IP) 16 Bytes. Daher muss eine Puffergröße von mindestens 32 Bytes für die lokalen und Remoteadressen angegeben werden.
Die AcceptEx-Funktion verwendet im Gegensatz zur Accept-Funktion überlappende E/A. Wenn Ihre Anwendung AcceptEx verwendet, kann sie eine große Anzahl von Clients mit einer relativ kleinen Anzahl von Threads bedienen. Wie bei allen überlappenden Windows-Funktionen können entweder Windows-Ereignisse oder Vervollständigungsports als Vervollständigungsbenachrichtigungsmechanismus verwendet werden.
Ein weiterer wichtiger Unterschied zwischen der AcceptEx-Funktion und der Accept-Funktion besteht darin, dass acceptEx erfordert, dass der Aufrufer bereits über zwei Sockets verfügt:
- Eine, die den Socket angibt, an dem lauscht werden soll.
- Eine, die den Socket angibt, für den die Verbindung akzeptiert werden soll.
Der sAcceptSocket-Parameter muss ein offener Socket sein, der weder gebunden noch verbunden ist.
Der lpNumberOfBytesTransferred-Parameter der GetQueuedCompletionStatus-Funktion oder der GetOverlappedResult-Funktion gibt die Anzahl der in der Anforderung empfangenen Bytes an.
Wenn dieser Vorgang erfolgreich abgeschlossen wurde, kann sAcceptSocket übergeben werden, aber nur an die folgenden Funktionen:
- ReadFile
- WriteFile
- send
- WSASend
- Recv
- WSARecv
- Transmitfile
- closesocket
- setsockopt(nur für SO_UPDATE_ACCEPT_CONTEXT)
Wenn die AcceptEx-Funktion zurückgegeben wird, befindet sich der Socket sAcceptSocket im Standardzustand für ein verbundenes Socket. Der Socket sAcceptSocket erbt erst dann die Eigenschaften des Sockets, der dem sListenSocket-Parameter zugeordnet ist, bis SO_UPDATE_ACCEPT_CONTEXT für den Socket festgelegt ist. Verwenden Sie die setockopt-Funktion , um die Option SO_UPDATE_ACCEPT_CONTEXT festzulegen, indem Sie sAcceptSocket als Sockethandle und sListenSocket als Optionswert angeben.
Beispiel:
//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) );
Wenn ein Empfangspuffer bereitgestellt wird, wird der überlappende Vorgang erst abgeschlossen, wenn eine Verbindung akzeptiert und Daten gelesen werden. Verwenden Sie die getockopt-Funktion mit der Option SO_CONNECT_TIME, um zu überprüfen, ob eine Verbindung akzeptiert wurde. Wenn sie akzeptiert wurde, können Sie bestimmen, wie lange die Verbindung hergestellt wurde. Der Rückgabewert ist die Anzahl von Sekunden, die der Socket verbunden wurde. Wenn der Socket nicht verbunden ist, gibt der getsockopt 0xFFFFFFFF zurück. Anwendungen, die überprüfen, ob der überlappende Vorgang in Kombination mit der Option SO_CONNECT_TIME abgeschlossen wurde, können feststellen, dass eine Verbindung akzeptiert wurde, aber keine Daten empfangen wurden. Durch die Überprüfung einer Verbindung auf diese Weise kann eine Anwendung ermitteln, ob verbindungen, die eine Weile eingerichtet wurden, keine Daten empfangen haben. Es wird empfohlen, solche Verbindungen durch Schließen des akzeptierten Sockets zu beenden, wodurch der AcceptEx-Funktionsaufruf mit einem Fehler abgeschlossen wird.
Beispiel:
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: Diese Funktion wird für Windows Phone Store-Apps auf Windows Phone 8 und höher unterstützt.
Windows 8.1 und Windows Server 2012 R2: Diese Funktion wird für Windows Store-Apps auf Windows 8.1, Windows Server 2012 R2 und höher unterstützt.
Beispielcode
Im folgenden Beispiel wird die AcceptEx-Funktion mit überlappenden E/A- und Vervollständigungsports verwendet.#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;
}
Hinweise für QoS
Die TransmitFile-Funktion ermöglicht das Festlegen von zwei Flags, TF_DISCONNECT oder TF_REUSE_SOCKET, die den Socket nach der Übertragung in einen "getrennten, wiederverwendbaren" Zustand zurückgeben. Diese Flags sollten nicht für ein Socket verwendet werden, bei dem die Dienstqualität angefordert wurde, da der Dienstanbieter alle mit dem Socket verbundenen Dienstqualität sofort löschen kann, bevor die Dateiübertragung abgeschlossen ist. Der beste Ansatz für einen QoS-fähigen Socket besteht darin, einfach die Closesocket-Funktion aufzurufen, wenn die Dateiübertragung abgeschlossen ist, anstatt sich auf diese Flags zu verlassen.Hinweise für ATM
Bei Verwendung des asynchronen Übertragungsmodus (ATM) mit Windows Sockets 2 gibt es wichtige Probleme im Zusammenhang mit der Verbindungseinrichtung. Wichtige Informationen zur Einrichtung der ATM-Verbindung finden Sie im Abschnitt Hinweise in der Dokumentation zur Annahmefunktion .Anforderungen
Anforderung | Wert |
---|---|
Unterstützte Mindestversion (Client) | Windows 8.1, Windows Vista [Desktop-Apps | UWP-Apps] |
Unterstützte Mindestversion (Server) | Windows Server 2003 [Desktop-Apps | UWP-Apps] |
Zielplattform | Windows |
Kopfzeile | winsock.h (Mswsock.h einschließen) |
Bibliothek | Mswsock.lib |
DLL | Mswsock.dll |