Pergunta

O código a seguir não funciona corretamente no Windows (mas não em Linux):

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setblocking(True)
    sock.connect(address)
    gobject.io_add_watch(
            sock.fileno(),
            gobject.IO_OUT | gobject.IO_ERR | gobject.IO_HUP,
            callback)

Snippets de comentários em vários lugares na fonte glib, e outros lugares mencionar que no Windows, tomadas são colocadas em modo não-bloqueio durante a votação. Como resultado, o self.outgoing_cb callback é constantemente chamado, e escrita para o socket falhar com esta mensagem de erro:

[Errno 10035] A non-blocking socket operation could not be completed immediately

Chamando sock.setblocking(True) antes de escrever não parece contornar isso. Ao baixar a prioridade da votação, e ignorando a mensagem de erro, ele funciona como esperado, mas joga muito longe para muitos eventos, e consome muita CPU. Existe uma maneira de contornar esta limitação no Windows?

Atualizar

Eu poderia salientar, que todo o ponto de pesquisa para POLLOUT é que quando você faz a chamada de escrita que você não terá EAGAIN / EWOULDBLOCK. A mensagem de erro estranho que eu estou recebendo, eu acredito que seria o equivalente do Windows desses códigos de erro 2. Em outras palavras, eu estou recebendo eventos gobject.IO_OUT quando o soquete não me deixa escrever com sucesso, e colocá-lo em modo de bloqueio ainda me dá esse erro inadequada.

Outra atualização

No Linux, onde esta funciona corretamente, o soquete não está no modo sem bloqueio, e recebo IO_OUT, quando o socket vai me deixar escrever sem bloqueio ou jogando um erro. É essa funcionalidade Quero melhor emular / restauração no Windows.

Outras notas

De man poll:

   poll()  performs a similar task to select(2): it waits for one of a set
   of file descriptors to become ready to perform I/O.
          POLLOUT
                 Writing now will not block.

De man select:

A file descriptor  is considered ready if it is possible to perform the corre‐
sponding I/O operation (e.g., read(2)) without blocking.
Foi útil?

Solução

Existe um problema com fazendo non-blocking I / O? Parece meio estranho usar loops de votação se você estiver usando o bloqueio I / O.

Quando eu escrevo programas como este que tendem a fazer o seguinte:

  • Tampão os bytes que deseja enviar para o descritor de arquivo.

  • Apenas pedir IO_OUT (ou o equivalente poll(), POLLOUT) eventos quando o referido tampão é não-vazia.

  • Quando poll() (ou equivalente) tem sinalizado que você está pronto para escrever, emitir a gravação. Se você receber EAGAIN / EWOULDBLOCK, remover os bytes que você escreveu com sucesso a partir do buffer e espera para a próxima vez que você se sinalizado. Se você escreveu com sucesso todo o buffer, em seguida, parar de pedir POLLOUT para que você não spuriously acordar.

(Meu palpite é que as ligações Win32 estiver usando WSAEventSelect e WaitForMultipleObjects() para simular poll(), mas o resultado é o mesmo ...)

Eu não tenho certeza como a sua abordagem desejada com soquetes bloqueio iria funcionar. Você está "acordar" constantemente porque você pediu para acordá-lo quando você pode escrever. Você só quer especificar que quando você tem dados para escrever ... Mas então, quando você acorda, o sistema não vai realmente dizer-lhe quanto de dados você pode escrever sem bloqueio, de modo que é uma boa razão para usar non-blocking I / O.

Outras dicas

GIO contém GSocket , um "socket objeto de rede de baixo nível" desde 2,22. No entanto, este ainda está para ser portado para pygobject no Windows .

Eu não tenho certeza se isso ajuda (não estou acostumado com a função de pesquisa ou os soquetes MFC e não sei o polling é uma exigência da sua estrutura de programa), então tome isso com um grão de sal:

Mas, para evitar um bloqueio ou EAGAIN na escrita, usamos escolha, ou seja, adicionar o soquete para o conjunto de escrita que é passado para selecionar, e se select () volta com rc = 0 a tomada aceitará gravações imediatamente. ..

O ciclo de escrita que usamos em nosso aplicativo é (em pseudocódigo):

set_nonblocking.
count= 0.
do {
   FDSET writefds;
   add skt to writefds.
   call select with writefds and a reaonsable timeout.
   if (select fails with timeout) {
       die with some error;
   } 

   howmany= send(skt, buf+count, total-count).
   if (howmany>0) {
       count+= howmany.
   }
} while (howmany>0 && count<total);

Você pode usar torcida , que inclui suporte para GTK (mesmo no Windows) e irá lidar com todo o várias condições de erro que sem bloqueio soquetes no Windows gostaria de levantar.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top