Win32 API 日本語リファレンス
ホームNetworking.WinSock › connect

connect

関数
指定アドレスへのソケット接続を確立する。
DLLWS2_32.dll呼出規約winapiSetLastErrorあり対応OSWindows Vista 以降

シグネチャ

// WS2_32.dll
#include <windows.h>

INT connect(
    SOCKET s,
    const SOCKADDR* name,
    INT namelen
);

パラメーター

名前方向説明
sSOCKETin未接続のソケットを識別するディスクリプタです。
nameSOCKADDR*in接続の確立先となる sockaddr 構造体へのポインタです。
namelenINTinname パラメータが指し示す sockaddr 構造体の長さ(バイト単位)です。

戻り値の型: INT

公式ドキュメント

connect 関数は、指定されたソケットへの接続を確立します。

戻り値

エラーが発生しなかった場合、 connect はゼロを返します。それ以外の場合は SOCKET_ERROR を返し、 WSAGetLastError を呼び出すことで具体的なエラーコードを取得できます。

ブロッキングソケットでは、戻り値が接続試行の成否を示します。

ノンブロッキングソケットでは、接続試行を即座に完了できません。この場合、 connectSOCKET_ERROR を返し、 WSAGetLastErrorWSAEWOULDBLOCK を返します。このとき、次の3つのシナリオが考えられます。

ノンブロッキングソケットで接続試行が完了するまでの間、同じソケットに対する以降の connect 呼び出しはすべてエラーコード WSAEALREADY で失敗し、接続が正常に完了した場合は WSAEISCONN となります。Windows Sockets 仕様バージョン 1.1 のあいまいさにより、接続が既に保留中のときに connect から返されるエラーコードは実装によって異なる場合があります。そのため、アプリケーションが接続完了を検出するために connect を複数回呼び出すことは推奨されません。もし複数回呼び出す場合は、堅牢な動作を保証するために、 WSAEINVAL および WSAEWOULDBLOCK のエラー値を WSAEALREADY と同じように処理できるよう準備しておく必要があります。

返されたエラーコードが接続試行の失敗(つまり WSAECONNREFUSEDWSAENETUNREACHWSAETIMEDOUT)を示している場合、アプリケーションは同じソケットに対して再度 connect を呼び出すことができます。

エラーコード 意味
WSANOTINITIALISED
この関数を使用する前に、 WSAStartup の呼び出しが正常に完了している必要があります。
WSAENETDOWN
ネットワークサブシステムが失敗しました。
WSAEADDRINUSE
ソケットのローカルアドレスが既に使用中であり、SO_REUSEADDR によるアドレス再利用が許可されるようマークされていません。このエラーは通常 bind の実行時に発生しますが、ローカル IP アドレスへの bind がワイルドカードアドレス(INADDR_ANY または in6addr_any)に対して行われた場合は、connect 関数まで遅延されることがあります。connect 関数によって特定のアドレスを暗黙的にバインドする必要があります。
WSAEINTR
ブロッキング型の Windows Socket 1.1 呼び出しが WSACancelBlockingCall によってキャンセルされました。
WSAEINPROGRESS
ブロッキング型の Windows Sockets 1.1 呼び出しが進行中であるか、サービスプロバイダがコールバック関数をまだ処理しています。
WSAEALREADY
指定されたソケットでノンブロッキングの connect 呼び出しが進行中です。
メモ 下位互換性を保つため、Winsock.dll または Wsock32.dll にリンクする Windows Sockets 1.1 アプリケーションに対しては、このエラーは WSAEINVAL として報告されます。
WSAEADDRNOTAVAIL
リモートアドレスが有効なアドレスではありません(INADDR_ANYin6addr_any など)。
WSAEAFNOSUPPORT
指定されたファミリのアドレスは、このソケットでは使用できません。
WSAECONNREFUSED
接続の試行が強制的に拒否されました。
WSAEFAULT
name が指し示す sockaddr 構造体に、関連付けられたアドレスファミリに対して不正なアドレス形式が含まれているか、namelen パラメータが小さすぎます。このエラーは、namelen パラメータで指定された長さを持つ name パラメータが指し示す sockaddr 構造体が、ユーザーアドレス空間の有効な部分に存在しない場合にも返されます。
WSAEINVAL
パラメータ s がリスニングソケットです。
WSAEISCONN
ソケットは既に接続されています(コネクション指向のソケットのみ)。
WSAENETUNREACH
現時点では、このホストからネットワークに到達できません。
WSAEHOSTUNREACH
到達できないホストに対してソケット操作が試みられました。
WSAENOBUFS
メモ 利用可能なバッファ領域がありません。ソケットを接続できません。
WSAENOTSOCK
s パラメータで指定されたディスクリプタはソケットではありません。
WSAETIMEDOUT
接続を確立できないまま、接続の試行がタイムアウトしました。
WSAEWOULDBLOCK
ソケットがノンブロッキングとしてマークされており、接続を即座に完了できません。
WSAEACCES

