WSAConnectByNameA 函数 (winsock2.h)

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

此函数支持 IPv4 和 IPv6 地址。

语法

BOOL WSAConnectByNameA(
  [in]      SOCKET          s,
  [in]      LPCSTR          nodename,
  [in]      LPCSTR          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 结尾的字符串,其中包含主机的名称或要为其连接 IPv4 或 IPv6 的主机的 IP 地址。

[in] servicename

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

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

%WINDIR%\system32\drivers\etc\services

[in, out] LocalAddressLength

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

[out] LocalAddress

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

[in, out] RemoteAddressLength

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

[out] RemoteAddress

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

[in] timeout

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

Reserved

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

返回值

如果已建立连接, WSAConnectByName 将返回 TRUE ,如果调用方提供了这些缓冲区,则会填充 LocalAddressRemoteAddress 参数。

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

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

注解

WSAConnectByName 用于在特定端口上启用与远程主机的快速透明连接。 它与 IPv6 和 IPv4 版本兼容。

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

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

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

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

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

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 应用]
目标平台 Windows
标头 winsock2.h
Library Ws2_32.lib
DLL Ws2_32.dll

另请参阅

IPPROTO_IPV6套接字选项

SOCKADDR

WSAConnect

WSAConnectByList

WSAGetLastError

getaddrinfo

getpeername

getsockname

setsockopt