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

bind

関数
ソケットにローカルアドレスを割り当てる。
DLLWS2_32.dll呼出規約winapiSetLastErrorあり対応OSWindows 8.1 以降

シグネチャ

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

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

パラメーター

名前方向説明
sSOCKETinバインドされていない socket を識別するディスクリプタ。
nameSOCKADDR*in割り当てるローカルアドレスを格納したSOCKADDR構造体へのポインタ。
namelenINTinaddr が指す値の長さ (バイト単位)。

戻り値の型: INT

公式ドキュメント

bind 関数 (winsock.h) は、ローカルアドレスを socket に関連付けます。

戻り値

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

エラーコード 意味
WSANOTINITIALISED
この関数を使用する前に、 WSAStartup の呼び出しが成功している必要があります。
WSAENETDOWN
ネットワークサブシステムに障害が発生しました。
WSAEACCES
アクセス権限によって禁止されている方法で socket にアクセスしようとしました。

このエラーは、setsockoptSO_BROADCAST オプションが有効でないために、データグラム socket をブロードキャストアドレスにバインドしようとして失敗した場合に返されます。

WSAEADDRINUSE
通常、各 socket アドレス (プロトコル/ネットワークアドレス/ポート) は 1 回のみ使用が許可されます。

このエラーは、コンピューター上のプロセスが既に同じ完全修飾アドレスにバインドされており、socket が SO_REUSEADDR によるアドレス再利用を許可するようマークされていない場合に返されます。たとえば、name パラメーターで指定された IP アドレスとポートが、別のアプリケーションで使用されている別の socket に既にバインドされている場合などです。詳細については、SOL_SOCKET Socket Options リファレンスの SO_REUSEADDR socket オプション、Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE、および SO_EXCLUSIVEADDRUSE を参照してください。

WSAEADDRNOTAVAIL
要求されたアドレスはこのコンテキストでは無効です。

このエラーは、name パラメーターが指す指定アドレスが、このコンピューター上の有効なローカル IP アドレスでない場合に返されます。

WSAEFAULT
呼び出しでポインタ引数を使用しようとした際に、システムが無効なポインタアドレスを検出しました。

このエラーは、name パラメーターが NULL の場合、name または namelen パラメーターがユーザーアドレス空間の有効な部分でない場合、namelen パラメーターが小さすぎる場合、name パラメーターに関連するアドレスファミリに対して不正なアドレス形式が含まれている場合、または name で指定されたメモリブロックの先頭 2 バイトが socket ディスクリプタ s に関連付けられたアドレスファミリと一致しない場合に返されます。

WSAEINPROGRESS
ブロッキングする Windows Sockets 1.1 の呼び出しが進行中であるか、サービスプロバイダーがコールバック関数の処理中です。
WSAEINVAL
無効な引数が指定されました。

このエラーは、socket s が既にアドレスにバインドされている場合に返されます。

WSAENOBUFS
通常、WSAENOBUFS は、バインドに割り当てるための一時ポート (ephemeral port) が不足していることを示します。
WSAENOTSOCK
socket でないものに対して操作が試みられました。

このエラーは、s パラメーターのディスクリプタが socket でない場合に返されます。

解説(Remarks)

bind 関数は、接続されていない socket に対して、後続の listen 関数の呼び出しの前に必要です。通常、コネクション指向 (ストリーム) socket またはコネクションレス (データグラム) socket へのバインドに使用されます。また、bind 関数は raw socket (socket 関数で type パラメーターに SOCK_RAW を指定して作成された socket) へのバインドにも使用できます。さらに、bind 関数は、接続されていない socket に対して、送信操作の前の後続の connectConnectExWSAConnectWSAConnectByList、または WSAConnectByName 関数の呼び出しの前に使用することもできます。

socket 関数の呼び出しによって socket が作成されると、その socket は名前空間 (アドレスファミリ) 内に存在しますが、名前は割り当てられていません。bind 関数を使用して、名前のない socket にローカル名を割り当てることで、socket のローカルな関連付けを確立します。

インターネットアドレスファミリを使用する場合、名前は次の 3 つの部分で構成されます。