setsockoptSO_BROADCAST オプションが有効になっていないため、データグラムソケットをブロードキャストアドレスに接続する試行が失敗しました。

解説(Remarks)

connect 関数は、指定された宛先への接続を作成するために使用されます。ソケット s がバインドされていない場合、システムによってローカルアソシエーションに一意の値が割り当てられ、ソケットはバインド済みとしてマークされます。

コネクション指向のソケット(例: SOCK_STREAM タイプ)では、name(ソケットの名前空間におけるアドレス。詳細な説明については bind および sockaddr を参照)を使用して、外部ホストへのアクティブな接続が開始されます。

メモ ソケットがオープンされ、 setsockopt 呼び出しが行われた後に sendto 呼び出しが行われた場合、Windows Sockets は暗黙的に bind 関数の呼び出しを実行します。

ソケット呼び出しが正常に完了すると、ソケットはデータの送受信が可能な状態になります。name パラメータで指定された構造体のアドレスメンバがゼロで埋められている場合、 connect はエラー WSAEADDRNOTAVAIL を返します。アクティブな接続を再接続しようとすると、いずれもエラーコード WSAEISCONN で失敗します。

コネクション指向のノンブロッキングソケットでは、接続を即座に完了できないことがよくあります。そのような場合、この関数はエラー WSAEWOULDBLOCK を返します。ただし、操作自体は進行します。

成功または失敗の結果が判明すると、クライアントが通知をどのように登録しているかに応じて、次の2つのいずれかの方法で報告されます。

接続が即座に完了しない場合、クライアントは setsockopt を使用してソケットオプションを設定する前に、接続の完了を待つ必要があります。接続の進行中に setsockopt を呼び出すことはサポートされていません。

コネクションレスソケット(例: SOCK_DGRAM タイプ)では、 connect によって実行される操作は、以降の send/ WSASend および recv/ WSARecv 呼び出しで使用できる既定の宛先アドレスを確立するだけです。指定された宛先アドレス以外から受信したデータグラムはすべて破棄されます。name で指定された構造体のアドレスメンバがゼロで埋められている場合、ソケットは接続が解除されます。その後、既定のリモートアドレスは不定となるため、 send/ WSASend および recv/ WSARecv 呼び出しはエラーコード WSAENOTCONN を返します。ただし、 sendto/ WSASendTo および recvfrom/ WSARecvFrom は引き続き使用できます。既定の宛先は、ソケットが既に接続されている場合でも、単に再度 connect を呼び出すだけで変更できます。name が前回の connect と異なる場合、受信のためにキューに入れられているデータグラムはすべて破棄されます。

コネクションレスソケットでは、name はブロードキャストアドレスを含む任意の有効なアドレスを指定できます。ただし、ブロードキャストアドレスに接続するには、ソケットが setsockopt を使用して SO_BROADCAST オプションを有効にする必要があります。そうでない場合、 connect はエラーコード WSAEACCES で失敗します。

ソケット間の接続が切断された場合、接続されていたソケットは破棄し、新しいソケットを作成する必要があります。接続済みのソケットで問題が発生した場合、アプリケーションは安定した状態に戻るために、そのソケットを破棄し、ソケットを再度作成する必要があります。

メモ connect のようなブロッキング型の Winsock 呼び出しを発行する際、Winsock は呼び出しが完了する前にネットワークイベントを待つ必要が生じることがあります。この状況では Winsock はアラート可能な待機(alertable wait)を実行しますが、これは同じスレッドにスケジュールされた非同期プロシージャ呼び出し(APC)によって中断される可能性があります。同じスレッドで進行中のブロッキング型 Winsock 呼び出しを中断した APC の内部で、別のブロッキング型 Winsock 呼び出しを発行すると、未定義の動作につながるため、Winsock クライアントは決してこれを試みてはなりません。

サンプルコード

以下の例は、connect 関数の使用方法を示しています。
#ifndef UNICODE
#define UNICODE
#endif

#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>

// Need to link with Ws2_32.lib
#pragma comment(lib, "ws2_32.lib")

