Bagikan melalui


SIO_ACQUIRE_PORT_RESERVATION kode kontrol

Deskripsi

Kode kontrol SIO_ACQUIRE_PORT_RESERVATION memperoleh reservasi runtime untuk blok port TCP atau UDP.

Untuk melakukan operasi ini, panggil fungsi WSAIoctl atau WSPIoctl dengan parameter berikut.

int WSAIoctl(
  (socket) s,             // descriptor identifying a socket
  SIO_ACQUIRE_PORT_RESERVATION, // dwIoControlCode
  (LPVOID) lpvInBuffer,  // pointer to an INET_PORT_RANGE structure
  (DWORD) cbInBuffer,    // size, in bytes, of the input buffer
  (LPVOID) lpvOutBuffer,             // pointer to an INET_PORT_RESERVATION_INSTANCE structure
  (DWORD) cbOutBuffer,   // size, in bytes, of the output buffer
  (LPDWORD) lpcbBytesReturned,    // number of bytes returned
  (LPWSAOVERLAPPED) lpOverlapped,   // OVERLAPPED structure
  (LPWSAOVERLAPPED_COMPLETION_ROUTINE) lpCompletionRoutine,  // completion routine
);
int WSPIoctl(
  (socket) s,             // descriptor identifying a socket
  SIO_ACQUIRE_PORT_RESERVATION, // dwIoControlCode
  (LPVOID) lpvInBuffer,  // pointer to an INET_PORT_RANGE structure
  (DWORD) cbInBuffer,    // size, in bytes, of the input buffer
  (LPVOID) lpvOutBuffer,             // pointer to a INET_PORT_RESERVATION_INSTANCE structure
  (DWORD) cbOutBuffer,   // size, in bytes, of the output buffer
  (LPDWORD) lpcbBytesReturned,    // number of bytes returned
  (LPWSAOVERLAPPED) lpOverlapped,   // OVERLAPPED structure
  (LPWSAOVERLAPPED_COMPLETION_ROUTINE) lpCompletionRoutine,  // completion routine
  (LPWSATHREADID) lpThreadId,   // a WSATHREADID structure
  (LPINT) lpErrno   // a pointer to the error code.
);

Parameter

s

Deskriptor yang mengidentifikasi soket.

dwIoControlCode

Kode kontrol untuk operasi. Gunakan SIO_ACQUIRE_PORT_RESERVATION untuk operasi ini.

lpvInBuffer

Penunjuk ke buffer input. Parameter ini berisi penunjuk ke struktur INET_PORT_RANGE yang menentukan nomor titik awal dan jumlah port yang akan dicadangkan.

cbInBuffer

Ukuran, dalam byte, dari buffer input. Parameter ini harus menjadi ukuran struktur INET_PORT_RANGE .

lpvOutBuffer

Penunjuk ke buffer output. Pada output yang berhasil, parameter ini berisi penunjuk ke struktur INET_PORT_RESERVATION_INSTANCE .

cbOutBuffer

Ukuran, dalam byte, dari buffer output. Parameter ini harus setidaknya ukuran struktur INET_PORT_RESERVATION_INSTANCE .

lpcbBytesReturned

Penunjuk ke variabel yang menerima ukuran, dalam byte, dari data yang disimpan dalam buffer output.

Jika buffer output terlalu kecil, panggilan gagal, WSAGetLastError mengembalikan WSAEINVAL, dan parameter lpcbBytesReturned menunjuk ke nilai DWORD nol.

Jika lpOverlapped adalah NULL, nilai DWORD yang ditunjukkan oleh parameter lpcbBytesReturned yang dikembalikan pada panggilan yang berhasil tidak boleh nol.

Jika parameter lpOverlapped bukan NULL untuk soket yang tumpang tindih, operasi yang tidak dapat segera diselesaikan akan dimulai, dan penyelesaian akan ditunjukkan di lain waktu. Nilai DWORD yang ditunjukkan oleh parameter lpcbBytesReturned yang dikembalikan mungkin nol karena ukuran data yang disimpan tidak dapat ditentukan sampai operasi yang tumpang tindih selesai. Status penyelesaian akhir dapat diambil ketika metode penyelesaian yang sesuai disinyalkan ketika operasi telah selesai.

