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

closesocket

関数
ソケットを閉じてリソースを解放する。
DLLWS2_32.dll呼出規約winapiSetLastErrorあり対応OSWindows 8.1 以降

シグネチャ

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

INT closesocket(
    SOCKET s
);

パラメーター

名前方向説明
sSOCKETinクローズする socket を識別する記述子。

戻り値の型: INT

公式ドキュメント

closesocket 関数 (winsock.h) は、既存の socket をクローズします。

戻り値

エラーが発生しなかった場合、 closesocket は 0 を返します。それ以外の場合は SOCKET_ERROR が返され、 WSAGetLastError を呼び出すことで特定のエラーコードを取得できます。

エラーコード 意味
WSANOTINITIALISED
この関数を使用する前に、 WSAStartup の呼び出しが成功している必要があります。
WSAENETDOWN
ネットワークサブシステムが失敗しました。
WSAENOTSOCK
記述子が socket ではありません。
WSAEINPROGRESS
ブロッキングの Windows Sockets 1.1 呼び出しが進行中であるか、サービスプロバイダーがまだコールバック関数を処理しています。
WSAEINTR
(ブロッキングの)Windows Socket 1.1 呼び出しが WSACancelBlockingCall によってキャンセルされました。
WSAEWOULDBLOCK
socket が非ブロッキングとしてマークされていますが、linger 構造体の l_onoff メンバーが 0 以外に設定され、かつ linger 構造体の l_linger メンバーが 0 以外のタイムアウト値に設定されています。

解説(Remarks)

closesocket 関数は socket をクローズします。s パラメーターで渡された socket 記述子を解放するために使用します。s パラメーターで渡された socket 記述子は、closesocket 関数が発行された直後にシステムによって再利用される可能性があることに注意してください。そのため、s パラメーターで渡された socket 記述子への以降の参照が WSAENOTSOCK エラーで失敗することを期待するのは確実ではありません。Winsock クライアントは、別の Winsock 関数呼び出しと同時に s に対して closesocket を発行してはなりません。

このプロセス内の任意のスレッドが発行した、保留中のオーバーラップ送受信操作( WSASend/ WSASendTo/ WSARecv/ オーバーラップ socket に対する WSARecvFrom)も同様にキャンセルされます。これらのオーバーラップ操作に指定されたイベント、完了ルーチン、または完了ポートアクションは実行されます。保留中のオーバーラップ操作は、エラーステータス WSA_OPERATION_ABORTED で失敗します。

アプリケーションは、closesocket が返ったときに socket 上の未完了の I/O 操作がすべて完了することが保証されると想定すべきではありません。closesocket 関数は未完了の I/O 操作のキャンセルを開始しますが、それは closesocket 関数が返るまでにアプリケーションがこれらの I/O 操作の I/O 完了を受け取ることを意味しません。したがって、アプリケーションは、未完了の I/O 要求が実際に完了するまで、それらの I/O 要求が参照するリソース(例えば WSAOVERLAPPED 構造体)をクリーンアップすべきではありません。

アプリケーションは、socket リソースをシステムに返却するために、成功した socket の呼び出しごとに、対応する closesocket の呼び出しを常に行う必要があります。

linger 構造体は、送信のためにデータがキューに入れられた状態でその socket に対して closesocket 関数が呼び出されたときに、その socket がどのように動作すべきかを指定する、特定の socket に関する情報を保持します。

linger 構造体の l_onoff メンバーは、キューに入れられたデータを送信できるように、 closesocket 関数呼び出しの後で socket を指定された時間だけ開いたままにすべきかどうかを決定します。このメンバーは次の 2 つの方法で変更できます。

linger 構造体の l_linger メンバーは、socket を開いたままにしておく時間(秒単位)を決定します。このメンバーは、linger 構造体の l_onoff メンバーが 0 以外の場合にのみ適用されます。

socket の既定のパラメーターでは、linger 構造体の l_onoff メンバーは 0 であり、socket を開いたままにすべきでないことを示します。linger 構造体の l_linger メンバーの既定値は 0 ですが、この値は l_onoff メンバーが 0 に設定されている場合には無視されます。

socket を開いたままにできるようにするには、アプリケーションは l_onoff メンバーを 0 以外の値に設定し、l_linger メンバーを希望するタイムアウト(秒単位)に設定する必要があります。socket が開いたままにならないようにするには、アプリケーションは linger 構造体の l_onoff メンバーを 0 に設定するだけで済みます。

アプリケーションが setsockopt 関数を optname パラメーターに SO_DONTLINGER を設定して呼び出し、l_onoff メンバーを 0 以外の値に設定する場合、l_linger メンバーの値は指定されません。この場合、使用されるタイムアウトは実装依存です。socket に対して以前にタイムアウトが設定されていた場合(以前に setsockopt 関数を optname パラメーターに SO_LINGER を設定して呼び出した場合)、このタイムアウト値はサービスプロバイダーによって復元されます。

closesocket 関数のセマンティクスは、linger 構造体のメンバーを設定する socket オプションの影響を受けます。

l_onoff l_linger クローズの種類 クローズを待つか?
0 関係なし グレースフルクローズ いいえ
0 以外 0 ハード いいえ
0 以外 0 以外 l_linger メンバーで指定されたタイムアウト値以内にすべてのデータが送信された場合はグレースフル。

l_linger メンバーで指定されたタイムアウト値以内にすべてのデータを送信できなかった場合はハード。

はい

ストリーム socket で LINGER 構造体の l_onoff メンバーが 0 の場合、 closesocket 呼び出しは即座に返り、socket がブロッキングか非ブロッキングかにかかわらず WSAEWOULDBLOCK を受け取りません。ただし、送信のためにキューに入れられたデータは、可能であれば、基盤となる socket がクローズされる前に送信されます。これはグレースフル切断またはクローズとも呼ばれます。この場合、Windows Sockets プロバイダーは socket とその他のリソースを任意の期間にわたって解放できないため、利用可能なすべての socket を使用しようとするアプリケーションに影響を与えます。これは socket の既定の動作です。

