通过


关闭套接字

Winsock 内核 (WSK) 应用程序使用套接字后,它应关闭套接字并释放所有关联的资源。 WSK 应用程序必须关闭所有打开的套接字,然后应用程序才能从 WSK 子系统中分离自身。 有关从 WSK 子系统分离 WSK 应用程序的详细信息,请参阅 注销 Winsock 内核应用程序

WSK 应用程序通过调用 WskCloseSocket 函数关闭套接字。 在调用 WskCloseSocket 函数之前,WSK 应用程序必须确保没有任何其他函数正在调用套接字的任何函数,包括应用程序的其他任何线程中的任何扩展函数。 但是,WSK 应用程序可以调用 WskCloseSocket ,前提是之前对套接字函数的调用中存在挂起的 IRP,但尚未完成。

WSK 应用程序用来确保在调用 WskCloseSocket 函数之前没有对套接字的任何函数进行其他函数调用的方法取决于应用程序的设计。 例如,如果 WSK 应用程序可能需要关闭一个线程中的套接字,而该套接字的其他函数在一个或多个其他线程中可能正在进行调用,则应用程序通常会使用引用计数器来跟踪套接字上当前正在进行的函数调用数。 在这种情况下,WSK 应用程序在调用套接字的函数之一之前以原子方式测试和递增套接字的引用计数器,然后在函数返回时以原子方式递减套接字的引用计数器。 当引用计数器为零时,WSK 应用程序可以安全地调用 WskCloseSocket 函数来关闭套接字。

另一方面,如果 WSK 应用程序的设计保证在应用程序调用 WskCloseSocket 函数以关闭套接字时,不会对任何其他线程中的特定套接字函数进行任何调用,则 WSK 应用程序不需要使用引用计数器来跟踪套接字上当前正在进行的函数调用数。 例如,如果 WSK 应用程序从单个线程对特定套接字执行其所有套接字操作,则应用程序可以从该线程内安全地调用 WskCloseSocket 函数,而无需引用计数器。

调用 WskCloseSocket 函数会导致 WSK 子系统取消并完成之前调用套接字函数的所有挂起的 IRP。 WSK 子系统还确保在完成关闭操作之前,任何正在进行的事件回调函数都已将控制权返回给 WSK 子系统。

下面的代码示例演示 WSK 应用程序如何关闭套接字。

// Prototype for the socket close IoCompletion routine
NTSTATUS
  CloseSocketComplete(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp,
    PVOID Context
    );

// Function to close a socket
NTSTATUS
  CloseSocket(
    PWSK_SOCKET Socket,
    PWSK_APP_SOCKET_CONTEXT SocketContext
    )
{
  PWSK_PROVIDER_BASIC_DISPATCH Dispatch;
  PIRP Irp;
  NTSTATUS Status;

  // Get pointer to the socket's provider dispatch structure
  Dispatch =
    (PWSK_PROVIDER_BASIC_DISPATCH)(Socket->Dispatch);

  // Allocate an IRP
  Irp =
    IoAllocateIrp(
      1,
      FALSE
      );

  // Check result
  if (!Irp)
  {
    // Return error
    return STATUS_INSUFFICIENT_RESOURCES;
  }

  // Set the completion routine for the IRP
  IoSetCompletionRoutine(
    Irp,
    CloseSocketComplete,
    SocketContext,
    TRUE,
    TRUE,
    TRUE
    );

  // Initiate the close operation on the socket
  Status =
    Dispatch->WskCloseSocket(
      Socket,
      Irp
      );

  // Return the status of the call to WskCloseSocket()
  return Status;
}

// Socket close IoCompletion routine
NTSTATUS
  CloseSocketComplete(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp,
    PVOID Context
    )
{
  UNREFERENCED_PARAMETER(DeviceObject);

  PWSK_APP_SOCKET_CONTEXT SocketContext;

  // Check the result of the socket close operation
  if (Irp->IoStatus.Status == STATUS_SUCCESS)
  {
    // Get the pointer to the socket context
    SocketContext =
      (PWSK_APP_SOCKET_CONTEXT)Context;

    // Perform any cleanup and/or deallocation of the socket context
    ...
  }

  // Error status
  else
  {
    // Handle error
    ...
  }

  // Free the IRP
  IoFreeIrp(Irp);

  // Always return STATUS_MORE_PROCESSING_REQUIRED to
  // terminate the completion processing of the IRP.
  return STATUS_MORE_PROCESSING_REQUIRED;
}

在 WSK 应用程序调用 WskCloseSocket 后,它不应进一步调用任何套接字的函数。

如果 WSK 应用程序关闭了以前未在两个方向断开连接的面向连接的套接字,则 WSK 子系统会在关闭套接字之前自动执行套接字的中止断开连接。 有关断开套接字连接的详细信息,请参阅 断开与目标的套接字的连接