lpvOverlapped

Penunjuk ke struktur WSAOVERLAPPED .

Jika soket dibuat tanpa atribut yang tumpang tindih, parameter lpOverlapped diabaikan.

Jika s dibuka dengan atribut yang tumpang tindih dan parameter lpOverlapped bukan NULL, operasi dilakukan sebagai operasi yang tumpang tindih (asinkron). Dalam hal ini, parameter lpOverlapped harus menunjuk ke struktur WSAOVERLAPPED yang valid.

Untuk operasi yang tumpang tindih, fungsi WSAIoctl atau WSPIoctl segera kembali, dan metode penyelesaian yang sesuai disinyalkan ketika operasi telah selesai. Jika tidak, fungsi tidak kembali sampai operasi selesai atau terjadi kesalahan.

lpCompletionRoutine

Jenis: LPWSAOVERLAPPED_COMPLETION_ROUTINE _In_opt_

Penunjuk ke rutinitas penyelesaian yang dipanggil ketika operasi telah selesai (diabaikan untuk soket yang tidak tumpang tindih).

lpThreadId

Penunjuk ke struktur WSATHREADID yang akan digunakan oleh penyedia dalam panggilan berikutnya ke WPUQueueApc. Penyedia harus menyimpan struktur WSATHREADID yang direferensikan (bukan penunjuk ke yang sama) sampai setelah fungsi WPUQueueApc kembali.

Catatan Parameter ini hanya berlaku untuk fungsi WSPIoctl .

lpErrno

Penunjuk ke kode kesalahan.

Catatan Parameter ini hanya berlaku untuk fungsi WSPIoctl .

Nilai kembali

Jika operasi berhasil diselesaikan, fungsi WSAIoctl atau WSPIoctl mengembalikan nol.

Jika operasi gagal atau tertunda, fungsi WSAIoctl atau WSPIoctl mengembalikan SOCKET_ERROR. Untuk mendapatkan informasi kesalahan yang diperluas, hubungi WSAGetLastError.

Kode kesalahan Makna
WSA_IO_PENDING Operasi I/O yang tumpang tindih sedang berlangsung. Nilai ini dikembalikan jika operasi yang tumpang tindih berhasil dimulai dan penyelesaian akan ditunjukkan di lain waktu.
WSA_OPERATION_ABORTED Operasi I/O telah dibatalkan karena keluarnya utas atau permintaan aplikasi. Kesalahan ini dikembalikan jika operasi yang tumpang tindih dibatalkan karena penutupan soket atau eksekusi perintah SIO_FLUSH IOCTL.
WSAEFAULT Sistem mendeteksi alamat penunjuk yang tidak valid dalam mencoba menggunakan argumen pointer dalam panggilan. Kesalahan ini dikembalikan dari parameter lpvInBuffer, lpvoutBuffer, lpcbBytesReturned, lpOverlapped atau lpCompletionRoutine tidak sepenuhnya terkandung dalam bagian ruang alamat pengguna yang valid.
WSAEINPROGRESS Operasi pemblokiran saat ini sedang dijalankan. Kesalahan ini dikembalikan jika fungsi dipanggil saat panggilan balik sedang berlangsung.
WSAEINTR Operasi pemblokiran terganggu oleh panggilan ke WSACancelBlockingCall. Kesalahan ini dikembalikan jika operasi pemblokiran terganggu.
WSAEINVAL Argumen yang tidak valid disediakan. Kesalahan ini dikembalikan jika parameter dwIoControlCode bukan perintah yang valid, atau parameter input yang ditentukan tidak dapat diterima, atau perintah tidak berlaku untuk jenis soket yang ditentukan.
WSAENETDOWN Operasi soket menemukan jaringan mati. Kesalahan ini dikembalikan jika subsistem jaringan gagal.
WSAENOTSOCK Operasi dicoba pada sesuatu yang bukan soket. Kesalahan ini dikembalikan jika deskriptor s bukan soket.
WSAEOPNOTSUPP Operasi yang dicoba tidak didukung untuk jenis objek yang direferensikan. Kesalahan ini dikembalikan jika perintah IOCTL yang ditentukan tidak didukung. Kesalahan ini juga dikembalikan jika SIO_ACQUIRE_PORT_RESERVATION IOCTL tidak didukung oleh penyedia transportasi. Kesalahan ini juga dikembalikan ketika upaya untuk menggunakan SIO_ACQUIRE_PORT_RESERVATION IOCTL dibuat pada soket selain UDP atau TCP.

