WSAConnectByNameW 函数 (winsock2.h)

WSAConnectByName 函数建立与指定主机和端口的连接。 提供此函数以允许在给定主机名和端口的情况下快速连接到网络终结点。

此函数支持 IPv4 和 IPv6 地址。

语法

BOOL WSAConnectByNameW(
  [in]      SOCKET          s,
  [in]      LPWSTR          nodename,
  [in]      LPWSTR          servicename,
  [in, out] LPDWORD         LocalAddressLength,
  [out]     LPSOCKADDR      LocalAddress,
  [in, out] LPDWORD         RemoteAddressLength,
  [out]     LPSOCKADDR      RemoteAddress,
  [in]      const timeval   *timeout,
            LPWSAOVERLAPPED Reserved
);

参数

[in] s

标识未连接的套接字的描述符。

注释 Windows 7、Windows Server 2008 R2 及更早版本,WSAConnectByName 函数需要未绑定且未连接的套接字。 这不同于建立连接的其他 Winsock 调用(例如,WSAConnect)。
 

[in] nodename

NULL-terminated 字符串,其中包含主机的名称或要连接到 IPv4 或 IPv6 的主机的 IP 地址。

[in] servicename

NULL-terminated 字符串,其中包含要连接到 IPv4 或 IPv6 的主机的服务名称或目标端口。

服务名称是端口号的字符串别名。 例如,“http”是 Internet 工程工作队(IETF)定义的端口 80 的别名,作为 Web 服务器用于 HTTP 协议的默认端口。 如果未指定端口号,则以下文件中列出了 servicename 参数的可能值:

%WINDIR%\system32\drivers\etc\services

[in, out] LocalAddressLength

在输入时,指向调用方提供的 LocalAddress 缓冲区的大小(以字节为单位)的指针。 在输出中,指向 SOCKADDRLocalAddress 缓冲区中存储的本地地址的大小(以字节为单位)的指针,该缓冲区在调用成功完成后由系统填充。

[out] LocalAddress

指向接收连接的本地地址的 SOCKADDR 结构的指针。 参数的大小正好是 LocalAddressLength中返回的大小。 这是由 gets getsockname 函数返回的相同信息。 此参数可以 NULL,在这种情况下,将忽略 LocalAddressLength 参数。

[in, out] RemoteAddressLength

在输入时,指向调用方提供的 RemoteAddress 缓冲区的大小(以字节为单位)的指针。 在输出中,指向 SOCKADDRRemoteAddress 中存储的远程地址的大小(以字节为单位)的指针, 系统在调用成功完成后填充的缓冲区。

[out] RemoteAddress

指向接收连接的远程地址的 SOCKADDR 结构的指针。 这是 getpeername 函数返回的相同信息。 此参数可以 NULL,在这种情况下,将忽略 RemoteAddressLength

[in] timeout

在中止调用之前,等待来自远程应用程序的响应的时间(以毫秒为单位)。

Reserved

保留以供将来实现使用。 此参数必须设置为 NULL

返回值

如果建立连接,WSAConnectByName 返回 true TRUELocalAddressRemoteAddress 参数,前提是调用方提供了这些缓冲区。

如果调用失败,则返回 FALSE。 然后可以调用 WSAGetLastError 以获取扩展的错误信息。

返回代码 描述
WSAEHOSTUNREACH
作为 nodename 参数传递的主机无法访问。
WSAEINVAL
将无效参数传递给函数。 nodenameservicename 参数不得 NULL保留 参数必须 NULL
WSAENOBUFS
无法分配足够的内存。
WSAENOTSOCK
传递给函数的套接字无效。 参数不得 INVALID_SOCKETNULL
WSAETIMEDOUT
在超过 超时 参数之前,未收到来自远程应用程序的响应。

言论

提供了 WSAConnectByName,以便在特定端口上实现与远程主机的快速透明连接。 它与 IPv6 和 IPv4 版本兼容。

若要启用 IPv6 和 IPv4 通信,请使用以下方法:

  • 必须在为AF_INET6地址系列创建的套接字上调用 setsockopt 函数,以便在调用 WSAConnectByName之前禁用 IPV6_V6ONLY 套接字选项。 为此,在套接字上调用 setsockopt 函数,并将 级别 参数设置为 IPPROTO_IPV6(请参阅 IPPROTO_IPV6 套接字选项)、optname 参数设置为 IPV6_V6ONLY,并将 optvalue 参数值设置为零。

WSAConnectByName 有限制:它仅适用于面向连接的套接字,例如类型SOCK_STREAM的套接字。 该函数不支持重叠的 I/O 或非阻塞行为。 即使套接字处于非阻止模式,WSAConnectByName 也会阻止。

WSAConnectByName 在建立连接期间不支持用户提供的数据。 此调用也不支持 FLOWSPEC 结构。 如果需要这些功能,则必须改用 WSAConnect

在 Windows 10 之前的版本中,如果应用程序需要绑定到特定的本地地址或端口,则无法使用 WSAConnectByName,因为套接字参数 WSAConnectByName 必须是未绑定的套接字。

此限制已删除 Windows 10。

RemoteAddressLocalAddress 参数指向 SOCKADDR 结构,这是一种泛型数据类型。 调用 WSAConnectByName 时,预期实际会在这些参数中传递特定于网络协议或地址系列的套接字地址类型。 因此,对于 IPv4 地址,指向 sockaddr_in 结构的指针将转换为指向 SOCKADDR 的指针,作为 RemoteAddressLocalAddress 参数。 对于 IPv6 地址,指向 sockaddr_in6 结构的指针将转换为指向 SOCKADDR 的指针,作为 RemoteAddressLocalAddress 参数。

