Я программист Linux и недавно участвовал в переносе клиента на основе epoll с двумя файловыми дескрипторами, написанными на c, в Windows.
Как вы знаете, в Linux используется epoll или select (я знаю, что Windows поддерживает select, но это неэффективно при все) вы можете блокировать файловые дескрипторы до тех пор, пока файловый дескриптор не будет готов, и вы сможете узнать, когда он будет готов для записи и когда он будет прочитан.
Я взглянул на Windows IOCP, и это звучит нормально для перекрывающихся операций ввода-вывода в мире Microsoft. Но во всех примерах для многоклиентского сервера используется независимость сокета каждого клиента от других сокетов.
используя порты завершения, это можно сделать, создав структуру completeKey для каждого клиента и поместив переменную в структуру и сделав ее читаемой при вызове WSArecv и wirt, когда WSAsend и другая переменная, указывающая значение сокета и извлекающая их из GetQueuedCompletionStatus, чтобы знать, что делать, если для сокета выполняется запись, выполните чтение и наоборот.
Но в моем случае файловые дескрипторы (fd) действительно перекрываются. чтение из одного fd приводит к чтению и записи в другой fd, и это затрудняет понимание того, какая операция действительно произошла для каждого fd в результате GetQueuedCompletionStatus, потому что для каждого fd связан один ключ завершения. чтобы быть ясным, рассмотрите это, пожалуйста:
Существует два дескриптора, называемых fd1 и fd2, и завершениеKey1 содержит дескриптор и статус для f1 и завершениеKey2 для fd2, а переменная completeKey предназначена для получения завершения из GetQueuedCompletionStatus.
GetQueuedCompletionStatus(port_handle, &completionKey.bufflen, (PULONG_PTR)&completionKey,(LPOVERLAPPED *)&ovl,INFINITE);
switch (completionKey.status)
{
case READ:
if(completionKey->handle == fd1)
{
fd1_read_is_done(completionKey.buffer,completionKey.bufflen);
completionKey->status = WRITE;
do_fd1_write(completionKey);
completionKey2->status = WRITE;
completionKey2->buffer = "somedata";
do_fd2_write(completionKey2);
}
else if(completionKey->handle == fd2)
{
fd2_read_is_done(completionKey.buffer,completionKey.bufflen);
completionKey->status = WRITE;
do_fd2_write(completionKey);
completionKey1->status = WRITE;
completionKey1->buffer = "somedata";
do_fd1_write(completionKey1);
}
break;
case WRITE_EVENT:
if(completionKey->handle == fd1)
{
fd1_write_is_done(completionKey.bufflen);
completionKey->status = READ;
do_fd1_read(completionKey);
completionKey2->status = READ;
do_fd2_read(completionKey2);
}
else if(completionKey->handle == fd2)
{
fd2_write_is_done(completionKey.bufflen);
completionKey->status = READ;
do_fd2_read(completionKey);
completionKey1->status = READ;
do_fd1_read(completionKey1);
}
break;
}
в приведенном выше коде возникает ситуация, когда некоторые из измененных ключей завершения будут переопределять ожидающие чтения или записи, и полученный статус завершения-> будет неправильным (например, он будет сообщать о чтении вместо записи), и в худшем случае буфер будет переопределен. если я использую блокировку для завершенияKeys, это приведет к ситуациям взаимоблокировки.
Посмотрев на WSAsend или WSArecv, заметил, что для каждой отправки или получения можно установить параметр перекрытия. но это приводит к двум основным проблемам. согласно структуре WSAOVERLAPPED:
typedef struct _WSAOVERLAPPED {
ULONG_PTR Internal;
ULONG_PTR InternalHigh;
union {
struct {
DWORD Offset;
DWORD OffsetHigh;
};
PVOID Pointer;
};
HANDLE hEvent;
} WSAOVERLAPPED, *LPWSAOVERLAPPED;
Во-первых, в нем нет места для размещения статуса и соответствующего буфера, и большинство из них зарезервированы.
Во-вторых, если бы я мог решить первую проблему, мне нужно проверить, нет ли доступных перекрывающихся левых, и все ли они используются в ожидающих операциях, выделить новый для каждого чтения и записи, и из-за клиента будет так заняты, это может происходить часто, и, кроме того, управление этими перекрывающимися пулами — головная боль. так я что-то пропустил, или майкрософт напортачил?
И поскольку мне не нужна многопоточность, есть ли другой способ решить мою проблему?
заранее спасибо
Изменить
Как я уже догадался, первая проблема, которую я упомянул в использовании перекрывающейся структуры, имеет решение, и мне нужно просто создать еще одну структуру со всеми буферами, статусом и т. д. и поместите OVERLAPPED в качестве первого файла. теперь ты решаешь мне другие ;)