Keterangan

IOCTL SIO_ACQUIRE_PORT_RESERVATION didukung pada Windows Vista dan versi sistem operasi yang lebih baru.

Aplikasi dan layanan yang perlu memesan port termasuk dalam dua kategori. Kategori pertama mencakup komponen yang membutuhkan port tertentu sebagai bagian dari operasi mereka. Komponen tersebut umumnya akan lebih memilih untuk menentukan port yang diperlukan pada waktu penginstalan (misalnya dalam manifes aplikasi). Kategori kedua mencakup komponen yang memerlukan port atau blok port yang tersedia saat runtime. Kedua kategori ini sesuai dengan permintaan reservasi port tertentu dan kartubebas. Permintaan reservasi tertentu mungkin persisten atau runtime, sementara permintaan reservasi port wildcard hanya didukung saat runtime.

IOCTL SIO_ACQUIRE_PORT_RESERVATION digunakan untuk meminta reservasi runtime untuk blok port TCP atau UDP. Untuk reservasi port runtime, kumpulan port mengharuskan reservasi dikonsumsi dari proses yang soket reservasinya diberikan. Reservasi port runtime hanya berlangsung selama masa pakai soket tempat IOCTL SIO_ACQUIRE_PORT_RESERVATION dipanggil. Sebaliknya, reservasi port persisten yang dibuat menggunakan fungsi CreatePersistentTcpPortReservation atau CreatePersistentUdpPortReservation dapat dikonsumsi oleh proses apa pun dengan kemampuan untuk mendapatkan reservasi persisten.

Setelah reservasi port TCP atau UDP runtime diperoleh, aplikasi dapat meminta penetapan port dari reservasi port dengan membuka soket TCP atau UDP, lalu memanggil fungsi WSAIoctl yang menentukan SIO_ASSOCIATE_PORT_RESERVATION IOCTL dan meneruskan token reservasi sebelum mengeluarkan panggilan ke fungsi ikat pada soket.

Jika parameter lpOverlapped dan lpCompletionRoutine adalah NULL, soket dalam fungsi ini akan diperlakukan sebagai soket yang tidak tumpang tindih. Untuk parameter soket yang tidak tumpang tindih, lpOverlapped dan lpCompletionRoutine diabaikan, kecuali bahwa fungsi dapat memblokir jika soket dalam mode pemblokiran. Jika soket dalam mode non-pemblokiran, fungsi ini akan tetap memblokir karena IOCTL khusus ini tidak mendukung mode non-pemblokiran.

Untuk soket yang tumpang tindih, operasi yang tidak dapat segera diselesaikan akan dimulai, dan penyelesaian akan ditunjukkan di lain waktu.

Setiap IOCTL dapat memblokir tanpa batas waktu, tergantung pada implementasi penyedia layanan. Jika aplikasi tidak dapat mentolerir pemblokiran dalam panggilan fungsi WSAIoctl atau WSPIoctl , I/O yang tumpang tindih akan disarankan untuk IOCTL yang sangat mungkin diblokir.

