LPFN_CONNECTEX回调函数 (mswsock.h)
ConnectEx 函数与指定的套接字建立连接,并可以选择在建立连接后发送数据。 仅在面向连接的套接字上支持 ConnectEx 函数。
语法
LPFN_CONNECTEX LpfnConnectex;
BOOL LpfnConnectex(
[in] SOCKET s,
[in] const sockaddr *name,
[in] int namelen,
[in, optional] PVOID lpSendBuffer,
[in] DWORD dwSendDataLength,
[out] LPDWORD lpdwBytesSent,
[in] LPOVERLAPPED lpOverlapped
)
{...}
参数
[in] s
标识未连接的以前绑定的套接字的描述符。 有关更多信息,请参见备注。
[in] name
指向 的指针
sockaddr 结构,指定要连接到的地址。 对于 IPv4,sockaddr 包含地址系列、目标 IPv4 地址和目标端口的AF_INET。 对于 IPv6,sockaddr 结构包含地址系列、目标 IPv6 地址、目标端口 的AF_INET6 ,并且可能包含其他 IPv6 流和范围 ID 信息。
[in] namelen
name 参数指向的 sockaddr 结构的长度(以字节为单位)。
[in, optional] lpSendBuffer
指向建立连接后要传输的缓冲区的指针。 此参数是可选的。 如果在调用 ConnectEx之前启用了 TCP_FASTOPEN 选项,则在建立连接期间可能会发送其中一些数据。
[in] dwSendDataLength
lpSendBuffer 参数指向的数据的长度(以字节为单位)。 当 lpSendBuffer 参数为 NULL 时,将忽略此参数。
[out] lpdwBytesSent
成功返回后,此参数指向 一个 DWORD 值,该值指示建立连接后发送的字节数。 发送的字节来自 lpSendBuffer 参数指向的缓冲区。 当 lpSendBuffer 参数为 NULL 时,将忽略此参数。
[in] lpOverlapped
用于处理请求的 OVERLAPPED 结构。 必须指定 lpOverlapped 参数,并且不能为 NULL。
返回值
成功后, ConnectEx 函数返回 TRUE。 失败时,函数返回 FALSE。 使用 WSAGetLastError 函数获取扩展错误信息。 如果对 WSAGetLastError 函数的调用返回 ERROR_IO_PENDING,则表示操作已成功启动并正在进行中。 在这种情况下,当重叠的操作完成时,调用可能仍然失败。
如果返回的错误代码是 WSAECONNREFUSED、 WSAENETUNREACH 或 WSAETIMEDOUT,则应用程序可以调用 ConnectEx、 WSAConnect 或在同一套接字上再次 连接 。
错误代码 | 说明 |
---|---|
在使用 ConnectEx 之前,必须成功调用 WSAStartup 函数。 | |
网络子系统发生故障。 | |
套接字的本地地址已在使用中,并且未将套接字标记为允许使用 SO_REUSEADDR 重用地址。 此错误通常在绑定操作期间发生,但如果调用绑定函数时使用通配符地址 (INADDR_ANY或in6addr_any为本地 IP 地址指定) ,则错误可能会延迟到 ConnectEx 函数调用。 特定 IP 地址需要由 ConnectEx 函数隐式绑定。 | |
在指定的套接字上正在进行非阻止 连接、 WSAConnect 或 ConnectEx 函数调用。 | |
远程地址不是有效的地址,例如ADDR_ANY (ConnectEx 函数仅支持面向连接的套接字) 。 | |
指定系列中的地址无法与此套接字一起使用。 | |
:连接尝试被拒绝。 | |
name、lpSendBuffer 或 lpOverlapped 参数不是用户地址空间的有效部分,或者 namelen 太小。 | |
参数 s 是未绑定或侦听套接字。 | |
:套接字已连接。 | |
此时不可以从此主机访问该网络。 | |
套接字操作尝试访问无法访问的主机。 | |
没有可用的缓冲区空间;无法连接套接字。 | |
:描述符不是套接字。 | |
:连接尝试超时,没有建立连接。 |
注解
ConnectEx 函数将多个套接字函数合并到单个 API/内核转换中。 对 ConnectEx 函数的调用成功完成时,将执行以下操作:
- 建立新连接。
- 建立连接后,会发送可选的数据块。
对于面向 Windows Vista 及更高版本的应用程序,请考虑使用 WSAConnectByList 或 WSAConnectByName 函数,以大大简化客户端应用程序设计。
ConnectEx 函数只能与面向连接的套接字一起使用。 必须使用 SOCK_STREAM、SOCK_RDM 或 SOCK_SEQPACKET 的套接字类型创建在 s 参数中传递的套接字。
lpSendBuffer 参数指向建立连接后要发送的数据缓冲区。 dwSendDataLength 参数指定要发送的此数据的长度(以字节为单位)。 应用程序可以请求使用 ConnectEx 发送大型数据缓冲区,其方式与使用 send 和 WSASend 函数的方式相同。 但强烈建议开发人员不要使用 ConnectEx 在单个调用中发送大型缓冲区,因为此操作会使用大量的系统内存资源,直到发送整个缓冲区。
如果 ConnectEx 函数成功,则建立连接,并将 lpSendBuffer 参数指向的所有数据发送到 name 参数指向的 sockaddr 结构中指定的地址。
ConnectEx 函数使用重叠的 I/O。 因此, ConnectEx 函数使应用程序能够为大量线程相对较少的客户端提供服务。 相比之下, WSAConnect 函数(它不使用重叠的 I/O)通常需要一个单独的线程在同时收到请求时为每个连接请求提供服务。
面向连接的套接字通常无法立即完成其连接,因此会启动操作,并且函数会立即返回ERROR_IO_PENDING或WSA_IO_PENDING错误。 当连接操作完成并成功或失败时,将使用 lpOverlapped 中指示的完成通知机制报告状态。 与所有重叠函数调用一样,可以使用事件或完成端口作为完成通知机制。 GetQueuedCompletionStatus 或 GetOverlappedResult 或 WSAGetOverlappedResult 函数的 lpNumberOfBytesTransferred 参数指示请求中发送的字节数。
ConnectEx 函数成功完成后,套接字句柄 只能传递给以下函数:
如果在具有TF_DISCONNECT标志和TF_REUSE_SOCKET标志的以前连接的套接字上调用 TransmitFile 函数,则指定的套接字将返回到未连接但仍绑定的状态。 在这种情况下,套接字的句柄可以传递到其 s 参数中的 ConnectEx 函数,但套接字不能在 AcceptEx 函数调用中重复使用。 同样,使用 TransmitFile 函数重用的接受套接字不能用于 对 ConnectEx 的调用。 请注意,对于重复使用的套接字, ConnectEx 受基础传输行为的约束。 例如,TCP 套接字可能受 TCP TIME_WAIT状态的约束,从而导致 ConnectEx 调用延迟。
当 ConnectEx 函数返回 TRUE 时 ,套接字处于 已连接套接字的默认状态。 在 套接字上 设置SO_UPDATE_CONNECT_CONTEXT之前,套接字不会启用以前设置的属性或选项。 使用 setsockopt 函数设置 SO_UPDATE_CONNECT_CONTEXT 选项。
例如:
//Need to #include <mswsock.h> for SO_UPDATE_CONNECT_CONTEXT
int iResult = 0;
iResult = setsockopt( s, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0 );
getsockopt 函数可与 SO_CONNECT_TIME 套接字选项一起使用,以检查 ConnectEx 正在进行时是否已建立连接。 如果已建立连接,则传递给 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 结构的 address 参数全部为零,则 ConnectEx 将返回错误 WSAEADDRNOTAVAIL。 重新连接活动连接的任何尝试都将失败,错误代码为 WSAEISCONN。
当连接的套接字因任何原因关闭时,建议丢弃该套接字并创建一个新套接字。 其原因是,最安全的假设是,当连接套接字由于任何原因而出现问题时,应用程序必须放弃套接字并再次创建所需的套接字,以便返回到稳定点。
如果使用 TF_REUSE_SOCKET 标志调用 DisconnectEx 函数,则指定的套接字将返回到未连接但仍绑定的状态。 在这种情况下,套接字的句柄可以传递给 ConnectEx 函数的 s 参数。
在 TCP 可以释放已关闭的连接并重用其资源之前必须经过的时间间隔称为TIME_WAIT状态或 2MSL 状态。 在此期间,与建立新连接相比,重新打开连接对客户端和服务器的成本要低得多。
TIME_WAIT行为在 RFC 793 中指定,该行为要求 TCP 在至少等于网络 MSL) 最大段生存期 (两倍的间隔内保持关闭连接。 释放连接后,其套接字对和用于套接字的内部资源可用于支持另一个连接。
Windows TCP 在连接关闭后还原为TIME_WAIT状态。 处于TIME_WAIT状态时,不能重复使用套接字对。 可以通过修改以下 DWORD 注册表设置来配置TIME_WAIT周期,该 DWORD 注册表设置表示以秒为单位的TIME_WAIT周期。
\ HKEY_LOCAL_MACHINE系统\CurrentControlSet\服务\TCPIP\参数\TcpTimedWaitDelay
默认情况下,MSL 定义为 120 秒。 TcpTimedWaitDelay 注册表设置默认为值 240 秒,表示 120 秒或 4 分钟的最大段生存期的 2 倍。 但是,可以使用此项来自定义间隔。
通过减小此项的值,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 应用商店应用支持此函数。
要求
要求 | 值 |
---|---|
最低受支持的客户端 | Windows 8.1、Windows Vista [桌面应用 |UWP 应用] |
最低受支持的服务器 | Windows Server 2003 [桌面应用 | UWP 应用] |
目标平台 | Windows |
标头 | mswsock.h |