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

accept

関数
接続要求を受け入れ新しいソケットを生成する。
DLLWS2_32.dll呼出規約winapiSetLastErrorあり対応OSWindows 8.1 以降

シグネチャ

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

SOCKET accept(
    SOCKET s,
    SOCKADDR* addr,   // optional
    INT* addrlen   // optional
);

パラメーター

名前方向説明
sSOCKETinlisten 関数によってリスニング状態に置かれたソケットを識別する記述子。実際の接続は accept が返すソケットで確立されます。
addrSOCKADDR*outoptional通信層が認識している、接続元エンティティのアドレスを受け取るバッファーへのオプションのポインター。addr パラメーターの正確な形式は、 sockaddr 構造体からソケットが作成された際に確立されたアドレスファミリによって決まります。
addrlenINT*inoutoptionaladdr パラメーターが指す構造体の長さを格納する整数へのオプションのポインター。

戻り値の型: SOCKET

公式ドキュメント

accept 関数は、ソケットへの着信接続要求を受け付けます。

戻り値

エラーが発生しなかった場合、 accept は新しいソケットの記述子である SOCKET 型の値を返します。この戻り値は、実際に接続が確立されるソケットのハンドルです。

それ以外の場合は INVALID_SOCKET が返され、 WSAGetLastError を呼び出すことで特定のエラーコードを取得できます。

addrlen が参照する整数には、初期状態では addr が指す領域のサイズが格納されています。戻り時には、返されたアドレスの実際の長さ(バイト単位)が格納されます。

エラーコード 意味
WSANOTINITIALISED
この関数を使用する前に、 WSAStartup の呼び出しが正常に完了している必要があります。
WSAECONNRESET
着信接続が示されましたが、呼び出しを受け付ける前にリモートピアによって終了されました。
WSAEFAULT
addrlen パラメーターが小さすぎるか、addr がユーザーアドレス空間の有効な部分ではありません。
WSAEINTR
ブロッキング Windows Sockets 1.1 呼び出しが WSACancelBlockingCall によってキャンセルされました。
WSAEINVAL
accept の前に listen 関数が呼び出されていません。
WSAEINPROGRESS
ブロッキング Windows Sockets 1.1 呼び出しが進行中であるか、サービスプロバイダーがコールバック関数をまだ処理しています。
WSAEMFILE
accept の呼び出し時にキューが空でなく、利用可能な記述子がありません。
WSAENETDOWN
ネットワークサブシステムが失敗しました。
WSAENOBUFS
利用可能なバッファー領域がありません。
WSAENOTSOCK
記述子がソケットではありません。
WSAEOPNOTSUPP
参照されたソケットは、コネクション指向サービスをサポートする種類ではありません。
WSAEWOULDBLOCK
ソケットが非ブロッキングとしてマークされており、受け付け可能な接続が存在しません。

解説(Remarks)

accept 関数は、ソケット s の保留中接続のキューから先頭の接続を取り出します。次に、新しいソケットへのハンドルを作成して返します。新しく作成されたソケットが実際の接続を処理するソケットであり、 WSAAsyncSelect または WSAEventSelect 関数で登録された非同期イベントを含め、ソケット s と同じプロパティを持ちます。

キューに保留中の接続がなく、ソケットがブロッキングとしてマークされている場合、 accept 関数は接続が存在するまで呼び出し元をブロックすることがあります。ソケットが非ブロッキングとしてマークされており、キューに保留中の接続がない場合、 accept は以下で説明するエラーを返します。 accept が正常に完了して新しいソケットハンドルを返した後、受け付けたソケットを使用してさらに接続を受け付けることはできません。元のソケットは開いたままで、新しい接続要求をリスニングし続けます。

パラメーター addr は結果パラメーターであり、通信層が認識している接続元エンティティのアドレスが格納されます。addr パラメーターの正確な形式は、通信が行われているアドレスファミリによって決まります。addrlen は入出力両用のパラメーターで、初期状態では addr が指す領域のサイズを格納しておく必要があり、戻り時には返されたアドレスの実際の長さ(バイト単位)が格納されます。