IOCTL SIO_ACQUIRE_PORT_RESERVATION dapat gagal dengan WSAEINTR atau WSA_OPERATION_ABORTED dalam kasus berikut:

  • Permintaan dibatalkan oleh Manajer I/O.
  • Soket ditutup.

Contoh

Contoh berikut memperoleh reservasi port runtime, lalu membuat soket dan mengalokasikan port dari reservasi port runtime untuk soket, lalu menutup soket dan merilis reservasi port runtime.

#ifndef UNICODE
#define UNICODE
#endif

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <Windows.h.>
#include <winsock2.h>
#include <mstcpip.h>
#include <ws2ipdef.h>
#include <stdio.h>
#include <stdlib.h>

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

int wmain(int argc, WCHAR ** argv)
{

    // Declare and initialize variables

    int startPort = 0;          // host byte order
    int numPorts = 0;
    USHORT startPortns = 0;     // Network byte order

    INET_PORT_RANGE portRange = { 0 };
    INET_PORT_RESERVATION_INSTANCE portRes = { 0 };

    unsigned long status = 0;

    WSADATA wsaData = { 0 };
    int iResult = 0;

    SOCKET sock = INVALID_SOCKET;
    int iFamily = AF_INET;
    int iType = 0;
    int iProtocol = 0;

    SOCKET sockRes = INVALID_SOCKET;

    DWORD bytesReturned = 0;

    // Note that the sockaddr_in struct works only with AF_INET not AF_INET6
    // An application needs to use the sockaddr_in6 for AF_INET6
    sockaddr_in service;
    sockaddr_in sockName;
    int nameLen = sizeof (sockName);

    // Validate the parameters
    if (argc != 6) {
        wprintf
            (L"usage: %s <addressfamily> <type> <protocol> <StartingPort> <NumberOfPorts>\n",
             argv[0]);
        wprintf(L"Opens a socket for the specified family, type, & protocol\n");
        wprintf
            (L"and then acquires a runtime port reservation for the protocol specified\n");
        wprintf(L"%ws example usage\n", argv[0]);
        wprintf(L"   %ws 2 2 17 5000 20\n", argv[0]);
        wprintf(L"   where AF_INET=2 SOCK_DGRAM=2 IPPROTO_UDP=17 StartPort=5000 NumPorts=20", argv[0]);

        return 1;
    }

    iFamily = _wtoi(argv[1]);
    iType = _wtoi(argv[2]);
    iProtocol = _wtoi(argv[3]);

    startPort = _wtoi(argv[4]);
    if (startPort < 0 || startPort > 65535) {
        wprintf(L"Starting point must be either 0 or between 1 and 65,535\n");
        return 1;
    }
    startPortns = htons((USHORT) startPort);

    numPorts = _wtoi(argv[5]);
    if (numPorts < 0) {
        wprintf(L"Number of ports must be a positive number\n");
        return 1;
    }

    portRange.StartPort = startPortns;
    portRange.NumberOfPorts = (USHORT) numPorts;

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        wprintf(L"WSAStartup failed with error = %d\n", iResult);
        return 1;
    }

    sock = socket(iFamily, iType, iProtocol);
    if (sock == INVALID_SOCKET) {
        wprintf(L"socket function failed with error = %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    } else {
        wprintf(L"socket function succeeded\n");

        iResult =
            WSAIoctl(sock, SIO_ACQUIRE_PORT_RESERVATION, (LPVOID) & portRange,
                     sizeof (INET_PORT_RANGE), (LPVOID) & portRes,
                     sizeof (INET_PORT_RESERVATION_INSTANCE), &bytesReturned, NULL, NULL);
        if (iResult != 0) {
            wprintf(L"WSAIoctl(SIO_ACQUIRE_PORT_RESERVATION) failed with error = %d\n",
                    WSAGetLastError());
            closesocket(sock);
            WSACleanup();
            return 1;
        } else {
            wprintf
                (L"WSAIoctl(SIO_ACQUIRE_PORT_RESERVATION) succeeded, bytesReturned = %u\n",
                 bytesReturned);
            wprintf(L"  Starting port=%d,  Number of Ports=%d, Token=%I64d\n",
                    htons(portRes.Reservation.StartPort),
                    portRes.Reservation.NumberOfPorts, portRes.Token);

            sockRes = socket(iFamily, iType, iProtocol);
            if (sockRes == INVALID_SOCKET) {
                wprintf(L"socket function for second socket failed with error = %d\n",
                        WSAGetLastError());
                closesocket(sock);
                WSACleanup();
                return 1;
            } else {
                wprintf(L"socket function for second socket succeeded\n");

                iResult =
                    WSAIoctl(sock, SIO_ASSOCIATE_PORT_RESERVATION,
                             (LPVOID) & portRes.Token, sizeof (ULONG64), NULL, 0,
                             &bytesReturned, NULL, NULL);
                if (iResult != 0) {
                    wprintf
                        (L"WSAIoctl(SIO_ASSOCIATE_PORT_RESERVATION) failed with error = %d\n",
                         WSAGetLastError());
                } else {
                    wprintf
                        (L"WSAIoctl(SIO_ASSOCIATE_PORT_RESERVATION) succeeded, bytesReturned = %u\n",
                         bytesReturned);

                    service.sin_family = (ADDRESS_FAMILY) iFamily;
                    service.sin_addr.s_addr = INADDR_ANY;
                    service.sin_port = 0;

                    iResult = bind(sock, (SOCKADDR *) & service, sizeof (service));
                    if (iResult == SOCKET_ERROR)
                        wprintf(L"bind failed with error = %d\n", WSAGetLastError());
                    else {
                        wprintf(L"bind succeeded\n");
                        iResult = getsockname(sock, (SOCKADDR *) & sockName, &nameLen);
                        if (iResult == SOCKET_ERROR)
                            wprintf(L"getsockname failed with error = %d\n",
                                    WSAGetLastError());
                        else {
                            wprintf(L"getsockname succeeded\n");
                            wprintf(L"Port number allocated = %u\n",
                                    ntohs(sockName.sin_port));
                        }
                    }
                }
            }

            // comment out this block of code if you don't want to delete the reservation just created
            iResult =
                WSAIoctl(sock, SIO_RELEASE_PORT_RESERVATION, (LPVOID) & portRes.Token,
                         sizeof (ULONG64), NULL, 0, &bytesReturned, NULL, NULL);
            if (iResult != 0) {
                wprintf
                    (L"WSAIoctl(SIO_RELEASE_PORT_RESERVATION) failed with error = %d\n",
                     WSAGetLastError());
            } else {
                wprintf
                    (L"WSAIoctl(SIO_RELEASE_PORT_RESERVATION) succeeded, bytesReturned = %u\n",
                     bytesReturned);
            }
        }

        if (sockRes != INVALID_SOCKET) {
            iResult = closesocket(sockRes);
            if (iResult == SOCKET_ERROR) {
                wprintf(L"closesocket for second socket failed with error = %d\n",
                        WSAGetLastError());
            }
        }
        if (sock != INVALID_SOCKET) {
            iResult = closesocket(sock);
            if (iResult == SOCKET_ERROR) {
                wprintf(L"closesocket for first socket failed with error = %d\n",
                        WSAGetLastError());
            }
        }
    }

    WSACleanup();

    return 0;
}

Lihat juga

Menerima

Mengikat

CreatePersistentTcpPortReservation

CreatePersistentUdpPortReservation

DeletePersistentTcpPortReservation

DeletePersistentUdpPortReservation

INET_PORT_RANGE

INET_PORT_RESERVATION_INSTANCE

LookupPersistentTcpPortReservation

LookupPersistentUdpPortReservation

SIO_ASSOCIATE_PORT_RESERVATION

SIO_RELEASE_PORT_RESERVATION

soket

WSAGetLastError

WSAGetOverlappedResult

WSAIoctl

WSAOVERLAPPED

WSASocketA

WSASocketW