Windows Sockets 2 では、name パラメーターは厳密には sockaddr 構造体へのポインタとして解釈されません。これは Windows Sockets 1.1 との互換性のためにこのようにキャストされています。サービスプロバイダーは、これをサイズ namelen のメモリブロックへのポインタとみなすことができます。このブロックの先頭 2 バイト (sockaddr 構造体の sa_family メンバー、sockaddr_in 構造体の sin_family メンバー、または sockaddr_in6 構造体の sin6_family メンバーに相当) には、socket の作成に使用したアドレスファミリが含まれている必要があります。そうでない場合、WSAEFAULT エラーが発生します。

アプリケーションがどのローカルアドレスが割り当てられるかを気にしない場合は、name パラメーターの sa_data メンバーに、IPv4 ローカルアドレスでは定数値 INADDR_ANY を、IPv6 ローカルアドレスでは定数値 in6addr_any を指定します。これにより、基盤となるサービスプロバイダーが適切な任意のネットワークアドレスを使用できるようになり、マルチホームホスト (つまり、複数のネットワークインターフェイスとアドレスを持つホスト) が存在する環境でのアプリケーションプログラミングを簡素化できる可能性があります。

TCP/IP の場合、ポートにゼロを指定すると、サービスプロバイダーは動的クライアントポート範囲から一意のポートをアプリケーションに割り当てます。Windows Vista 以降では、動的クライアントポート範囲は 49152 から 65535 の間の値です。これは、動的クライアントポート範囲が 1025 から 5000 の間の値であった Windows Server 2003 以前からの変更点です。クライアント動的ポート範囲の最大値は、次のレジストリキーの下に値を設定することで変更できます。

HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

MaxUserPort レジストリ値は、動的クライアントポート範囲の最大値として使用する値を設定します。この設定を有効にするには、コンピューターを再起動する必要があります。

Windows Vista 以降では、動的クライアントポート範囲は netsh コマンドを使用して表示および変更できます。動的クライアントポート範囲は、UDP と TCP、および IPv4 と IPv6 で個別に設定できます。詳細については、KB 929851 を参照してください。

アプリケーションは、bind の呼び出し後に getsockname を使用して、socket に割り当てられたアドレスとポートを知ることができます。インターネットアドレスが INADDR_ANY または in6addr_any と等しい場合、ホストがマルチホームのときは複数のアドレスが有効になりうるため、socket が接続されるまで getsockname は必ずしもアドレスを提供できるとは限りません。クライアントアプリケーションでは、ポート 0 以外の特定のポート番号にバインドすることは推奨されません。ローカルコンピューター上でそのポート番号を既に使用している別の socket と競合する危険があるためです。

bindSO_EXCLUSIVEADDRUSE または SO_REUSEADDR socket オプションとともに使用する場合、効果を得るには、bind を実行する前にその socket オプションを設定する必要があります。詳細については、SO_EXCLUSIVEADDRUSE および Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE を参照してください。

マルチキャスト操作では、推奨される方法は、bind 関数を呼び出して socket をローカル IP アドレスに関連付けてから、マルチキャストグループに参加することです。この操作順序は必須ではありませんが、強く推奨されます。したがって、マルチキャストアプリケーションはまず、ローカルコンピューター上の IPv4 または IPv6 アドレス、ワイルドカード IPv4 アドレス (INADDR_ANY)、またはワイルドカード IPv6 アドレス (in6addr_any) を選択します。次に、マルチキャストアプリケーションは、このアドレスを name パラメーターの sa_data メンバーに指定して bind 関数を呼び出し、ローカル IP アドレスを socket に関連付けます。ワイルドカードアドレスが指定された場合、Windows が使用するローカル IP アドレスを選択します。bind 関数が完了した後、アプリケーションは対象のマルチキャストグループに参加します。マルチキャストグループへの参加方法の詳細については、Multicast Programming のセクションを参照してください。この socket は、recvrecvfromWSARecvWSARecvExWSARecvFrom、または LPFN_WSARECVMSG (WSARecvMsg) 関数を使用して、マルチキャストグループからマルチキャストパケットを受信するために使用できます。