accept 関数は、SOCK_STREAM などのコネクション指向のソケットタイプで使用します。addraddrlenNULL の場合、受け付けたソケットのリモートアドレスに関する情報は返されません。

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

サンプルコード

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

#include <winsock2.h>
#include <WS2tcpip.h>
#include <stdio.h>
#include <windows.h>

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

int wmain(void)
{

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

    if (bind(ListenSocket,
             (SOCKADDR *) & service, sizeof (service)) == SOCKET_ERROR) {
        wprintf(L"bind failed with error: %ld\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
    //----------------------
    // Listen for incoming connection requests.
    // on the created socket
    if (listen(ListenSocket, 1) == SOCKET_ERROR) {
        wprintf(L"listen failed with error: %ld\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
    //----------------------
    // Create a SOCKET for accepting incoming requests.
    SOCKET AcceptSocket;
    wprintf(L"Waiting for client to connect...\n");

    //----------------------
    // Accept the connection.
    AcceptSocket = accept(ListenSocket, NULL, NULL);
    if (AcceptSocket == INVALID_SOCKET) {
        wprintf(L"accept failed with error: %ld\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    } else
        wprintf(L"Client connected.\n");

    // No longer need server socket
    closesocket(ListenSocket);

    WSACleanup();
    return 0;
}

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

ATM に関する注意事項

以下は接続設定に関連する重要な問題であり、Windows Sockets 2 で Asynchronous Transfer Mode(ATM)を使用する際に考慮する必要があります。

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

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

各言語での呼び出し定義

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

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

accept = ctypes.windll.ws2_32.accept
accept.restype = ctypes.c_size_t
accept.argtypes = [
    ctypes.c_size_t,  # s : SOCKET
    ctypes.c_void_p,  # addr : SOCKADDR* optional, out
    ctypes.POINTER(ctypes.c_int),  # addrlen : INT* optional, in/out
]
# GetLastError: use ctypes.GetLastError() (or ctypes.WinDLL(use_last_error=True))
require 'fiddle'
require 'fiddle/import'

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

var (
	ws2_32 = windows.NewLazySystemDLL("WS2_32.dll")
	procaccept = ws2_32.NewProc("accept")
)

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

extern "ws2_32" fn accept(
    s: usize, // SOCKET
    addr: [*c]SOCKADDR, // SOCKADDR* optional, out
    addrlen: [*c]i32 // INT* optional, in/out
) callconv(std.os.windows.WINAPI) usize;
proc accept(
    s: uint,  # SOCKET
    `addr`: ptr SOCKADDR,  # SOCKADDR* optional, out
    addrlen: ptr int32  # INT* optional, in/out
): uint {.importc: "accept", stdcall, dynlib: "WS2_32.dll".}
pragma(lib, "ws2_32");
extern(Windows)
size_t accept(
    size_t s,   // SOCKET
    SOCKADDR* addr,   // SOCKADDR* optional, out
    int* addrlen   // INT* optional, in/out
);
ccall((:accept, "WS2_32.dll"), stdcall, Csize_t,
      (Csize_t, Ptr{SOCKADDR}, Ptr{Int32}),
      s, addr, addrlen)
# s : SOCKET -> Csize_t
# addr : SOCKADDR* optional, out -> Ptr{SOCKADDR}
# addrlen : INT* optional, in/out -> Ptr{Int32}
# stdcall は 32bit のみ意味を持つ(x64 では無視)。
local ffi = require("ffi")
ffi.cdef[[
uintptr_t accept(
    uintptr_t s,
    void* addr,
    int32_t* addrlen);
]]
local ws2_32 = ffi.load("ws2_32")
-- ws2_32.accept(s, addr, addrlen)
-- s : SOCKET
-- addr : SOCKADDR* optional, out
-- addrlen : INT* optional, in/out
-- 構造体/GUIDへのポインタは cdef が通るよう void* で表記(実型は各引数コメント参照)。値渡し構造体・enum は対応する typedef を cdef に追加すること。
const koffi = require('koffi');
const lib = koffi.load('WS2_32.dll');
const accept = lib.func('__stdcall', 'accept', 'uintptr_t', ['uintptr_t', 'void *', 'int32_t *']);
// accept(s, addr, addrlen)
// s : SOCKET -> 'uintptr_t'
// addr : SOCKADDR* optional, out -> 'void *'
// addrlen : INT* optional, in/out -> 'int32_t *'
// 出力ポインタは koffi.out(...) で包む。構造体は koffi.struct で定義。
const lib = Deno.dlopen("WS2_32.dll", {
  accept: { parameters: ["usize", "pointer", "pointer"], result: "usize" },
});
// lib.symbols.accept(s, addr, addrlen)
// s : SOCKET -> "usize"
// addr : SOCKADDR* optional, out -> "pointer"
// addrlen : INT* optional, in/out -> "pointer"
// 文字列引数は "buffer"(NUL 終端のバイト列を Uint8Array で渡す)。
// 値渡し構造体は { struct: [ ...field types... ] } を使用。
<?php
$ffi = FFI::cdef(<<<C
size_t accept(
    size_t s,
    void* addr,
    int32_t* addrlen);
C, "WS2_32.dll");
// $ffi->accept(s, addr, addrlen);
// s : SOCKET
// addr : SOCKADDR* optional, out
// addrlen : INT* optional, in/out
// 構造体/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);
    long accept(
        long s,   // SOCKET
        Pointer addr,   // SOCKADDR* optional, out
        IntByReference addrlen   // INT* optional, in/out
    );
}
@[Link("ws2_32")]
lib LibWS2_32
  fun accept = accept(
    s : LibC::SizeT,   # SOCKET
    addr : SOCKADDR*,   # SOCKADDR* optional, out
    addrlen : Int32*   # INT* optional, in/out
  ) : LibC::SizeT
end
# 構造体/GUID/enum は lib 内に対応する型定義が必要。
# 呼出規約: x64 は規約統一のため OK。x86(32bit)は WINAPI=stdcall だが Crystal の fun に stdcall 付与構文がなく非対応。
import 'dart:ffi';
import 'package:ffi/ffi.dart';

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

foreign import stdcall safe "accept"
  c_accept :: CUIntPtr -> Ptr () -> Ptr Int32 -> IO CUIntPtr
-- s : SOCKET -> CUIntPtr
-- addr : SOCKADDR* optional, out -> Ptr ()
-- addrlen : INT* optional, in/out -> Ptr Int32
-- 要 GHC(Windows)。stdcall は x64 では ccall として扱われる。ブロックする API は safe 呼び出し推奨。
open Ctypes
open Foreign

let accept =
  foreign "accept"
    (size_t @-> (ptr void) @-> (ptr int32_t) @-> returning size_t)
(* s : SOCKET -> size_t *)
(* addr : SOCKADDR* optional, out -> (ptr void) *)
(* addrlen : INT* optional, in/out -> (ptr 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 ("accept" accept :convention :stdcall) :uint64
  (s :uint64)   ; SOCKET
  (addr :pointer)   ; SOCKADDR* optional, out
  (addrlen :pointer))   ; INT* optional, in/out
; isize/usize(INT_PTR/SIZE_T)は x64 前提で :int64/:uint64。x86 では :int32/:uint32。
use Win32::API;
my $accept = Win32::API::More->new('WS2_32',
    'WPARAM accept(WPARAM s, LPVOID addr, LPVOID addrlen)');
# my $ret = $accept->Call($s, $addr, $addrlen);
# s : SOCKET -> WPARAM
# addr : SOCKADDR* optional, out -> LPVOID
# addrlen : INT* optional, in/out -> LPVOID
# 値渡し構造体は pack() した文字列、または Win32::API::Struct を使用。

関連項目

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