int wmain()
{
    //----------------------
    // Initialize Winsock
    WSADATA wsaData;
    int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != NO_ERROR) {
        wprintf(L"WSAStartup function failed with error: %d\n", iResult);
        return 1;
    }
    //----------------------
    // Create a SOCKET for connecting to server
    SOCKET ConnectSocket;
    ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (ConnectSocket == INVALID_SOCKET) {
        wprintf(L"socket function failed with error: %ld\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }
    //----------------------
    // The sockaddr_in structure specifies the address family,
    // IP address, and port of the server to be connected to.
    sockaddr_in clientService;
    clientService.sin_family = AF_INET;
    clientService.sin_addr.s_addr = inet_addr("127.0.0.1");
    clientService.sin_port = htons(27015);

    //----------------------
    // Connect to server.
    iResult = connect(ConnectSocket, (SOCKADDR *) & clientService, sizeof (clientService));
    if (iResult == SOCKET_ERROR) {
        wprintf(L"connect function failed with error: %ld\n", WSAGetLastError());
        iResult = closesocket(ConnectSocket);
        if (iResult == SOCKET_ERROR)
            wprintf(L"closesocket function failed with error: %ld\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }

    wprintf(L"Connected to server.\n");

    iResult = closesocket(ConnectSocket);
    if (iResult == SOCKET_ERROR) {
        wprintf(L"closesocket function failed with error: %ld\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }

    WSACleanup();
    return 0;
}

connect 関数を使用する別の例については、Getting Started With Winsock を参照してください。

IrDA ソケットに関する注意

IrDA は、sockaddr_irda 形式のアドレスを使用して connect 関数を実装します。通常、クライアントアプリケーションは socket 関数でソケットを作成し、IRLMP_ENUMDEVICES ソケットオプションで周辺の IrDA デバイスをスキャンし、返されたリストからデバイスを選択し、アドレスを形成してから connect を呼び出します。ブロッキングとノンブロッキングのセマンティクスに違いはありません。

出典・ライセンス: 上記「公式ドキュメント」の内容は Microsoft の Win32 API ドキュメント(MicrosoftDocs/sdk-api)を日本語に翻訳・改変したものです。© Microsoft Corporation. CC BY 4.0 で提供。
Microsoft 公式リファレンス: 英語 (en-us) · 日本語 (ja-jp) · 原文ソース (GitHub)

各言語での呼び出し定義

// WS2_32.dll
#include <windows.h>

INT connect(
    SOCKET s,
    const SOCKADDR* name,
    INT namelen
);
[DllImport("WS2_32.dll", SetLastError = true, ExactSpelling = true)]
static extern int connect(
    UIntPtr s,   // SOCKET
    IntPtr name,   // SOCKADDR*
    int namelen   // INT
);
<DllImport("WS2_32.dll", SetLastError:=True, ExactSpelling:=True)>
Public Shared Function connect(
    s As UIntPtr,   ' SOCKET
    name As IntPtr,   ' SOCKADDR*
    namelen As Integer   ' INT
) As Integer
End Function
' s : SOCKET
' name : SOCKADDR*
' namelen : INT
Declare PtrSafe Function connect Lib "ws2_32" ( _
    ByVal s As LongPtr, _
    ByVal name As LongPtr, _
    ByVal namelen As Long) As Long
' VBA7前提(PtrSafe)。32bit Office では LongPtr→Long。Integer=16bit / Long=32bit / LongLong=64bit。
import ctypes
from ctypes import wintypes

connect = ctypes.windll.ws2_32.connect
connect.restype = ctypes.c_int
connect.argtypes = [
    ctypes.c_size_t,  # s : SOCKET
    ctypes.c_void_p,  # name : SOCKADDR*
    ctypes.c_int,  # namelen : INT
]
# GetLastError: use ctypes.GetLastError() (or ctypes.WinDLL(use_last_error=True))
require 'fiddle'
require 'fiddle/import'

lib = Fiddle.dlopen('WS2_32.dll')
connect = Fiddle::Function.new(
  lib['connect'],
  [
    Fiddle::TYPE_UINTPTR_T,  # s : SOCKET
    Fiddle::TYPE_VOIDP,  # name : SOCKADDR*
    Fiddle::TYPE_INT,  # namelen : INT
  ],
  Fiddle::TYPE_INT)
#[link(name = "ws2_32")]
extern "system" {
    fn connect(
        s: usize,  // SOCKET
        name: *const SOCKADDR,  // SOCKADDR*
        namelen: i32  // INT
    ) -> i32;
}
// crates: windows-sys provides ready-made bindings for this API.
$sig = @"
[DllImport("WS2_32.dll", SetLastError = true)]
public static extern int connect(UIntPtr s, IntPtr name, int namelen);
"@
$api = Add-Type -MemberDefinition $sig -Name 'WS2_32_connect' -Namespace Win32 -PassThru
# $api::connect(s, name, namelen)
#uselib "WS2_32.dll"
#func global connect "connect" sptr, sptr, sptr
; connect s, varptr(name), namelen   ; 戻り値は stat
; s : SOCKET -> "sptr"
; name : SOCKADDR* -> "sptr"
; namelen : INT -> "sptr"
; ※HSP3.7は #func のため戻り値はシステム変数 stat に格納されます。
出力引数:
#uselib "WS2_32.dll"
#cfunc global connect "connect" sptr, var, int
; res = connect(s, name, namelen)
; s : SOCKET -> "sptr"
; name : SOCKADDR* -> "var"
; namelen : INT -> "int"
; ※出力/バッファ引数は var 方式(変数を直接渡す)。varptr 方式にも切替可。
出力引数:
; INT connect(SOCKET s, SOCKADDR* name, INT namelen)
#uselib "WS2_32.dll"
#cfunc global connect "connect" intptr, var, int
; res = connect(s, name, namelen)
; s : SOCKET -> "intptr"
; name : SOCKADDR* -> "var"
; namelen : INT -> "int"
; ※出力/バッファ引数は var 方式(変数を直接渡す)。varptr 方式にも切替可。
import (
	"golang.org/x/sys/windows"
	"unsafe"
)

var (
	ws2_32 = windows.NewLazySystemDLL("WS2_32.dll")
	procconnect = ws2_32.NewProc("connect")
)

// s (SOCKET), name (SOCKADDR*), namelen (INT)
r1, _, err := procconnect.Call(
	uintptr(s),
	uintptr(name),
	uintptr(namelen),
)
_ = err  // syscall.Errno (valid when the call sets last-error)
_ = r1   // INT
function connect(
  s: NativeUInt;   // SOCKET
  name: Pointer;   // SOCKADDR*
  namelen: Integer   // INT
): Integer; stdcall;
  external 'WS2_32.dll' name 'connect';
result := DllCall("WS2_32\connect"
    , "UPtr", s   ; SOCKET
    , "Ptr", name   ; SOCKADDR*
    , "Int", namelen   ; INT
    , "Int")   ; return: INT
●connect(s, name, namelen) = DLL("WS2_32.dll", "int connect(int, void*, int)")
# 呼び出し: connect(s, name, namelen)
# s : SOCKET -> "int"
# name : SOCKADDR* -> "void*"
# namelen : INT -> "int"
# なでしこ1は32bit・ANSI(Shift_JIS)。文字列=char*(ANSI)、ポインタ/ハンドル=void*(4byte)。
const std = @import("std");

extern "ws2_32" fn connect(
    s: usize, // SOCKET
    name: [*c]SOCKADDR, // SOCKADDR*
    namelen: i32 // INT
) callconv(std.os.windows.WINAPI) i32;
proc connect(
    s: uint,  # SOCKET
    name: ptr SOCKADDR,  # SOCKADDR*
    namelen: int32  # INT
): int32 {.importc: "connect", stdcall, dynlib: "WS2_32.dll".}
pragma(lib, "ws2_32");
extern(Windows)
int connect(
    size_t s,   // SOCKET
    SOCKADDR* name,   // SOCKADDR*
    int namelen   // INT
);
ccall((:connect, "WS2_32.dll"), stdcall, Int32,
      (Csize_t, Ptr{SOCKADDR}, Int32),
      s, name, namelen)
# s : SOCKET -> Csize_t
# name : SOCKADDR* -> Ptr{SOCKADDR}
# namelen : INT -> Int32
# stdcall は 32bit のみ意味を持つ(x64 では無視)。
local ffi = require("ffi")
ffi.cdef[[
int32_t connect(
    uintptr_t s,
    void* name,
    int32_t namelen);
]]
local ws2_32 = ffi.load("ws2_32")
-- ws2_32.connect(s, name, namelen)
-- s : SOCKET
-- name : SOCKADDR*
-- namelen : INT
-- 構造体/GUIDへのポインタは cdef が通るよう void* で表記(実型は各引数コメント参照)。値渡し構造体・enum は対応する typedef を cdef に追加すること。
const koffi = require('koffi');
const lib = koffi.load('WS2_32.dll');
const connect = lib.func('__stdcall', 'connect', 'int32_t', ['uintptr_t', 'void *', 'int32_t']);
// connect(s, name, namelen)
// s : SOCKET -> 'uintptr_t'
// name : SOCKADDR* -> 'void *'
// namelen : INT -> 'int32_t'
// 出力ポインタは koffi.out(...) で包む。構造体は koffi.struct で定義。
const lib = Deno.dlopen("WS2_32.dll", {
  connect: { parameters: ["usize", "pointer", "i32"], result: "i32" },
});
// lib.symbols.connect(s, name, namelen)
// s : SOCKET -> "usize"
// name : SOCKADDR* -> "pointer"
// namelen : INT -> "i32"
// 文字列引数は "buffer"(NUL 終端のバイト列を Uint8Array で渡す)。
// 値渡し構造体は { struct: [ ...field types... ] } を使用。
<?php
$ffi = FFI::cdef(<<<C
int32_t connect(
    size_t s,
    void* name,
    int32_t namelen);
C, "WS2_32.dll");
// $ffi->connect(s, name, namelen);
// s : SOCKET
// name : SOCKADDR*
// namelen : INT
// 構造体/GUIDへのポインタは cdef が通るよう void* で表記(実型は各引数コメント参照)。値渡し構造体・enum は対応する typedef を cdef に追加すること。
// WINAPI(stdcall): x64 では呼出規約が統一されるため問題なし。x86 では __stdcall 対応のラッパが必要な場合あり。
import com.sun.jna.*;
import com.sun.jna.ptr.*;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;

public interface Ws2_32 extends StdCallLibrary {
    Ws2_32 INSTANCE = Native.load("ws2_32", Ws2_32.class);
    int connect(
        long s,   // SOCKET
        Pointer name,   // SOCKADDR*
        int namelen   // INT
    );
}
@[Link("ws2_32")]
lib LibWS2_32
  fun connect = connect(
    s : LibC::SizeT,   # SOCKET
    name : SOCKADDR*,   # SOCKADDR*
    namelen : Int32   # INT
  ) : Int32
end
# 構造体/GUID/enum は lib 内に対応する型定義が必要。
# 呼出規約: x64 は規約統一のため OK。x86(32bit)は WINAPI=stdcall だが Crystal の fun に stdcall 付与構文がなく非対応。
import 'dart:ffi';
import 'package:ffi/ffi.dart';

typedef connectNative = Int32 Function(UintPtr, Pointer<Void>, Int32);
typedef connectDart = int Function(int, Pointer<Void>, int);
final connect = DynamicLibrary.open('WS2_32.dll')
    .lookupFunction<connectNative, connectDart>('connect');
// s : SOCKET -> UintPtr
// name : SOCKADDR* -> Pointer<Void>
// namelen : INT -> Int32
// 文字列は package:ffi の "...".toNativeUtf16()/toNativeUtf8() で変換。
{$mode objfpc}{$H+}
function connect(
  s: NativeUInt;   // SOCKET
  name: Pointer;   // SOCKADDR*
  namelen: Integer   // INT
): Integer; stdcall;
  external 'WS2_32.dll' name 'connect';
import Foreign
import Foreign.C.Types
import Foreign.C.String

foreign import stdcall safe "connect"
  c_connect :: CUIntPtr -> Ptr () -> Int32 -> IO Int32
-- s : SOCKET -> CUIntPtr
-- name : SOCKADDR* -> Ptr ()
-- namelen : INT -> Int32
-- 要 GHC(Windows)。stdcall は x64 では ccall として扱われる。ブロックする API は safe 呼び出し推奨。
open Ctypes
open Foreign

let connect =
  foreign "connect"
    (size_t @-> (ptr void) @-> int32_t @-> returning int32_t)
(* s : SOCKET -> size_t *)
(* name : SOCKADDR* -> (ptr void) *)
(* namelen : INT -> int32_t *)
(* foreign は cdecl 前提。x64 Windows では WINAPI と一致。構造体は ctypes structure を定義のこと。 *)
(cffi:define-foreign-library ws2_32 (t "WS2_32.dll"))
(cffi:use-foreign-library ws2_32)

(cffi:defcfun ("connect" connect :convention :stdcall) :int32
  (s :uint64)   ; SOCKET
  (name :pointer)   ; SOCKADDR*
  (namelen :int32))   ; INT
; isize/usize(INT_PTR/SIZE_T)は x64 前提で :int64/:uint64。x86 では :int32/:uint32。
use Win32::API;
my $connect = Win32::API::More->new('WS2_32',
    'int connect(WPARAM s, LPVOID name, int namelen)');
# my $ret = $connect->Call($s, $name, $namelen);
# s : SOCKET -> WPARAM
# name : SOCKADDR* -> LPVOID
# namelen : INT -> int
# 値渡し構造体は pack() した文字列、または Win32::API::Struct を使用。

関連項目

公式の関連項目
使用する型