bind 関数は、通常、マルチキャストグループへの送信操作には必要ありません。sendtoWSASendMsg、および WSASendTo 関数は、socket がまだバインドされていない場合、socket を暗黙的にワイルドカードアドレスにバインドします。send または WSASend 関数を使用する前には bind 関数が必要です。これらは暗黙的なバインドを行わず、接続済みの socket でのみ許可されます。つまり、socket が接続されるためには、あらかじめバインドされている必要があります。複数のネットワークインターフェイスとローカル IP アドレスを持つローカルコンピューター上で特定のローカル IP アドレスを選択したい場合は、sendtoWSASendMsg、または WSASendTo 関数を使用した送信操作の前に bind 関数を使用することがあります。そうでない場合、sendtoWSASendMsg、または WSASendTo 関数によるワイルドカードアドレスへの暗黙的なバインドにより、送信操作で異なるローカル IP アドレスが使用される可能性があります。

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

IrDA Sockets に関する注意

Windows Phone 8: この関数は、Windows Phone 8 以降の Windows Phone ストアアプリでサポートされています。

Windows 8.1 および Windows Server 2012 R2: この関数は、Windows 8.1、Windows Server 2012 R2 以降の Windows ストアアプリでサポートされています。

次の例は、bind 関数の使用方法を示しています。bind 関数を使用する別の例については、Getting Started With Winsock を参照してください。

#ifndef UNICODE
#define UNICODE
#endif

#define WIN32_LEAN_AND_MEAN

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

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

