Windows - Tunggu acara dan soket secara bersamaan

Saya sedang menulis kode Win32-API C yang perlu menunggu koneksi TCP baru dan di sisi lain dapat ditutup kapan saja oleh proses/utas lainnya.

Oleh karena itu, saya perlu WaitForSingleObject pada acara stop dan menunggu koneksi menggunakan WSAaccept secara bersamaan.

Saya mencoba WaitForMultipleObjects pada soket dan pegangan tetapi koneksi baru tidak akan memicu fungsi tersebut (juga WaitForSingleObject pada soket tidak akan dipicu pada koneksi baru).

Ada ide?


person CodeNinja    schedule 19.01.2017    source sumber
comment
Anda perlu menggunakan AcceptEx sebagai gantinya WSAAccept - api ini tidak sinkron. Anda tidak perlu menunggu sama sekali. jika Anda mengikat soket Anda (param kedua) ke IOCP - Anda mendapat panggilan balik ketika koneksi selesai   -  person RbMm    schedule 19.01.2017


Jawaban (2)


Anda perlu menggunakan WSAWaitForMultipleEvents. Untuk soket, berikut beberapa kode semu:

HANDLE hEvent[1];
hEvent[0] = WSACreateEvent();
WSAEventSelect(hSocket, hEvent[0], FD_READ | FD_WRITE);

while (WSAWaitForMultipleEvents(...)) {
    if (WSAEnumNetworkEvents(...)) { // Multiple events max exist
        if (... & FD_ACCEPT) {
        }
        if (... & FD_WRITE) {
        }
        ....
    }
}

Jika Anda menggunakan beberapa peristiwa (misalnya peristiwa berhenti untuk memberi sinyal agar thread berhenti), gunakan nilai kembalian dari WSAWaitForMultipleEvents untuk menentukan peristiwa yang diberi sinyal (seperti yang Anda lakukan dengan WaitForMultipleObjects).

person Ton Plooij    schedule 19.01.2017
comment
Ini hanya memungkinkan Anda menunggu pada acara soket WSA, bukan objek acara Win32 standar, jadi Anda harus menggunakan acara soket WSA untuk acara penghentian, lalu Anda dapat menunggu semua acara bersama dengan WSAWaitForMultipleEvents(). Jika Anda ingin menggunakan objek acara standar untuk acara penghentian, maka Anda harus menggunakan I/O atau IOCP yang tumpang tindih untuk operasi soket (AcceptEx(), WSARecv(), WSASend(), dll) sehingga Anda dapat menetapkan objek acara standar untuk setiap operasi, dan maka Anda dapat menggunakan WaitForMultipleObjects(). - person Remy Lebeau; 20.01.2017
comment
Array peristiwa untuk WSAWaitForMultipleEvents dapat menangani beberapa tipe ('Array dapat berisi pegangan objek dari tipe berbeda' adalah apa yang dikatakan dalam dokumentasi). Dokumentasi WSACreateEvent menambahkan: 'jika aplikasi Windows ingin menggunakan event auto-reset daripada event manual-reset, aplikasi dapat memanggil fungsi CreateEvent secara langsung'. - person Ton Plooij; 20.01.2017

Anda tidak dapat menunggu gagang soket secara langsung.

WSAAccept() sinkron, satu-satunya cara untuk membatalkannya adalah dengan menutup soket pendengaran.

Untuk apa yang ingin Anda lakukan, gunakan AcceptEx() sebagai gantinya, yang tidak sinkron dan mendukung Port Penyelesaian I/O dan I/O yang Tumpang Tindih.

Jika Anda menggunakan I/O yang Tumpang Tindih, Anda dapat mengaitkan objek peristiwa Win32 standar ke setiap operasi soket berkemampuan I/O yang Tumpang Tindih (AcceptEx(), WSARecv(), WSASend(), dll), dan menggunakan objek peristiwa Win32 standar untuk peristiwa penghentian Anda. Dan kemudian Anda dapat menggunakan loop WaitForMultipleObjects() untuk mengetahui peristiwa mana yang diberi sinyal dan bertindak sesuai dengan itu.

Jika Anda menggunakan Port Penyelesaian I/O, Anda tidak memerlukan objek acara sama sekali. Anda dapat mengaitkan setiap soket dengan satu antrean IOCP, dan pengendali IOCP Anda (baik panggilan ke GetQueuedCompletionStatus() atau fungsi panggilan balik) akan diberi tahu setiap kali setiap operasi soket berkemampuan IOCP selesai. Anda kemudian dapat menggunakan PostQueuedCompletionStatus() untuk mengirim pesan berhenti khusus ke antrian IOCP. Pengendali IOCP Anda dapat bertindak sesuai dengan jenis kejadian yang diterimanya.

person Remy Lebeau    schedule 19.01.2017
comment
use PostQueuedCompletionStatus() to post a custom stop message to the IOCP queue - kita dapat mengikat soket ke antrian yang ditangani sistem dengan BindIoCompletionCallback atau CreateThreadpoolIo - antrian ini tidak perlu berhenti dan memiliki pengendali sendiri. namun jika menggunakan IOCP yang dibuat sendiri - beberapa thread yang berfungsi perlu dibuat untuk menangani IOCP ini (jumlah thread biasa == jumlah prosesor) - jadi perlu memanggil PostQueuedCompletionStatus tidak hanya sekali, tetapi beberapa kali thread - untuk memberi tahu setiap thread agar berhenti. - person RbMm; 20.01.2017