WSAConnectByName 函数返回 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 );

注意 发出阻止的 Winsock 调用(如 WSAConnectByName)时,超时 参数设置为 NULL时,Winsock 可能需要等待网络事件才能完成调用。 在这种情况下,Winsock 会执行可警报的等待,这可以通过在同一线程上计划的异步过程调用(APC)中断。 在 APC 中发出另一个阻止 Winsock 调用,中断同一线程上的持续阻止 Winsock 调用将导致未定义的行为,并且永远不会由 Winsock 客户端尝试。
 
Windows Phone 8: Windows Phone 8 及更高版本的 Windows Phone 应用商店应用支持 WSAConnectByNameW 功能。

Windows 8.1Windows Server 2012 R2:Windows 8.1、Windows Server 2012 R2 及更高版本上的 Windows 应用商店应用支持 WSAConnectByNameW 函数。

例子

使用 WSAConnectByName建立连接。

#ifndef UNICODE
#define UNICODE
#endif

#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <Ws2tcpip.h>
#include <mswsock.h>   // Need for SO_UPDATE_CONNECT_CONTEXT
#include <stdio.h>

// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")

SOCKET
OpenAndConnect(LPWSTR NodeName, LPWSTR PortName) 
{
    SOCKET ConnSocket = INVALID_SOCKET;
    int ipv6only = 0;
    int iResult;
    BOOL bSuccess;
    SOCKADDR_STORAGE LocalAddr = {0};
    SOCKADDR_STORAGE RemoteAddr = {0};
    DWORD dwLocalAddr = sizeof(LocalAddr);
    DWORD dwRemoteAddr = sizeof(RemoteAddr);
  
    ConnSocket = socket(AF_INET6, SOCK_STREAM, 0);
    if (ConnSocket == INVALID_SOCKET){
        wprintf(L"socket failed with error: %d\n", WSAGetLastError());
        return INVALID_SOCKET;
    }

    iResult = setsockopt(ConnSocket, IPPROTO_IPV6,
        IPV6_V6ONLY, (char*)&ipv6only, sizeof(ipv6only) );
    if (iResult == SOCKET_ERROR){
        wprintf(L"setsockopt for IPV6_V6ONLY failed with error: %d\n",
            WSAGetLastError());
        closesocket(ConnSocket);
        return INVALID_SOCKET;       
    }

    bSuccess = WSAConnectByName(ConnSocket, NodeName, 
            PortName, &dwLocalAddr,
            (SOCKADDR*)&LocalAddr,
            &dwRemoteAddr,
            (SOCKADDR*)&RemoteAddr,
            NULL,
            NULL);
    if (!bSuccess){
        wprintf(L"WsaConnectByName failed with error: %d\n", WSAGetLastError());
        closesocket(ConnSocket);
        return INVALID_SOCKET;       

    
    }

    iResult = setsockopt(ConnSocket, SOL_SOCKET,
        SO_UPDATE_CONNECT_CONTEXT, NULL, 0);
    if (iResult == SOCKET_ERROR){
        wprintf(L"setsockopt for SO_UPDATE_CONNECT_CONTEXT failed with error: %d\n",
            WSAGetLastError());
        closesocket(ConnSocket);
        return INVALID_SOCKET;       
    }

    return ConnSocket;
}

int __cdecl wmain(int argc, wchar_t **argv)
{
   //-----------------------------------------
    // Declare and initialize variables
    WSADATA wsaData;
    int iResult;

    SOCKET s = INVALID_SOCKET;

    // Validate the parameters
    if (argc != 3) {
        wprintf(L"usage: %ws <Nodename> <Portname>\n", argv[0]);
        wprintf(L"wsaconnectbyname establishes a connection to a specified host and port.\n");
        wprintf(L"%ws www.contoso.com 8080\n", argv[0]);
        return 1;
    }

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        wprintf(L"WSAStartup failed: %d\n", iResult);
        return 1;
    }

    wprintf(L"WsaConnectByName with following parameters:\n");
    wprintf(L"\tNodename = %ws\n", argv[1]);
    wprintf(L"\tPortname (or port) = %ws\n\n", argv[2]);

    //--------------------------------
    // Call our function that uses the WsaConnectByName. 
    
    s = OpenAndConnect(argv[1], argv[2]);
    if ( s == INVALID_SOCKET ) {
        wprintf(L"WsaConnectByName failed with error: %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }
    else
    {
        wprintf(L"WsaConnectByName succeeded\n");
        
        closesocket(s);
        WSACleanup();
        return 0;
    }
}

注意

winsock2.h 标头将 WSAConnectByName 定义为一个别名,该别名根据 UNICODE 预处理器常量的定义自动选择此函数的 ANSI 或 Unicode 版本。 将中性编码别名与不中性编码的代码混合使用可能会导致编译或运行时错误不匹配。 有关详细信息,请参阅函数原型的 约定。

要求

要求 价值
最低支持的客户端 Windows 8.1、Windows Vista [桌面应用 |UWP 应用]
支持的最低服务器 Windows Server 2008 [桌面应用 |UWP 应用]
目标平台 窗户
标头 winsock2.h
Ws2_32.lib
DLL Ws2_32.dll

另请参阅

IPPROTO_IPV6 套接字选项

SOCKADDR

WSAConnect

WSAConnectByList

WSAGetLastError

getaddrinfo

getpeername

getsockname

setsockopt