2009-08-11 19 views
5

¿Cómo se puede comunicar una aplicación de escritorio con un servicio de Windows en Vista/Windows2008/Windows7? La aplicación necesita enviar cadenas pequeñas al servicio y recibir respuestas de cadenas. Ambos están escritos en Delphi 2009. (Proporcione también un código de muestra)Delphi 2009: ¿Cómo comunicarse entre el servicio de Windows y la aplicación de escritorio en Vista?

+0

¡Es asombroso! Le hice casi la misma pregunta y también fui más humilde, pero recibí críticas en lugar de respuestas ... ;-) – PSyLoCKe

Respuesta

6

El camino a seguir es named pipes, probablemente tenga que echar un vistazo a la comunicación entre Integrity levels.

This article explora cómo hacerlo en vista. Aunque está escrito en C++, solo se trata de llamadas básicas a la API de Windows, por lo que debe traducirse lo suficientemente rápido a Delphi.

Si desea buscar más sobre este tema, esta comunicación se llama Inter Process Communication, pero un mejor término de búsqueda es IPC.

+1

¿Es esto cierto? He hecho varios servicios de Windows actuando como servidor TCP y como cliente TCP. Todos han funcionado bien como "sistema local". Siempre he creído que la restricción está en los recursos de la red (// máquina/recurso/...). –

+1

La primera afirmación es completamente falsa. Cada servicio de Windows que he escrito ha sido un daemon de red de algún tipo. La única vez que se necesitan permisos originales fue uno que también necesitaba poder mostrar la interfaz de usuario. –

+0

Sí, recuerdo mal, no está permitido crear una conexión de red a recursos externos, o tiene que ejecutarse como NetworkService. Eliminé la primera afirmación. Pero aún así, las tuberías con nombre son una mejor manera de comunicarse con su servicio (tenga problemas para localizar el artículo de compatibilidad de vista sobre IPC) –

2

No lo he probado, pero creo que podría usar tubos con nombre.

3

Echa un vistazo a las respuestas en Exchange Data between two apps across PC on LAN, que es más o menos la misma pregunta hoy en día. Las comunicaciones locales a través de TCP son estándar. Como dije en mi respuesta allí, las soluciones que usan interfaces tipo "Llamada a procedimiento remoto" funcionan bien. Utilizo RemObjects SDK para este tipo de cosas, y hace que sea fácil de expandir para controlar a través de la red si lo desea más adelante.

Ambos le permiten crear una conexión que para la mayoría de su código es "transparente", y solo llama a una interfaz que envía los datos por el cable y obtiene resultados. Luego puede programar cómo lo hace normalmente y olvidarse de los detalles de los zócalos, etc.

+1

No es necesario que un servicio tenga permisos especiales para usar la red, incluso si solo está escuchando a nivel local? –

+0

@Rob, depende de la cuenta con la que se esté ejecutando el servicio. – Kevin

+0

No he tenido problemas al utilizar RemObjects utilizando la cuenta del sistema o una cuenta de usuario. El problema se relaciona más con los derechos de los usuarios del dominio que con el acceso al socket TCP/IP que es independiente. – mj2008

5

Al usar Indy, puede crear una conexión TCP relativamente fácil entre sus aplicaciones. Especialmente si solo necesitas enviar mensajes de cadena. Para el cliente (en su caso, la aplicación de escritorio) es básicamente

var 
    Client : TIdTCPClient; 
... 
Client.Host := 'localhost'; 
Client.Port := AnyFreePortNumber; 
Client.Connect; 
Client.IOHandler.Writeln (SomeString); 
Response := Client.Readln; 
... 
Client.Disconnect; 

para el servidor (que sería el servicio en su caso)

var 
    Server : TIdTCPServer; 
    Binding : TIdSocketHandle; 
... 
Server.DefaultPort := SameFreePortNumberAsInClient; 
Binding := Server.Bindings.Add; 
Binding.IP := '127.0.0.1';  
Binding.Port := Server.DefaultPort; 
Server.OnConnect := HandleConnection; 
Server.OnDisconnect := HandleDisconnection; 
Server.OnExecute := HandleCommunication; 
Server.Active := True; 

Sólo implementar el método HandleCommunication. Se llama siempre que el cliente decide enviar algo. Ejemplo:

procedure MyClass.HandleCommunication (AContext : TIdContext); 
var 
    Request : String; 
begin 
    Request := AContext.Connection.IOHandler.Readln; 
    if (Request = Command1) then 
    HandleCommand1 
    else if (Request = Command2) then 
    HandleCommand2 
    ... 
end; 

IIRC un servicio sólo se le permite tener una interfaz gráfica de usuario o tener acceso a la red, por lo que este podría ser un problema si su servicio necesita una interfaz gráfica de usuario (que se debe evitar de todos modos, ver este question). No sé cómo se maneja esto en Windwos Vista y más tarde.

3

Tiene que cambiar el usuario del servicio de localsystem a networkservice y luego el servicio puede usar TCPIP fine. Tengo varios servicios que usan TCPIP para un enlace de control externo. Solo asegúrese de que su puerto de servicio sea configurable para que pueda manejar cualquier colisión.

Algunas de mis interfaces de control se basan en páginas XML servidas desde un servidor HTTP interno. Esto me permite verificar remotamente el estado del servicio usando cualquier navegador web que pueda llegar al puerto en esa máquina. La ventaja de utilizar HTTP sobre otros métodos es que funciona bien cuando necesita trabajar sobre hardware de red existente.

Si su ÚNICO se va a comunicar localmente, entonces las tuberías con nombre, mail slots or a memory mapped file podrían ser el mejor método.

+0

No necesita usar la cuenta NetworkService solo para usar TCP. Funciona muy bien con las cuentas LocalSystem y LocalService también. –

1

Uso en mis aplicaciones de servicio un conjunto de componentes, freeware con código fuente llamado Simple IPC.

Buscar en torry.net. Ha funcionado muy bien en todas mis aplicaciones de servicio cuando me comunico con una aplicación de escritorio.

John

Cuestiones relacionadas