linger 構造体の l_onoff メンバーが 0 以外で l_linger メンバーが 0 の場合、キューに入れられたデータがまだ送信または確認応答されていなくても closesocket はブロックされません。これはハードクローズまたはアボーティブクローズと呼ばれます。なぜなら、socket の仮想回線が即座にリセットされ、未送信のデータはすべて失われるからです。Windows では、回線のリモート側での recv 呼び出しはすべて WSAECONNRESET で失敗します。

ブロッキング socket で linger 構造体の l_onoff メンバーが 0 以外に設定され、l_linger メンバーが 0 以外のタイムアウトに設定されている場合、 closesocket 呼び出しは残りのデータが送信されるか、タイムアウトが切れるまでブロックします。l_linger メンバーで指定されたタイムアウト値以内にすべてのデータが送信された場合、これはグレースフル切断またはクローズと呼ばれます。すべてのデータが送信される前にタイムアウトが切れた場合、Windows Sockets 実装は closesocket が返る前に接続を終了し、これはハードクローズまたはアボーティブクローズと呼ばれます。

非ブロッキング socket で linger 構造体の l_onoff メンバーを 0 以外に設定し、l_linger メンバーを 0 以外のタイムアウト間隔に設定することは推奨されません。この場合、クローズ操作を即座に完了できないと、 closesocket の呼び出しは WSAEWOULDBLOCK エラーで失敗します。 closesocketWSAEWOULDBLOCK で失敗した場合、socket ハンドルは依然として有効であり、切断は開始されません。アプリケーションは socket をクローズするために再度 closesocket を呼び出す必要があります。

ブロッキング socket で linger 構造体の l_onoff メンバーが 0 以外で l_linger メンバーが 0 以外のタイムアウト間隔の場合、closesocket 関数の結果を使用してすべてのデータがピアに送信されたかどうかを判断することはできません。l_linger メンバーで指定されたタイムアウトが切れる前にデータが送信された場合、または接続が中止された場合、closesocket 関数はエラーコードを返しません(closesocket 関数の戻り値は 0 です)。

closesocket 呼び出しは、すべてのデータがピアに配信されるか、タイムアウトが切れるまでのみブロックします。タイムアウトが切れたために接続がリセットされた場合、socket は TIME_WAIT 状態にはなりません。タイムアウト期間内にすべてのデータが送信された場合、socket は TIME_WAIT 状態になることがあります。

ブロッキング socket で linger 構造体の l_onoff メンバーが 0 以外で l_linger メンバーが 0 のタイムアウト間隔の場合、closesocket の呼び出しは接続をリセットします。socket は TIME_WAIT 状態にはなりません。

getsockopt 関数を optname パラメーターに SO_LINGER を設定して呼び出すことで、socket に関連付けられた linger 構造体の現在の値を取得できます。

注意 接続上ですべてのデータが送受信されることを保証するには、アプリケーションは closesocket を呼び出す前に shutdown を呼び出す必要があります(詳細については Graceful shutdown, linger options, and socket closure を参照してください)。また、 closesocket が呼び出された後に FD_CLOSE ネットワークイベントが通知されないことにも注意してください。

closesocket の動作の概要は次のとおりです。

詳細については Graceful Shutdown, Linger Options, and Socket Closure を参照してください。

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

IrDA socket に関する注意

次の点に留意してください。

ATM に関する注意

非同期転送モード(ATM)と Windows Sockets 2 を使用する場合の接続切断に関連する重要な問題は次のとおりです。

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

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>

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

closesocket = ctypes.windll.ws2_32.closesocket
closesocket.restype = ctypes.c_int
closesocket.argtypes = [
    ctypes.c_size_t,  # s : SOCKET
]
# GetLastError: use ctypes.GetLastError() (or ctypes.WinDLL(use_last_error=True))
require 'fiddle'
require 'fiddle/import'

lib = Fiddle.dlopen('WS2_32.dll')
closesocket = Fiddle::Function.new(
  lib['closesocket'],
  [
    Fiddle::TYPE_UINTPTR_T,  # s : SOCKET
  ],
  Fiddle::TYPE_INT)
#[link(name = "ws2_32")]
extern "system" {
    fn closesocket(
        s: usize  // SOCKET
    ) -> i32;
}
// crates: windows-sys provides ready-made bindings for this API.
$sig = @"
[DllImport("WS2_32.dll", SetLastError = true)]
public static extern int closesocket(UIntPtr s);
"@
$api = Add-Type -MemberDefinition $sig -Name 'WS2_32_closesocket' -Namespace Win32 -PassThru
# $api::closesocket(s)
#uselib "WS2_32.dll"
#func global closesocket "closesocket" sptr
; closesocket s   ; 戻り値は stat
; s : SOCKET -> "sptr"
; ※HSP3.7は #func のため戻り値はシステム変数 stat に格納されます。
#uselib "WS2_32.dll"
#cfunc global closesocket "closesocket" sptr
; res = closesocket(s)
; s : SOCKET -> "sptr"
; INT closesocket(SOCKET s)
#uselib "WS2_32.dll"
#cfunc global closesocket "closesocket" intptr
; res = closesocket(s)
; s : SOCKET -> "intptr"
import (
	"golang.org/x/sys/windows"
	"unsafe"
)

var (
	ws2_32 = windows.NewLazySystemDLL("WS2_32.dll")
	procclosesocket = ws2_32.NewProc("closesocket")
)

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

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

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

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

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

関連項目

公式の関連項目