int main()
{

    // Declare some variables
    WSADATA wsaData;

    int iResult = 0;            // used to return function results

    // the listening socket to be created
    SOCKET ListenSocket = INVALID_SOCKET;

    // The socket address to be passed to bind
    sockaddr_in service;

    //----------------------
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != NO_ERROR) {
        wprintf(L"Error at WSAStartup()\n");
        return 1;
    }
    //----------------------
    // Create a SOCKET for listening for 
    // incoming connection requests
    ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (ListenSocket == INVALID_SOCKET) {
        wprintf(L"socket function failed with error: %u\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }
    //----------------------
    // The sockaddr_in structure specifies the address family,
    // IP address, and port for the socket that is being bound.
    service.sin_family = AF_INET;
    service.sin_addr.s_addr = inet_addr("127.0.0.1");
    service.sin_port = htons(27015);

    //----------------------
    // Bind the socket.
    iResult = bind(ListenSocket, (SOCKADDR *) &service, sizeof (service));
    if (iResult == SOCKET_ERROR) {
        wprintf(L"bind failed with error %u\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
    else
        wprintf(L"bind returned success\n");

    WSACleanup();
    return 0;
}
出典・ライセンス: 上記「公式ドキュメント」の内容は 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 bind(
    SOCKET s,
    const SOCKADDR* name,
    INT namelen
);
[DllImport("WS2_32.dll", SetLastError = true, ExactSpelling = true)]
static extern int bind(
    UIntPtr s,   // SOCKET
    IntPtr name,   // SOCKADDR*
    int namelen   // INT
);
<DllImport("WS2_32.dll", SetLastError:=True, ExactSpelling:=True)>
Public Shared Function bind(
    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 bind 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

bind = ctypes.windll.ws2_32.bind
bind.restype = ctypes.c_int
bind.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')
bind = Fiddle::Function.new(
  lib['bind'],
  [
    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 bind(
        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 bind(UIntPtr s, IntPtr name, int namelen);
"@
$api = Add-Type -MemberDefinition $sig -Name 'WS2_32_bind' -Namespace Win32 -PassThru
# $api::bind(s, name, namelen)
#uselib "WS2_32.dll"
#func global bind "bind" sptr, sptr, sptr
; bind s, varptr(name), namelen   ; 戻り値は stat
; s : SOCKET -> "sptr"
; name : SOCKADDR* -> "sptr"
; namelen : INT -> "sptr"
; ※HSP3.7は #func のため戻り値はシステム変数 stat に格納されます。
出力引数:
#uselib "WS2_32.dll"
#cfunc global bind "bind" sptr, var, int
; res = bind(s, name, namelen)
; s : SOCKET -> "sptr"
; name : SOCKADDR* -> "var"
; namelen : INT -> "int"
; ※出力/バッファ引数は var 方式(変数を直接渡す)。varptr 方式にも切替可。
出力引数:
; INT bind(SOCKET s, SOCKADDR* name, INT namelen)
#uselib "WS2_32.dll"
#cfunc global bind "bind" intptr, var, int
; res = bind(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")
	procbind = ws2_32.NewProc("bind")
)

// s (SOCKET), name (SOCKADDR*), namelen (INT)
r1, _, err := procbind.Call(
	uintptr(s),
	uintptr(name),
	uintptr(namelen),
)
_ = err  // syscall.Errno (valid when the call sets last-error)
_ = r1   // INT
function bind(
  s: NativeUInt;   // SOCKET
  name: Pointer;   // SOCKADDR*
  namelen: Integer   // INT
): Integer; stdcall;
  external 'WS2_32.dll' name 'bind';
result := DllCall("WS2_32\bind"
    , "UPtr", s   ; SOCKET
    , "Ptr", name   ; SOCKADDR*
    , "Int", namelen   ; INT
    , "Int")   ; return: INT
●bind(s, name, namelen) = DLL("WS2_32.dll", "int bind(int, void*, int)")
# 呼び出し: bind(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 bind(
    s: usize, // SOCKET
    name: [*c]SOCKADDR, // SOCKADDR*
    namelen: i32 // INT
) callconv(std.os.windows.WINAPI) i32;
proc bind(
    s: uint,  # SOCKET
    name: ptr SOCKADDR,  # SOCKADDR*
    namelen: int32  # INT
): int32 {.importc: "bind", stdcall, dynlib: "WS2_32.dll".}
pragma(lib, "ws2_32");
extern(Windows)
int bind(
    size_t s,   // SOCKET
    SOCKADDR* name,   // SOCKADDR*
    int namelen   // INT
);
ccall((:bind, "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 bind(
    uintptr_t s,
    void* name,
    int32_t namelen);
]]
local ws2_32 = ffi.load("ws2_32")
-- ws2_32.bind(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 bind = lib.func('__stdcall', 'bind', 'int32_t', ['uintptr_t', 'void *', 'int32_t']);
// bind(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", {
  bind: { parameters: ["usize", "pointer", "i32"], result: "i32" },
});
// lib.symbols.bind(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 bind(
    size_t s,
    void* name,
    int32_t namelen);
C, "WS2_32.dll");
// $ffi->bind(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 bind(
        long s,   // SOCKET
        Pointer name,   // SOCKADDR*
        int namelen   // INT
    );
}
@[Link("ws2_32")]
lib LibWS2_32
  fun bind = bind(
    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 bindNative = Int32 Function(UintPtr, Pointer<Void>, Int32);
typedef bindDart = int Function(int, Pointer<Void>, int);
final bind = DynamicLibrary.open('WS2_32.dll')
    .lookupFunction<bindNative, bindDart>('bind');
// s : SOCKET -> UintPtr
// name : SOCKADDR* -> Pointer<Void>
// namelen : INT -> Int32
// 文字列は package:ffi の "...".toNativeUtf16()/toNativeUtf8() で変換。
{$mode objfpc}{$H+}
function bind(
  s: NativeUInt;   // SOCKET
  name: Pointer;   // SOCKADDR*
  namelen: Integer   // INT
): Integer; stdcall;
  external 'WS2_32.dll' name 'bind';
import Foreign
import Foreign.C.Types
import Foreign.C.String

foreign import stdcall safe "bind"
  c_bind :: 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 bind =
  foreign "bind"
    (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 ("bind" bind :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 $bind = Win32::API::More->new('WS2_32',
    'int bind(WPARAM s, LPVOID name, int namelen)');
# my $ret = $bind->Call($s, $name, $namelen);
# s : SOCKET -> WPARAM
# name : SOCKADDR* -> LPVOID
# namelen : INT -> int
# 値渡し構造体は pack() した文字列、または Win32::API::Struct を使用。

関連項目

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