2012-02-20 10 views
5

Estoy usando process-send-string para enviar datos a una conexión de socket, pero no estoy satisfecho con el efecto de esta función. Aproximadamente, llamando al (process-send-string "foo") puede terminar enviando "bar" y luego "foo", como se explica a continuación.escribiendo atómicamente en un socket

Como ha señalado mantenedores de Emacs, el código C de process-send-string llama a una función wait_reading_process_output (incluso antes de escribir realmente nada), que puede ejecutar temporizadores, que a su vez pueden llamar process-send-string, y ningún pedido está forzada entre dichas llamadas anidadas.

Esto hace que sea prácticamente imposible implementar un protocolo RPC que esté destinado a ser utilizado por ganchos llamados en momentos no controlados. Entonces mi pregunta es, ¿cómo podríamos lograr una primitiva de escritura atómica, "sincronizada" para este propósito?

+1

¿De verdad experimentaste ese efecto? Echando un vistazo al código fuente de Emacs, parece que el caso que describe podría surgir cuando los datos no se pueden escribir en el socket en un lote, pero requiere varias llamadas a 'sendto '. Después de cada una de estas llamadas, se llama a 'wait_reading_process_output 'para manejar los eventos del teclado y volver a mostrarlos. No me queda claro cómo los temporizadores utilizados en esa función podrían llamar 'process-send-string 'nuevamente. – Thomas

+0

Sí, he visto lo siguiente: enviando m1, m2, m3, el extremo de conexión recibe m2, m3, m1. –

+0

Tenga en cuenta que TCP está orientado a bytes, no orientado a paquetes. Si la aplicación escribe "1234", la pila TCP puede enviar esto en cualquier segmentación posible, por ejemplo, "12", "3", "4". Si desea ejecutar un protocolo por encima de TCP, debe encontrar definir una forma de encontrar los límites de sus mensajes, por ej. usando un campo de longitud. – bew

Respuesta

1

Finalmente, una opción que funcionó para mí fue utilizar la API de cola de transacciones, que es de nivel superior (por lo que no puede manejar todo tipo de protocolos), pero asegura el orden correcto de los mensajes alternativos.

2

En lugar de usar process-send-string directamente en sus hooks, anexar a un búfer, luego hacer que las llamadas a process-send-string se ejecuten de una manera que no sea asincrónica.

+1

"hacer que las llamadas process-send-string se ejecuten de una manera que no sea asincrónica" ¿cómo? –

3

Se podría hacer algo como:

(defun my-send-cmd (proc str) 
    (if (process-get proc 'my-waiting) 
     (process-put proc 'my-pending (append (process-get proc 'my-pending) (list str))) 
    (process-put proc 'my-waiting t) 
    (process-send-string proc str))) 

a continuación en el proceso de filtro, cuando llegue la respuesta a un comando, compruebe `mi-pendiente' y si no nula, tomar el primer argumento, enviarlo al proceso; de lo contrario, establecer my-waiting en cero. Por supuesto, esto supone que cada comando recibirá una respuesta del servidor y que no puede transmitir los comandos.

Dicho esto, el comportamiento que veas probablemente debería contar como un error, o al menos como un error, así que infórmalo con M-x report-emacs-bug.

+0

Esto parece funcionar: la comunicación de protocolo todavía funciona y no puedo observar (las consecuencias de) un intercambio de mensajes, así que supongo que acabas de salvarme la vida resolviendo este gran problema a la hora del lanzamiento :-) –

+0

La idea de Usar el filtro de proceso como un "hilo de envío" era lo que me faltaba, y funciona bien aquí ya que siempre tengo mensajes alternos. –

+0

Y sobre un informe de error, envié uno, obtuve algunos comentarios cortos, pero todavía no estoy seguro si se lo considera un error, un error o ninguno. Me aseguraré de obtener una respuesta clara. –

Cuestiones relacionadas